当一个模块引用了一个定义在共享对象的全局变量的时候,它无法根据上下文判断出这个变量是定义在同一个模块的其他目标文件上还是定义在另一个共享对象上,即无法判断是否是跨模块的调用
如果不是跨模块的话,那么不会使用这种 PIC 的机制,不会进行重定位,如果此时在共享对象上还存在一个一样的变量的话,就会造成两份定义一样的全局变量存在,这是不可行的
解决方法是把所有使用这个变量的指令都指向位于可执行文件中的那个副本,ELF 共享库在编译的时候,默认都把定义在模块内部的全局变量当作定义在其他模块的全局变量。也就是在装载的时候,如果某个全局变量在可执行文件中拥有副本(不管有没有初始化),那么动态链接器就将 GOT 相应的地址指向该副本,这样这个变量在运行的时候实际上只会有一个实例;如果变量在共享模块中被初始化,那么动态链接器还需要将该初始值复制到程序主模块的变量副本中;如果该全局变量在程序主模块中没有副本,那么 GOT 中的相应地址就指向模块内部的该变量副本