25

我最近收到一个:

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

尝试将程序编译为共享库时出错。

现在解决这个问题并不太难(使用 -fPIC 重新编译所有依赖项),但经过一些研究发现这个问题只存在于 x86-64 平台上。在 32 位上,任何位置相关的代码仍然可以由动态加载器重新定位。

我能找到的最佳答案是:

x86 支持 .text 重定位(当您有位置相关代码时会发生这种情况)。这种支持是有代价的,即包含这种重定位的每个页面基本上都变得不共享,即使它位于共享库中,从而破坏了共享库的概念。因此我们决定在 amd64 上禁止这个(如果值需要超过 32 位,它会产生问题,因为所有 .text 重定位都只有大小“word32”)

但我觉得这还不够。如果重定位破坏了共享库的概念,为什么可以在 32 位平台上完成呢?此外,如果需要对 ELF 格式进行更改以支持 64 位,那么为什么不增加所有字段的大小以适应?

这可能是一个小问题,但它的动机是:a) 所讨论的代码是科学代码,不必受到性能影响会很好,b) 在第一名!

[编辑:'答案'

@awoodlands答案可能是最好的“字面答案”,@servn添加了一些很好的信息。

在搜索以查找有关不同类型重定位的更多信息时,我发现了这个并最终找到了x86_64 ABI 参考(参见第 68 页)]

4

3 回答 3

11

据我了解,问题是 x86-64 似乎引入了一种新的、更快的方式来引用相对于指令指针的数据,而 x86-32 不存在这种方式。

这篇文章对它进行了很好的深入分析,并给出了以下执行摘要:

x86-64 使用指令指针相对数据地址偏移的能力是一个很好的优化,但在共享库的情况下,关于数据相对位置的假设是无效的并且不能使用。在这种情况下,对全局数据的访问(即任何可能在你身上发生变化的东西)必须经过一个抽象层,即全局偏移表。

-fPIC寻址为寻址增加了一个额外的抽象层,以使以前在通常的寻址样式中可能(和一个理想的特性)仍然适用于较新的体系结构。

于 2011-08-27T20:14:30.897 回答
7

但我觉得这还不够。如果重定位破坏了共享库的概念,为什么可以在 32 位平台上完成呢?

可以做到,只是效率不是特别高……计算重定位有运行时成本,重定位的可执行文件占用额外的内存,并且该机制在可执行加载程序中引入了很多复杂性。此外,Linux 发行版确实希望鼓励使用 -fPIC 编译所有代码,因为更改可执行文件的基地址是一种缓解策略,这使得编写针对安全漏洞的漏洞利用变得更加困难。

还值得一提的是, -fPIC 通常不会带来显着的性能成本,特别是如果您使用 -fvisibility=hidden 或等效项。

为什么不是所有字段都增加了大小以适应?

有问题的“字段”是 x86-64 寻址模式的直接字段,它不受 ELF 开发人员的控制。

于 2011-08-28T02:22:39.437 回答
0

您可以使用 -mcmodel=large 选项在 x86_64 上构建不带 -fpic 的共享库

参考:http ://eli.thegreenplace.net/2012/01/03/understanding-the-x64-code-models/

于 2013-04-08T19:35:00.260 回答