_dl_runtime_resolve


  • _dl_runtime_resolve是怎么知要查找printf函数的
  • _dl_runtime_resolve找到printf函数地址之后,它怎么知道回填到哪个GOT表项
  • 到底_dl_runtime_resolve是什么时候被写到GOT表的
前2个问题,只需要一个信息就可以了知道,这个信息就在藏在在函数对应的xxx@plt表中,以foo@plt为例:

0000000000400590 <foo@plt>:
  400590:	ff 25 92 0a 20 00    	jmpq   *0x200a92(%rip)        # 601028 <_GLOBAL_OFFSET_TABLE_+0x28>
  400596:	68 02 00 00 00       	pushq  $0x2
  40059b:	e9 c0 ff ff ff       	jmpq   400560 <_init+0x20>

第二条指令就是秘密所在,每个xxx@plt的第二条指令push的操作数都是不一样的,它就相当于函数的id,动态链接器通过它就可以知道是要解析哪个函数了。

真有这么神吗?这不是神,是编译链接器和动态链接器故意安排的巧合罢了。

使用readelf -r test命令可以查看test可执行文件中的重定位信息,其中.rel.plt这一段就大有秘密:

Relocation section '.rela.dyn' at offset 0x4e0 contains 1 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000600ff8  000300000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0

Relocation section '.rela.plt' at offset 0x4f8 contains 3 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000601018  000200000007 R_X86_64_JUMP_SLO 0000000000000000 __libc_start_main + 0
000000601020  000300000007 R_X86_64_JUMP_SLO 0000000000000000 __gmon_start__ + 0
000000601028  000400000007 R_X86_64_JUMP_SLO 0000000000000000 foo + 0



再看看各函数plt指令中的push操作数: 
printf对应push 0x0 
gmon_start对应push 0x8 
__libc_start_main对应push 0x10

这3个push操作数刚好对应3个函数在.rel.plt段的偏移量。在_dl_runtime_resolve函数内,根据这个offset和.rel.plt段的信息,就知道要解析的函数。再看看.rel.plt最左边的offset字段,它就是GOT表项的地址,也即_dl_runtime_resolve做完符号解析之后,重定位回写的空间。

第三个问题:到底_dl_runtime_resolve是什么时候被写到GOT表的。 
答案很简单,可执行文件在Linux内核通过exeve装载完成之后,不直接执行,而是先跳到动态链接器(ld-linux-XXX)执行。在ld-linux-XXX里将_dl_runtime_resolve地址写到GOT表项内。

事实上,不单单是预先写_dl_runtime_resolve地址到GOT表项中,在i386架构下,除了每个函数占用一个GOT表项外,GOT表项还保留了3个公共表项,也即got的前3项,分别保存:

got[0]: 本ELF动态段(.dynamic段)的装载地址 
got[1]:本ELF的link_map数据结构描述符地址 
got[2]:_dl_runtime_resolve函数的地址

动态链接器在加载完ELF之后,都会将这3地址写到GOT表的前3项。 
其实上述公共的plt指令里面,还有一个操作数是没有分析的,其实它就是got[1](本ELF的link_map)地址,因为只有link_map结构,结合.rel.plt段的偏移量,才能真正找到该elf的.rel.plt表项。

有兴趣的读者可以使用gdb,在执行到main函数时,将GOT表的这3项数据看一下,验证一下。

好了,谈到这里是否对PLT和GOT机制有个更清晰认识了呢?最后一篇会使用图文结构将整个PLT/GOT机制串起来。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值