与位置无关的代码差异:x86与x86-64

我最近正在构build一个针对x86-64架构的特定共享库(ELF),如下所示:

g++ -o binary.so -shared --no-undefined ... -lfoo -lbar 

这失败了以下错误:

在创build共享对象时,不能使用“对本地符号”进行重定位R_X86_64_32; 用-fPIC重新编译

当然,这意味着我需要重build它作为位置无关的代码,所以适合链接到共享库。

但是,这完全适用于x86,完全相同的构build参数。 所以问题是,如何重新定位x86不同于x86-64,为什么我不需要使用-fPIC编译前者?

Solutions Collecting From Web of "与位置无关的代码差异:x86与x86-64"

我找到了一个很好的和详细的解释 ,归结为:

  1. x86-64使用IP相对偏移量加载全局数据,x86-32不能,所以它取消了一个全局偏移量。
  2. IP相对偏移不适用于共享库,因为全局符号可以被覆盖,所以x86-64在没有使用PIC构建时会崩溃。
  3. 如果使用PIC构建x86-64,则IP相对偏移量解引用现在会生成一个指向GOT条目的指针 ,然后该条目被解引用。
  4. 但是,x86-32 已经使用全局偏移量的解引用,所以它直接转换成GOT条目。

这是一个代码模型的问题。 默认情况下,构建静态代码假设整个程序将停留在内存地址空间的较低的2G部分。 共享库的代码需要编译为另一种内存模型,或者是PIC,或者是-mcmodel = large,这样的编译就不用做这个假设。

请注意,-mcmodel = large在较早的gcc版本中没有实现(它在4.4中,不在4.2中,我不知道是4.3)。 。

这纯粹是ABI人强加给我们的一个武断的要求。 x86_64上的动态链接程序不支持非PIC库是没有道理的。 但是,由于x86_64没有像x86那样可怕的寄存器压力(对于PIC来说具有更好的功能),所以我不知道不使用PIC的重要原因。