深入理解-位置无关代码

位置无关代码:

起因:

当程序在多个不空地址空间运行时,操作系统通常会将程序加载到各个地址空间的相同位置,
这样可以让链接期在程序加载时不用再重定位,将地址绑定到固定位置。
对于动态库而言,如果如果我们不将动态库编译成PIC的也就是意味着loader一定要把动态库加载到某个特定
的地址(该地址编译的时候就确定了)上它才可以正确的执行。

--
如果有ABCD四个库,,假设程序P1依赖A B两个动态库,P2依赖C D两个动态库,那么A B和C D的动态库的加载地址有重叠也
没有关系,P1和P2可以同时运行。但是如果有一个新的程序P3依赖A B C D四个动态库,那么前面为动态库分配的加载地址就
不能正常工作了。当然,重新为这四个动态库分配load address(让地址不重叠)也是ok的,但是这样一来,P1虽然没有使用
C D这两个动态库,但是P1的地址空间还是要保留C D动态库的那段地址,浪费资源。


PIC

于是出现了可以直接加载而无需重定位的代码(位置无关代码)。
主要是因为无论内存在何处加载目标模块,数据段和代码段的距离总是保持不变的。
因此,代码段中的任意指令与数据段中的任意变量之间的距离在运行时都是一个常量,而与代码和数据加载的绝对内存位置无关。

延迟绑定

一个程序只会调用共享库中一部分的程序,将函数地址的绑定推迟到实际调用的时候,能够避免动态
链接器在加载的时候进行成百上千不需要的重定位。

--
延时绑定主要是通过两个数据结构来实现GOT和PLT(过程链接表).
如果一个目标模块调用了共享库中的任意函数,那么它就有它自己的GOT和PLT。GOT是.data段的一部分。PLT是.text段的一部分。

  • GOT[0]中保存的是.dynamic段的地址,其中保存着动态链接器用来绑定过程地址所需要的信息,包括符号表的位置和重定位信息。
  • GOT[1]中保存着当前模块的一些信息。
  • GOT[2]是动态链接器延迟绑定代码的入口地址。
  • GOT[3]开始。比如,定义在libc.so的printf,以及定义在libvector.so的addvec。
GOT[0]:addr of .dynamic
...
GOT[4]:0x4005c6 #add()      ->(调用过后)   GOT[4]:&add

每个PLT占了16个字节,PLT[0]条目是跳转到动态链接器,PLT[1]则是调用系统启动函数。

#PLT[0]
4005a0:pushq *GOT[1]
4005a6:jmpq *GOT[2]
...
#PLT[2]: call add()
4005c0: jmpq *GOT[4]
4005c6: pushq $0x1
4005cb: jmpq 4005a0

如果运行过程中遇到一个函数add:
如果add是第一次被调用,初始时GOT条目指向的 其PLT的下一条指令。于是将add()的ID(0x1)压入栈,然后跳转到PLT[0]
PLT[0]通过GOT[1]间接地把动态链接器的一个参数压入栈,然后GOT[2]跳转到动态链接器。
动态链接器通过 两个栈条目来确定 add()的位置,然后写入GOT[4]。
所以仅在第一次调用是会产生额外的时间开销(通过动态链接器找地址),但在后面的调用中仅仅消耗一条额外指令和内存引用。


参考:

位置无关(PIC)代码原理剖析:http://blog.csdn.net/loushuai/article/details/50493603
深入理解计算机结构
计算机科学基础知识(四): 动态库和位置无关代码:http://www.wowotech.net/basic_subject/pic.html
位置无关代码:http://www.cnblogs.com/tekkaman/archive/2013/03/04/2943118.html

转载于:https://www.cnblogs.com/Przz/p/6505917.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值