天天看点

浅谈内存函数栈中的栈帧

栈是函数调用的实现基础,而栈帧就是函数调用栈中的一个基础知识点。对栈帧理解后能更好的理解函数运行过程。

简单来理解,程序运行过程中,PC指针每遇到一个函数,栈都会新增一个栈帧。栈帧记录着函数的参数,返回地址,父函数的栈底指针和自身相关的局部变量等。理解栈帧前先明确以下几个寄存器概念:

  • esp,栈顶指针
  • ebp,栈底指针
  • pc,指向程序运行的下一行程序地址

    注意:ebp指向当前位于系统栈最上边一个栈帧的底部,而不是系统栈的底部。严格说来,“栈帧底部”和“栈底”是不同的概念;esp所指的栈帧顶部和系统栈的顶部是同一个位置。

下面以一个简单的函数调用,对应函数的运行状态总结下栈帧的生命周期。程序的执行顺序如代码注释

int fun(int x, int y)
{
	int c = 4;					//4
	return c;					//5
}
int main()						//1
{
	int a = 1;
	int b = 2;					//2
	fun(a, b);					//3
	printf("hello world\n");	//6
	return 0;					//7
}
           

首先main函数也是被运行库调用的所以,栈会有一个初始状态。

浅谈内存函数栈中的栈帧

两个关键点

1、函数调用,参数由右到左依次拷贝压栈,跟新PC指针到fun函数起始地址,更新栈底指针ebp为当前栈顶也就是ebp = esp

2、函数返回,更新PC指针为返回地址,跟新ebp栈底指针为old esp(上一级的栈底)。跟新esp为栈ebp,销毁函数栈帧。

疑:学习栈帧之前一直有个疑问,栈都是先进后出的,那比如我定义了a和b个局部变量,现在想用a的值,岂不是要先把b出栈???实在不然,栈的先进后出只是对于新增删除而言,一个栈内的变量都是可以通过ebp-x(x带边变量在栈帧中的偏移)来访问的。

总结栈帧的组成:参、返、B、局

继续阅读