5

我正在将一个线程局部变量添加到几个始终直接链接到可执行文件的目标文件中。这些对象永远不会包含在共享库中(可以肯定地假设这在可预见的将来会成立)。这意味着这些对象不需要 -fPIC 标志,对吗?

默认情况下,我们的代码库对所有对象都有 -fPIC 标志。其中许多都包含在共享库中,因此使用 -fPIC 是有意义的。但是,此标志在调试新线程局部变量时会出现问题,因为GDB 在使用 -fPIC 跨过线程局部变量时会崩溃。如果我使用新的线程局部变量从这几个目标文件中删除 -fPIC,我可以正确调试。

我找不到任何权威性的声明表明在可执行文件中将非 PIC 对象与 PIC 对象混合是可以的。到目前为止,我的测试表明它还可以,但感觉不干净,由于共享库的情况,在线讨论通常是“不要混合 PIC 和非 PIC”。

在这种情况下,将非 PIC 对象链接到使用 PIC 对象和库构建的可执行文件是否安全?也许 GCC 文档有一个关于这是安全的权威声明,但我找不到它。

编辑:二进制修补 gcc 以避免此错误在短期内不是解决方案。在 Linux 上切换编译器不是一个可行的解决方案。

4

2 回答 2

4

除了像上面这样的错误应该没问题。我无法向您提供描述此内容的权威文件的参考资料,而只能根据经验发言。当您指定 -fPIC 时,gcc(或汇编程序)将生成不同的代码,但生成的代码仍使用标准化的重定位符号。对于将各个部分链接在一起,起初这并不重要,链接器只会顽固地将所有内容串在一起,并且不知道代码是否表示非 PIC 代码上的 PIC。我知道这一点是因为我使用不支持共享库的系统,并且我必须包装自己的加载器。

最后一点很困难,您可以告诉链接器结果对象是否应该是共享库。只有这样,链接器才会生成一些(特定于操作系统的)结构和符号来表示 im-/exports。否则链接器将完成其工作,主要区别在于缺少符号将导致错误。

编译器 + 链接器之间的清晰分离应确保标志无关紧要(除了性能差异之外)。我会小心 LTO 强硬,这在过去有几个不同编译器设置的问题。

如前所述,我花了一些时间研究这个并红色了几个关于 ELF 和动态加载器的文档。您会发现无处链接 PIC/非 PIC 的明确提及,但链接过程实际上并不关心输入的编译器设置,有效代码将保持有效代码。

如果要将非 PIC 代码链接到共享库 (PIC),如果遇到绝对重定位(很可能),链接器将退出。如果要将任何代码链接到程序,则仅限于最终程序可以处理的内容。在支持 PIC 的操作系统上,您可以使用任何东西,否则链接器可能会抱怨缺少符号或不支持的节/重定位类型。

于 2016-06-10T10:31:12.233 回答
0

It is possible almost always, but sometimes it requires some tricks

于 2019-12-04T07:25:10.150 回答