11

如果共享库链接到二进制文件,并且共享库还依赖于其他库,那么共享库的 RPATH 和二进制文件的 RPATH 的优先级(链接器搜索顺序)是什么?二进制文件的 RPATH 可以覆盖共享库中的 RPATH 吗?我在共享库 RPATH 中设置的 $ORIGIN 是指 lib 位置还是二进制位置?
提前致谢。

4

1 回答 1

9

根据我的观察,如果有一个应用程序main动态加载 library first.so,而后者又动态加载 library second.so,并且两者都main包含first.soRPATH,那么动态链接器将second.so首先使用first.so's RPATH 进行搜索,将 $ORIGIN 解析为first.so's 目录,并且只有当它失败时,链接器才会继续到main's RPATH 现在将 $ORIGIN 解析为main's 目录。

这与动态链接器文档(查找 Rpath 令牌扩展)并不矛盾:

$ORIGIN(或等效的 ${ORIGIN}):这将扩展为包含程序或共享对象的目录。...

为了检查这一点,我创建了一个测试应用程序和两个库mainlibalibbmain与 相关联liba,并且liba与 相关联libb

main -> liba.so -> libb.so

构建的二进制文件以这种方式定位:

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

两者mainliba都使用--rpath=\$ORIGIN/lib链接器标志构建:

~$ 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]

LD_DEBUG环境变量的帮助下,我检查了动态链接器如何处理 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

从中我们可以看出,链接器首先遇到了加载需求,liba.so并使用main二进制文件的 RPATH 来解决这个问题。然后它遇到了加载的需要libb.so,它首先使用liba.so库的 RPATH 来解决这个问题。但由于 RPATH$ORIGIN/liblibb.so位于同一目录中liba.so,因此链接器无法libb.so使用liba.so的 RPATH 找到。之后,它回退到main's RPATH 并且仅使用后者成功找到libb.so

测试环境:Linux ubuntu 4.15.0-34-generic #37~16.04.1-Ubuntu (64-bit), /lib/x86_64-linux-gnu/ld-2.23.so。

于 2018-10-04T12:47:50.410 回答