Linker and Libraries Guide

Locating Shared Object Dependencies

Usually, during the link-edit of a dynamic executable, one or more shared objects are explicitly referenced. These objects are recorded as dependencies within the dynamic executable (see "Shared Object Processing" for more information).

The runtime linker first locates this dependency information and uses it to locate and map the associated objects. These dependencies are processed in the same order as they were referenced during the link-edit of the executable.

Once all the dynamic executable's dependencies are loaded, they too are inspected, in the order they are loaded, to locate any additional dependencies. This process continues until all dependencies are located and loaded. This technique results in a breadth-first ordering of all dependencies.

Directories Searched by the Runtime Linker

By default, the runtime linker looks in only one standard place for dependencies: /usr/lib for 32-bit dependencies, or /usr/lib/64 for 64-bit dependencies. Any dependency specified as a simple filename is prefixed with this default directory name and the resulting pathname is used to locate the actual file.

The actual dependencies of any dynamic executable or shared object can be displayed using ldd(1). For example, the file /usr/bin/cat has the following dependencies:


$ ldd /usr/bin/cat
        libc.so.1 =>     /usr/lib/libc.so.1
        libdl.so.1 =>    /usr/lib/libdl.so.1

Here, the file /usr/bin/cat has a dependency, or needs, the files libc.so.1 and libdl.so.1.

The dependencies actually recorded in a file can be inspected by using the dump(1) command to display the file's .dynamic section, and referencing any entries that have a NEEDED tag. For example:


$ dump -Lvp /usr/bin/cat
 
/usr/bin/cat:
[INDEX] Tag      Value
[1]     NEEDED   libc.so.1
.........

Notice that the dependency libdl.so.1, displayed in the previous ldd(1) example, is not recorded in the file /usr/bin/cat. This is because ldd(1) shows the total dependencies of the specified file, and libdl.so.1 is actually a dependency of /usr/lib/libc.so.1.

In the previous dump(1) example, the dependencies are expressed as simple filenames -- in other words there is no `/' in the name. The use of a simple filename requires the runtime linker to generate the required pathname from a set of rules. Filenames that contain an embedded `/' will be used as-is.

The simple filename recording is the standard, most flexible mechanism of recording dependencies, and is provided by using the -h option of the link-editor to record a simple name within the dependency (see "Naming Conventions" and "Recording a Shared Object Name" for additional information on this topic).

Frequently, dependencies are distributed in directories other than /usr/lib or /usr/lib/64. If a dynamic executable or shared object needs to locate dependencies in another directory, the runtime linker must explicitly be told to search this directory.

The recommended way to indicate additional search paths to the runtime linker is to record a runpath during the link-edit of the dynamic executable or shared object (see "Directories Searched by the Runtime Linker" for details on recording this information).

Any runpath recording can be displayed using dump(1) and referring to the entry that has the RPATH tag. For example:


$ dump -Lvp prog
 
prog:
[INDEX] Tag      Value
[1]     NEEDED   libfoo.so.1
[2]     NEEDED   libc.so.1
[3]     RPATH    /home/me/lib:/home/you/lib
.........

Here, prog has a dependency on libfoo.so.1 and requires the runtime linker to search directories /home/me/lib and /home/you/lib before it looks in the default location /usr/lib.

Another way to add to the runtime linker's search path is to set the environment variable LD_LIBRARY_PATH. This environment variable (which is analyzed once at process start-up) can be set to a colon-separated list of directories, and these directories will be searched by the runtime linker before any runpath specification or default directory.

These environment variables are well suited to debugging purposes, such as forcing an application to bind to a local dependency. For example:


$ LD_LIBRARY_PATH=. prog

Here the file prog from the previous example is bound to libfoo.so.1, found in the present working directory.

Although useful as a temporary mechanism of influencing the runtime linker's search path, the use of this environment variable is strongly discouraged in production software. Any dynamic executables that can reference this environment variable will have their search paths augmented, which can result in an overall degradation in performance. Also, as pointed out in "Using an Environment Variable" and "Directories Searched by the Runtime Linker", this environment variable affects the link-editor.

It is possible to inherit an environment such that a 64-bit executable is given a search path that contains a 32-bit library matching the name being looked for, or vice versa. When this occurs, the runtime linker rejects the mismatched 32-bit library and continues down its search path looking for a valid 64-bit match. If no match is found, an error message is generated. This can be observed in detail by setting the LD_DEBUG environment variable (see "Debugging Aids") to include files.


$ LD_LIBRARY_PATH=/usr/bin/64 LD_DEBUG=files /usr/bin/ls
...
00283: file=libc.so.1;  needed by /usr/bin/ls
00283: 
00283: file=/usr/lib/64/libc.so.1  rejected: ELF class mismatch: \
00283:                                  32-bit/64-bit
00283: 
00283: file=/usr/lib/libc.so.1  [ ELF ]; generating link map
00283:     dynamic:  0xef631180  base:  0xef580000  size:      0xb8000
00283:     entry:    0xef5a1240  phdr:  0xef580034  phnum:           3
00283:      lmid:           0x0
00283: 
00283: file=/usr/lib/libc.so.1;  analyzing  [ RTLD_GLOBAL  RTLD_LAZY ]
...

If a dependency cannot be located, ldd(1) indicates that the object cannot be found, and any attempt to execute the application results in an appropriate error message from the runtime linker:


$ ldd prog
        libfoo.so.1 =>   (file not found)
        libc.so.1 =>     /usr/lib/libc.so.1
        libdl.so.1 =>    /usr/lib/libdl.so.1
$ prog
ld.so.1: prog: fatal: libfoo.so.1: open failed: No such file or directory

Configuring the Default Search Paths

The default search paths used by the runtime linker (/usr/lib or /usr/lib/64) can be administered using a runtime configuration file. This file is created by the crle(1) utility, and is often a useful aid for establishing search paths for applications that have not been built with the correct runpaths.

A configuration file constructed in the default location /var/ld/ld.config (for 32-bit applications) or /var/ld/64/ld.config (for 64-bit applications) will affect all applications, of the respective type, on a system. Configuration files can also be created in other locations and the runtime linkers LD_CONFIG environment variable used to select these files. This latter method is useful for testing a configuration file before installing it in the default location.

Dynamic String Tokens

The runtime linker will replace the following string token when used in a runpath (DT_RUNPATH or DT_RPATH), filter (DT_FILTER), or auxiliary filter (DT_AUXILIARY):

$ISALIST

Expands to the native instruction sets (see isalist(1)) executable on this platform. A pathname containing this token is replicated for each instruction set available. See "Instruction Set Specific Shared Objects".

The runtime linker will replace the following string tokens when used in the paths specified above or in dependency (DT_NEEDED) entries:

$ORIGIN

Provides the directory the object was loaded from; typical use is for locating dependencies in unbundled packages. See "Locating Associated Dependencies".

$OSNAME

Expands to the name of the operating system (see uname(1) -s). See "System Specific Shared Objects".

$OSREL

Expands to the operating system release level (see uname(1) -r). See "System Specific Shared Objects".

$PLATFORM

Expands to the current processor type (see uname(1) -i) of the current machine. See "System Specific Shared Objects".


Note -

$PLATFORM was added in Solaris2.5, but prior to Solaris2.6 was only available for expressing auxiliary filters (DT_AUXILIARY), see "Generating an Auxiliary Filter".