函数的调用及栈帧的创建和销毁

实例代码为:环境为vc++6.0

为了研究函数过程调用,我们先来了解几个寄存器,esp:堆栈指针寄存器,指向栈顶。ebp:基址寄存器,指向栈底。

eip/ip/pc:程序计数器。程序计数器保存的内容永远是当前正在执行指令的下一条指令的地址。

call:在调用函数的时候用。 1.通过修改eip来实现函数的跳转(jmp跳转)。

   2.将当前正在执行指令的下一条指令的地址保存起来,以便返回。

ret:将当前的栈顶的位置(返回值地址)返回到main函数里。在返回的时候要保证现在的内容写在ip里。

#include<stdio.h>
int myfunction(int x,int y)
{
int z=x+y;
return z;
}
int main()
{
int a=0xaaaaaaaa;
int b=0xbbbbbbbb;
int c=myfunction(a,b);
printf("you should run here!ret=%d\n",c);
return 0;
}

一.调用栈


首先我们通过打开call stack(调用堆栈)可以看出一个程序在运行的时候第一个执行的函数不是main函数,从这张图可以看出main函数是由mainCRTstartup()所调用,main函数虽然不是第一个被调用的函数,但main函数却是应用逻辑中的入口函数.所谓栈,是一种先进后出的数据结构,每一次的函数调用都是一个过程,在这个过程中要开辟一段栈空间,用于保存过程中的临时变量,现场保护,这段栈空间我们称为函数栈帧。



这张图清楚的展示了c程序的内存空间,栈通常是在用户空间的最高地址处分配,而堆通常位于栈的下方。对于栈而言,先入栈的低至高,后入栈的地址低,stack向下生长,即地址从大到小,而堆heap正好相反。

二.利用call调用myfunction函数




函数在形参实例化的顺序是从右到左的,从右到左的进行压栈。







三.执行后释放函数空间返回调用主函数





此时eip的内容变为00401093,即call的下一条指令的地址。





此时调用myfunction函数之后,和在调用myfunction函数之前是一样的,函数调用过程中调用的变量叫做临时变量,在当前调用函数的栈帧的栈顶结构处。函数调用调用之后的函数之中的变量以及栈帧结构都被释放掉,所以函数的临时变量具有临时性。每调用一个函数就是形成一个栈帧结构的过程,返回之后释放。函数返回通过寄存器返回。









  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值