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

时间:2010-06-30 05:45:42

标签: c linux x86 x86-64 elf

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

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

此操作失败并出现以下错误:

  在制作共享对象时,不能使用

对“本地符号”重新定位R_X86_64_32;用-fPIC重新编译

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

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

3 个答案:

答案 0 :(得分:17)

我找到a nice and detailed explanation,归结为:

  1. x86-64使用IP相对偏移量来加载全局数据,x86-32不能,因此它取消引用全局偏移量。
  2. IP相对偏移量对共享库不起作用,因为可以覆盖全局符号,因此当不使用PIC构建时,x86-64会崩溃。
  3. 如果使用PIC构建x86-64,则IP相对偏移取消引用现在产生指向GOT条目的指针,然后将其取消引用。
  4. x86-32但是,已经使用了全局偏移的解除引用,因此它直接转换为GOT条目。

答案 1 :(得分:4)

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

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

答案 2 :(得分:0)

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