函數調用的壓棧出棧過程


作者:李根
鏈接:https://www.zhihu.com/question/22444939/answer/22200552
來源:知乎
著作權歸作者所有,轉載請聯系作者獲得授權。

湊合看吧親 ^_^

在main函數調用func_A的時候,首先在自己的棧幀中壓入函數返回地址,然后為func_A創建新棧幀並壓入系統棧
在func_A調用func_B的時候,同樣先在自己的棧幀中壓入函數返回地址,然后為func_B創建新棧幀並壓入系統棧
在func_B返回時,func_B的棧幀被彈出系統棧,func_A棧幀中的返回地址被“露”在棧頂,此時處理器按照這個返回地址重新跳到func_A代碼區中執行
在func_A返回時,func_A的棧幀被彈出系統棧,main函數棧幀中的返回地址被“露”在棧頂,此時處理器按照這個返回地址跳到main函數代碼區中執行

在實際運行中,main函數並不是第一個被調用的函數,程序被裝入內存前還有一些其他操作,上圖只是棧在函數調用過程中所起作用的示意圖

ESP:棧指針寄存器(extended stack pointer),其內存放着一個指針,該指針永遠指向系統棧最上面一個棧幀的棧頂
EBP:基址指針寄存器(extended base pointer),其內存放着一個指針,該指針永遠指向系統棧最上面一個棧幀的底部
函數棧幀:ESP和EBP之間的內存空間為當前棧幀,EBP標識了當前棧幀的底部,ESP標識了當前棧幀的頂部。


EIP:指令寄存器(extended instruction pointer), 其內存放着一個指針,該指針永遠指向下一條待執行的指令地址。

函數調用大致包括以下幾個步驟:

參數入棧:將參數從右向左依次壓入系統棧中
返回地址入棧:將當前代碼區調用指令的下一條指令地址壓入棧中,供函數返回時繼續執行
代碼區跳轉:處理器從當前代碼區跳轉到被調用函數的入口處
棧幀調整:具體包括
保存當前棧幀狀態值,已備后面恢復本棧幀時使用(EBP入棧)
將當前棧幀切換到新棧幀。(將ESP值裝入EBP,更新棧幀底部)
給新棧幀分配空間。(把ESP減去所需空間的大小,抬高棧頂)



————————————————分割線——————————————————————
以下內容代碼感謝原評論中 @陳中正 同學提供,答案經過重新編輯后原評論就不見鳥

void func_A(arg_A1, arg_A2);
void func_B(arg_B1, arg_B2);

int main(int argc, char *argv[], char **envp)
{
func_A(arg_A1, arg_A2);
}

void func_A(arg_A1, arg_A2)
{
var_A;
func_B(arg_B1, arg_B2);
}

void func_B(arg_B1, arg_B2)
{
var_B1;
var_B2;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM