"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
所示,正在修改内部堆栈框架。那么,为什么没有 leave
或 add rsp, n
?
从堆栈指针不变的意义上说,它“未修改”。因为我们从来没有在进入时从 rsp
中减去任何偏移量,所以我们当然不应该在退出时添加任何偏移量。
而leave
只是相当于mov rsp, rbp ; pop rbp
。我们确实包含了 pop rbp
,而 mov rsp, rbp
是多余的,因为如您所见,rsp
和 rbp
在代码中的那个点仍然相等。
事实上,这个函数将它的局部变量存储在堆栈上而没有为它们调整堆栈指针到“make space”,所以它们最终在堆栈指针。这是合法的,因为 x86-64 SysV ABI 要求 red zone;不进行任何函数调用的代码可以安全地使用堆栈指针下方的 128 个字节。信号处理程序保证不会覆盖它。
Why does the x86-64 GCC function prologue allocate less stack than the local variables?
这是一个简单的函数
#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
所示,正在修改内部堆栈框架。那么,为什么没有 leave
或 add rsp, n
?
从堆栈指针不变的意义上说,它“未修改”。因为我们从来没有在进入时从 rsp
中减去任何偏移量,所以我们当然不应该在退出时添加任何偏移量。
而leave
只是相当于mov rsp, rbp ; pop rbp
。我们确实包含了 pop rbp
,而 mov rsp, rbp
是多余的,因为如您所见,rsp
和 rbp
在代码中的那个点仍然相等。
事实上,这个函数将它的局部变量存储在堆栈上而没有为它们调整堆栈指针到“make space”,所以它们最终在堆栈指针。这是合法的,因为 x86-64 SysV ABI 要求 red zone;不进行任何函数调用的代码可以安全地使用堆栈指针下方的 128 个字节。信号处理程序保证不会覆盖它。
Why does the x86-64 GCC function prologue allocate less stack than the local variables?