Linker and Libraries Guide

Lazy Loading of Dynamic Dependencies

The default method for loading a dynamic dependency is to map it into memory and then examine it for any dependencies, and if it has any they are immediately loaded. Those dependencies are then in turn examined and additional objects continue to be loaded until the full tree has been exhausted; all inter-object references are then resolved. The issue here is that all of these objects are being loaded into memory, whether or not the code in these objects will actually be referenced by the current program being run.

Lazy loading of dynamic dependencies will instead map the initial object into memory and then load those dependencies which are not labeled for lazy loading. Objects which have been labeled for lazy loading will not be loaded until explicitly being referenced (by relocations). By taking advantage of the fact that procedure call bindings are delayed until a procedures first invocation via the Procedure Linkage Table we can now delay the loading of an object into memory until it is referenced, and those objects which are never referenced will never be loaded into memory.

An example of this is the link-editor, which has a debugging library called liblddbg.so.4, but since debugging output is rarely used by ld, it would be expensive if it had to be loaded every time the link-editor was invoked. Now -- by delaying the loading of this library until the first reference to the debugging library is made we can put off the expense of loading for only those invocations which use the debugging library. The alternate method to do this would be to dlopen()/dlsym() a library when it is needed; this is ideal if it is a small library with a simple interface or if its name and location is not known at link-edit time. But -- if both are known, it is simpler to designate the library in question to be lazily loaded so that it is loaded only when referenced.

Designating an object to be lazily loaded is done via the link-editor options -z lazyload and -z nolazyload. These options are position-dependent on the link-edit line. Here in a simple compile of a program with a dependency on a library called libdebug.so.1, which is to be lazily loaded, we show the dynamic section, which has marked libdebug.so.1, to be lazily loaded, and the Syminfo section, which has recorded the symbol to cause libdebug.so.1 to be loaded:


$ 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 libdebug.so.1 will be lazily loaded while libc.so.1 will be loaded at the initial startup of prog.

The environment variable LD_FLAGS can be set to nolazyload or nodirect to disable the lazy or direct binding of dependencies that request these features.