我正在了解堆栈如何在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个字节,而无需分配空间。因此,如果我在add()
内插入对任何其他哑函数的调用-sub rsp, X
和add rsp, X
将分别添加到序言和结语中。