天天看點

函數調用過程中棧到底是怎麼壓入和彈出的?

函數調用過程中棧到底是怎麼壓入和彈出的?

在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減去所需空間的大小,擡高棧頂)

函數調用過程中棧到底是怎麼壓入和彈出的?