我想了解有关堆栈的更多信息。特别是,当调用带参数的函数时会发生什么。为此,我写下面的代码:
#include <stdio.h>
int sum(int d, int e, int f){
int result = d + e + f;
return result;
}
int main(void){
int a = 5;
int b = 4;
int c = 2;
int erg = sum(a,b,c);
printf("Result is: %d", erg);
}
我得到以下汇编代码(我只会添加main
函数的一部分,因为首先我要理解这一部分):
push ebp,
mov ebp, esp
and esp, -16
sub esp, 32
mov DWORD PTR[esp+28], 5
mov DWORD PTR[esp+24], 4
mov DWORD PTR[esp+20], 2
mov eax, DWORD PTR[esp+20]
mov DWORD PTR[esp+8], eax
mov eax, DWORD PTR[esp+24]
mov DWORTD PTR[esp+4], eax
mov eax, DWORD PTR[esp+28]
mov DWORD PTR[esp], eax
call sum
........
........
所以,对于这部分,我为自己绘制了一个小草图。请看一下 :)
我的问题:那时我的ebp
在哪里?由于汇编程序代码的第2行,它必须位于[esp]
的同一个地方,对吧?
现在,sum函数的一部分跟随我的第二个问题。
所以这是汇编代码:
push ebp
mov ebp, esp
sub esp, 16
mov eax, DWORD PTR[ebp+12]
mov edx, DWORD PTR[ebp+8]
mov edx, eax
------------
所以,我了解到我们可以在[eb+12]
和[ebp+8]
中找到我们的参数。
(我跳过了第三个参数,因为我想保持简单)
所以现在我的问题是:
如果我假设esp
= ebp
并且我看了我的草图,那么我发现[esp+12]
或现在[ebp+12]
中没有任何内容。但是,它被使用了。
我怎么能想象呢?
有人能帮助我吗?我读了这么多论文,但似乎没有人勾勒出这些东西。因此,很难理解这一点。
谢谢!
这是我的草图:
答案 0 :(得分:5)
在第一个函数执行期间esp
和ebp
仅在指令mov ebp, esp
之后立即执行相同的值。之后and esp, -16
将esp
的最低4位(最低半字节)归零,esp
和ebp
发散,除非esp
的最低位为零已经。然后sub esp, 32
从esp
减去32,此处esp
和ebp
分歧。
push ebp ; esp = esp - 4; [esp] = ebp.
mov ebp, esp ; ebp = esp. create the stack frame.
and esp, -16 ; make lowest 4 bits of esp zeros, for alignment.
sub esp, 32 ; esp = esp - 32. make space for local variables.
mov DWORD PTR[esp+28], 5 ; a = 5
mov DWORD PTR[esp+24], 4 ; b = 4
mov DWORD PTR[esp+20], 2 ; c = 2
mov eax, DWORD PTR[esp+20] ; eax = c (eax = 2)
mov DWORD PTR[esp+8], eax ; [esp+8] = dword 2
mov eax, DWORD PTR[esp+24] ; eax = b (eax = 4)
mov DWORTD PTR[esp+4], eax ; [esp+4] = dword 4
mov eax, DWORD PTR[esp+28] ; eax = a (eax = 5)
mov DWORD PTR[esp], eax ; [esp] = dword 5
call sum ; the above lines define the parameters for the
; function sum, that is called now.
然后关于你的第二个问题:
push ebp ; esp = esp - 4; [esp] = ebp.
mov ebp, esp ; ebp = esp.
sub esp, 16 ; esp = esp - 16. create space for local variables.
; at this point:
; [ebp] == old value of ebp.
; [ebp+4] == return address pushed by call,
; to be used by the next ret.
; [ebp+8] == dword 5 (a)
; [ebp+12] == dword 4 (b)
; [ebp+16] == dword 2 (c)
mov eax, DWORD PTR[ebp+12] ; eax = 4
mov edx, DWORD PTR[ebp+8] ; edx = 5. gets overwritten by the next instruction.
mov edx, eax ; edx = eax = 4
不要假设esp
== ebp
。在第二个函数中,esp
和ebp
在执行指令sub esp,16
时也会发生分歧。学习使用调试器,例如GDB并单步执行代码,并在每条指令后遵循寄存器(尤其是esp
)和内存的值。您也可以像上面那样调试头脑中的代码,但如果您是程序集的初学者,使用调试器通常会更容易,并且更不容易出错。
答案 1 :(得分:0)
以下对使用参数调用例程时堆栈,堆栈帧,ebp和esp的内容进行了相当不错的解释。我希望它有所帮助。 What is stack frame in assembly?