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

ale*_*ari 3 c x86-64 abi stack-memory red-zone

我的系统:在 x86_64 上运行的 Ubuntu 22.04.3。海湾合作委员会版本 11.4.0

我读到 System V ABI 强制要求使用红色区域。来自海湾合作委员会手册

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

我的问题:

  1. 如果我在 gcc 中使用该标志,红色区域是否仍然存在-mno-red-zone

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

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

Pet*_*des 5

即使您编译代码不使用它,红色区域仍然存在。 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. 您可以自由地混合这些选项,并将生成的.o文件链接到同一个可执行文件/库中,或链接到不同的库或其他内容中。

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


尽管它是一个-m选项,但它不必更改 ABI(确实gcc -m32 -mregparm=3如此),只是不以利用 ABI 的该部分的方式进行优化。

然而,内核代码通常不能使用红区(除非它使用 TSS 和 IDT 机制来使用备用堆栈进行中断,即使在内核模式下也是如此,而 Linux 则不然),因此必须进行编译以匹配-mno-red-zone该 ABI 。 也许这就是它成为一个-m选项的原因:您可以将其视为告诉 GCC,ABI 其目标不提供红色区域。具有红区的 x86-64 SysV可以运行为没有红区的 x86-64 SysV 编译的代码,但反之则不然。

有关的: