函数的调用过程

 函数的声明和定义很容易理解,接下来我们来讲讲函数的调用的过程。

先插入简单的一段代码。

#include <stdio.h>
int Add(int x, int y)
{
	int z = 0;
	z = x + y;
	return z;
}
int main()
{
	int a = 10;
	int b = 10;
	int ret = Add(a,b);
	printf("ret = %d \n",ret);
	return 0;
}

函数的使用就是调用,那么main函数也不例外也是需要调用的,main函数先在  __tmainCRTStartup  函数中调用,而 __tmainCRTStartup 函数是在 mainCRTStartup  中被调用的。函数的每一次调用都是一个过程,叫做函数的调用过程

而函数的调用过程要为函数开辟栈空间,用于本次函数调用中临时变量的保存,现场保护。我们通常把这个栈空间叫做函数栈帧

栈帧的维护我们要了解两个寄存器,在函数调用的过程中这两个寄存器存放了维护这个栈的栈底和栈顶指针。

ebp:存放了指向函数栈帧栈底的地址。

esp:存放了指向函数栈帧栈顶的地址。



这就是调用mian函数时,栈维护的图解。

要更深入了解函数的调用过程,我们需要转到反汇编观察


可以自己打开内存验证一下是否被初始化   还有a,b是否已经创建并赋值。

接下来是函数Add的调用,参数传递过程

执行到call指令的时候按两次F11就进入Add函数的代码执行处如下图



ret指令会使出栈一次并将出栈的内容当做该地址。将程序执行跳转到该地址处。

栈的方向始终是栈底到栈顶并且esp始终存放的是栈顶的地址,ebp始终存放的是栈底的地址

这就是整个函数调用的大概过程,希望对大家能有帮助

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
函数调用过程是程序中常见的一种操作,它通常涉及到参数传递、栈帧的建立与销毁、返回值的传递等多个方面。从汇编的角度来看,函数调用过程可以分为以下几个步骤: 1. 将函数的参数压入栈中。在调用函数时,需要将函数所需的参数传递给它。这些参数通常以一定的顺序压入栈中,以便在函数内部使用。在 x86 架构中,参数的传递是通过将参数压入栈顶实现的。 2. 调用函数函数调用的指令通常是 CALL 指令。在调用函数前,需要将函数的入口地址压入栈中,以便在函数执行完毕后返回到调用位置。CALL 指令会将当前的程序计数器(PC)压入栈中,并将函数的入口地址作为新的 PC。 3. 建立栈帧。在函数调用时,需要为函数建立一个独立的栈帧,以便在函数内部使用局部变量和临时变量。栈帧通常包括以下几个部分:返回地址、旧的基址指针、局部变量和临时变量。在 x86 架构中,栈帧的建立是通过将 ESP 寄存器减去一个固定的值实现的。 4. 执行函数。在函数调用后,CPU 会跳转到函数的入口地址并开始执行函数函数内部可以通过栈中的参数和局部变量完成相应的计算和操作。 5. 返回值传递。在函数执行完毕后,需要将函数的返回值传递给调用者。在 x86 架构中,函数的返回值通常通过 EAX 寄存器传递。 6. 销毁栈帧。在函数执行完毕后,需要将栈帧销毁,以便释放栈空间。栈帧的销毁通常是通过将 ESP 寄存器还原到旧的基址指针处实现的。 7. 返回到调用位置。在函数执行完毕后,需要返回到函数调用的位置。在 x86 架构中,返回指令通常是 RET 指令。RET 指令会将栈顶的返回地址弹出,并将其作为新的 PC。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值