浅谈函数的调用和栈帧的创建和销毁
2017-05-21 14:17
169 查看
演示代码:
转到反汇编如下:
第一部分:
首先,main函数在mainCRTStartup()中调用的,所以系统先给mainCRTStartup()开辟一块空间,即开辟栈帧,如图:
接下来看我们的汇编代码
push为压栈的意思,即把ebp的地址压入栈中,此时esp会向上移动指向新开辟的栈,如图:
即把esp的值赋给ebp,此时ebp 和esp指向同一个位置,此时esp会移开,但是我们这里暂时不动如图:
sub为减的意思,即esp指向esp-0E4h的这个地方,即开辟了0E4h这块空间,并且esp指向它的栈顶,这也是为main函数开辟了空间
三个push压栈分别将ebx,esi,esi,分别按顺序压入栈顶,此时esp也会向上指向栈顶,如图
这句话的意思是把[ebp-0E4h]的值放入edi中,这样edi便指向了[ebp-0E4h]的位置,如图:
首先看第一句话意思是把39h放到ecx中(ecx是寄存器),重复rep的前指令。
第二句话的意思是把0CCCCCCCCh放入eax中(eax也是寄存器)。
第三句话的意思是对edi所指向的位置开始向高地址进行拷贝,拷贝的内容为eax的内容,拷贝次数为39h次(即对ebp-0E4h这块区域进行了初始化)。如图
我们继续向下看
第二部分的代码
继续分析我们的代码
int a=10,mov dword ptr [ebp-8],0Ah(10),这句话的意思即把10放入ebp-8的位置;
以此类推,分别把20放入ebp-14h的位置,把0放入ebp-20h的地方,这里相当于创建好了变量a,b,ret并且分别赋上了相应的值。机器并不认识你的变量名,只认识地址
忘记说栈帧中从栈底到栈顶是高地址指向低地址。如图
在这里,mov eax,dword ptr [ebp-14h]
push eax,
的意思就是把ebp-14hd的值放入eax中,然后对eax进行压栈,刚才已经知道ebp-14h里面放的是20的值,所以在这里相当于函数的传参,并且把参数进行了压栈,
此时esp会向上移动并且指向ecx栈顶
所以如图所示
在这里call 00AE10EBd的意思是再一次进行压栈,将00AE10EB压进去,然后进入add()函数里面
接下来看我们的add函数部分代码
首先我们可以看到
这段代码和main函数开始的代码一样,都是先将ebp压栈,这里的ebp是main函数的ebp,然后开辟空间,然后再进行三次压栈,然后初始化
当然esp和ebp也会改变他们的位置,此时相当于开辟了add函数的栈帧,如图
这句话的意思是把0放到ebp-8的位置,即创建变量z并且赋值为0
在这里相当于把ebp+8放到了eax中,即将10的值放入eax中,然后再将20(ebp+0Ch)的值和eax中的值(10)进行相加,所以现在eax中的值为30
然后再将eax(30)的值放入ebp-8(即变量z)中
如图
在这里把ebp-8的值放回到寄存器eax中返回,因为ebp-8为函数临时开辟的变量空间等函数执行完会销毁,这样的话就不能将结果返回去,所以放在寄存器中返回,
接来下执行pop出栈操作,edi,esi,ebx分别从上向下出栈,体现了栈的特点:先进后出,后进先出。然后将ebp的值赋值给esp,esp向下移动指向ebp的位置,之后pop ebp,这个时候ebp返回继续维护main函数的栈帧,在这个时候上面的空间不属于你了,但依然存在。
在这里,执行ret指令后,会把之前push 的地址(00AE10EB)弹出去,这个时候就从Add()函数返回main()函数了。这就是为什么当初要push这个地址了,这样call指令就完成了。程序走完自动会到当初call指令的下一条指令
给esp+8意思即把esp向下移,即把形参也弹出去了,形参被销毁,然后把eax(里面存的是30)放到ebp-20h(ret)中
到这里Add函数栈帧的调用和销毁已经完成。接下来就是对main()函数的返回和栈帧的销毁和Add()函数一样,就不继续做讲解了。
最后附上整个流程图
上面的整个流程就是函数栈帧的创建和销毁。
如果哪里有错误的地方欢迎大家积极指出!!!
#include<stdio.h> int Add(int x,int y) { int z=0; z=x+y; return z; } int main() { int a=10; int b=20; int ret=0; ret=Add(a,b); return 0; }
转到反汇编如下:
第一部分:
int main() { 00AE1420 push ebp 00AE1421 mov ebp,esp 00AE1423 sub esp,0E4h 00AE1429 push ebx 00AE142A push esi 00AE142B push edi 00AE142C lea edi,[ebp-0E4h] 00AE1432 mov ecx,39h 00AE1437 mov eax,0CCCCCCCCh 00AE143C rep stos dword ptr es:[edi]
首先,main函数在mainCRTStartup()中调用的,所以系统先给mainCRTStartup()开辟一块空间,即开辟栈帧,如图:
接下来看我们的汇编代码
1.00AE1420 push ebp
push为压栈的意思,即把ebp的地址压入栈中,此时esp会向上移动指向新开辟的栈,如图:
2.00AE1421 mov ebp,esp
即把esp的值赋给ebp,此时ebp 和esp指向同一个位置,此时esp会移开,但是我们这里暂时不动如图:
3.00AE1423 sub esp,0E4h
sub为减的意思,即esp指向esp-0E4h的这个地方,即开辟了0E4h这块空间,并且esp指向它的栈顶,这也是为main函数开辟了空间
4. 00AE1429 push ebx 00AE142A push esi 00AE142B push edi
三个push压栈分别将ebx,esi,esi,分别按顺序压入栈顶,此时esp也会向上指向栈顶,如图
5.00AE142C lea edi,[ebp-0E4h]
这句话的意思是把[ebp-0E4h]的值放入edi中,这样edi便指向了[ebp-0E4h]的位置,如图:
6.00AE1432 mov ecx,39h 00AE1437 mov eax,0CCCCCCCCh 00AE143C rep stos dword ptr es:[edi]
首先看第一句话意思是把39h放到ecx中(ecx是寄存器),重复rep的前指令。
第二句话的意思是把0CCCCCCCCh放入eax中(eax也是寄存器)。
第三句话的意思是对edi所指向的位置开始向高地址进行拷贝,拷贝的内容为eax的内容,拷贝次数为39h次(即对ebp-0E4h这块区域进行了初始化)。如图
我们继续向下看
第二部分的代码
00AE143C rep stos dword ptr es:[edi] int a = 10; 00AE143E mov dword ptr [ebp-8],0Ah int b = 20; 00AE1445 mov dword ptr [ebp-14h],14h int ret = 0; 00AE144C mov dword ptr [ebp-20h],0 ret = add(a, b); 00AE1453 mov eax,dword ptr [ebp-14h] 00AE1456 push eax 00AE1457 mov ecx,dword ptr [ebp-8] 00AE145A push ecx 00AE145B call 00AE10EB 00AE1460 add esp,8 00AE1463 mov dword ptr [ebp-20h],eax return 0;
继续分析我们的代码
7. int a = 10; 00AE143E mov dword ptr [ebp-8],0Ah int b = 20; 00AE1445 mov dword ptr [ebp-14h],14h int ret = 0; 00AE144C mov dword ptr [ebp-20h],0
int a=10,mov dword ptr [ebp-8],0Ah(10),这句话的意思即把10放入ebp-8的位置;
以此类推,分别把20放入ebp-14h的位置,把0放入ebp-20h的地方,这里相当于创建好了变量a,b,ret并且分别赋上了相应的值。机器并不认识你的变量名,只认识地址
忘记说栈帧中从栈底到栈顶是高地址指向低地址。如图
8. ret = add(a, b); 00AE1453 mov eax,dword ptr [ebp-14h] 00AE1456 push eax 00AE1457 mov ecx,dword ptr [ebp-8] 00AE145A push ecx
在这里,mov eax,dword ptr [ebp-14h]
push eax,
的意思就是把ebp-14hd的值放入eax中,然后对eax进行压栈,刚才已经知道ebp-14h里面放的是20的值,所以在这里相当于函数的传参,并且把参数进行了压栈,
此时esp会向上移动并且指向ecx栈顶
所以如图所示
9.00AE145B call 00AE10EB
在这里call 00AE10EBd的意思是再一次进行压栈,将00AE10EB压进去,然后进入add()函数里面
接下来看我们的add函数部分代码
00AE13D0 push ebp 00AE13D1 mov ebp,esp 00AE13D3 sub esp,0CCh 00AE13D9 push ebx 00AE13DA push esi 00AE13DB push edi 00AE13DC lea edi,[ebp+FFFFFF34h] 00AE13E2 mov ecx,33h 00AE13E7 mov eax,0CCCCCCCCh 00AE13EC rep stos dword ptr es:[edi] int z = 0; 00AE13EE mov dword ptr [ebp-8],0 z = x + y; 00AE13F5 mov eax,dword ptr [ebp+8] 00AE13F8 add eax,dword ptr [ebp+0Ch] 00AE13FB mov dword ptr [ebp-8],eax return z; 00AE13FE mov eax,dword ptr [ebp-8] } 00AE1401 pop edi 00AE1402 pop esi 00AE1403 pop ebx 00AE1404 mov esp,ebp 00AE1406 pop ebp 00AE1407 ret
首先我们可以看到
10.00AE13D0 push ebp 00AE13D1 mov ebp,esp 00AE13D3 sub esp,0CCh 00AE13D9 push ebx 00AE13DA push esi 00AE13DB push edi 00AE13DC lea edi,[ebp+FFFFFF34h] 00AE13E2 mov ecx,33h 00AE13E7 mov eax,0CCCCCCCCh 00AE13EC rep stos dword ptr es:[edi]
这段代码和main函数开始的代码一样,都是先将ebp压栈,这里的ebp是main函数的ebp,然后开辟空间,然后再进行三次压栈,然后初始化
当然esp和ebp也会改变他们的位置,此时相当于开辟了add函数的栈帧,如图
11. int z = 0; 00AE13EE mov dword ptr [ebp-8],0
这句话的意思是把0放到ebp-8的位置,即创建变量z并且赋值为0
12. z = x + y; 00AE13F5 mov eax,dword ptr [ebp+8] 00AE13F8 add eax,dword ptr [ebp+0Ch] 00AE13FB mov dword ptr [ebp-8],eax
在这里相当于把ebp+8放到了eax中,即将10的值放入eax中,然后再将20(ebp+0Ch)的值和eax中的值(10)进行相加,所以现在eax中的值为30
然后再将eax(30)的值放入ebp-8(即变量z)中
如图
13. return z; 00AE13FE mov eax,dword ptr [ebp-8]
在这里把ebp-8的值放回到寄存器eax中返回,因为ebp-8为函数临时开辟的变量空间等函数执行完会销毁,这样的话就不能将结果返回去,所以放在寄存器中返回,
14.00AE1401 pop edi 00AE1402 pop esi 00AE1403 pop ebx 00AE1404 mov esp,ebp 00AE1406 pop ebp 00AE1407 ret
接来下执行pop出栈操作,edi,esi,ebx分别从上向下出栈,体现了栈的特点:先进后出,后进先出。然后将ebp的值赋值给esp,esp向下移动指向ebp的位置,之后pop ebp,这个时候ebp返回继续维护main函数的栈帧,在这个时候上面的空间不属于你了,但依然存在。
15.00AE1407 ret
在这里,执行ret指令后,会把之前push 的地址(00AE10EB)弹出去,这个时候就从Add()函数返回main()函数了。这就是为什么当初要push这个地址了,这样call指令就完成了。程序走完自动会到当初call指令的下一条指令
16.00AE1460 add esp,8 00AE1463 mov dword ptr [ebp-20h],eax
给esp+8意思即把esp向下移,即把形参也弹出去了,形参被销毁,然后把eax(里面存的是30)放到ebp-20h(ret)中
到这里Add函数栈帧的调用和销毁已经完成。接下来就是对main()函数的返回和栈帧的销毁和Add()函数一样,就不继续做讲解了。
最后附上整个流程图
上面的整个流程就是函数栈帧的创建和销毁。
如果哪里有错误的地方欢迎大家积极指出!!!
相关文章推荐
- 谈谈函数的调用过程,栈帧的创建和销毁。
- 函数调用过程,栈帧的创建和销毁
- 函数的调用过程,栈帧的创建和销毁
- 浅谈函数的调用,栈帧的创建和销毁
- 函数的调用过程、栈帧的创建以及销毁
- 【C】函数的调用过程,栈帧的创建和销毁
- 函数的调用过程,栈帧的创建和销毁。
- 函数调用的具体过程以及栈帧的创建和销毁
- 函数的调用过程,栈帧的创建与销毁
- 函数调用过程,栈帧的创建和销毁
- 函数的调用,栈帧的创建和销毁
- 谈谈函数的调用过程,栈帧的创建和销毁。
- 函数的调用过程,栈帧的创建和销毁
- c语言函数调用过程(栈帧的创建与销毁)
- 函数的调用过程(栈帧的创建和销毁)
- 函数的调用过程,栈帧的创建和销毁
- 浅谈函数的调用过程,栈帧的创建和销毁,附图讲解
- 函数的调用过程 栈帧的创建和销毁
- 函数的调用(栈帧的创建和销毁)
- 函数的调用及栈帧的创建和销毁