C++ 为什么x64上的函数epilog没有“leave”指令?
我正在了解堆栈在x86和x64机器上的工作原理。然而,我观察到,当我手动编写代码并将其反汇编时,它与我在人们提供的代码中看到的不同(例如,在他们的问题和教程中)。以下是一个小例子: 来源C++ 为什么x64上的函数epilog没有“leave”指令?,c++,c,assembly,x86-64,red-zone,C++,C,Assembly,X86 64,Red Zone,我正在了解堆栈在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
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时-我错过了leave指令或精确的以下顺序:mov-rsp,rbp
thenpop-rbp
。怎么了
更新
似乎leave
丢失了,只是因为它以前没有被更改。但是,还有一个问题——为什么框架中没有本地变量的分配
对于这个问题给出了非常简单的答案——因为“红色区域”。这基本上意味着不调用其他函数(leaf)的函数可以在不分配空间的情况下使用堆栈下面的前128个字节。因此,如果我在一个
add()
到任何其他哑函数的内部插入一个调用-子rsp,X
和add rsp,X
将分别添加到序言和尾声中。Esp未被更改,因此无需执行任何操作。为什么要恢复一些不受影响的东西是的,我现在明白了,就在你提到之前。我已经更新了帖子。现在,还有另一个问题..看.如果调用add()中的函数会发生什么?e、 g使用intf(){return 5;}
将其更改为a+b+c+f()
。我很好奇在调用f
之前,rsp
会发生什么。应该调整它,否则局部变量将被覆盖。@AndreasH。它添加了推送rbx;将rsp 16分到序言中,并将rsp 16添加到序言中;弹出rbx
至尾声