3.6. Dynamic Linker (or Runtime Linker)
The Linux dynamic linker (/lib/ld.so.1 or /lib64/ld64.so.1) finds and loads the shared libraries needed by a program, prepares the program to run, and then runs it. Linux binaries require dynamic linking unless the static option was given to ld during compilation.
On all modern UNIX operating systems, environment variables can be used to affect the operation of the runtime linker. An example is the environment variable LIBPATH on AIX, which alters the search path of the runtime linker. The following environment variables affect the operation of the runtime linker on Linux:
The Linux dynamic linker loads library dependencies breadth first. That is, first the dependencies of the executable are added in the order listed in its dynamic section. Then the dependencies of the first dependency are added in the same fashion.
Typing the following from a shell prompt gives more information about the Linux dynamic linker:
3.6.1. Programming Interface
Linux provides a set of APIs used to dynamically load libraries. The dynamic linking interfaces used by Linux are as follows:
C users need to include the header file dlfcn.h to use these APIs. Glibc adds two APIs not specified by POSIX:
In Linux, a program that uses dynamic linking is linked with the libdl.so library, -ldl. The libraries it loads do not need to be linked in during the build process. Example 3-1 is a sample program using dl* routines in Linux.
Example 3-1. A Sample Program Illustrating How to Use dl* Routines
3.6.2. Lazy Relocation
Lazy relocation or loading is a feature that allows the relocations associated with a symbol to be delayed until the symbol is needed. This is used on different UNIX architectures for calls to functions. This feature can prove useful if an application that is linked to a shared library may have the slightest possibility of not calling the function in the shared library. In this case, the library is only loaded if the function is called by the application; otherwise, the shared library is never loaded, thereby saving system resources. However, by setting the environment variable LD_BIND_NOW to a nonempty value, all the relocations are performed at the program startup time. Lazy relocation can also be disabled for an individual object by adding the z now option to the linker command line. This setting cannot be undone without relinking the shared objects.
3.6.3. Initializing and Finalizing Routine
Sometimes legacy code may include two special functions, _init and _fini. The _init and _fini functions are used to control constructors and destructors when loading and unloading a module, respectively. They have the following C prototypes:
void _init(void); void _fini(void);
When a library is opened through dlopen() or simply as a shared library, the _init function is called if it is exported within the same library. When the library is closed with dlclose() or unloaded because no other applications are using symbols from that library, the routine _fini is called just before the library is unloaded. When using your own _init and _fini routines, you may need to avoid linking against the system startup files. To do this, use the GCC option -nostartfiles.
However, using these routines or the GCC -nostartfiles option is not recommended because it may result in undesired behavior. Instead, libraries should export routines using the __attribute__((constructor)) and __attribute__((destructor)) function attributes, as in the following:
void __attribute__ ((constructor)) x_init(void); void __attribute__ ((destructor)) x_fini(void);
The constructor routine is called before dlopen() returns or when the library is loaded at load time. The destructor routine is called before dlclose() returns or after main() returns or when exit() is called if the library is loaded at load time.