棧是函數調用的實作基礎,而棧幀就是函數調用棧中的一個基礎知識點。對棧幀了解後能更好的了解函數運作過程。
簡單來了解,程式運作過程中,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、局