![可执行文件在运行时在哪里寻找共享对象?](https://linux22.com/image/18391/%E5%8F%AF%E6%89%A7%E8%A1%8C%E6%96%87%E4%BB%B6%E5%9C%A8%E8%BF%90%E8%A1%8C%E6%97%B6%E5%9C%A8%E5%93%AA%E9%87%8C%E5%AF%BB%E6%89%BE%E5%85%B1%E4%BA%AB%E5%AF%B9%E8%B1%A1%EF%BC%9F.png)
我了解如何在链接/编译时定义包含共享对象。但是,我仍然想知道可执行文件*.so
在执行时如何查找共享对象(库)。
例如,我的应用程序a.out
调用库中定义的函数lib.so
。编译后,我移动lib.so
到我的$HOME
.
我怎么知道a.out
去那里寻找它?
答案1
这共享库指南解释了所涉及的大部分机制,并且动态加载器手册更详细的内容。每个 UNIX 变体都有自己的方式,但大多数都使用相同的可执行格式(极低频)并有类似的动态链接器1(源自 Solaris)。下面我将重点总结 Linux 上的常见行为;检查您的系统手册以了解完整的情况。
(术语说明:系统中加载共享库的部分通常被称为“动态链接器”,但有时更准确地说是“动态加载器”。“动态链接器”也可以指编译时为动态加载器生成指令的工具一个程序,或者编译时工具和运行时加载器的组合。在这个答案中,“链接器”指的是运行时部分。)
简而言之,当.so
链接器寻找动态库(文件)时,它会尝试:
- 环境变量中列出的目录
LD_LIBRARY_PATH
(DYLD_LIBRARY_PATH
在 OSX 上); - 可执行文件中列出的目录路径;
- 系统搜索路径上的目录,(至少在 Linux 上)由
/etc/ld.so.conf
plus/lib
和中的条目组成/usr/lib
。
rpath 存储在可执行文件中(它是DT_RPATH
或DT_RUNPATH
动态属性)。它可以包含绝对路径或以 开头的路径,$ORIGIN
以指示相对于可执行文件位置的路径(例如,如果可执行文件位于/opt/myapp/bin
且其 rpath 为,$ORIGIN/../lib:$ORIGIN/../plugins
则动态链接器将在/opt/myapp/lib
和中查找/opt/myapp/plugins
)。 rpath 通常在编译可执行文件时通过选项 确定-rpath
,ld
但您可以随后使用chrpath
。
在您描述的场景中,如果您是应用程序的开发人员或打包者,并打算将其安装在…/bin
,…/lib
结构中,则链接到-rpath='$ORIGIN/../lib'
.如果您要在系统上安装预构建的二进制文件,请将库放在搜索路径上的目录中(/usr/local/lib
如果您是系统管理员,则将其放在您添加到的目录中$LD_LIBRARY_PATH
),或者尝试chrpath
.
答案2
在 Linux 中,该行为在ld(1)
手册页中有明确说明
The linker uses the following search paths to locate required shared libraries: 1. Any directories specified by -rpath-link options. 2. Any directories specified by -rpath options. The difference between -rpath and -rpath-link is that directories specified by -rpath options are included in the executable and used at runtime, whereas the -rpath-link option is only effective at link time. Searching -rpath in this way is only supported by native linkers and cross linkers which have been configured with the --with-sysroot option. 3. On an ELF system, for native linkers, if the -rpath and -rpath-link options were not used, search the contents of the environment variable "LD_RUN_PATH". 4. On SunOS, if the -rpath option was not used, search any directories specified using -L options. 5. For a native linker, the search the contents of the environment variable "LD_LIBRARY_PATH". 6. For a native ELF linker, the directories in "DT_RUNPATH" or "DT_RPATH" of a shared library are searched for shared libraries needed by it. The "DT_RPATH" entries are ignored if "DT_RUNPATH" entries exist. 7. The default directories, normally /lib and /usr/lib. 8. For a native linker on an ELF system, if the file /etc/ld.so.conf exists, the list of directories found in that file. If the required shared library is not found, the linker will issue a warning and continue with the link.
答案3
我很确定这里的答案是ldconfig
。
ldconfig 创建指向在命令行指定的目录、文件 /etc/ld.so.conf 以及受信任目录(/lib 和 /usr/lib)中找到的最新共享库的必要链接和缓存。该缓存由运行时链接器 ld.so 或 ld-linux.so 使用。 ldconfig 在确定应更新哪些版本的链接时会检查它遇到的库的标头和文件名。
答案4
对于正在运行的应用程序,该文件/proc/1234/maps
包含所有实际的动态链接库。
1234
正在运行的可执行文件的 pid 在哪里。
Linux 遵循 LD_LIBRARY_PATH 和其他变量,正如 Gilles 在回答中指出的那样。