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

今天阅读ELF文件结构中的GOT表与PLT表,生啪啪的文字没看懂,索性从一个小实验说起 ,一来记录自己的技术成长轨迹,二来帮助需要之人。。
前言理论篇:
【理解ELF动态链接中GOT与PLT表】第一:为什么要实现延迟绑定?
开始把所有的函数都链接实际是一种浪费,因此采用延迟绑定技术,核心是第一次用的时候进行绑定,没有用到不进行绑定。
优点:加快程序的启动速度
第二:怎么实现上面的延迟绑定?(这一块详细介绍在程序员的自我修养这本书的7.4节)
使用PLT的方法,每个外部函数在PLT中都有一个相应的项,比如外部函数XXX为XXX@plt,实现为:

jmp“地址”
push“ printf引用在重定位表的“.rel.plt”中的下标”;
jump_dl_runtime_resolve//这个函数是完成符号解析和重定位的;
首先简单的写一个小程序:

#include int add(int a,int b) { int c=0; c=a+b; printf("%d\n",c);

return 0; } void main() { add(2,3); }

编 译
gcc -g Got.c -o Got
反汇编看汇编代码:

#include int add(int a,int b) { 4004f4: 55push%rbp 4004f5: 48 89 e5mov%rsp,%rbp 4004f8: 48 83 ec 20sub$0x20,%rsp 4004fc: 89 7d ecmov%edi,-0x14(%rbp) 4004ff: 89 75 e8mov%esi,-0x18(%rbp) int c=0; 400502: c7 45 fc 00 00 00 00movl$0x0,-0x4(%rbp) c=a+b; 400509: 8b 45 e8mov-0x18(%rbp),%eax 40050c: 8b 55 ecmov-0x14(%rbp),%edx 40050f: 01 d0add%edx,%eax 400511: 89 45 fcmov%eax,-0x4(%rbp) printf("%d\n",c); 400514: b8 3c 06 40 00mov$0x40063c,%eax 400519: 8b 55 fcmov-0x4(%rbp),%edx 40051c: 89 d6mov%edx,%esi 40051e: 48 89 c7mov%rax,%rdi 400521: b8 00 00 00 00mov$0x0,%eax 400526: e8 c5 fe ff ffcallq4003f0 return 0; 40052b: b8 00 00 00 00mov$0x0,%eax} 400530: c9leaveq 400531: c3retq0000000000400532
: void main() { 400532: 55push%rbp 400533: 48 89 e5mov%rsp,%rbp add(2,3); 400536: be 03 00 00 00mov$0x3,%esi 40053b: bf 02 00 00 00mov$0x2,%edi 400540: e8 af ff ff ffcallq4004f4 }


我们看到主函数中调用子函数add是没问题的,看到子函数中调用“400526:e8 c5 fe ff ffcallq4003f0 ”看到这个“printf@plt”这是一个延迟绑定,不是通过GOT中相应的项进行间接跳转,而是通过PLT项来进行跳转,每个外部函数在PLT中都有一个项,这里是printf函数。并且XXX@plt都有一个固定的结构:jmp“地址”
push“ printf引用在重定位表的“.rel.plt”中的下标”;
jump_dl_runtime_resolve//这个函数是完成符号解析和重定位的;
继续看一下printf@plt的汇编代码:果然是这样的套路:

00000000004003f0 : 4003f0: ff 25 0a 0c 20 00jmpq*0x200c0a(%rip)# 601000 <_GLOBAL_OFFSET_TABLE_+0x18> 4003f6: 68 00 00 00 00pushq$0x0 4003fb: e9 e0 ff ff ffjmpq4003e0 <_init+0x18>


在这里用gdb来调试一下:
很奇怪的事出现这个:
理解ELF动态链接中GOT与PLT表
文章图片


很纳闷,对于我这种底层不是很懂的小白,之能首先怀疑是不是样本的问题?
首先很肯定一点的不是样本问题:欢迎各位大侠指正。
建议大家看一下这几个博客写的比较好:
http://www.programlife.net/linux-got-plt.html;

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

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







    推荐阅读