将非PIC对象链接到带有PIC对象的可执行文件是否有效

时间:2016-04-06 19:17:03

标签: linux gcc x86-64 fpic

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

默认情况下,我们的代码库为所有对象都有-fPIC标志。其中许多都包含在共享库中,因此使用-fPIC是有意义的。但是,此标志提出了调试新线程局部变量的问题,因为GDB crashes while stepping over thread local variable with -fPIC。如果我使用新的线程局部变量从那些少数目标文件中删除-fPIC,我可以正确调试。

我无法找到任何权威声明,将非PIC对象与可执行文件中的PIC对象混合在一起是可以的。到目前为止,我的测试表明它没有问题,但它并没有感觉到犹太人,而且在线讨论通常是“不混合PIC和非PIC"由于共享库案例。

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

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

2 个答案:

答案 0 :(得分:3)

除了上面提到的Bug之外,应该没问题。我无法向您提供描述此事的最终文件的参考,但只能从经验中说出来。 当您指定-fPIC时,gcc(或汇编程序)将生成不同的代码,但生成的代码仍使用标准化的重定位符号。 为了将各个部分链接在一起,这一点无关紧要,链接器只会顽固地将所有内容串在一起,并且不知道代码是否表示非PIC代码上的PIC。我知道这是因为我使用的系统不支持共享库,我不得不包装自己的加载器。

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

Compiler + Linker之间的清晰分离应该保证标志不重要(在性能差异之外)。我会小心LTO很难,这在过去有不同的编译器设置有几个问题。

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

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

答案 1 :(得分:0)

几乎总是可能的,但有时需要一些技巧