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

Ale*_*x B 24 c linux x86 x86-64 elf

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

g++ -o binary.so -shared --no-undefined ... -lfoo -lbar
Run Code Online (Sandbox Code Playgroud)

这失败,出现以下错误:

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

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

But this works perfectly well on x86 with exactly the same build arguments. So the question is, how is relocation on x86 different from x86-64 and why don't I need to compile with -fPIC on the former?

Ale*_*x B 17

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

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


APr*_*mer 5

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

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