ELF格式和动态链接
可执行文件和共享库通常采用ELF格式。ELF格式不仅定义了文件的结构,还包含了一系列的头部信息,这些信息对于动态链接和程序的执行至关重要。
ELF文件结构
一个典型的ELF文件由以下几个部分组成:
- 文件头(ELF Header):包含了关于整个文件的一般信息,如文件类型(可执行文件、共享库等)、机器类型、入口点地址等。
- 程序头表(Program Header Table):指定了程序执行所需的各种段(segment)的位置和属性。对于动态链接来说,其中最重要的是动态段(Dynamic Segment),它包含了动态链接所需的信息,如RPATH。
- 节头表(Section Header Table):描述了文件中的各个节(section)的信息。节是文件的逻辑分割,用于存储程序的代码、数据、符号表等。
- 节内容(Section Contents):包含了实际的代码、数据等。
动态链接器的角色
动态链接器在Linux系统中扮演着至关重要的角色。它负责在程序启动时加载和链接其依赖的共享库,确保程序能够正确执行。
加载共享库
当一个程序启动时,动态链接器会根据程序的ELF文件中的信息来加载所需的共享库。这个过程包括:
- 解析依赖:动态链接器首先解析程序的动态段,获取它依赖的共享库列表。
- 搜索共享库:接着,动态链接器按照一定的顺序搜索这些共享库。这个顺序通常是:
RPATH → LD_LIBRARY_PATH → 系统默认路径 - 加载共享库:一旦找到共享库,动态链接器会将它们加载到内存中,并进行必要的符号解析和重定位。
符号解析和重定位
加载共享库后,动态链接器需要解析程序和库之间的符号引用,并进行重定位。这包括:
- 符号解析:动态链接器会查找程序中引用的符号(如函数和变量)在共享库中的地址。
- 重定位:根据找到的地址,动态链接器会调整程序中的符号引用,确保它们指向正确的位置。
设置库寻找路径
查看so依赖信息
查看动态库依赖:ldd myso,查看详细依赖search过程:LD_DEBUG=libs ldd myso
查看二进制/动态库详细信息:readelf -d myso | head -n 20
设置LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/home/user/mylibs:$LD_LIBRARY_PATH
设置RPATH
- 编译参数
-Wl,-rpath='$$ORIGIN/',$ORIGIN是表示so所在执行路径
在bash中添加单引号防止$被转义,在string中(如BUILD配置)额外添加一个$防止$O丢失,是否设置成功可以通过 chrpath 查看 - chrpath修改so
查看rpath:chrpath -l myso
设置rpath:chrpath -r /home/user/mylibs myso,限制:新RPATH长度不能超过原始长度 - patchelf修改so
patchelf --set-rpath /home/user/mylibs myso
CXXABI_1.3.8 not found
- 查询当前 libstdc++.so 支持的CXXABI版本
strings /lib64/libstdc++.so.6 | grep CXXABI - 查询系统上的 libstdc++.so,从中找到符合 CXXABI 版本的
find / -name "libstdc++.so*" - 把这个动态库(如libstdc++.so.6.0.25)复制到 /usr/lib64,建立软链接。
这里的 xx.so.6 和 xx.so 都是 xx.so.6.0.25 的软链接sudo ln -s libstdc++.so.6.0.25 libstdc++.so.6