x86-64架构中的红色区域确切位置在哪里?

34

来自维基百科

在计算机中,红区是函数栈帧中一个固定大小的区域,超出返回地址范围,该函数不予保留。调用者函数可以利用红区存储本地变量,而无需修改堆栈指针。这段内存区域不得由中断/异常/信号处理程序修改。System V使用的x86-64 ABI规定了128字节的红区,它直接开始于返回地址之后,并包括函数的参数。OpenRISC toolchain假定有一个128字节的红区。

来自System V x86-64 ABI:

%rsp指向位置之后的128个字节被认为是保留的,并且不得被信号或中断处理程序修改。因此,函数可以使用此区域存储跨函数调用不需要的临时数据。特别地,叶子函数可以将整个堆栈帧作为其使用,而无需在序言和尾声中调整堆栈指针。这个区域称为红区。

  • 给定这两个引用,红区是在堆栈返回地址上方还是下方?

  • 由于此红区相对于RSP,每次push是否向下移动,每次pop是否向上移动?

答案:
  • 红区在堆栈返回地址上方。

  • 由于该红区是相对于%rsp的,因此每次push将使其向下移动,每次pop将使其向上移动。


9
可能有趣?http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/。看起来可以澄清这个问题。在内存中,栈向“下”(低地址)增长。“红色区域”是当前“堆栈指针”下方(低内存地址)的区域。 - Ryan Vincent
2
确实很有趣。一如既往:一张图片胜过千言万语! - Sep Roland
9
维基百科上的描述听起来完全错误。直接从返回地址开始并包括函数的参数是完全胡说八道的。在函数进入时,%rsp指向返回地址,因此红区从那里开始一直到函数修改%rsp为止。参数在返回地址上方。它们不会被异步修改,原因是它们在%rsp之上,而不是因为红区。维基文章的这部分是完全错误的,我看不出任何有效的解释。 - Peter Cordes
1
@PeterCordes Cody Gray的回答正是让我产生了疑问,因为负偏移量(-8)与32字节临时存储区的注释之间存在差异。我看到你已经修复了这个问题。现在一切都说得通了。 - Sep Roland
1
@SepRoland: 哎哟。文档错误真的很令人困惑。我非常狂热地确保答案不包含任何错误信息,即使它们对主要问题的回答是可以的。(例如,这个内联asm存在不安全的约束条件,唯一让OP明白我的意思的方法是写一个完整的答案。)总之,很高兴听到我的细节关注是正确的。太遗憾了,我没有早点注意到,因为我在Cody发布后不久就已经点赞了它 :) - Peter Cordes
显示剩余4条评论
2个回答

27
鉴于这两个引用,红色区域是在堆叠返回地址之上还是之下?
红色区域指的是紧挨着rsp向下128字节,即rsp - 128rsp - 1之间。
由于这个红色区域与RSP有关,每次push时它是否向下移动,每次pop时是否向上移动?
是的。

如果一个函数使用了它的红区,然后想要调用另一个函数,它是否仍然需要在执行call之前使用sub rsp,128?或者硬件会将这个新的返回地址放在当前红区下面吗? - Sep Roland
7
硬件并不知道红区,红区是软件的惯例,其使用受到硬件能力的限制。在函数调用期间,红区不会被保留,因此您需要将必须在函数调用期间保持活动状态的数据存储在堆栈帧内,或者(暂时)降低堆栈指针。红区的整个目的是避免移动堆栈指针,因此编译器不会执行这种操作。 - fuz
1
“硬件不知道红区。”这让我感到困惑。那么当中断/异常/信号触发时,硬件如何知道不使用RSP下面的128个字节呢? - Sep Roland
2
@SepRoland 没有,参见这个答案 - fuz
11
@SepRoland说,用户空间栈从未用于中断。内核无法信任它们。内核代码必须使用-mno-red-zone编译,正是因为中断会将RIP和RFLAGS压入内核栈,这正是你提到的原因。(参考链接:https://dev59.com/9l8e5IYBdhLWcg3wwMhW)。顺便说一下,在看到这个问题之前我刚回答了那个问题 :P - Peter Cordes

11

维基百科有关红区(Red Zone)的文章是错误的,因此导致了歧义。

我在2017年4月修改了这篇文章以解决问题。截至那次更新,维基百科文章如下:

在计算机中,红区是函数堆栈帧中当前堆栈指针之外的固定大小区域,该函数不保留。被调用的函数可以使用红区存储本地变量,而无需额外开销来修改堆栈指针。该内存区域不得被中断/异常/信号处理程序修改。System V使用的x86-64 ABI规定128字节的红区,直接从堆栈指针的当前值下方开始。OpenRISC工具链假定有128字节的红区。

这使得维基百科文章更符合64位System V ABI定义。通过解决上述的歧义,关于下面这个问题:

由于这个红区是相对于RSP的,每次PUSH是否会向下移动,每次POP是否会向上移动?

红区始终是位于RSP的下方128字节。随着RSP的更改(通过PUSH/POP/MOV等指令),红区的位置也会相应地改变。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接