天天看點

淺談記憶體函數棧中的棧幀

棧是函數調用的實作基礎,而棧幀就是函數調用棧中的一個基礎知識點。對棧幀了解後能更好的了解函數運作過程。

簡單來了解,程式運作過程中,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、局

繼續閱讀