我正在了解堆栈如何在 x86 和 x64 机器上工作。然而,我观察到的是,当我手动编写代码并对其进行反汇编时,它与我在人们提供的代码中看到的不同(例如,在他们的问题和教程中)。这是一个小例子:
资源
int add(int a, int b) {
int c = 16;
return a + b + c;
}
int main () {
add(3,4);
return 0;
}
x86
add(int, int):
push ebp
mov ebp, esp
sub esp, 16
mov DWORD PTR [ebp-4], 16
mov edx, DWORD PTR [ebp+8]
mov eax, DWORD PTR [ebp+12]
add edx, eax
mov eax, DWORD PTR [ebp-4]
add eax, edx
leave (!)
ret
main:
push ebp
mov ebp, esp
push 4
push 3
call add(int, int)
add esp, 8
mov eax, 0
leave (!)
ret
现在去 x64
add(int, int):
push rbp
mov rbp, rsp
(?) where is `sub rsp, X`?
mov DWORD PTR [rbp-20], edi
mov DWORD PTR [rbp-24], esi
mov DWORD PTR [rbp-4], 16
mov edx, DWORD PTR [rbp-20]
mov eax, DWORD PTR [rbp-24]
add edx, eax
mov eax, DWORD PTR [rbp-4]
add eax, edx
(?) where is `mov rsp, rbp` before popping rbp?
pop rbp
ret
main:
push rbp
mov rbp, rsp
mov esi, 4
mov edi, 3
call add(int, int)
mov eax, 0
(?) where is `mov rsp, rbp` before popping rbp?
pop rbp
ret
如您所见,我的主要困惑是当我针对 x86 进行编译时 - 我看到了我的期望。当它是 x64 时 - 我错过了离开指令或确切的以下序列:mov rsp, rbp
然后pop rbp
. 穿什么?
更新
它似乎leave
丢失了,只是因为它以前没有被改变过。但是,还有另一个问题——为什么框架中没有本地变量的分配?
对于这个问题@melpomene给出了非常简单的答案 - 因为“红色区域”。这基本上意味着不调用其他函数(叶)的函数可以使用堆栈下方的前 128 个字节而无需分配空间。因此,如果我在 an 内插入add()
对任何其他哑函数的调用 -sub rsp, X
并将add rsp, X
分别添加到序言和结尾。