dynamic libraries loading
02 Aug 2016When working with dynamic libraries we can sometimes wonder where does some dependencies come from! In this post, we will explore this issue and present the commands ldd and readelf to get more informations about dynamic libraries.
How are library loaded
To start, let’s do a simple reminder of how dependencies are loaded on linux using ld-linux. It will look for libraries in the following order (from ld-linux ):
- Using the environment variable LD_LIBRARY_PATH. Except if the executable is a set-user-ID/set-group-ID binary, in which case it is ignored.
- Using the directories specified in the DT_RUNPATH dynamic section attribute of the binary if present.
- From the cache file /etc/ld.so.cache, which contains a compiled list of candidate libraries previously found in the augmented library path. If, however, the binary was linked with the -z nodeflib linker option, libraries in the default library paths are skipped. Libraries installed in hardware capability directories (see below) are preferred to other libraries.
- In the default path /lib, and then /usr/lib. If the binary was linked with the -z nodeflib linker option, this step is skipped.
Where does this dependency come from
We can now explore which dependencies will be loaded by our library with the command ldd:
tcabel@fantasy:/home/tcabel/De...e-geometry/build$ ldd lib64/libQVTKWidgetPlugin.so
linux-vdso.so.1 => (0x00007ffc64b0c000)
libQt5Widgets.so.5 => /lib64/libQt5Widgets.so.5 (0x00007f9f47f26000)
libQt5Gui.so.5 => /lib64/libQt5Gui.so.5 (0x00007f9f4796f000)
libQt5Core.so.5 => /lib64/libQt5Core.so.5 (0x00007f9f474a1000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f9f47199000)
libm.so.6 => /lib64/libm.so.6 (0x00007f9f46e96000)
libc.so.6 => /lib64/libc.so.6 (0x00007f9f46ad5000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f9f468bf000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f9f466a2000)
libgobject-2.0.so.0 => /lib64/libgobject-2.0.so.0 (0x00007f9f46452000)
libglib-2.0.so.0 => /lib64/libglib-2.0.so.0 (0x00007f9f4611b000)
libXext.so.6 => /lib64/libXext.so.6 (0x00007f9f45f08000)
libX11.so.6 => /lib64/libX11.so.6 (0x00007f9f45bca000)
libGL.so.1 => /usr/lib64/nvidia/libGL.so.1 (0x00007f9f4589a000)
libpng15.so.15 => /lib64/libpng15.so.15 (0x00007f9f4566e000)
libz.so.1 => /lib64/libz.so.1 (0x00007f9f45458000)
libicui18n.so.50 => /lib64/libicui18n.so.50 (0x00007f9f45059000)
libicuuc.so.50 => /lib64/libicuuc.so.50 (0x00007f9f44cdf000)
libicudata.so.50 => /lib64/libicudata.so.50 (0x00007f9f4370b000)
libpcre16.so.0 => /lib64/libpcre16.so.0 (0x00007f9f434b3000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f9f432ae000)
libgthread-2.0.so.0 => /lib64/libgthread-2.0.so.0 (0x00007f9f430ac000)
librt.so.1 => /lib64/librt.so.1 (0x00007f9f42ea4000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9f487f4000)
libffi.so.6 => /lib64/libffi.so.6 (0x00007f9f42c9b000)
libxcb.so.1 => /lib64/libxcb.so.1 (0x00007f9f42a79000)
libnvidia-tls.so.352.79 => /usr/lib64/nvidia/tls/libnvidia-tls.so.352.79 (0x00007f9f42875000)
libnvidia-glcore.so.352.79 => /usr/lib64/nvidia/libnvidia-glcore.so.352.79 (0x00007f9f3fde1000)
libXau.so.6 => /lib64/libXau.so.6 (0x00007f9f3fbdd000)
However, ldd print all the needed libraries, meaning libraries needed by our library and dependencies of libraries loaded! In the example above, let’s say the dependency to libX11 is annoying me and I want to know where does it come from.
The first thing I can do is checking it doesn’t come directly from my lib printing only it’s direct dependencies thanks to readelf:
tcabel@fantasy:/home/tcabel/De...e-geometry/build$readelf -d lib64/libQVTKWidgetPlugin.so
Dynamic section at offset 0xad50 contains 31 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libQt5Widgets.so.5]
0x0000000000000001 (NEEDED) Shared library: [libQt5Gui.so.5]
0x0000000000000001 (NEEDED) Shared library: [libQt5Core.so.5]
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6]
0x0000000000000001 (NEEDED) Shared library: [libm.so.6]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x0000000000000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x000000000000000e (SONAME) Library soname: [libQVTKWidgetPlugin.so]
0x000000000000000f (RPATH) Library rpath: [/user/tcabel/home/Devel/dtk/build/lib64:/home/tcabel/lib/QT-5.4/5.4/gcc_64/lib:]
As it name implies readelf reads ELF information (which is the format of dynamic libraries on Linux) and as we can see there is no direct dependencies to libX11 in my lib :) .
But the question remain : where is libX11 coming from? We can find the culprit using the environment variable LD_DEBUG:
tcabel@fantasy:/home/tcabel/De...e-geometry/build$LD_DEBUG=files ldd lib64/libQVTKWidgetPlugin.so
13861: file=libGL.so.1 [0]; needed by /user/tcabel/home/lib/QT-5.4/5.4/gcc_64/lib/libQt5Gui.so [0]
13861: file=libGL.so.1 [0]; generating link map
13861: dynamic: 0x00007f6326978038 base: 0x00007f63266eb000 size: 0x000000000028eef8
13861: entry: 0x00007f6326717710 phdr: 0x00007f63266eb040 phnum: 4
[...]
13861: file=libGLX.so.0 [0]; needed by /lib64/libGL.so.1 [0]
13861: file=libGLX.so.0 [0]; generating link map
13861: dynamic: 0x00007f632472e7c8 base: 0x00007f632451f000 size: 0x000000000022ffa0
13861: entry: 0x00007f6324522770 phdr: 0x00007f632451f040 phnum: 4
[...]
13861: file=libGLX.so.0 [0]; needed by /lib64/libGL.so.1 [0]
13861: file=libGLX.so.0 [0]; generating link map
13861: dynamic: 0x00007f632472e7c8 base: 0x00007f632451f000 size: 0x000000000022ffa0
13861: entry: 0x00007f6324522770 phdr: 0x00007f632451f040 phnum:
[...]
13861: file=libX11.so.6 [0]; needed by /lib64/libGLX.so.0 [0]
13861: file=libX11.so.6 [0]; generating link map
13861: dynamic: 0x00007f6322ba7630 base: 0x00007f632286d000 size: 0x000000000033f8f8
13861: entry: 0x00007f632288afe0 phdr: 0x00007f632286d040 phnum:
Then we can solve the puzzle libQVTKWidgetPlugin->libQt5Gui->libGL->libGLX->libX11 !!