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

Kiz*_*aru 5 linux gcc x86-64 fpic

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

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

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

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

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

Nor*_*nge 4

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

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

编译器 + 链接器之间的清晰分离应保证标志不重要(除了性能差异之外)。我会对 LTO 非常小心,因为过去不同的编译器设置存在一些问题。

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

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