gcc “-fno-pie”和“-no-pie”的区别

vlf7wbxs  于 2023-04-21  发布在  其他
关注(0)|答案(1)|浏览(1116)

我没有找到任何有用的信息,关于“-fno-pie”和“-no-pie”之间的区别。它们是gcc标志还是ld标志?它们是否都是必要的?
我发现了一个makefile,它使用了这些行:

CC = @gcc -fno-pie -no-pie
LD = @gcc -fno-pie -no-pie

所以它使用gcc进行链接,而不是直接调用ld,但我不明白这两个标志之间的区别,以及它们是否都是编译和链接阶段所必需的

osh3o9ms

osh3o9ms1#

TLDR;-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位立即数/位移。
Check out what -fpie / -fno-pie do in terms of assembly instructions.
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可执行文件,您需要将-no-pie传递给GCC。
您可以在编译文件时将-v传递给GCC,以查看传递给collect2(链接器的 Package 器)的选项。
不管-fno-pie是否存在,-pie仍然传递给collect2
-no-pie添加到GCC将在collect2命令行中抑制-pie

注意:旧版本构建的GCC不默认为-fpie -pie

相关问题