为什么保留局部变量的堆栈空间?

时间:2015-05-05 15:04:14

标签: assembly compilation stack compiler-optimization red-zone

我是汇编语言的新手,我想知道局部变量,为什么我们(或编译器)通常通过递减" 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)行,那么最后一个代码片段将完全正确地执行此操作

 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

2 个答案:

答案 0 :(得分:1)

通常,您只能使用堆栈指针上方的堆栈。堆栈指针定义堆栈的末尾。在堆栈指针下访问可能会也可能不起作用。如果你调用另一个函数,它尤其不会工作,因为返回地址会被推送,并且被调用的函数也会从堆栈指针开始使用堆栈,从而覆盖你的本地。即使在叶函数中,信号处理程序等异步事件也可能使用堆栈,并且它们也假设堆栈指针下的所有内容都未使用。

此外,操作系统可能会按需增加堆栈,并且还使用堆栈指针。如果你在堆栈指针下访问,内存甚至可能都没有映射,如果操作系统抓到你那么你的程序就会崩溃。

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

答案 1 :(得分:0)

先生先生。 @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