为啥要为局部变量保留堆栈空间?

Posted

技术标签:

【中文标题】为啥要为局部变量保留堆栈空间?【英文标题】:why preserve stack space for local variables?为什么要为局部变量保留堆栈空间? 【发布时间】:2015-07-15 09:42:18 【问题描述】:

我是汇编语言的新手,我想知道局部变量,为什么我们(或编译器)通常通过在过程开始时减少“ESP”寄存器和程序结束我们再次分配“ESP”它的旧值。喜欢这个代码示例:

; a procedure that create the stack frame then assign 10, 20 values for two local variables then return to caller

two_localv_proc PROC
push ebp
mov ebp,esp
sub esp,8
mov DWORD PTR [ebp-4],10
mov DWORD PTR [ebp-8],20
mov esp,ebp
pop ebp
ret
two_localv_proc ENDP

如果我们删除 (sub esp,8) 行和 (mov esp,ebp) 行,最后一个代码 sn-p 将完全一样

 two_localv_proc PROC
push ebp
mov ebp,esp
mov DWORD PTR [ebp-4],10
mov DWORD PTR [ebp-8],20
pop ebp
ret
two_localv_proc ENDP

那么为什么我们(或编译器)会这样做! ,我们为什么不直接使用堆栈内存来存储我们的局部变量,只要“ESP”指针不会受到在堆栈上存储值的影响,代码如下:

mov DWORD PTR [ebp-8],20

【问题讨论】:

【参考方案1】:

在先生之后。 @Jester 有用的答案我查看了“红色区域”,发现它对我很有帮助,所以我与你分享 首先这是根据这篇文章从 AMD64 ABI 定义的 http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/

"%rsp 指向的位置之外的 128 字节区域被认为是保留的,不应被信号或中断处理程序修改。因此,函数可以使用该区域来存储跨函数调用不需要的临时数据. 特别是,叶子函数可能会在整个堆栈帧中使用这个区域,而不是在序言和尾声中调整堆栈指针。这个区域被称为红色区域。”

这是一个和我非常相似的问题:

https://softwareengineering.stackexchange.com/questions/230089/what-is-the-purpose-of-red-zone/230095#230095

【讨论】:

【参考方案2】:

一般来说,只能使用栈指针上面的栈。堆栈指针定义堆栈的结尾。在堆栈指针下访问可能有效,也可能无效。如果您调用另一个函数,它尤其不起作用,因为返回地址将被推送,并且被调用的函数将开始使用堆栈指针中的堆栈,从而覆盖您的本地人。即使在叶函数中,信号处理程序等异步事物也可能使用堆栈,并且它们还假定堆栈指针下的所有内容都未使用。

此外,操作系统可能会按需增长您的堆栈,并且它还为此使用堆栈指针。如果你在堆栈指针下访问,内存甚至可能不会被映射,如果操作系统发现你这样做,你的程序就会崩溃。

请注意,某些调用约定,例如 x86-64 abi,​​允许在堆栈指针下存在所谓的红色区域。该区域保证不被修改,并且可以在本地的叶子函数中使用,而无需调整堆栈指针。

【讨论】:

谢谢。现在我看起来很清楚。但是 x86-64 ABI“调用约定”如何保证这个红色区域至少不会被操作系统或信号处理程序修改,它只是一个调用约定!

以上是关于为啥要为局部变量保留堆栈空间?的主要内容,如果未能解决你的问题,请参考以下文章

为啥局部变量在 Java 中是线程安全的

数据压入堆栈时,ESP寄存器的指向?

为啥 alloca 与创建局部变量不同?

GO语言局部变量堆栈分析

要同步哪些对象?为啥局部变量不好? [复制]

如何从堆栈中访问函数局部变量?