在使用GCC编译时是否还需要使用-fPIC?

在gcc目标机器上,当想要编译共享库时,需要指定-fpic或-fPIC来使事情正常工作。 这是因为默认使用绝对寻址,它适用于完全控制自己的地址空间的可执行文件,但不适用于可以加载到可执行文件地址空间中任何位置的共享库。

然而,现代内核现在正在实现地址空间随机化,并且许多现代架构支持PC相对寻址。 这似乎使绝对寻址不可用(地址空间随机化)或不需要(PC相对寻址)。

我还注意到clang没有-fPIC选项,这使得我不再需要它。

那么-fpic现在是多余的,还是需要生成单独的.o文件,一个用于静态库,一个用于共享库?

您仍然需要使用-fPIC进行编译。 pc相对寻址无法解决该问题。 问题是如何解析外部符号。 在动态链接的程序中,分辨率遵循不同的规则,尤其是在地址空间随机化时,它在链接时间内无法解析。

而clang确实像gcc一样拥有-fPIC标志。

$ cat > foo.c void foo(void); void bar(void) { foo(); } $ gcc -S foo.c && grep call.*foo foo.s call foo $ gcc -fPIC -S foo.c && grep call.*foo foo.s call foo@PLT $ clang -S foo.c && grep call.*foo foo.s callq foo $ clang -fPIC -S foo.c && grep call.*foo foo.s callq foo@PLT $ 

我同意你的观点:在许多情况下-fpic / -fPIC选项几乎是多余的,但我确实使用它们来确保:

  • 可移植性(永远不确定可用的特定OS /内核)
  • 向后兼容性:使用这些选项可确保您在旧内核上的行为
  • 习惯 – 难以打破:)
  • 遵守可能需要它的旧代码库

您永远不需要生成单独的.o文件。 始终指定编译器选项以生成可移植代码(通常为-fPIC )。

在某些系统上,编译器可能配置为强制启用此选项,或默认设置它。 但无论如何指定它并没有什么坏处。

注意:人们希望在支持PC相关寻址并且性能良好的情况下-fPIC使用该模式而不是专用额外的寄存器。

gcc针对很多平台和架构,并不是像x86架构那样支持本机PIC。 在某些情况下,创建PIC意味着额外的开销,这可能是不受欢迎的,您想要或需要的更多是取决于您的项目和您所针对的平台。

这取决于目标。 默认情况下,某些目标(如x86_64)与位置无关,sp -fpic是noop,对生成的代码没有影响。 因此,在这些情况下,您可以省略它并且没有任何变化。 默认情况下,其他目标(如x86 32位)不是位置独立的,因此在这些计算机上,如果省略可执行文件的-fpic ,它将禁用该图像文件的ASLR(但不使用它所使用的共享库)。