《程序员的自我修养——链接、装载与库》读书笔记—— 7.5 动态链接相关结构

本文详细解析了ELF文件中的.interp、.dynamic、.dynsym、.rel.dyn和.rel.plt段,以及它们在动态链接过程中的作用。.interp存放动态链接器路径,.dynamic保存各种地址和配置信息,.dynsym是动态符号表,.rel.dyn和.rel.plt则是动态链接重定位表,分别用于修正数据和函数引用。通过实例展示了R_X86_64_GLOB_DAT和R_X86_64_JUMP_SLOT的重定位过程,并探讨了延迟绑定的概念。

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

7.5.x 这几小节看的有点懵,只能多看几遍,慢慢理解。定几个小目标:

  1. 搞清楚.dynamic, .dynsym, .rel.dyn, .rel.plt 这几个段都保存了哪些信息?
  2. 这些段能在什么阶段起到什么作用?
.interp 段

保存了动态链接器的路径

.dynamic 段

保存了各种地址。该段中,数组元素的类型有如下几种(部分):
在这里插入图片描述

.dynsym段 (动态符号表)

这个表与静态链接里的符号表十分类似,静态链接中的符号表可以参考这篇文章:
《程序员的自我修养——链接、装载与库》读书笔记—— 3.5 链接的接口:符号

.rel.dyn 和 .rel.plt (动态链接重定位表)

重定位表的作用:
共享对象的重定位,与静态链接的目标文件重定位十分相似。不同的是静态链接的重定位发生在静态链接时,共享对象的重定位发生在装载时。其中,
.rel.dyn 对数据引用的修正,修正的位置位于.got以及数据段
.rel.plt 是对函数引用的修正,修正的位置位于.got.plt

接下来,编写两个.so,其中一个引用另外一个中的全局变量。分别分析三种重定位入口类型:_JUMP_SLOT, _GLOB_DATA, _RELATIVE
源码参考文末附录。

.rel.dyn 和 R_X86_64_GLOB_DAT

从下边的重定位表.rela.dyn 中可以看出,g_var_a 的Offset为 200fd8,
在这里插入图片描述
从反汇编中可以看出,对g_var_a的访问确实是去*0x200fd8 (注意此处有*号)。
在这里插入图片描述
当然,实际的寻址是通过%rip(pc指针)+一个偏移来实现的。汇编代码中的这个0x20096e 应该就是根据重定位表中的0x200fd8来计算出来的。这就是重定位表所发挥的作用。
下图可以看出0x200fd8所在段正是.got段。印证了书中“.rel.dyn 修正的位置位于.got以及数据段”这个说法
在这里插入图片描述
gdb 停在断点上,然后反汇编,可以看到%rax = 0x7ffff7dd1fd8,也就是g_var_a 的地址保存在 0x7ffff7dd1fd8 这块内存上。
在这里插入图片描述
查看0x7ffff7dd1fd8 的内容,以及maps
在这里插入图片描述
通过map 可以看到,0x00007ffff77df024 这个地址确实位于liba 的权限为rw 的segment上。
在这里插入图片描述

.rel.plt 和 R_X86_64_JUMP_SLO

libb.so 的重定位表中,g_func_a 位于 .rel.plt 段,其类型为书中所述的R_X86_64_JUMP_SLO。offset 为0x201018,如下图所示
在这里插入图片描述
代码中对g_func_a 的访问,会直接跳转到g_func_a@plt,g_func_a@plt中会以offset 0x201018地址中保存的地址作为g_func_a 的地址。代码中的0x200ab2 应该就是根据重定位表中的0x201018 计算得来。
在这里插入图片描述
同样可以看到,0x201018 位于.got.plt段中,也印证了书中“.rel.plt 修正的位置位于.got.plt”的说法
在这里插入图片描述
后面如何访问真正的g_func_a,在《程序员的自我修养——链接、装载与库》读书笔记—— 7.4 延迟绑定 中已经推过一遍了,这里就不重复了。

R_X86_64_RELATIVE

书中提到了 _RELATIVE 类型的重定位入口,我没有复现出来,暂时搁置吧。

附录

/*a.c*/
int g_var_a;
void g_func_a(void)
{
	g_var_a = 0x123;
}
/*b.c*/
extern int g_var_a;

static int *g_ptr_var_a = &g_var_a;

void g_func_a(void);
void g_func_b()
{
	g_func_a();
	g_var_a = 0x456;
	g_ptr_var_a = 0;
}
/*ab.c*/
extern void g_func_b();

int main(int argc, char *argv[])
{

	g_func_b();

	return 0;
}

# Makefile
ab: a.c b.c ab.c
	gcc a.c -fPIC -shared -g -o liba.so
	gcc b.c -fPIC -shared -g -o libb.so -L. -la
	gcc ab.c -no-pie -g -o ab -L. -la -lb
	objdump -ds libb.so > libb.so.S

参考
https://www.cnblogs.com/cocoajin/p/10904646.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值