glibc动态链接器dl_runtime_resolve简要分析

本文简要分析了glibc动态链接器的核心部分——dl_runtime_resolve,包括动态链接过程、plt节的作用、link_map结构分析以及_dl_fixup函数的功能。通过对elf动态段的了解,展示了动态绑定如何在首次调用时完成重定位。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

dl_runtime_resolve简要分析

资料

glibc 2.9 source
linux elf 手册
&各种百度搜索

基于32位elf,64位一些结构会略有不同,新手学习,如果有理解错误,请师傅们帮忙指出。

elf执行时动态绑定简要分析

动态链接的过程

动态链接中起到核心作用的是got节和plt节,链接器为所有共享目标文件(shared object)中未定义的(undef)外部符号生成一个got表,每个got表项存储符号在运行时的实际值(地址),plt表中的每一项实际是一段指令,每个外部函数都有一个对应的plt项他指导系统完成动态链接,或是执行外部函数。

plt节

plt节中一组代码如下所示:

 fgets.plt:
       jmp      fgets.got
       push     fgets.rel offset
       jmp      xxxxx ;plt[0]的地址这里存储的是调用动态链接器的过程指令

如上所示,如果程序调用了fgets函数(代码段中实际调用了fgets.plt的地址),并且fgets使用动态链接方式,linux的延迟绑定机制(直到第一次调用才会完成重定位)会为当前函数调用动态链接器已完成对got表的修改。

由于所有函数在完成绑定之前,他们对应got表的值实际上是对应plt项的第二条指令,即如上push xxxx,该指令会将fgets函数在重定位表中的偏移压入栈上,而后执行jmp plt[0],去执行plt[0]位置的代码。

plt[0]保存的代码如下:

       push  got 1  ;link_map
       jmp   got 2  ;dl_rumtime_resolve

压got[1] (保存了本模块的link_map结构,后文介绍)中保存的值入栈,跳转执行got[2]中的函数,实际上就是动态链接器dl_runtime_resolve的地址。dl_runtime_resolve的实现在glibc源代码中的dl-trampoline.c中,是一段汇编形式的代码,他调用了内部函数 _dl_fixup(struct link_map *__unbounded l, ElfW(Word) reloc_offset)来处理动态链接,刚刚压入栈的值就是作为他的参数。完成链接后,对应got表项中的值会变为实际函数地址,此后对plt表项的调用,将直接跳转到实际got表项的函数内,不会再进行重复绑定。


link_map结构简要分析

有关link_map的定义位于glibc源码的link.h中

r_scope_elem

/* Structure to describe a single list of scope elements.  The lookup
   functions get passed an array
### 安装特定版本的GLIBC 对于Ubuntu 20.04,默认情况下可能不提供最新的GLIBC版本,如`GLIBC_2.32`, `GLIBC_2.33`, 或者 `GLIBC_2.34`. 若要安装这些更高版本的GLIBC库,可以考虑以下几种方法: #### 方法一:通过源码编译安装指定版本的GLIBC 1. 下载所需版本的GLIBC源代码包。可以从GNU官方网站获取不同版本的GLIBC源文件。 ```bash wget http://ftp.gnu.org/gnu/libc/glibc-2.34.tar.gz tar -2.34.tar.gz cd glibc-2.34 ``` 2. 创建一个新的构建目录并配置编译环境。 ```bash mkdir build && cd build ../configure --prefix=/opt/glibc-2.34 make -j$(nproc) sudo make install ``` 3. 更新动态链接配置以便能够找到新安装的GLIBC库。 ```bash echo '/opt/glibc-2.34/lib' | sudo tee /etc/ld.so.conf.d/opt-glibc-2.34.conf sudo ldconfig ``` 此过程适用于任何想要安装的具体版本,只需更改下载地址中的版本号即可[^1]。 #### 方法二:利用Docker容来隔离不同的GLIBC环境 如果应用程序运行在一个受控环境中,比如Docker容内,则可以通过创建自定义的基础镜像来包含所需的GLIBC版本。这避免了修改主机系统的风险,并且更容易管理依赖关系。 例如,在Dockerfile中指定基础镜像为较新的Ubuntu发行版或其他已知带有适当GLIBC版本的操作系统映像: ```dockerfile FROM ubuntu:latest as builder RUN apt-get update \ && apt-y software-properties-common \ && add-apt-repository ppa:ubuntu-toolchain-r/test \ && apt-get update \ && apt-get install -y gcc g++ make cmake libtool autoconf automake pkg-config git WORKDIR /app COPY . . # 编译应用... ``` 这种方法特别适合于开发和测试阶段,因为它允许快速切换到具有不同GLIBC版本的不同环境而无需改变宿主机设置[^3]。 #### 注意事项 当尝试更新或替换现有的GLIBC时要格外小心,因为这是操作系统的核心组件之一;错误操作可能导致系统不稳定甚至无法启动。建议先备份重要数据再进行此类改动。另外,某些程序可能会严格绑定至特定版本的GLIBC,因此即使成功安装了较高版本也可能遇到兼容性问题[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值