Search code examples
c++boostlinkerglibcldd

Dynamic dependency lib/tls search path


I have an executable which depends on two basic boost libraries, libboost_system and libboost_thread, and when the executable is loading the libraries, the search path bafflingly differs with respect to lib/tls:

 $ LD_DEBUG=libs ./var.exe
 25130:     find library=libboost_system.so.1.55.0 [0]; searching
 25130:      search path=/opt/boost_1_55_0/stage/lib/tls/x86_64:/opt/boost_1_55_0/stage/lib/tls:/opt/boost_1_55_0/stage/lib/x86_64:/opt/boost_1_55_0/stage/lib         (RPATH from file ./var.exe)
 25130:       trying file=/opt/boost_1_55_0/stage/lib/tls/x86_64/libboost_system.so.1.55.0
 25130:       trying file=/opt/boost_1_55_0/stage/lib/tls/libboost_system.so.1.55.0
 25130:       trying file=/opt/boost_1_55_0/stage/lib/x86_64/libboost_system.so.1.55.0
 25130:       trying file=/opt/boost_1_55_0/stage/lib/libboost_system.so.1.55.0
 25130:
 25130:     find library=libboost_thread.so.1.55.0 [0]; searching
 25130:      search path=/opt/boost_1_55_0/stage/lib            (RPATH from file ./var.exe)
 25130:       trying file=/opt/boost_1_55_0/stage/lib/libboost_thread.so.1.55.0

The executable has been linked with exactly the same -rpath=/opt/... setting for both libraries, and I know that boost have been built by a common invocation of b2 (ie exactly the same command line parameters for both). The /etc/ld.so.cache doesn't have any related entries.

Further, it doesn't seem that there is anything remarkable about the built libraries themselves in terms of rpath or ABI requirements,

$ readelf -d /opt/boost_1_55_0/stage/lib/libboost_system.so.1.55.0 | grep -i rpath
# empty
$ eu-readelf -h /opt/boost_1_55_0/stage/lib/libboost_system.so.1.55.0
# there is no difference in ABI versions

Both libraries have exactly the same shared library dependencies, apart from the fact that libboost_thread depends on libboost_system, and both need GLIBC_2.2.5.

I reckon that it is decided that libboost_system somehow needs to links with an NPTL glibc and that's why <rpath>/lib/tls is searched, but it isn't obvious to me looking at the objdump of the libboost_system library why it is the case.

How is an NPTL library is tagged? How does dlopen(3) decide to look in the lib/tls path?


Solution

  • the search path bafflingly differs with respect to lib/tls

    You are barking up the wrong tree.

    The GLIBC loader takes RPATH from your executable, and appends PLATFORM strings (tls/x86_64:tls:x86_64 here) to it to construct the full search path.

    Once the loader discovers that e.g. RPATH/tls directory does not exist, it removes that entry from the search path (there is no point in repeatedly searching non-existent directory). Eventually you end up with just RPATH itself being present.

    If you relink your binary to e.g. invert the order of dependency on libboost_thread and libboost_system, you'll discover that again only the first library is being searched in RPATH/tls, etc. and the second only in RPATH.