今天阅读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来调试一下:
很奇怪的事出现这个:
文章图片
很纳闷,对于我这种底层不是很懂的小白,之能首先怀疑是不是样本的问题?
首先很肯定一点的不是样本问题:欢迎各位大侠指正。
建议大家看一下这几个博客写的比较好:
http://www.programlife.net/linux-got-plt.html;
http://blog.csdn.net/lmh12506/article/details/6801630;
总结篇:
总的来说:第一次其实是调用_dl_runtime_resolve进行GOT对应的表项的修改,以增加爱延迟绑定的目的,从而达到不用链接所用的函数,就是用到的时候再链接,当链接以后就直接从GOT调转到真正的函数,从而增加效率。不要被生啪啪的理论文字吓到。
推荐阅读
- Linux|109 个实用 shell 脚本
- linux笔记|linux 常用命令汇总(面向面试)
- Linux|Linux--网络基础
- linux|apt update和apt upgrade命令 - 有什么区别()
- linux|2022年云原生趋势
- Go|Docker后端部署详解(Go+Nginx)
- 开源生态|GPL、MIT、Apache...开发者如何选择开源协议(一文讲清根本区别)
- GitHub|7 款可替代 top 命令的工具