我没有找到任何有用的信息,关于“-fno-pie”和“-no-pie”之间的区别。它们是gcc标志还是ld标志?它们是否都是必要的?我发现了一个makefile,它使用了这些行:
CC = @gcc -fno-pie -no-pie LD = @gcc -fno-pie -no-pie
所以它使用gcc进行链接,而不是直接调用ld,但我不明白这两个标志之间的区别,以及它们是否都是编译和链接阶段所必需的
osh3o9ms1#
TLDR;-fno-pie是“编译器选项”,-no-pie是“链接器选项”,两者都需要。
-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。
-shared
&foo
mov eax, OFFSET FLAT foo
-fpie
R_X86_64_32
-pie
-v
collect2
注意:旧版本构建的GCC不默认为-fpie -pie。
-fpie -pie
1条答案
按热度按时间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
。