总结:位置无关代码

提出问题:多进程是如何共享程序的一个副本?
如果对于上述问题并不清除,请继续往下看:

最开始的想法是为每一个共享库分配一个实现预备的专用地址空间片,然后要求加载器总是在这个地址加载共享库。如果没有共享库需要加载,那么这个专用地址空间也不能被占用。弊端是:由于内存资源稀缺,一个系统中的库很多的情况下,就需要把地址空间分裂成大量小的、未被使用的小空间,比较浪费内存资源。另一方面由于这些大量的专用地址空间片很难管理。举个生活中的例子——共享单车:我们的共享单车就像一个一个的共享库,需要在路边划分专用的路段来停放共享单车(这里就对应的是需要为共享库分配专用的地址空间),共享单车的路段不能被其他小汽车占用(这里对应的就是即使共享库没有被加载,但是它的专用地址空间也不可以被其他程序占用)。随着对共享单车的需求增大,以及我们不同品牌的共享单车推出(这里对应着许多共享库,以及共享库的不同版本问题),对专用的共享单车停放区需求增大,那么我们对这些停放共享单车的地块管理难度也会相应增大,要求停放整齐、不占用太多人行道等等问题。而内存资源稀缺,所以这种方法是不可行的。

后来,就想出了:
通过位置无关代码(位置无关代码,简称:PIC,简而言之就是可以加载而无需重定位的代码),使得共享模块的代码被加载到内存的任何位置而无需链接器修改。这里还是就上述例子而言就是:共享单车不需要专门停放在指定的区域内,只要停放在人行道的路边任意位置都可以,不要管理人员进行专门的搬移。

用户对GCC使用-fpic选项指示GNU编译系统生成PIC代码,共享库的编译必须总是使用该选项。

 1.PIC数据引用


生成全局变量PIC就需要在数据段开始的地方创建一个全局偏移量表(GOT),在GOT中,每一个被这个目标模块引用的全局数据目标都有一个8字节的条目,编译器为每一个条目生成一个重定位记录,在加载时,动态链接器就会重定位GOT中的每一个条目,使得每一个条目中包含目标的正确绝对地址,最后程序中需要使用某个全局变量的时候,就查询全局偏移量表,从对应的条目中间接的加载全局变量地址。


2.PIC函数调用


但是上述对PIC数据引用的方法并不适用于PIC函数调用,原因是:对于PIC函数调用需要链接器修改调用模块的代码,所以并不是位置无关代码。

对于PIC函数调用,GNU编译系统使用延迟绑定的技术将过程地址的绑定推迟到第一次调用该过程时。延迟绑定通过GOT和PLT(过程连接表,是代码段的一部分)来交互实现。

比如一个PIC函数名为fun:
第一次被调用,会延迟解析它的运行时地址:
第一步:程序不直接调用fun函数,而是进入PLT[i](PIC[i]对应的是用户代码的fun函数)
第二步:PLT[i]里面主要有三个指令,第一个指令会跳转到GOT[i+2](这个函数在数据段中全局偏移量表里的对应信息),然后将fun的ID压入栈中,此时数据已经准备完毕,就需要开始链接,因此PLT[i]跳转到PLT[0],从而进入动态链接器中
第三步:要想进入动态链接器中,需要做一些前期信息准备,包括:①通过GOT[1]间接把动态链接器的一个参数压入栈,②通过GOT[2]间接跳转进动态链接器中。
第四步:动态链接器通过两个栈条目来确定fun的运行时位置,用这个地址重写GOT[i+2],最后把程序控制传给fun函数。
再次被调用:
第一步:程序控制传到PLT[i]
第二步:由于先前已经做了些许操作,所以再次被调用直接将控制传给fun函数。

注:
过程链接表(PLT):是一个数组,数组的每一个元素是16字节代码。PLT[0]会跳转到动态链接器中,PLT[1]调用系统启动函数(_libc_start_main)来初始化执行环境,PLT[2]之后的数组元素是调用用户代码调用的函数。
全局偏移量表(GOT):是一个数组,数组的每一个元素是8字节地址,和PLT联合使用。GOT[0]和GOT[1]包含动态链接器在解析函数地址时会使用的信息。GOT[2]是动态链接器在ld-linux.so模块中的入口点。GOT[3]对应的系统启动函数。GOT[4]之后每一个元素对应被调用的函数。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

仟各

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值