浅谈函数的调用过程,栈桢的创建和销毁

版权声明: https://blog.csdn.net/spaceman_c/article/details/80045269
函数的调用
  • 函数的调用过程

    main 函数在_tmainCRTStartup函数调用中,而_tmainCRTStartup函数是早mainCRTStartup被调用的。

函数栈桢的创建和销毁

函数的调用过程要开辟栈空间,用于本次函数的调用中临时变量的保存、现场保存。这块栈空间我们称之为函数栈桢。

int add(int x,int y)
{
    int z = 0;
    z = x + y;
    return z;
}
int main()
{
    int a = 10;
    int b = 20;
    int ret = add(a, b);
    printf("%d\n", ret);
    system("pause");
    return 0;
}`

main 函数栈桢的创建
这里写图片描述
1:ebp和esp是用来维护函数栈底栈顶的指针,esp指向栈顶,ebp指向栈底;
在main函数被调用的时候,push ebp,就是压栈,在栈顶开辟一块空间,move esp,ebp esp指向新开辟的栈顶。
2:sub esp,0E4h esp减去0E4h大小的值在ebp的上面开辟了0E4h这个大小的空间,栈空间是从高地址向低地址走的。
3:push ebx,push esi,push edi进行三次压栈,esp指向栈顶。这里写图片描述
4:lea edi,[ebp-0E4h] 加载有效地址,把ebp-0E4h存放在edi这个寄存器中。
5:mov ecx,39h 将39h存放在ecx中。mov eax,0cccccccch 将0cccccccch存放在eax中。
6: rep stos dword ptr es:[edi] ,表示按双字节从ebp-0E4h往下拷贝39h次cccccccc 。这里写图片描述
局部变量初始化
7:把0Ah拷贝到ebp-8指向的这个地址空间,把14h拷贝到ebp-14这个地址空间中,这两个过程就是局部变量的初始化,如果不初始化里面的值就是cccccccc.
8:为调用add函数做准备,将b的值拷贝到eax中;push eax进行压栈,esp指向eax的地址空间。将a的值拷贝到ecx中;push eax进行压栈.
9:call指令,调用函数,在栈顶ecx又开辟了一块新空间,用于存放call指令下一条指令的地址,这个地址的作用是call指令调用add()结束时jump能够找到call指令下一条指令的地址。
这里写图片描述
这里写图片描述
10:add()函数空间的开辟和初始化
把0拷贝到 ebp-8这个空间里面去(创建临时变量ret 且初始化为0);
a的值拷贝到eax这个寄存器中间去;
b的值加上a的值加起来放在eax里面;
把eax里面的值拷给ebp-8也就是ret里面,ret的值变为30 ,再将ret的值放回到eax中;

这里写图片描述
11:pop是弹出的意思,将edi,esi,ebx这三块空间弹出;
将ebp给esp,意味着esp回到ebp所指向的地址,刚刚创建的add函数的空间瞬间被销毁;
pop ebp 这里弹出的ebp是main函数的ebp,所以ebp栈底指针回到main函数ebp的位置;
ret是指重复的意思,继续执行pop指令,pop这次弹出的是call指令,call指令面存放的是call指令的下一条指令的地址;所以ret执行按完成后,程序回到call指令下一条指令的地址;
这里写图片描述

12:call指令的下一条指令就是esp+8,把esp向下挪动8个字节,所以形参的两个空间ecx,eax被销毁;10和20 被弹出去,把eax带回来的值付给ebp-20;也就是ret所在的空间,此时ret复制为30;

猜你喜欢

转载自blog.csdn.net/spaceman_c/article/details/80045269
今日推荐