-
-fPIC
是一个编译选择,生成位置无关的.o文件,这些.o文件可以用来链接生成动态库(.so),也可以用来生成可执行文件(包括位置无关或者位置固定的)。 -
-fPIE
与-fPIC类似,差别就是生成的.o文件不能用来链接生成动态度(.so),只能用来生成可执行文件(也包括位置无关或者位置固定的),。 -
-pie
是一个链接选项,它要求链接器使用的所有.o文件编译是必须使用-fPIC或者-fPIE。
补充一点,如果命令行中同时使用了-fPIC和-fPIE会怎么选?回答是gcc只会选后出现的一个,把前一个覆盖掉了,且不会给出任务提示信息。即-fPIC和-fPIE不可同时有效,出现在命令行后面的那个会替换前面的那个。
所以:
- 生成动态库的.o文件必须使用-fPIC编译选项。
- 生成可执行文件的.o文件则,
2.1 如果链接没有-pie选项,则使用的.o文件在生成时可以使用-fPIC或者-fPIE,或者什么都没有。
2.2 如果链接包含-pie选项,则使用的.o文件在生成时必须使用-fPIC或者-fPIE选项。 - 那么是不是-fPIE的价值不太大呢,因为完全可以使用-fPIC替代就行了;我觉得应该是是的,如果只考虑功能,任何使用-fPIE的地方都可以使用-fPIC代替,无非就是用-fPIE代替-fPIC在某些场景下能够减少一次GOT/PLT的位移计算,提升一些性能。
我们看一个-fPIC,和-fPIE,以及标准的(即无-fPIC,也无-fPIE)的差异例子:
int global_var = 0x10;
int global_func(void) { return 0x11; }
static int static_var = 0x20;
static int static_func(void) { return 0x21; }
extern int extern_var;
extern int extern_func(void);
int main(void) {
int x = 0;
x = global_func();
global_var = 0x12;
x = static_func();
static_var = 0x22;
x = extern_func();
extern_var = 0x32;
return 0;
}
使用gcc -c编译后看它们main函数生成的指令码差异:
image.png- 在global变量和函数(global_var/global_func)的引用上,PIE代码和STD代码是一样的,都是直接使用地址,而PIC代码则计算GOT/PLT表位移。
- 在extern变量和函数(extern_var/extern_func)的引用上,PIE代码和PIC代码是一样的,都是计算 GOT/PLT表位移,而STD代码则是直接使用。
- 对static变量和函数(static_var/static_func)的引用上,所有PIE,PIC,和STD的使用都是一样的。
网友评论