static int a;
static int* p = &a;

如果某一个共享对象里有这样一段代码的时候,变量 a 的地址会随着共享对象的装载地址改变而改变

对于数据段来说,每一个进程都有一个独立的副本,所以不用担心被进程改变。我们可以通过选择在装载的时候重定位来解决数据段中绝对地址引用问题。对于共享对象来说,如通过数据段中有绝对地址引用,那么编译器和链接器就会产生一个重定位表,这个重定位表里面包含了 R_386_RELATIVE 类型的重定位入口

当动态链接器发现有这样的入口的时候,就会对其重定位

其实就是前面不加 -fPIC 的情况,这里延迟到链接阶段对其重定位的目标只有在模块内部可见的 static 变量,不加 pic 参数是所有的代码都不用写成 pic 格式,直接重定位,不过就没有了 data 段复制代码段保存节省内存的优点了

对于可执行文件来说,默认如果可执行文件是动态链接的,那么 GCC 会使用 PIC 的方法来产生可执行文件的代码段部分,以便于不同的进程中能够共享代码段,节省内存