Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

the shared library RPATH and the binary RPATH priority

if a shared library is linked to a binary, and the shared library also depends on other libs , what are the priorities (linker search order) of the RPATH of the shared library and the RPATH of the binary ? Could the RPATH of the binary override the one in the shared library? and the $ORIGIN I set in the shared library RPATH refers to the lib location or the binary location?
Thanks in advance.

like image 895
user3450805 Avatar asked Apr 11 '14 08:04

user3450805


1 Answers

According to my observation, if there is an application main which dynamically loads library first.so, and the latter in turn dynamically loads library second.so, and both main and first.so contain RPATH, then dynamic linker will search second.so first using the first.so's RPATH, resolving $ORIGIN as the first.so's directory, and only if it fails, the linker will proceed to the main's RPATH now resolving $ORIGIN as main's directory.

This does not contradict the dynamic linker doc (look for Rpath token expansion):

$ORIGIN (or equivalently ${ORIGIN}): This expands to the directory containing the program or shared object. ...

To check this I've created a test application and two libraries: main, liba and libb respectively. main is linked against liba, and liba is linked against libb:

main -> liba.so -> libb.so

The built binaries are located this way:

/cwd/main
/cwd/lib/liba.so
/cwd/lib/libb.so

Both main and liba are built with the --rpath=\$ORIGIN/lib linker flag:

~$ readelf -a /cwd/main | grep ORIGIN
 0x000000000000000f (RPATH)              Library rpath: [$ORIGIN/lib]
~$ readelf -a /cwd/lib/liba.so | grep ORIGIN
 0x000000000000000f (RPATH)              Library rpath: [$ORIGIN/lib]

With the help of the LD_DEBUG environment variable I've checked how dynamic linker processes RPATH:

~$ LD_DEBUG=libs /cwd/main
:     find library=liba.so [0]; searching
:      search path=/cwd/lib/tls/x86_64:/cwd/lib/tls:/cwd/lib/x86_64:/cwd/lib              (RPATH from file /cwd/main)
:       trying file=/cwd/lib/tls/x86_64/liba.so
:       trying file=/cwd/lib/tls/liba.so
:       trying file=/cwd/lib/x86_64/liba.so
:       trying file=/cwd/lib/liba.so
94313:
:     find library=libc.so.6 [0]; searching
:      search path=/cwd/lib                (RPATH from file /cwd/main)
:       trying file=/cwd/lib/libc.so.6
:      search cache=/etc/ld.so.cache
:       trying file=/lib/x86_64-linux-gnu/libc.so.6
94313:
:     find library=libb.so [0]; searching
:      search path=/cwd/lib/lib/tls/x86_64:/cwd/lib/lib/tls:/cwd/lib/lib/x86_64:/cwd/lib/lib              (RPATH from file /cwd/lib/liba.so)
:       trying file=/cwd/lib/lib/tls/x86_64/libb.so
:       trying file=/cwd/lib/lib/tls/libb.so
:       trying file=/cwd/lib/lib/x86_64/libb.so
:       trying file=/cwd/lib/lib/libb.so
:      search path=/cwd/lib                (RPATH from file /cwd/main)
:       trying file=/cwd/lib/libb.so

From that we can see, that the linker first encounters the need to load liba.so and uses the main binary's RPATH to resolve this. Then it encounters the need to load libb.so and it first uses the liba.so library's RPATH to resolve this. But since the RPATH is $ORIGIN/lib and libb.so is in the same directory as liba.so, the linker fails to find libb.so using liba.so's RPATH. After that it falls back to main's RPATH and only using the latter it succeeds to find libb.so.

Test environment: Linux ubuntu 4.15.0-34-generic #37~16.04.1-Ubuntu (64-bit), /lib/x86_64-linux-gnu/ld-2.23.so.

like image 113
Alex Che Avatar answered Sep 20 '22 05:09

Alex Che