函数调用过程详解:函数栈帧的创建与销毁

前言:我们在学习C语言的过程中,可以会产生很多疑问,比如:

  • 局部变量是怎么创建的
  • 为什么局部变量的值不做初始化就是随机值
  • 函数是怎么传参的?传参的顺序是怎么样的?
  • 形参和实参是什么关系?
  • 函数调用是怎么做的?
  • 函数调用结束后是怎样返回的?

注意:本文博主选用VS2013进行讲解,同时在不同的编译器下,函数调用过程中栈帧的创建是略有差异的,具体细节取决于编译器的实现。

而这些种种的疑问,我们都能在 函数栈帧的创建与销毁中 一一进行解答,相信大家看了本文后,都能对函数是如何调用的做出自己独特的见解,话不多说,下面博主就将函数栈帧的创建与销毁过程一一讲解:


1. 基础认知

首先我们以以下代码作为实列进行讲解:

#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 c = 0;
	c = Add(a, b);

	printf("%d\n", c);

	return 0;
}

我们对代码F10进行调式,之后在反汇编窗口中我们可以看到以下信息:
在这里插入图片描述
通过观察底层代码中我们不难发现,我们平时一直使用的main函数竟然也是被调用的,他们的调用关系如下:
在这里插入图片描述

在这里插入图片描述

3 调用了 2 , 2 又去调用了 1 (main函数)

接着我们需要了解,在CPU中存在在若干寄存器,如: (加粗是重点)

(1)esp:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。 (栈顶指针)
(2)ebp:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。 (栈底指针)

(3)eax 是”累加器”(accumulator), 它是很多加法乘法指令的缺省寄存器。
(4)ebx 是”基地址”(base)寄存器, 在内存寻址时存放基地址。
(5)ecx 是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器。 (6)edx 则总是被用来放整数除法产生的余数。
(7)esi/edi分别叫做”源/目标索引寄存器”(source/destination index),因为在很多字符串操作指令中, DS:ESI指向源串,而ES:EDI指向目标串. 在32位平台上,ESP每次减少4字节。

寄存器中存放的是地址,esp ebp 这两个地址是用来维护函数栈帧的。

在这里插入图片描述

2. 函数栈帧的创建

在开始讲解前我们先来了解提交反汇编指令:

mov :数据传送指令,也是最基本的编程指令,用于将一个数据从源地址传送到目标地址(寄存器间的数据传送本质上也是一样的) (右边传进左边)
sub:减法指令
lea:取偏移地址 (加载有效地址 )
push:实现压入操作的 (压栈)
pop:实现弹出操作的指令
call:用于保存当前指令的下一条指令并跳转到目标函数。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.函数栈帧的销毁

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
至此,有关该函数的栈帧的创建与销毁我们就大致梳理了一遍,最终 Add 函数加法运算的值是存放在寄存器 eax 中的,所以 Add函数栈帧销毁了也不会影响和©的值的打印。


Last .总结

通过该函数栈帧的创建与销毁过程分析我们就可以解答文章开头给出的种种疑问:

  • 局部变量是怎么创建的
    答:局部变量是通过在该函数栈帧初始化一定空间后,在该空间分配的一部分空间创建的。
  • 为什么局部变量的值不做初始化就是随机值
    答:因为不初始化操作的话这些空间中的值是编译器给定的一些随机数 (如上面的cccccccc)
  • 函数是怎么传参的?传参的顺序是怎么样的?
    答:在调用函数前已经push push 从右向左顺序压栈进去,在Add函数中通过指针的偏移找到了实参。
  • 形参和实参是什么关系?
    答:形参只是实参的一份临时拷贝,改变形参的量不影响实参的变化
  • 函数调用是怎么做的?
    答: 详情见上文。
  • 函数调用结束后是怎样返回的?
    答:再调用Add函数之前我们就把call指令下面的地址压栈进去啦,返回时候弹出ebp就能找到原始main函数ebp的地址,实现返回。返回值是存在寄存器eax中的 ,实现打印

至此有关函数栈帧的创建与返回介绍就完毕啦,如果觉得文章对自己有所帮助还望大家多多点赞 ~ 谢谢各位啦 !

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值