"-fno-pie"和"-no-pie"之间的区别

3
我在区分“-fno-pie”和“-no-pie”之间没有找到任何有用的信息。它们是gcc标志还是ld标志?它们是否都是必要的?请注意,以下是一段使用这些行的makefile代码:
CC = @gcc -fno-pie -no-pie
LD = @gcc -fno-pie -no-pie

因此,它使用gcc进行链接,而不是直接调用ld,但我不理解标志之间的差异以及它们是否都对编译和链接阶段必要。
1个回答

3

简而言之:-fno-pie是“代码生成选项”,而-no-pie是“链接器选项”。你需要两者。

-fno-pie告诉GCC你不想制作PIE。如果你不制作PIE,那么你就会制作共享对象(使用-shared)或普通可执行文件。
普通可执行文件加载在4GiB以下的固定地址,此外它们的符号不能被替换,因此-fno-pie告诉GCC可以将类似&foo的表达式转换为mov eax,OFFSET FLAT foo
它不必使用GOT,因为符号没有被替换,也不必使用RIP相对寻址,因为32位地址适合于x86-64指令的32位立即数/位移。

查看-fpie/-fno-pie在汇编指令方面的作用。

mov eax, OFFSET FLAT foo 这样的指令会创建一个 R_X86_64_32 重定位,当编译器确定地址始终适合 32 位(即低于 4GiB)时,该重定位用于 64 位程序。
然而,-fno-pie不会阻止 GCC 将 -pie 传递给链接器。
因此,链接器看到了一个 R_X86_64_32 重定位,并仍被指示制作一个 PIE 可执行文件。该重定位承诺地址将低于 4GiB,但 -pie 标志承诺可在任何地方加载可执行文件,包括高于 4GiB。
这些相互矛盾,链接器需要检查这种僵局并产生错误。

要告诉链接器确实不想链接 PIE 可执行文件,您需要向 GCC 传递 -no-pie

在编译文件时,您可以通过向GCC传递-v来查看传递给链接器包装器collect2的选项。
无论有没有-fno-pie-pie仍会传递到collect2中。
向GCC添加-no-pie将抑制collect2命令行中的-pie

注意:旧版发行版构建GCC时未默认使用-fpie -pie


可能更清楚地说,-fpie 是一个“代码生成选项”(就像大多数 -f 选项一样),而 -pie 是一个“链接选项”(不影响生成的汇编代码,只是由编译器驱动程序传递给链接器)。 - amonakov
根据**TLDR;**,我需要的是CC = @gcc -fno-pieLD = @gcc -no-pie,对吗?所以在这两行脚本中我不需要两者都有。 - Francesco

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接