Position-independent Code

固定装载地址的困扰

共享对象在被装载的时候,如何确定它在虚拟地址空间中的位置?固定装载地址容易产生冲突问题或内存利用率低的问题,不过也有一些系统采用这样的做法:静态共享库

为了解决这个模块装载地址固定的问题,我们设想有没有一种方法能够将共享对象在任何地址加载?即共享对象在编译的时候不能假设自己在进程虚拟地址空间的的位置

装载时重定位(Load Time Relocation)

首先想到的方法是链接的时候不做重定位,当模块装载地址确定的时候系统再对程序中所有的绝对地址引用进行重定位。这样的方法实现也很简单,只需要在知道目标地址的情况下,遍历整个所有绝对引用地址加上一个偏移量就行了

但是因为要修改指令,所以没办法实现共享同一份代码的要求

Linux 和 GCC 支持这种装载时重定位的方法,我们前面在产生共享对象的时候,使用了两个 GCC 参数 -shared-fPIC 如果只使用 -shared,那么输出的共享对象就是使用装载时重定位的方法

-fpic 更小更快,不过在某些平台上可能会有一些限制,比如全局符号的数量或者是代码的长度之类

地址无关代码

上面的方法离成功还差了一点:我们希望程序模块中共享的指令部分在装载的时候不需要因为装载地址的改变而改变,也就是 .so 中没有绝对地址引用。可以将指令中那些需要被修改的部分分离出来,跟数据放在一起,这样指令部分就可以保持不变,而数据部分可以在每一个进程中都有一个副本。这就是地址无关代码技术

地址引用方式(动态链接情况)

如何区分一个DSO是否为PIC

共享模块的全局变量问题

数据段地址无关性