2

我是汇编语言的新手,我想知道局部变量,为什么我们(或编译器)通常通过在过程的序言和过程结束时减少“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
4

2 回答 2

1

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

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

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

于 2015-05-05T15:15:08.033 回答
0

在先生之后。@Jester 有用的答案我查看了“红色区域”,发现它对我很有帮助,所以我先与您分享这是根据这篇文章 http://eli.thegreenplace.net来自 AMD64 ABI 的定义/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

于 2015-05-05T17:51:46.347 回答