Linker and Libraries Guide

Lazy Loading of Dynamic Dependencies

The default model for loading a dynamic dependency is to map it into memory and examine it for any additional dependencies. If any exist they in turn are immediately loaded. This cycle continues until the full dependency tree is exhausted, at which point all inter-object references (relocations) are resolved.

This model results in all dependencies of an application being loaded into memory, and all data relocations being performed, regardless of whether the code in these dependencies will actually be referenced by the application during its execution.

Under a lazy loading model, any dependencies that are labeled for lazy loading will not be loaded until explicitly referenced. By taking advantage of a function calls lazy binding (see "Procedure Linkage Table (Processor-Specific)"), we can delay the loading of a dependency until it is first referenced. In fact, objects that are never referenced will never be loaded.


Note -

An object reference can be to a data item or a function (see"When Relocations Are Performed"). As data references must be resolved when an object is initialized, any dependency that satisfies a data reference must be immediately loaded. Therefore identifying such a dependency as lazy loadable has little effect. Data references between dynamic objects are generally discouraged.


An example of lazy loading is the link-editor itself which references a debugging library, liblddbg.so.4. Since debugging is only called upon infrequently, it would be unnecessary and expensive to load this library every time the link-editor was invoked. By indicating that this library can be lazily loaded the expense of processing it can be moved to those invocations which ask for debugging output.

The alternate method of achieving this lazy loading model is to dlopen()/dlsym() a dependency when needed. This is ideal if the number of references (through dlsym()) is small, or the dependency name or location is not known at link-edit time. But for more complex interactions with known dependencies it is simpler to code to normal symbol references and designate the dependency to be lazily loaded.

Designating an object to be lazily or normally loaded is done via the link-editor options -zlazyload and -znolazyload respectfully. These options are position-dependent on the link-edit command line, and any dependency found following the flag takes on the loading attribute specified by the flag.

Here a simple program with a dependency on libdebug.so.1 is to be lazily loaded. Inspection of the dynamic section (.dynamic) indicates that libdebug.so.1 is marked for lazy loading, and inspection of the symbol information section (.SUNW_syminfo) indicates the symbol reference that will trigger its loading:


$ cc -o prog prog.c -L. -zlazyload -ldebug -znolazyload -R'$ORIGIN'
$ elfdump -d prog
 
Dynamic Section:  .dynamic
     index  tag           value
       [1]  POSFLAG_1     0x1           [ LAZY ]
       [2]  NEEDED        0x123         libdebug.so.1
       [3]  NEEDED        0x131         libc.so.1
       [6]  RPATH         0x13b         $ORIGIN
       ...
$ elfdump -y prog
 
Syminfo section: .SUNW_syminfo
     index flgs  boundto                symbol
	      ...
      [52] DL       [1] libdebug.so.1   debug

Notice that the POSFLAG_1 above with the value of LAZY designates that the following NEEDED entry, libdebug.so.1, should be lazily loaded. libc.so.1 however, has no preceding LAZY flag and thus will be loaded at the initial start-up of prog.


Note -

Lazy loading can be disabled at runtime by setting the environment variable LD_NOLAZYLOAD to a non-null value.