Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

Yveltals Blog

ELF格式和动态链接

可执行文件和共享库通常采用ELF格式。ELF格式不仅定义了文件的结构,还包含了一系列的头部信息,这些信息对于动态链接和程序的执行至关重要。

ELF文件结构

一个典型的ELF文件由以下几个部分组成:

  • 文件头(ELF Header):包含了关于整个文件的一般信息,如文件类型(可执行文件、共享库等)、机器类型、入口点地址等。
  • 程序头表(Program Header Table):指定了程序执行所需的各种段(segment)的位置和属性。对于动态链接来说,其中最重要的是动态段(Dynamic Segment),它包含了动态链接所需的信息,如RPATH。
  • 节头表(Section Header Table):描述了文件中的各个节(section)的信息。节是文件的逻辑分割,用于存储程序的代码、数据、符号表等。
  • 节内容(Section Contents):包含了实际的代码、数据等。

动态链接器的角色

动态链接器在Linux系统中扮演着至关重要的角色。它负责在程序启动时加载和链接其依赖的共享库,确保程序能够正确执行。

加载共享库

当一个程序启动时,动态链接器会根据程序的ELF文件中的信息来加载所需的共享库。这个过程包括:

  1. 解析依赖:动态链接器首先解析程序的动态段,获取它依赖的共享库列表。
  2. 搜索共享库:接着,动态链接器按照一定的顺序搜索这些共享库。这个顺序通常是:RPATH → LD_LIBRARY_PATH → 系统默认路径
  3. 加载共享库:一旦找到共享库,动态链接器会将它们加载到内存中,并进行必要的符号解析和重定位。

符号解析和重定位

加载共享库后,动态链接器需要解析程序和库之间的符号引用,并进行重定位。这包括:

  • 符号解析:动态链接器会查找程序中引用的符号(如函数和变量)在共享库中的地址。
  • 重定位:根据找到的地址,动态链接器会调整程序中的符号引用,确保它们指向正确的位置。

设置库寻找路径

查看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

  1. 编译参数
    -Wl,-rpath='$$ORIGIN/'$ORIGIN是表示so所在执行路径
    在bash中添加单引号防止 $ 被转义,在string中(如BUILD配置)额外添加一个 $ 防止 $O 丢失,是否设置成功可以通过 chrpath 查看
  2. chrpath修改so
    查看rpath:chrpath -l myso
    设置rpath:chrpath -r /home/user/mylibs myso,限制:新RPATH长度不能超过原始长度
  3. patchelf修改so
    patchelf --set-rpath /home/user/mylibs myso

CXXABI_1.3.8 not found

  1. 查询当前 libstdc++.so 支持的CXXABI版本
    strings /lib64/libstdc++.so.6 | grep CXXABI
  2. 查询系统上的 libstdc++.so,从中找到符合 CXXABI 版本的
    find / -name "libstdc++.so*"
  3. 把这个动态库(如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