红色区域的目的是什么?


12

红色区域是内存中超出“未分配”堆栈指针的固定大小区域。编译器确实会生成汇编程序,以通过简单的叶函数访问该区域。

但是我看不出红色区域有任何真正的优势。在堆栈指针之外访问内存确实很危险,并且很容易导致数据损坏。为什么还要这样做?保存2条处理器指令(push ebp; mov ebp esp)不会真正提高速度。

Answers:


16

纯粹是简单地,红色区域是可以保存指令的优化。这意味着不再需要为每个函数所发出的代码从堆栈指针中减去以进行本地存储,就像这样

sub XXX, %rsp 

在每个函数调用的开始,即使它们不是叶函数也是如此。通常,从编译器发出的代码可以使用堆栈指针下方红色区域中的临时空间,而无需保存它并在调用其他函数之前。这是有用的优化。

如果您不再需要从堆栈指针中继承,则发出的代码可以将rsp用作基本指针,这通常是为rbp保留的作业,发出的代码可以将rbp用作另一个通用寄存器。

这最终意味着每个函数调用的序言和结尾都可以保存两条指令,这些指令可以保存和恢复rbp:

(gnu汇编程序)

pushq %rbp       # prologue [ two instructions not necessary ]
movq %rsp,%rbp

.... [code]

movq %rbp,%rsp   # epilogue [ two instructions not necessary ]
popq %rbp        

请注意,在gcc中,如果您不需要它,则可以传递-mno-red-zone标志(但是x86-64 ABI要求它)。Linux内核不需要与ABI兼容,因此所有内核代码都使用-mno-red-zone进行编译。

此外,如果这是预期的操作模式,则访问超出堆栈指针的内存并不危险。这只是危险,在计划外和意外的情况下可能导致腐败。当发出的代码执行此操作时,它知道它在做什么。


是的,我明白这一点。但是保存1条指令(从esp提取)真的是优化吗?我的意思是节省几字节和1个处理器周期的代价是破坏数据的真实可能性看起来很奇怪。也许还有其他原因吗?
2014年

3
并不是真正的优化来自esp,但是由于不再需要从esp继承,因此可以将esp用作基本指针(通常由ebp完成),并将ebp用作功能代码中的其他内容。最后,由于esp现在是基本指针,因此代码可以避免在序言/结尾中保存和恢复ebp。我将用这些额外的信息来阐明答案
Brian Onn 2014年

编辑并更改为rbp / rsp而不是ebp / esp,因为红色区域仅是x86-64 ABI的一部分(尽管没有什么可以阻止使用32位寄存器的相同技术;但是今天没有编译器这样做)
Brian Onn 2014年

1
帧指针的遗漏根本与红色区域无关-编译器可以使用%rsp两种方法中的任何一种作为基本指针来索引堆栈。
alecov
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.