"There is no need to deallocate the stack at the end of the function when the inner-stack frame isn't modified",但在本例中正在修改

"There is no need to deallocate the stack at the end of the function when the inner-stack frame isn't modified", but it is being modified in this case

这是一个简单的函数

#include <stdio.h>

int foo() {
    int a = 3;
    int b = 4;
    int c = 5;
    return a * b * c;
}

int main() {
    int a = foo();
}

foo() 的程序集看起来像

foo:
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], 3
        mov     DWORD PTR [rbp-8], 4
        mov     DWORD PTR [rbp-12], 5
        mov     eax, DWORD PTR [rbp-4]
        imul    eax, DWORD PTR [rbp-8]
        imul    eax, DWORD PTR [rbp-12]
        pop     rbp
        ret

rbp - N 所示,正在修改内部堆栈框架。那么,为什么没有 leaveadd rsp, n

从堆栈指针不变的意义上说,它“未修改”。因为我们从来没有在进入时从 rsp 中减去任何偏移量,所以我们当然不应该在退出时添加任何偏移量。

leave只是相当于mov rsp, rbp ; pop rbp。我们确实包含了 pop rbp,而 mov rsp, rbp 是多余的,因为如您所见,rsprbp 在代码中的那个点仍然相等。

事实上,这个函数将它的局部变量存储在堆栈上而没有为它们调整堆栈指针到“make space”,所以它们最终在堆栈指针。这是合法的,因为 x86-64 SysV ABI 要求 red zone;不进行任何函数调用的代码可以安全地使用堆栈指针下方的 128 个字节。信号处理程序保证不会覆盖它。

Why does the x86-64 GCC function prologue allocate less stack than the local variables?