Linker and Libraries Guide

Localizing Symbol Instances

Multiply defined symbols of the same name that provide different implementations, should be isolated to avoid accidental interposition. The simplest way to remove a symbol from the interfaces that are exported by an object, is to reduce the symbol to local. Demoting a symbol to local can be achieved by defining the symbol “static”, or possibly through the use of symbol attributes provided by the compilers.

A symbol can also be reduced to local by using the link-editor and a mapfile. The following example shows a mapfile that reduces the global function error() to a local symbol by using the local scoping directive.


$ cc -o A.so.1 -G -Kpic error.c a.c b.c ...
$ elfdump -sN.symtab A.so.1 | fgrep error
    [36]  0x000002d0 0x00000014  FUNC GLOB  D    0 .text      error
$ cat mapfile
$mapfile_version 2
SYMBOL_SCOPE {
        local:
                error;
};
$ cc -o A.so.2 -G -Kpic -M mapfile error.c a.c b.c ...
$ elfdump -sN.symtab A.so.2 | fgrep error
    [24]  0x000002c8 0x00000014  FUNC LOCL  H    0 .text      error

Although individual symbols can be reduced to locals using explicit mapfile definitions, defining the entire interface family through symbol versioning is recommended. See Chapter 5, Application Binary Interfaces and Versioning.

Versioning is a useful technique typically employed to identify the interfaces that are exported from shared objects. Similarly, dynamic executables can be versioned to define their exported interfaces. A dynamic executable need only export the interfaces that must be made available for the dependencies of the object to bind to. Frequently, the code that you add to a dynamic executable need export no interfaces.

The removal of exported interfaces from a dynamic executable should take into account any symbol definitions that have been established by the compiler drivers. These definitions originate from auxiliary files that the compiler drivers add to the final link-edit. See Using a Compiler Driver.

The following example mapfile exports a common set of symbol definitions that a compiler driver might establish, while demoting all other global definitions to local.


$ cat mapfile
$mapfile_version 2
SYMBOL_SCOPE {
        global:
                __Argv;
                __environ_lock;
                _environ;
                _lib_version;
                environ;
        local:
                *;
};

You should determine the symbol definitions that your compiler driver establishes. Any of these definitions that are used within the dynamic executable should remain global.

By removing any exported interfaces from a dynamic executable, the executable is protected from future interposition issues than might occur as the objects dependencies evolve.