27

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

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

这失败并出现以下错误:

制作共享对象时,不能使用针对“本地符号”的重定位 R_X86_64_32;使用 -fPIC 重新编译

当然,这意味着我需要将它重新构建为与位置无关的代码,因此它适合链接到共享库中。

但这在具有完全相同构建参数的 x86 上运行良好。所以问题是,x86 上的重定位与 x86-64 有何不同,为什么我不需要-fPIC在前者上编译?

4

3 回答 3

21

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

  1. x86-64 使用 IP 相对偏移量来加载全局数据,x86-32 不能,因此它取消引用全局偏移量。
  2. IP 相对偏移不适用于共享库,因为可以覆盖全局符号,因此 x86-64 在不使用 PIC 构建时会崩溃。
  3. 如果 x86-64 使用 PIC 构建,IP 相对偏移解引用现在会产生一个指向 GOT entry 的指针,然后将其解引用。
  4. 然而,x86-32已经使用了全局偏移量的解引用,所以它直接变成了 GOT 条目。
于 2010-08-02T03:22:21.050 回答
4

这是一个代码模型问题。默认情况下,静态代码是在假设整个程序将停留在内存地址空间的较低 2G 部分的情况下构建的。共享库的代码需要为另一个内存模型编译,无论是 PIC,还是使用 -mcmodel=large 进行编译,而无需做出该假设。

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

于 2010-06-30T06:56:11.717 回答
1

这纯粹是 ABI 人强加给我们的任意要求。x86_64 上的动态链接器不能支持非 PIC 库没有任何合乎逻辑的原因。然而,由于 x86_64 不像 x86 那样承受如此可怕的寄存器压力(并且具有更好的 PIC 功能),我不知道有什么重要的理由不使用 PIC。

于 2010-06-30T06:56:51.470 回答