C语言:函数栈帧的创建与销毁

目录

  • [1. 前言](#1. 前言)
  • [2. main函数栈帧的创建](#2. main函数栈帧的创建)
  • [3. 变量空间的开辟与初始化](#3. 变量空间的开辟与初始化)
  • [4. 传参与Add函数栈帧的创建](#4. 传参与Add函数栈帧的创建)
  • [5. Add函数内的运算与返回值](#5. Add函数内的运算与返回值)
  • [6. Add函数栈帧的销毁](#6. Add函数栈帧的销毁)

1. 前言

  1. 不同的开发环境对于函数栈帧的创建与销毁,实现细节上是不同的,但思路上大体相同,我们接下来对函数栈帧的刨析都是基于vs2013这一个集成开发环境的结果。
  2. 观察所用示例代码,如下:
cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 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;
}
  1. 接下来我们会配合编译生成的汇编代码,监视窗口,内存窗口等工具,在调试模式下,来具体观察函数栈帧创建于销毁的每一步骤。

2. main函数栈帧的创建

  1. vs2013中,main函数也是被其他函数调用的(__tmainCRTStartup)
  2. 函数栈帧的创建都是自高地址向低地址进行
  3. 图中,esp,ebp,ebx等单词缩写都代表着计算机中的寄存器,我们可以将他们视作独立于内存之外的一块块小空间,可以用来存储各种数据,参与各种运算
  4. esp,ebp这两个寄存器,我们分别称之为栈顶指针 (esp),栈底指针(ebp),他们分别用来维护函数栈帧的栈顶与栈底地址,在整个函数栈帧的创建中起着至关重要的作用
  5. lea(load efficient address):载入有效地址,给寄存器edi中,存入值ebp - 0E4h,记录可用的内存地址边界
  6. word两个字节,dword(double word)四个字节
  7. 初始化开辟的函数栈帧空间:
    <1> mov ecx, 39h,将39h存入寄存器ecx
    <2> mov eax, 0CCCCCCCCH,将0CCCCCCCCh存入寄存器eax中
    <3> rep stos dword ptr es: edi,从edi记录的地址开始,向下以四字节为单位,以0CCCCCCCCh为内容初始化39h次

3. 变量空间的开辟与初始化

  1. 第一个变量开辟空间,地址与ebp(栈底指针)间隔4字节
  2. 其余定义变量,地址与前一个变量间隔8字节

4. 传参与Add函数栈帧的创建

  1. 向Add函数传参的方式为,将对应的参数值压栈至main函数的栈顶
  2. 压栈的顺序根据函数参数自右向左
  3. 正式创建Add函数栈帧之前,会将main函数栈底指针(ebp)的地址,作为元素压入main函数栈顶,以便后续Add函数执行完毕返回main函数的栈帧空间中
  4. call指令执行后会跳转至对应的指令地址处,并且记录call指令的下一条指令地址

5. Add函数内的运算与返回值

  1. 获得传参的方式为以当前函数栈帧的栈底指针为基准,向下找寻此前最后压入main栈顶的参数值
  2. 计算方式为,以寄存器为载体,最后将结果赋予对应的内存空间
  3. 当有返回值要被返回时,函数返回值会被记录到对应的寄存器中,从而被带回

6. Add函数栈帧的销毁

  1. Add函数栈帧的销毁,首先将栈顶的三个元素弹出栈帧,弹出后栈顶指针对应缩减下移
  2. pop ebp,此条指令执行完成之后,栈底指针(ebp)会通过指向的main函数ebp地址重新指向main函数的栈底,而栈顶指针(esp)只被视作弹出了一个元素,指针下移一个元素
  3. ret指令指令执行后,执行流返回到先前要执行的下一条指令地址处
  4. add esp, 8,栈顶指针下移8个字节,将Add函数的参数弹出main函数栈帧
相关推荐
LuminousCPP1 小时前
数据结构-双向循环链表
c语言·数据结构·笔记·链表
小僧景贤4 小时前
嵌入式C语言 第二篇:基础语法|嵌入式C与标准C的核心差异
c语言·开发语言·嵌入式c语言
wuyk5556 小时前
1.栈:后进先出的线性数据结构
c语言·数据结构·stm32·单片机
LuminousCPP7 小时前
数据结构-时间与复杂度|时间/空间复杂度 + 两道力扣练习 + 二分查找复盘
c语言·数据结构·经验分享·算法·leetcode
带鱼吃猫7 小时前
预处理器:宏、运算符与条件编译
c语言·开发语言
(Charon)8 小时前
【C++】线程安全队列(二):生产者消费者模型与 condition_variable 阻塞等待
c语言·开发语言·c++
SunnyByte8 小时前
排序进阶:快速排序与归并排序的迭代实现,并与递归版本对比
c语言·数据结构·算法·排序算法
wuminyu10 小时前
JDK21解决虚拟线程IO阻塞原理剖析
java·linux·c语言·jvm·c++
MC皮蛋侠客12 小时前
TDengine C++ 系列(5):C/C++ 连接器——连接管理与查询 API
c语言·c++·tdengine
天空'之城12 小时前
C 语言工业级通用组件手写 27:配置参数管理组件
c语言·eeprom·参数管理·工业级组件·掉电存储