Search Paths for Dynamic Linking & Loading

Before we start

When talking about “dynamic linking”, people could refer to any of the following two processes: one is a step of program’s construction, where (relocatable) object files are dynamically linked by the linker – a toolchain’s component; the other is a pre-processing stage of program’s execution, performed by the dynamic linker , which is usually provided by the operating system. Obviously it could easily lead to confusion due to their similar names. Therefore, personally I prefer dynamic loading, its another commonly recognizable name, to refer to the latter one, and correspondingly dynamic loader to its performer.


Search paths are different for dynamic linking and loading. The simple answer to the question “why does this difference ever exist” is that the two operations are done by not a single but different entries. But the more fundamental reason for this, I think, is that we can’t always align the environment of producers with the one of consumers, although most of the time they are on the same site (i.e. we build our own program and run it on our own machine) and we therefore simply overlook this potential difference.

The search paths of dynamic linking can be obtained by querying ld, the linker:

1ld --verbose | grep SEARCH_DIR
2gcc -print-search-dirs

As for search paths of dynamic loading, system manual of ld.so is the right place to check:

 1o  Using the directories specified in the DT_RPATH dynamic
 2   section attribute of the binary if present and DT_RUNPATH
 3   attribute does not exist.  Use of DT_RPATH is deprecated.
 4
 5o  Using the environment variable LD_LIBRARY_PATH, unless the
 6   executable is being run in secure-execution mode (see below),
 7   in which case this variable is ignored.
 8
 9o  Using the directories specified in the DT_RUNPATH dynamic
10   section attribute of the binary if present.  Such directories
11   are searched only to find those objects required by DT_NEEDED
12   (direct dependencies) entries and do not apply to those
13   objects' children, which must themselves have their own
14   DT_RUNPATH entries.  This is unlike DT_RPATH, which is applied
15   to searches for all children in the dependency tree.
16
17o  From the cache file /etc/ld.so.cache, which contains a
18   compiled list of candidate shared objects previously found in
19   the augmented library path.  If, however, the binary was
20   linked with the -z nodeflib linker option, shared objects in
21   the default paths are skipped.  Shared objects installed in
22   hardware capability directories (see below) are preferred to
23   other shared objects.
24
25o  In the default path /lib, and then /usr/lib.  (On some 64-bit
26   architectures, the default paths for 64-bit shared objects are
27   /lib64, and then /usr/lib64.)  If the binary was linked with
28   the -z nodeflib linker option, this step is skipped.

Program Library HOWTO by David A. Wheeler is a great material explaining how all kinds of libraries are created and used on Linux, and I recommend you to read it through. However, take a look at section 3.2 and 3.3 if you only care about how dynamic loading is done and relevant environment variables like LD_LIBRARY_PATH.

P.s. Append LD_LIBRARY_PATH when it’s unset

LD_LIBRARY_PATH is often unset, and when we set it by the usual way: LD_LIBRARY_PATH=/my/path:$LD_LIBRARY_PATH, sometimes Bash complains:

1bash: LD_LIBRARY_PATH: unbound variable

It’s related to the following shell option:

1set -u # or `set -o nounset`
2
3# check shell options of the current shell
4echo $-
5
6# unset the shell option
7set +u

Smartly create/append LD_LIBRARY_PATH via shell parameter expansion :

1export LD_LIBRARY_PATH=/mypath${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}

Reference


【C++ 小问答】5:对结构体成员字符数组的访问
“7/28 XX 版本容器 at 大面积失败问题”分析报告