fPIC vs. fPIE
fPIC vs. fPIE
这两个都是编译选项,具体可以参考GCC的官方文档 。其作用就是
参考[4], 实际-fPIC和-fPIE的区别非常有限。
It works very much like what PIC does for dynamic libraries, the difference is that a Procedure Linkage Table (PLT) is not created, instead PC-relative relocation is used.
差别就是体现在导出的全局变量上。如果使用-fPIE编译的.o文件,则不会为这些全局变量创建PLT表项。但用-fPIC选项则会创建。则使用-fPIC编译的代码,性能会略差。参考[5],这一点性能损失也非常有限
注: 根据编译器同学的推测,这一差别也有可能在链接二进制的时候被抹去。
LLVM和GCC针对这两个编译选项的处理也不尽相同。GCC的处理可以参考[1]。而LLVM的处理是采用互相覆盖的方法。
clang++ -fPIE -fPIC -o a.o -c a.cpp
如果最后一个参数是-fPIC,则fPIE会被忽略。
clang++ -fPIE -fPIC -fPIE -o a.o -c a.cpp
同理,如果最后一个是-fPIE,那么-fPIC就会被忽略。这也是我们编译报错的原因。
cmake编译时的默认选项
cmake在2.8以后加入了编译策略(policy),每个策略拥有一个CMP的编号,例如:CMP0018 — CMake 3.22.1 Documentation。编译策略可以通过cmake_policy命令进行设置。
在CMP0018中,就阐明了针对position independent相关编译选项的设置,即POSITION_INDEPENDENT_CODE。通过设置该选项,可以为构建目标加入-fPIE的编译选项,以及-pie的链接选项。
1 | cmake_minimum_required(VERSION 3.18.1) |
-fPIE的参数会通过该编译选项加入要链接到二进制的.o文件中,而动态库会默认加上-fPIC选项,即便设置了POSITION_INDEPENDENT_CODE,也不会加上-fPIE选项。当然如果通过CMAKE_C_FLAG之类的变量强行加上,还是可以的。
另外即便指定了POSITION_INDEPENDENT_CODE,-pie的链接选项仍然不会被加上。可以参考[3]。必须要指定这两行才可以:
1 | include(CheckPIESupported) |