为什么同一个可执行文件使用不同的 RUNPATH 进行不同的库查找?



我有一个Linux C++程序,它构建和链接(使用-Wl,--no-undefined,不少(,但是当我尝试运行它时无法加载其所有库。 我一直在尝试检查它与ldd的依赖关系,但我无法弄清楚为什么它会在失败的库上绊倒:

$ ldd standalone_test
...  lots of libraries that are found ...
libPythia6.so => not found

现在,这个库位于应该根据可执行文件中嵌入的RUNPATH找到它的地方:

$ readelf -d ./standalone_test | grep "RUNPATH"
0x000000000000001d (RUNPATH)            Library runpath: [/home/jeremy/code/NOvARwgt/cmake-build-debug/src:/home/jeremy/code/genie-2.12.2/lib:/opt/genie/GENIESupport/pythia6/v6_424/lib:/opt/root/lib:/cvmfs/nova-development.opensciencegrid.org/novasoft/releases/development/lib/Linux2.6-GCC-debug]
$ ls /opt/genie/GENIESupport/pythia6/v6_424/lib
liblund.a  libPythia6.so  pydata.o

(可执行文件standalone_test和库libPythia6.so都是ELF64,所以我不认为这是处理器架构不匹配或类似的东西。

我尝试进一步深入研究库加载期间发生的事情,我注意到在同一可执行文件下加载不同库时报告了不同的RUNPATH(其中一些是"链"加载,它们是由可执行文件请求的库请求的(:

$ LD_DEBUG=libs,files ./standalone_test 2>&1 | ack RUNPATH
# this one is the 'correct' RUNPATH (the one from the executable)
19553:  search path=/opt/root/lib/tls/haswell/x86_64:/opt/root/lib/tls/haswell:/opt/root/lib/tls/x86_64:/opt/root/lib/tls:/opt/root/lib/haswell/x86_64:/opt/root/lib/haswell:/opt/root/lib/x86_64:/opt/root/lib        (RUNPATH from file ./standalone_test)
# next one has been 'augmented' with processor architecture subdirs
19553:  search path=/home/jeremy/code/NOvARwgt/cmake-build-debug/src/tls/haswell/x86_64:/home/jeremy/code/NOvARwgt/cmake-build-debug/src/tls/haswell:/home/jeremy/code/NOvARwgt/cmake-build-debug/src/tls/x86_64:/home/jeremy/code/NOvARwgt/cmake-build-debug/src/tls:/home/jeremy/code/NOvARwgt/cmake-build-debug/src/haswell/x86_64:/home/jeremy/code/NOvARwgt/cmake-build-debug/src/haswell:/home/jeremy/code/NOvARwgt/cmake-build-debug/src/x86_64:/home/jeremy/code/NOvARwgt/cmake-build-debug/src:/home/jeremy/code/genie-2.12.2/lib/tls/haswell/x86_64:/home/jeremy/code/genie-2.12.2/lib/tls/haswell:/home/jeremy/code/genie-2.12.2/lib/tls/x86_64:/home/jeremy/code/genie-2.12.2/lib/tls:/home/jeremy/code/genie-2.12.2/lib/haswell/x86_64:/home/jeremy/code/genie-2.12.2/lib/haswell:/home/jeremy/code/genie-2.12.2/lib/x86_64:/home/jeremy/code/genie-2.12.2/lib:/opt/genie/GENIESupport/pythia6/v6_424/lib/tls/haswell/x86_64:/opt/genie/GENIESupport/pythia6/v6_424/lib/tls/haswell:/opt/genie/GENIESupport/pythia6/v6_424/lib/tls/x86_64:/opt/genie/GENIESupport/pythia6/v6_424/lib/tls:/opt/genie/GENIESupport/pythia6/v6_424/lib/haswell/x86_64:/opt/genie/GENIESupport/pythia6/v6_424/lib/haswell:/opt/genie/GENIESupport/pythia6/v6_424/lib/x86_64:/opt/genie/GENIESupport/pythia6/v6_424/lib:/opt/root/lib:/cvmfs/nova-development.opensciencegrid.org/novasoft/releases/development/lib/Linux2.6-GCC-debug/tls/haswell/x86_64:/cvmfs/nova-development.opensciencegrid.org/novasoft/releases/development/lib/Linux2.6-GCC-debug/tls/haswell:/cvmfs/nova-development.opensciencegrid.org/novasoft/releases/development/lib/Linux2.6-GCC-debug/tls/x86_64:/cvmfs/nova-development.opensciencegrid.org/novasoft/releases/development/lib/Linux2.6-GCC-debug/tls:/cvmfs/nova-development.opensciencegrid.org/novasoft/releases/development/lib/Linux2.6-GCC-debug/haswell/x86_64:/cvmfs/nova-development.opensciencegrid.org/novasoft/releases/development/lib/Linux2.6-GCC-debug/haswell:/cvmfs/nova-development.opensciencegrid.org/novasoft/releases/development/lib/Linux2.6-GCC-debug/x86_64:/cvmfs/nova-development.opensciencegrid.org/novasoft/releases/development/lib/Linux2.6-GCC-debug      (RUNPATH from file ./standalone_test)
... more variants of these two ...
# this one contains only a single entry from the real runpath??
19553:  search path=/opt/root/lib      (RUNPATH from file ./standalone_test)

在最后一种情况下,库未找到并且可执行文件失败并出现cannot open shared object file: No such file or directory错误,它也会继续查找系统搜索路径。

我的问题是:这些变体是如何炮制RUNPATH的?我收集到它们被以某种方式请求它们的各种库修改了,但我似乎在谷歌网络上找不到任何解释。 (也许我搜索错了东西? 似乎如果我了解这里发生了什么,我就可以向后工作,以理解为什么首先找不到该库。

我的问题是:RUNPATH 上的这些变体是如何炮制的?

与旧RPATH不同,该RUNPATH适用于搜索二进制文件的直接依赖关系。

也就是说,如果a.out/fooRUNPATHlibfoo.soNEEDED(位于/foo(,那么就会找到libfoo.so。但是如果libfoo.so本身取决于libbar.so(也位于/foo(,如果libfoo.so没有RUNPATH,那么libbar.so找不到

这种行为提倡"每个 ELF 二进制都应该是自给自足的"。在上面的情况下,libfoo.so不是自给自足的(需要libbar.so但没有说明在哪里可以找到它(。

如果改用RPATH,则那里的路径将应用于每个搜索,并且将找到libbar.so。您可以在链接a.out时使用-Wl,--disable-new-dtags来实现此目的。

最新更新