C++ -fPIC仅用于共享库吗?

C++ -fPIC仅用于共享库吗?,c++,c,gcc,compilation,elf,C++,C,Gcc,Compilation,Elf,我知道共享库需要fPIC,并且知道为什么 但是,我不清楚这个问题: 在构建可执行文件或静态库时,是否应禁止使用-fPIC 在构建可执行或静态库期间,是否应该永远不要使用-fPIC “从不”是一个强有力的词,上面的陈述是错误的 使用-fPIC构建的代码(稍微)不太理想,那么除了共享库之外,您为什么还要将其放入其他库中呢 让我们从一个静态库开始,它有一个简单的答案 假设您希望为用户提供一个静态库,该库可以链接到可执行文件中,也可以链接到用户自己的共享库中 在这种情况下,您必须为他们提供3个单独的存档

我知道共享库需要fPIC,并且知道为什么

但是,我不清楚这个问题:

在构建可执行文件或静态库时,是否应禁止使用
-fPIC

在构建可执行或静态库期间,是否应该永远不要使用
-fPIC

“从不”是一个强有力的词,上面的陈述是错误的

使用-fPIC构建的代码(稍微)不太理想,那么除了共享库之外,您为什么还要将其放入其他库中呢

让我们从一个静态库开始,它有一个简单的答案

假设您希望为用户提供一个静态库,该库可以链接到可执行文件中,也可以链接到用户自己的共享库中

在这种情况下,您必须为他们提供3个单独的存档库(一个是使用
-fPIC
构建的,用于链接到共享库中;一个是使用
-fPIE
构建的,用于链接到饼图可执行文件中;另一个是“常规”存档库),或者您可以为他们提供一个单独的存档库(必须使用
-fPIC
构建代码)

现在,有人可能会争辩说,你应该给他们一个共享库,但这会迫使你的最终用户分发2个二进制文件,而他们可能不愿意这样做

但假设您想要构建一个常规(非饼图)可执行文件。将
-fPIC
代码链接到此类可执行文件中的原因是什么

好吧,假设您正处于开发阶段,并且还不太关心优化代码。进一步假设您希望将代码测试为共享库,以及PIE和非PIE可执行文件的一部分

在上述条件下,您可以编译代码3次(使用和不使用
-fPIC
,以及使用
-fPIE
),也可以编译一次(使用
-fPIC
),并将其链接到共享库、饼图和非饼图可执行文件中的所有3个。这样做可以节省大量的编译时间和一些构建系统的复杂性

TL;DR:将
-fPIC
对象放入可执行文件和静态库是有其位置的,您应该理解这样做的原因(如果您最终这样做的话)

更新:


对象文件中的代码始终是可重定位的

它是位置独立代码吗

否:并非所有可重定位代码都与位置无关


位置无关代码是可重定位代码的子集。可重定位代码可以具有适用于任何节的重定位。与位置无关的代码不得对
.text
(和
.rodata
)进行任何重新定位。

我的印象与知识渊博的人的看法相矛盾,即现在的编译器无论如何都会生成PIC。从理论上讲,PIC代码的效率比非PIC代码稍低,但对于ASLR(地址空间布局随机化)这样的代码,PIC可能在大多数情况下都是需要的。我主要考虑PC桌面系统和更大的系统;在“嵌入式”空间中,规则可能会有所不同。(在Mac电脑上,使用
-fPIC
-fPIC
或两者都不使用编译时,会给出与GCC 7.3.0相同大小的对象代码。但这不一定是ELF;对象文件是'Mach-O 64位对象x86_64')。对象文件中的代码总是可重定位的,它是位置无关的代码吗?静态库由对象文件组成,那么,我们能说静态库中的代码已经是位置独立的吗?