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

问题描述 投票:0回答:1

我没有找到任何关于“-fno-pie”和“-no-pie”之间区别的有用信息。它们是 gcc 标志还是 ld 标志?它们是否都需要?

我找到了一段使用这些行的 makefile:

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

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

gcc ld compiler-flags linker-flags
1个回答
0
投票

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 位立即数/位移。

查看

-fpie
/
-fno-pie
在组装说明方面做了什么。

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

要告诉链接器您确实不想链接 PIE 可执行文件,您需要将

-no-pie
传递给 GCC。

您可以在编译文件时将

-v
传递给 GCC,以查看传递给
collect2
(链接器的包装器)的选项。
不管
-fno-pie
的存在,
-pie
仍然传递给
collect2
.
-no-pie
添加到 GCC 将在
-pie
命令行中抑制
collect2

注意:较旧的发行版构建了 GCC 而没有默认为

-fpie -pie
.

© www.soinside.com 2019 - 2024. All rights reserved.