Go to main content

Oracle® Solaris 11.4 Linkers and Libraries Guide

Exit Print View

Updated: March 2019
 
 

Enabling Direct Binding

An object that uses direct bindings maintains the relationship between a symbol reference and the dependency that provided the definition. The runtime linker uses this information to search directly for the symbol in the associated object, rather than carry out the default symbol search model.

Direct binding information for a dynamic object is recorded at link-edit time. This information can only be established for the dependencies that are specified with the link-edit of that object. Use the –z defs option to ensure that all of the necessary dependencies are provided as part of the link-edit.

Objects that use direct bindings can exist within a process with objects that do not use direct bindings. Those objects that do not use direct bindings use the default symbol search model.

The direct binding of a symbol reference to a symbol definition can be established with one of the following link-editing mechanisms.

  • With the –B direct option. This option establishes direct bindings between the object being built and all of the objects dependencies. This option also establishes direct bindings between any symbol reference and symbol definition within the object being built.

    The use of the –B direct option also enables lazy loading. This enabling is equivalent to adding the –z lazyload option to the front of the link-edit command line. This attribute was introduced in Lazy Loading of Dynamic Dependencies.

  • With the –z direct option. This option establishes direct bindings from the object being built to any dependencies that follow the option on the command line. This option can be used together with the –z nodirect option to toggle the use of direct bindings between dependencies. This option does not establish direct bindings between any symbol reference and symbol definition within the object being built.

  • With the DIRECT mapfile keyword. This keyword provides for directly binding individual symbols. This keyword is described in SYMBOL_SCOPE and SYMBOL_VERSION Directives.


Note -  Direct bindings can be disabled at runtime by setting the environment variable LD_NODIRECT to a non-null value. By setting this environment variable, all symbol binding within a process is carried out using the default search model.

The following sections describe the use of each of the direct binding mechanisms.

Using the –B direct Option

The –B direct option provides the simplest mechanism of enabling direct binding for any dynamic object. This option establishes direct bindings to any dependencies, and within the object being built.

From the components used in the previous example, a directly bound object, W.so.2, can be produced.

$ cc -o W.so.2 -G -Kpic W.c -R. -B direct w.so.1
$ cc -o prog2 -R. main.c W.so.2 X.so.1

The direct binding information is maintained in a symbol information section, .SUNW_syminfo, within W.so.2. This section can be viewed with elfdump(1).

$ elfdump -y W.so.2
     [6]  [ DEPEND DIRECT ]              <self>         a
     [7]  [ DEPEND LAZY DIRECT ]     [1] w.so.1         b

"DIRECT" indicates a direct binding has been recorded for the associated symbol. The function a() has been bound to the containing object W.so.2. The function b() has been bound directly to the dependency w.so.1. "LAZY" indicates that the dependency w.so.1 should also be lazily loaded.

The direct bindings that are established for W.so.2 can be observed using the LD_DEBUG environment variable. The detail token adds additional information to the binding diagnostics. For W.so.2, this token indicates the direct nature of the binding. The detail token also provides additional information about the binding addresses. For simplification, this address information has been omitted from the output generated from the following examples.

$ LD_DEBUG=symbols,bindings,detail  prog2
....
18452: symbol=a;  lookup in file=./W.so.2  [ ELF ]
18452: binding file=./W.so.2 to file=./W.so.2: symbol 'a'  (direct)
18452: symbol=b;  lookup in file=./w.so.1  [ ELF ]
18452: binding file=./W.so.2 to file=./w.so.1: symbol 'b'  (direct)

The lari(1) utility can also reveal the direct binding information.

$ lari prog2
[2:2ESD]: a(): ./W.so.2
[2:0]: a(): ./X.so.1
[2:2ED]: b(): ./w.so.1
[2:0]: b(): ./x.so.1

The letter "D" indicates that the function a() defined by W.so.2 has been bound to directly. Similarly, the function b() defined in w.so.1 has been bound to directly.


Note -  The direct binding of W.so.2 to W.so.2 for the function a() results in a similar effect as would be created had the –B symbolic option been used to build W.so.2. However, the –B symbolic option causes references such as a(), that can be resolved internally, to be finalized at link-edit time. This symbol resolution leaves no binding to resolve at runtime.

Unlike –B symbolic bindings, a –B direct binding is left for resolution at runtime. Therefore, this binding can be overridden by explicit interposition, or disabled by setting the environment variable LD_NODIRECT to a non-null value.

Symbolic bindings have often been employed to reduce the runtime relocation overhead incurred when loading complex objects. Direct bindings can be used to establish exactly the same symbol bindings. However, a runtime relocation is still required to create each direct binding. Direct bindings require more overhead than symbolic bindings, but provide for greater flexibility.


Using the –z direct Option

The –z direct option provides a mechanism of establishing direct bindings to any dependencies that follow the option on the link-edit command line. Unlike the –B direct option, no direct bindings are established within the object that is being built.

This option is well suited for building objects that are designed to be interposed upon. For example, shared objects are sometimes designed that contain a number of default, or fallback, interfaces. Applications are free to define their own definitions of these interfaces with the intent that the application definitions are bound to at runtime. To allow an application to interpose on the interfaces of a shared object, build the shared object using the –z direct option rather than the –B direct option.

The –z direct option is also useful if you want to be selective over directly binding to one or more dependencies. The –z nodirect option allows you to toggle the use of direct bindings between the dependencies supplied with a link-edit.

From the components used in the previous example, a directly bound object X.so.2 can be produced.

$ cc -o X.so.2 -G -Kpic X.c -R. -z direct x.so.1
$ cc -o prog3 -R. main.c W.so.2 X.so.2

The direct binding information can be viewed with elfdump(1).

$ elfdump -y X.so.2
     [6]  [ DEPEND ]                 <self>         a
     [7]  [ DEPEND DIRECT ]      [1] x.so.1         b

The function b() has been bound directly to the dependency x.so.1. The function a()is defined as having a potential direct binding, "D", with the object X.so.2, but no direct binding is established.

The LD_DEBUG environment variable can be used to observe the runtime bindings.

$ LD_DEBUG=symbols,bindings,detail  prog3
....
06177: symbol=a;  lookup in file=prog3  [ ELF ]
06177: symbol=a;  lookup in file=./W.so.2  [ ELF ]
06177: binding file=./X.so.2 to file=./W.so.2: symbol 'a'
06177: symbol=b;  lookup in file=./x.so.1  [ ELF ]
06177: binding file=./X.so.2 to file=./x.so.1: symbol 'b'  (direct)

The lari(1) utility can also reveal the direct binding information.

$ lari prog3
[2:2ESD]: a(): ./W.so.2
[2:0]: a(): ./X.so.2
[2:1ED]: b(): ./w.so.1
[2:1ED]: b(): ./x.so.1

The function a() defined by W.so.2 continues to satisfy the default symbol reference made by X.so.2. However, the function b() defined in x.so.1 has now been bound to directly from the reference made by X.so.2.

Using the DIRECT mapfile Keyword

The DIRECT mapfile keyword provides a means of establishing a direct binding for individual symbols. This mechanism is intended for specialized link-editing scenarios.

From the components used in the previous example, the function main() references the external functions W() and X(). The binding of these functions follow the default search model.

$ LD_DEBUG=symbols,bindings  prog3
....
18754: symbol=W;  lookup in file=prog3  [ ELF ]
18754: symbol=W;  lookup in file=./W.so.2  [ ELF ]
18754: binding file=prog3 to file=./W.so.2: symbol 'W'
....
18754: symbol=X;  lookup in file=prog3  [ ELF ]
18754: symbol=X;  lookup in file=./W.so.2  [ ELF ]
18754: symbol=X;  lookup in file=./X.so.2  [ ELF ]
18754: binding file=prog3 to file=./X.so.2: symbol 'X'

prog3 can be rebuilt with DIRECT mapfile keywords so that direct bindings are established to the functions W() and X().

$ cat mapfile
$mapfile_version 2
SYMBOL_SCOPE {
        global:
                W       { FLAGS = EXTERN DIRECT };
                X       { FLAGS = EXTERN DIRECT };
};
$ cc -o prog4 -R. main.c W.so.2 X.so.2 -Mmapfile

The LD_DEBUG environment variable can be used to observe the runtime bindings.

$ LD_DEBUG=symbols,bindings,detail prog4
....
23432: symbol=W;  lookup in file=./W.so.2  [ ELF ]
23432: binding file=prog4 to file=./W.so.2: symbol 'W'  (direct)
23432: symbol=X;  lookup in file=./X.so.2  [ ELF ]
23432: binding file=prog4 to file=./x.so.2: symbol 'X'  (direct)

The lari(1) utility can also reveal the direct binding information. However in this case, the functions W() and X() are not multiply defined. Therefore, by default lari does not find these functions interesting. The –a option must be used to display all symbol information.

$ lari -a prog4
....
[1:1ED]: W(): ./W.so.2
....
[2:1ED]: X(): ./X.so.2
....

Note -  The same direct binding to W.so.2 and X.so.1, can be produced by building prog4 with the –B direct option or the –z direct option. The intent of this example is solely to convey how the mapfile keyword can be used.