理解ELF动态链接中GOT与PLT表

今天阅读ELF文件结构中的GOT表与PLT表,生啪啪的文字没看懂,索性从一个小实验说起 ,一来记录自己的技术成长轨迹,二来帮助需要之人。。

前言理论篇:

第一:为什么要实现延迟绑定?

开始把所有的函数都链接实际是一种浪费,因此采用延迟绑定技术,核心是第一次用的时候进行绑定,没有用到不进行绑定。

优点:加快程序的启动速度

第二:怎么实现上面的延迟绑定?(这一块详细介绍在程序员的自我修养这本书的7.4节)

使用PLT的方法,每个外部函数在PLT中都有一个相应的项,比如外部函数XXX为XXX@plt,实现为:

jmp      “地址”

push    “ printf引用在重定位表的“.rel.plt”中的下标”;

jump   _dl_runtime_resolve//这个函数是完成符号解析和重定位的;

首先简单的写一个小程序:

<span style="font-size:24px;">#include <stdio.h>
int add(int a,int b)
{
	int c=0;
	c=a+b;
	printf("%d\n",c);</span>
<span style="font-size:24px;">        return 0;
}
void main()
{
	add(2,3);
}</span>

gcc -g Got.c -o Got

反汇编看汇编代码:

<span style="font-size:24px;">#include <stdio.h>
int add(int a,int b)
{
  4004f4:	55                   	push   %rbp
  4004f5:	48 89 e5             	mov    %rsp,%rbp
  4004f8:	48 83 ec 20          	sub    $0x20,%rsp
  4004fc:	89 7d ec             	mov    %edi,-0x14(%rbp)
  4004ff:	89 75 e8             	mov    %esi,-0x18(%rbp)
	int c=0;
  400502:	c7 45 fc 00 00 00 00 	movl   $0x0,-0x4(%rbp)
	c=a+b;
  400509:	8b 45 e8             	mov    -0x18(%rbp),%eax
  40050c:	8b 55 ec             	mov    -0x14(%rbp),%edx
  40050f:	01 d0                	add    %edx,%eax
  400511:	89 45 fc             	mov    %eax,-0x4(%rbp)
	printf("%d\n",c);
  400514:	b8 3c 06 40 00       	mov    $0x40063c,%eax
  400519:	8b 55 fc             	mov    -0x4(%rbp),%edx
  40051c:	89 d6                	mov    %edx,%esi
  40051e:	48 89 c7             	mov    %rax,%rdi
  400521:	b8 00 00 00 00       	mov    $0x0,%eax
  400526:	e8 c5 fe ff ff       	callq  4003f0 <printf@plt>
        return 0;
  40052b:	b8 00 00 00 00       	mov    $0x0,%eax

}
  400530:	c9                   	leaveq 
  400531:	c3                   	retq   

0000000000400532 <main>:
void main()
{
  400532:	55                   	push   %rbp
  400533:	48 89 e5             	mov    %rsp,%rbp
	add(2,3);
  400536:	be 03 00 00 00       	mov    $0x3,%esi
  40053b:	bf 02 00 00 00       	mov    $0x2,%edi
  400540:	e8 af ff ff ff       	callq  4004f4 <add>
} </span>
</pre><span style="font-size:24px">我们看到主函数中调用子函数add是没问题的,看到子函数中调用“400526:<span style="white-space:pre"></span>e8 c5 fe ff ff      <span style="white-space:pre"></span>callq  4003f0 <printf@plt>”看到这个“printf@plt”这是一个延迟绑定,不是通过GOT中相应的项进行间接跳转,而是通过PLT项来进行跳转,每个外部函数在PLT中都有一个项,这里是printf函数。并且XXX@plt都有一个固定的结构:</span><p><span style="font-size:24px"><span style="background-color:rgb(240,240,240)">jmp      “地址”</span></span></p><p><span style="font-size:24px"><span style="background-color:rgb(240,240,240)">push    “ printf引用在重定位表的“.rel.plt”中的下标”;</span></span></p><p><span style="font-size:24px"><span style="background-color:rgb(240,240,240)">jump   _dl_runtime_resolve//这个函数是完成符号解析和重定位的;</span></span></p><p><span style="font-size:24px; background-color:rgb(240,240,240)">继续看一下</span><span style="font-size:24px; background-color:rgb(240,240,240)">printf@plt的汇编代码:果然是这样的套路:</span></p><p><span style="font-size:24px; background-color:rgb(240,240,240)"></span></p><pre name="code" class="plain"><span style="font-size:24px;">00000000004003f0 <printf@plt>:
  4003f0:	ff 25 0a 0c 20 00    	jmpq   *0x200c0a(%rip)        # 601000 <_GLOBAL_OFFSET_TABLE_+0x18>
  4003f6:	68 00 00 00 00       	pushq  $0x0
  4003fb:	e9 e0 ff ff ff       	jmpq   4003e0 <_init+0x18></span>

在这里用gdb来调试一下:

很奇怪的事出现这个:


很纳闷,对于我这种底层不是很懂的小白,之能首先怀疑是不是样本的问题?
首先很肯定一点的不是样本问题:欢迎各位大侠指正。

建议大家看一下这几个博客写的比较好:

http://www.programlife.net/linux-got-plt.html;

http://blog.csdn.net/lmh12506/article/details/6801630;

总结篇:

总的来说:第一次其实是调用_dl_runtime_resolve进行GOT对应的表项的修改,以增加爱延迟绑定的目的,从而达到不用链接所用的函数,就是用到的时候再链接,当链接以后就直接从GOT调转到真正的函数,从而增加效率。不要被生啪啪的理论文字吓到。





评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值