即使我们在 gcc 中使用 -mno-red-zone 标志,红色区域仍然存在吗?

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

我的系统:在 x86_64 上运行的 Ubuntu 22.04.3。 GCC 版本 11.4.0

我读到 System V ABI 强制要求使用红色区域。来自 GCC 手册

红色区域是 x86-64 ABI 强制规定的,它是超出堆栈指针位置的 128 字节区域,不会被信号或中断处理程序修改,因此可以用于临时数据而无需调整堆栈指针。标志

-mno-red-zone
禁用此红色区域。

我的问题:

  1. 如果我在 gcc 中使用

    -mno-red-zone
    标志,红色区域是否仍然存在?

  2. 如果红色区域被“禁用”,这是否意味着我不再遵守系统 V ABI?

  3. 这会产生什么后果(不符合 System V ABI)?

c x86-64 stack-memory abi red-zone
1个回答
0
投票

即使您编译代码不使用它,红色区域仍然存在。

gcc -mno-red-zone
纯粹是一个代码生成选项,类似于
-fno-omit-frame-pointer
,或MIPS GCC的
-fno-delayed-branch
留下仅用NOP填充的延迟槽有用的说明。
gcc -mno-red-zone
只是避免依赖 RSP 下面的空间来保持其值,就像 GCC 在非叶函数中总是做的那样。

使用

-mno-red-zone
编译的代码与使用默认
-mred-zone
编译的代码是 ABI 兼容的。
您可以自由地混合这些选项并将生成的
.o
文件链接到同一个可执行文件/库中,或者链接到不同的库或无论如何。

内核的信号传递代码和其他任何代码仍然会保留 RSP 下面的 128 字节红色区域不变。它不知道也不关心当前正在执行的机器代码不会重新加载该数据(在这种情况下,因为编译器选择不在那里保留任何内容。)没有任何机制可以让可执行文件向内核发出它应该重新加载的信号。不使用替代堆栈传递信号时,不要在当前堆栈指针下方留下 128 字节的间隙。 (因为一次保存少量的堆栈空间并不重要,也不值得使用任何额外的内核代码来使其成为条件。信号处理程序不会嵌套得很深,如果有的话,所以它不会增加大量的总未使用空间。)


尽管它是一个

-m
选项,但它不必更改 ABI(就像
gcc -m32 -mregparm=3
所做的那样),只是不以利用 ABI 这部分优势的方式进行优化。

但是,内核代码通常不能使用红区(除非它使用 TSS 和 IDT 机制来使用备用堆栈进行中断,即使在内核模式下也是如此,而 Linux 则不然),因此必须使用

-mno-red-zone
进行编译以匹配该 ABI。 可能这就是为什么它是一个
-m
选项:您可以将其视为告诉 GCC,其目标 ABI 不提供红色区域。
x86-64 SysV with 红色区域可以运行为 x86 编译的代码-64 SysV 红色区域,但反之则不然。

相关:

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