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

Assembly 为什么要为局部变量保留堆栈空间?,assembly,compilation,stack,compiler-optimization,red-zone,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,e

我不熟悉汇编语言,我想知道局部变量,为什么我们(或编译器)在堆栈上为它们保留一个空间,通常是在过程开始时减少“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

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

此外,操作系统可能会按需增加堆栈,它也会为此使用堆栈指针。如果您在堆栈指针下进行访问,内存甚至可能不会被映射,如果操作系统捕捉到您这样做,您的程序将崩溃


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

在@Jester先生的帮助回答后,我查找了“红色区域”,发现它对我非常有用,因此我将与您分享 首先,根据本文,这是AMD64 ABI的定义

“超出%rsp所指位置的128字节区域被认为是保留的,不应由信号或中断处理程序修改。因此,函数可以将此区域用于函数调用中不需要的临时数据。特别是,叶函数可以将此区域用于其整个堆栈帧,而不是在序言和尾声中调整堆栈指针。该区域称为红色区域。”

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


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