从add函数分析函数栈帧的创建和销毁

来源:互联网 发布:网络东北大秧歌曲大全 编辑:程序博客网 时间:2024/06/11 11:59

对于加法函数add:

#inlcude <stdio.h>int add(int x, int y){    return x + y;}int main(){    int a = 10;    int b = 20;    int ret = 0;    ret=add(a, b);    system("pause");    return 0;}

为了理解执行的过程,先转到反汇编代码:
这里写图片描述
首先是”main”函数调用过程。
“ebp”和”esp”是用来维护函数的栈底指针和栈顶指针。
1.”push ebp” 即压栈,将运行时堆栈”_mainCRTStarup”函数的”ebp”压栈,在栈顶开辟出一块空间,放入”ebp”的地址;
2.”mov”,”ebp,esp” 此时”ebp”指向刚开辟出的顶端空间;
3.”esp”减去”0E4h”大小的值,在栈中元素存放是高地址到低地址,则此步骤相当于”ebp”上开辟了”0E4h”大小的空间;(给”main”函数开辟空间)
4.”push” 将”ebx “”esi” “edi”进行压栈,”esp”则接着指向edi的顶端;
5.”lea” 将”ebp-0E4h”的地址放入”edi”;
6.对于之后的三步”mov”—”mov”—”ret”,我们可以总结为:将”0CCCCCCCCh”这个内容循环拷贝39h次,放入”edi”存储的地址中。
这一步我们可以理解为初始化,即将刚刚开辟的”main”函数的空间全部初始化为”0CCCCCCCCh”。
这里写图片描述
7.”ebp-8”,”ebp-14h”,”ebp-20h”这三块空间放入10,20,0,相当于将”10”赋给a,20赋给”b”,并且将”ret”初始化为0;
这里写图片描述
8.”ebp-14h”里面存放着b的值,将他赋给”eax”并将”eax”压栈;同理”ebp-8”存放着a的值,将他赋值给”ecx”并将”ecx”压栈;
9.调用”call”指令。在调用”call”指令的同时,在”ecx”的上方又开辟了一块空间用于存放”call”指令下一条指令的地址(这个地址的作用是在”call”指令调用”add”函数结束的的时候jump指令能够找到”call”指令下一条指令的地址,从而回到”main”函数中);
这里写图片描述
10.由”call”指令进入函数之后,先进行压栈,同”main”函数开辟空间,在’main”函数上方开辟了大小为”0C0h”的空间,并进行相同的初始化。
这里写图片描述
11.因为此时的”ebp”指向”add”函数的栈底,所以”ebp+8”和”ebp+0Ch”的值分别为10,20;经过”mov”,”add”后,将和的值30赋值给”eax”,”eax”将会把和值30带回到”main”函数中;
12.之后执行”pop”出栈操作,”edi”“esi”“ebx”三块空间出栈,esp向下移动,将”ebp”的地址给”esp”后,”ebp”进行出栈操作;此时相当于add函数彻底被销毁了;
13.执行”ret”指令,”ret”指令会跳转到”call”指令下一条指令的地址,然后再执行一次出栈操作;
这里写图片描述
14.”call”指令下一条指令是”add esp,8”;即将”esp”向下移动8个字节,相当于将刚才的10和20也进行了出栈操作。
15.将”eax”的值30,放入到”ebp-20h”中,即”ret”的值被赋值为30;
16.”xor”操作,将两个相同的”eax”异或归零。
这里写图片描述
17.同”add”函数被销毁的过程一样,直到”esp”,”ebp”回到”_mainCRTStarup”函数相应的位置,整个函数运行结束。
这里写图片描述

原创粉丝点击