Linux 上的 2 种 ELF 文件类型:可执行文件
(Executable file)和 共享对象文件
(Shared object file),它们在执行期间需要通过 动态库链接器
(ld.so)来查找其依赖的动态库文件,然而系统中可能在不同的目录下存在相同的动态库文件,那么执行时到底链接到哪个目录下的呢,本文将描述其在不同目录间的查找顺序。
如何识别 ELF 文件类型
Linux 上可通过 file
命令来查询文件类型,以 64 位系统为例,可执行文件
的查询结果中将包含如下内容
1
ELF 64-bit LSB executable
共享对象文件
的查询结果中将包含以下内容:
1
ELF 64-bit LSB shared object
如何查询依赖库
Linux 上可通过 ldd
命令来查询 可执行文件
或 共享对象文件
的依赖库,例如查询 ls
命令的依赖库:
1
2
3
4
5
6
7
8
9
root@localhost:~# ldd /usr/bin/ls
linux-vdso.so.1 (0x00007ffff2eff000)
/$LIB/libonion.so => /lib/x86_64-linux-gnu/libonion.so (0x00007fbea7a43000)
libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007fbea7a05000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fbea7813000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fbea780d000)
libpcre2-8.so.0 => /lib/x86_64-linux-gnu/libpcre2-8.so.0 (0x00007fbea777d000)
/lib64/ld-linux-x86-64.so.2 (0x00007fbea7b70000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fbea775a000)
依赖库查找顺序
Linux 上查找依赖库是通过 ld.so
程序来完成的,其具体查找顺序如下:
ELF 文件头中
DT_RPATH
字段配置的目录:该字段是可选的,需要注意的是如果 ELF 文件头中同时包含了DT_RUNPATH
时,则DT_RPATH
将被忽略,可通过readelf -d FILENAME
命令来查看是否包含 DT_RPATH 和 DT_RUNPATH。环境变量
LD_LIBRARY_PATH
中配置的目录。ELF 文件头中
DT_RUNPATH
字段配置的目录:该字段也为可选的,需要注意的是该字段只会查找直接依赖
而不查找间接依赖
,而DT_RPATH
则会查找间接依赖。文件
/etc/ld.so.cache
中包含的动态库文件列表:该文件是ldconfig
命令将/etc/ld.so.conf.d/
目录下配置的目录列表中的所有动态库搜索后生成的一个缓存列表。默认系统库目录
/lib
和/usr/lib
:64 位系统则是/lib64
和/usr/lib64
。
rpath 中的特殊变量
DT_RPATH 和 DT_RUNPATH 统称为 rpath
,可以通过在编译时通过编译参数编译进去,也可以在编译后通过其他工具(如 patchelf)来添加修改。
在 rpath 中有一些特殊变量及其含义如下:
$ORIGIN
: 表示当前 ELF 文件所在的目录。$LIB
: 表示/lib
或lib64
(64 位系统)。
参考资料
- https://man7.org/linux/man-pages/man8/ld.so.8.html