函式棧幀(呼叫過程)
函式棧幀就是在呼叫函式是為其在棧空間上開闢了一段空間,指向過程呼叫,一個過程呼叫包括將資料(以過程引數和返回值的形式)和控制從程式碼的一部分傳遞到另一部分。
- 棧是向下生長的,從高地址到低地址延伸的
- 每個函式的每次呼叫的過程,都有它自己獨立的一個棧幀結構,用於變數的儲存,現場的保護
- 要維護這個棧幀必須使用ebp(棧底指標)和esp(棧頂指標)這倆個暫存器
- cpu如何知道函式執行到哪裡——暫存器存放著函式當前正在執行指令的下一條指令
我們以以下程式碼為例講解整個函式呼叫過程:
int my_add(int x, int y)
{
int z = 0;
z = x + y;
return z;
}
int main()
{
int a = 0xaaaaaaaa;
int b = 0xbbbbbbbb;
int ret = my_add(a, b);
printf("you shuold running here!\n");
system("pause");
return 0;
}
一、呼叫main()函式:
我們從main()函式的地方開始,要展開main()函式的呼叫就得為main()函式建立棧幀。
- main()函式不是程式的第一個入口,它被start函式呼叫
- 函式的棧幀被釋放,並不是將其內容清空,而是做了一個標記,說明此空間裡面的資料無效了。當又有函式被呼叫形成棧幀是,直接覆蓋掉這塊空間就好了
- 將當前執行的指令的下一條指令的地址壓入Start函式的棧中
- strat函式呼叫main()函式,把ebp先壓棧,用來儲存strat函式ebp佔地指標的位置
- 將strat函式的esp的值賦給ebp,也就是讓ebp作為將要開闢的main函式的棧底
- 讓ebp減去某個值,這是在為main函式棧幀開闢空間
- 將mian函式中的變數依次壓入棧中
二、呼叫my_add函式:
- mian函式呼叫my_add函式,形參例項化(形參列表從右向左壓棧)
- 執行call命令,將當前正在執行的指令的下一條指令壓入棧中,並跳轉到指定函式
- 將main函式的ebp壓棧,用來儲存main函式的ebp指標位置
三、my_add函式棧幀的建立
- 將main的esp賦值給ebp,讓ebp作為my_add函式的棧底
- 讓esp減去某個值,讓他指向另一個位置,即my_add函式的棧頂
- 將my_add函式中的變數壓棧(按先後順序)
四、my_add函式呼叫完畢返回main函式
- my_add函式的返回值通過eap暫存器返回
- 將my_add函式的esp指向ebp,即銷燬了my_add函式的棧幀
- pop my_add函式ebp,恢復到原來main的ebp(在呼叫之前儲存了main()函式的ebp,將這個值賦予ebp),使得ebp重新指向main函式的棧底
- 同時從main函式棧頂彈出esp當前指向的內容(下一條指令的地址)帶著my_add的返回值,取找下一條指令
- my_add函式呼叫結束,初始化的引數也隨之失效,通過移動esp指標將其移除
五、main函式的返回
- 暫存器出棧
- 將ebp賦給esp,esp和ebp同時指向棧底(也是start函式的棧頂),釋放了mian函式的棧幀
- 將ebp出棧,恢復到start函式的ebp,使得ebp指向strat函式的棧底
總結:
1.函式呼叫過程中會形成臨時變數(形參例項化)在呼叫函式和被呼叫函式的棧幀之間
2.形參例項化的順序,從右往左
3.臨時變數為什麼具有臨時性?
函式呼叫時形成棧幀,返回時銷燬棧幀,而定義的變數在自己的棧幀中,所以臨時變數的生命週期伴隨著自己的棧幀結構
4.每一個函式都有自己的棧幀,由自己產生(修改ebp,esp)
函式通過修改ebp,esp形成自己的棧幀
5.常規情況下,函式的返回值都會以暫存器的形式返回
總結:棧幀的主要作用是用來控制和儲存一個函式呼叫的所有資訊的。
相關文章
- 函式呼叫暫存器及棧幀結構函式
- 【圖文】函式呼叫過程中棧的變化函式
- 函式呼叫棧函式
- 20201023_081.遞迴函式_函式呼叫記憶體分析_棧幀的建立遞迴函式記憶體
- 函式呼叫棧的問題函式
- C語言函式呼叫棧C語言函式
- Presto 標量函式註冊和呼叫過程簡述REST函式
- C++函式呼叫棧從何而來C++函式
- 程式碼 or 指令,淺析ARM架構下的函式的呼叫過程架構函式
- 讀懂作業系統(x64)之堆疊幀(過程呼叫)作業系統
- 讀懂作業系統(x86)之堆疊幀(過程呼叫)作業系統
- MySQL儲存過程 (即函式)MySql儲存過程函式
- mySql 儲存過程與函式MySql儲存過程函式
- SQL server儲存過程函式SQLServer儲存過程函式
- MySQL 儲存過程和函式MySql儲存過程函式
- MySQL儲存過程和函式MySql儲存過程函式
- Servlet呼叫過程Servlet
- Python透過函式名呼叫函式的幾種場景Python函式
- 深入淺出CPU眼中的函式呼叫&棧溢位攻擊函式
- 子函式呼叫函式
- openGauss 函式及儲存過程支援函式儲存過程
- 儲存過程與儲存函式儲存過程儲存函式
- 儲存過程vs.函式QM儲存過程函式
- js函式執行過程的探究JS函式
- Lua中呼叫ref和out修飾引數的函式/過載函式函式
- javascript變數物件函式呼叫棧作用域閉包等細解!JavaScript變數物件函式
- 【譯】理解Javascript函式執行—呼叫棧、事件迴圈、任務等JavaScript函式事件
- 呼叫儲存過程儲存過程
- MySQL自定義函式與儲存過程MySql函式儲存過程
- 函式儲存過程併發控制-案例函式儲存過程
- GBASE88sSQL過程函式應用SQL函式
- 七、函式-儲存過程-觸發器函式儲存過程觸發器
- 外部函式的呼叫函式
- gdb 如何呼叫函式?函式
- C程式函式呼叫&系統呼叫C程式函式
- 棧空間受限情況下C/C++函式呼叫注意事項C++函式
- PostgreSQL函式裡呼叫函式(SETOF + RETURN QUERY)SQL函式
- 普通函式與函式模板呼叫規則函式