C语言 - 理解函数栈帧
一:概述
函数栈帧是函数调用过程中为管理和存储函数相关信息(如局部变量、返回地址等)而在栈上分配的一块内存区域。它是实现函数调用、递归和返回的关键机制。
二:栈帧的组成
一个典型的栈帧通常包含以下内容(从高地址到低地址):
-
函数参数(Function Arguments)
如果函数的参数通过栈传递,它们会首先被压入栈中。 -
返回地址(Return Address)
调用函数时,记录调用方的下一条指令的地址,以便函数执行完毕后返回。 -
帧指针(Frame Pointer, FP 或 Base Pointer, BP)
保存调用者的帧指针,以便能够恢复调用者的栈帧。 -
局部变量(Local Variables)
存储函数的局部变量。这些变量的大小和数量由编译器决定。 -
寄存器保存区(Saved Registers)
如果函数调用需要用到寄存器,则必须保存调用者寄存器的值,以便函数返回后恢复。
三:函数调用过程中的栈帧变化
对于32位 x86架构,有下列寄存器会在函数调用过程中用到:
1. eip 指令寄存器,指示下一条要执行的指令。
2. esp 栈顶寄存器
3. epb 栈底寄存器
4. eax, ebx, ecx, edx 通用寄存器
5. esi, edi 源和目的索引地址寄存器
6. eflags 状态寄存器
对于64位 x86架构,上面栈寄存器名称使用 r 前缀,比如 rbp, rsp等, 有更大的寻址空间。
下面通过一个列子来看看寄存器的变化
#include <stdio.h>void foo(int a, int b)
{int c = a * b;int d = a / b;printf("%d %d\n", c, d);
}int main(int argc, char* argv[])
{int x = 4;int y = 5;foo(y, x);return 0;
}
main函数反汇编如下: