关于 栈帧变化完整流程图(函数嵌套)

一、什么是栈帧(Stack Frame)

当一个函数被调用时,会在栈上开辟一段空间,叫做 栈帧

每个栈帧保存了:

  • 函数的参数

  • 返回地址(从哪里跳回来)

  • 上一个栈帧的栈底指针(保存调用者的 EBP / FP)

  • 局部变量

  • 保存的一些寄存器(可选)


二、函数嵌套调用例子

以 C 为例:

cpp 复制代码
void C() {
    int c = 3;
}

void B() {
    int b = 2;
    C();
}

void A() {
    int a = 1;
    B();
}

int main() {
    A();
    return 0;
}

三、每次函数调用的栈帧结构(以 x86 为例)

栈增长方向:从高地址向低地址

每次调用栈帧大致如下(从下到上):

bash 复制代码
高地址
│
│  上一帧的 EBP(caller 的栈底)
│  返回地址(RET)
│  参数(如有)
│  局部变量(如 int x)
│
↓
低地址

四、函数嵌套时完整栈帧流程图

以调用链**main → A → B → C** 为例,假设每层函数内部有 1 个**int** 局部变量。

bash 复制代码
初始状态:
栈空

main() 被调用:
+-------------------+ ← ESP,EBP(main 的栈底)
| 返回地址          |
+-------------------+
| 局部变量 return=0 |
+-------------------+

main() → A()
+-------------------+ ← ESP(当前)
| 返回地址(main)    |
+-------------------+
| 上一帧的 EBP      |
+-------------------+
| 局部变量 a=1      |
+-------------------+

A() → B()
+-------------------+
| 返回地址(A)       |
+-------------------+
| 上一帧的 EBP      |
+-------------------+
| 局部变量 b=2      |
+-------------------+

B() → C()
+-------------------+
| 返回地址(B)       |
+-------------------+
| 上一帧的 EBP      |
+-------------------+
| 局部变量 c=3      |
+-------------------+

栈顶 (ESP)

五、函数返回时的栈帧回退过程

函数返回时,会弹出当前栈帧,恢复上一个函数的栈帧(EBP 和 RET 地址)。

bash 复制代码
C() return → ESP 恢复到 B()
B() return → ESP 恢复到 A()
A() return → ESP 恢复到 main()
main() return → 程序结束

六、流程图总结

bash 复制代码
main
│
├── 调用 A()
│   │
│   └── 调用 B()
│       │
│       └── 调用 C()
│
└── 每层函数进栈,栈帧不断叠加
    每层函数返回,栈帧依次弹出

七、可视化理解

bash 复制代码
栈顶
│
│  C 的局部变量
│  返回地址(B)
│
│  B 的局部变量
│  返回地址(A)
│
│  A 的局部变量
│  返回地址(main)
│
│  main 的局部变量
│  返回地址(操作系统)
↓
栈底

八、汇编视角分析

以 x86 为例,函数调用时常见的指令:

Clojure 复制代码
CALL func   ; 压入返回地址 → 跳转
PUSH EBP    ; 保存当前帧
MOV EBP, ESP; 建立新栈帧
SUB ESP, n  ; 为局部变量分配空间
...
MOV ESP, EBP; 恢复 ESP
POP EBP     ; 恢复上层栈帧
RET         ; 弹出返回地址

九、总结

步骤 栈帧变化 关键指令
函数调用 新栈帧入栈 CALLPUSH EBP
建立栈帧 保存旧帧 & 分配空间 MOV EBP, ESPSUB ESP, n
函数返回 弹出栈帧 MOV ESP, EBPPOP EBPRE

补充:

  • 在 x86_64 下,函数参数会用寄存器传递(如 RDI、RSI)

  • 在 ARM64 下,栈帧也有 FP/LR(Frame Pointer / Link Register)结构

  • 调用链跟踪调试可用 gdb、ida、ghidra 中的栈回溯(backtrace)

相关推荐
kebeiovo1 天前
项目必备流程图,类图,E-R图实例速通
开发语言·r语言·流程图
晋人在秦 老K1 天前
入梦工具箱怎么检测硬件?3步完成CPU-Z跑分测试 硬件检测总出错?图吧工具箱免费功能实测 draw.io 部署指南:私有化流程图服务搭建教程
测试工具·流程图·工具·draw.io
zzywxc7872 天前
AI在金融、医疗、教育、制造业等领域的落地案例(含代码、流程图、Prompt示例与图表)
人工智能·spring·机器学习·金融·数据挖掘·prompt·流程图
ui小新4 天前
什么是流程图:流程六要素、三大结构及绘制规范总结
流程图·设计工具·流程图设计
小道士写程序4 天前
如何简单理解状态机、流程图和时序图
java·开发语言·流程图
zzywxc7874 天前
深入探讨AI三大领域的核心技术、实践方法以及未来发展趋势,结合具体代码示例、流程图和Prompt工程实践,全面展示AI编程的强大能力。
人工智能·spring·机器学习·ios·prompt·流程图·ai编程
皆过客,揽星河5 天前
c语言程序之魂——算法(练习题,流程图,程序源码)
c语言·算法·流程图·源码·辗转相除法·c语言程序设计
晓风残月淡5 天前
Mermaid流程图更改样式的方法
css·流程图·css3
disgare5 天前
如何画时序图、流程图
流程图
低代码布道师11 天前
UX 设计入门终章:让洞察落地!用用户流程图、IA 和旅程图,设计用户与产品的互动故事
大数据·流程图·ux