The runtime linker is invoked when a program that was linked
against a shared object is started or when a program requests that a
shared object be dynamically loaded. The runtime linker is contained
within the C runtime library.
The runtime linker performs several tasks when loading a
shared library (.so file):
- If the requested shared library isn't already loaded in memory,
the runtime linker loads it:
- If the shared library name is fully qualified (i.e., begins with a slash),
it's loaded directly from the specified location. If it
can't be found there, no further searches are performed.
- If it's not a fully qualified pathname, the runtime
linker searches for it as follows:
- If the executable's dynamic
section contains a DT_RPATH tag, then the path
specified by DT_RPATH is searched.
- If the shared library isn't found, the runtime linker
searches for it in the directories specified by
LD_LIBRARY_PATH.
Note:
For security reasons, the runtime linker unsets LD_LIBRARY_PATH if the binary has
the setuid bit set.
- If the shared library still isn't found, then the runtime linker
searches for the default library search path as specified by
the LD_LIBRARY_PATH environment variable to
procnto (i.e., the CS_LIBPATH configuration
string).
If none has been specified, then the
default library path is set to the image filesystem's path.
- Once the requested shared library is found, it's loaded into memory.
For ELF shared libraries, this is a very efficient
operation: the runtime linker simply needs to use the
mmap()
call twice to map the two load segments into memory.
- The shared library is then added to the internal list of all libraries
that the process has loaded.
The runtime linker maintains this list.
- The runtime linker then decodes the dynamic section of
the shared object.
This dynamic section provides information to the linker
about other libraries that this library was linked against. It also
gives information about the relocations that need to be
applied and the external symbols that need to be resolved.
The runtime linker will first load any other required shared libraries
(which may themselves reference other shared libraries). It will then
process the relocations for each library. Some of these
relocations are local to the library, while others require
the runtime linker to resolve a global symbol. In the latter
case, the runtime linker will search through the list of
libraries for this symbol. In ELF files, hash tables are
used for the symbol lookup, so they're very fast. The order
in which libraries are searched for symbols is very
important, as we'll see in the section on Symbol name resolution below.
Once all relocations have been applied, any initialization
functions that have been registered in the shared library's init
section are called. This is used in some implementations of
C++ to call global constructors.