linux 延迟重定位

1 篇文章 0 订阅

以前看书的时候,模模糊糊知道linux延迟重定位的意思,没对知识点进行总结和记录,面试的时候,问到了ELF文件的时候,才知道自己并没有搞懂。

在面试中,ELF文件中的plt和got是必问的问题,plt和got是用来实现linux中的延迟重定位,意思是等到调用到这个外部函数的时候再进行重定位,优点很明显,加快了程序的启动速度,在传统的运行时重定位中,在程序启动的时候,直接将对每个动态函数解析,将动态函数的地址填入到got表中,在程序比较大的时候,无疑会影响程序的启动速度,延迟重定位技术将重定位放到了动态函数第一次被调用的时候,这种技术的实现就是利用了ELF格式文件中的plt和got,首先plt表和got表类似于数组,两者的不同点是plt表中放的是可执行代码,所以plt表中的数据是不能改变的,接着是got表,got表中存放的是数据,所以got表中的数据是可以改动的,这些数据其实就是一些跳转地址,提供给plt中的代码使用。下面写个代码调试下。

#include<stdio.h>

void HelloWorld(){
        printf("Hello World!\n");
        return;
}

int main(){
        HelloWorld();
        return 0;
}

这段代码中,printf为外部模块函数,需要进行动态重定位,gcc -g test.c -o test,生成可执行文件test,gdb test 动态调试test。

可以看到HelloWorld函数在 0x40052d中,接着查看HelloWorld函数。

在HelloWorld中 callq 400410 <puts@plt> 代表了调用了puts函数,其中的@plt是关键,代表了0x400410这个地址并不是puts函数的真实地址,而是plt表的地址,说明函数会先跳到plt表中,接着看下0x400410中有什么内容。

可以看到0x40010 中是plt表中的内容,这里存放着三行代码。

jmpq *0x200c02(%rip)

pushq $0x0

jmpq 0x400400

这里看到plt中又直接跳转到了 *0x200c02(%rip)中,跳转到(0x200c02 + rip)中存放的数据,接着看一下(0x200c02 + rip)中存放了什么,在x86汇编中rip是指向下一条指令的地址,所以是0x601018,上面这条指令右边的注释已经帮我们标明了。

可以看到值为0x400416,正是当前指令的下一条指令pushq $0x0。pushq $0x0这条指令将要链接的函数的索引入栈,在rel.plt中使用该索引,可以用readelf -r test查看。可以看到puts再索引为0的地方,跟上面的push一致。

接着是jmpq 0x400400指令,不知道为啥disas指令不起作用,用了x /5i 0x400400指令。

到这里的时候,第一个pushq 0x200c02(%rip) 将link_map的地址入栈,jmpq *0x200c04(%rip)跳转到dl_runtime_reslove中解析函数,解析完毕,再将解析到的函数地址,填到对应的got表项中。关于dl_runtime_reslove怎么知道填到哪个got表项中,可以看rle.plt表项目中的offset,offset字段中的值为0x601018,跟前面GOT表项的地址对上了。每个外部函数第一次调用都要进行这样一次函数的查找,并将地址填到got表项中,这样下次调用的时候,就无需查找了,直接跳转到外部函数。

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值