棧幀詳解-轉自知乎


淺析函數調用的棧幀

淺析函數調用的棧幀

 
目錄

在x86的計算機系統中,內存空間中的棧主要用於保存函數的參數,返回值,返回地址,本地變量等。一切的函數調用都要將不同的數據、地址壓入或者彈出棧。

什么是棧?

棧是一種LIFO(后進先出)
可以想象下函數調用的時候,父函數調用子函數,父函數在前,子函數在后。返回的時候子函數先返回,父函數后返回。ps:遞歸就是明顯利用函數調用這種棧的結構來實現的。

什么是棧幀?

棧幀本質上是一種棧,只是這種棧專門用於保存函數調用過程中的各種信息(參數,返回地址,本地變量等)。棧幀有棧頂和棧底之分,其中棧頂的地址最低,棧底的地址最高。

兩個主要寄存器

1. ESP寄存器
棧指針寄存器(extended stack pointer),其內存放着一個指針,該指針永遠指向系統棧最上面一個棧幀的棧頂。

2.EBP寄存器
基址指針寄存器(extended base pointer),其內存放着一個指針,該指針永遠指向系統棧最上面一個棧幀的底部。

 

一般來說,我們將 %ebp 到 %esp 之間區域當做棧幀(也有人認為該從函數參數開始,不過這不影響分析)。並不是整個棧空間只有一個棧幀,每調用一個函數,就會生成一個新的棧幀。在函數調用過程中,我們將調用函數的函數稱為“調用者(caller)”,將被調用的函數稱為“被調用者(callee)”。在這個過程中,1)“調用者”需要知道在哪里獲取“被調用者”返回的值;2)“被調用者”需要知道傳入的參數在哪里,3)返回的地址在哪里。同時,我們需要保證在“被調用者”返回后,%ebp%esp 等寄存器的值應該和調用前一致。因此,我們需要使用棧來保存這些數據。

函數調用實例

函數的調用

//被調函數 callee int CalleeFunction(int x, int y, int z) { int a, b, c; a = 4; b = 5; c = 6; return; } //主調函數 caller int CallerFunction() { int x = 1, y = 2, z = 3; //調用被調函數  CalleeFunction(1, 2, 3); ... }

我們來看下Callee函數的匯編代碼

_CalleeFunction: push %ebp ; //保存%ebp的值  movl %esp, $ebp ; //將%esp的值賦給%ebp,使新的%ebp指向棧頂  movl -12(%esp), %esp ; //分配額外空間給本地變量  movl $4, -4(%ebp) ; movl $5, -8(%ebp) ; movl $6, -12(%ebp) ; 

此時調用者做了兩件事情:第一,將被調用函數的參數按照從右到左的順序壓入棧中。第二,將返回地址壓入棧中。這兩件事都是調用者負責的,因此壓入的棧應該屬於調用者的棧幀。我們再來看看被調用者,它也做了兩件事情:第一,將老的(調用者的) %ebp 壓入棧,此時 %esp 指向它。第二,將 %esp 的值賦給 %ebp%ebp 就有了新的值,它也指向存放老 %ebp 的棧空間。這時,它成了是函數 CalleeFunction() 棧幀的棧底。這樣,我們就保存了“調用者”函數的 %ebp,並且建立了一個新的棧幀。

在 %ebp 更新后,我們先分配一塊0x12字節的空間用於存放本地變量,這步一般都是用 sub 或者 mov 指令實現。在這里使用的是 movl。通過使用 mov 配合 -4(%ebp)-8(%ebp) 和 -12(%ebp) 我們便可以給 ab 和 c 賦值了。

函數返回

和調用函數時正好相反。當函數完成自己的任務后,它會將 %esp 移到 %ebp 處,然后再彈出舊的 %ebp 的值到 %ebp。這樣,%ebp 就恢復到了函數調用前的狀態。

//被調函數 callee int CalleeFunction(int x, int y, int z) { int a, b, c; ... return; }

匯編代碼

_CalleeFunction:
    push %ebp
    movl %esp, %ebp
    movl -12(%esp), %esp
    ...
    mov %ebp, %esp
    pop %ebp
    ret

ret 指令,這個指令相當於 pop + jum。它首先將數據(返回地址)彈出棧並保存到 %eip 中,然后處理器根據這個地址無條件地跳到相應位置獲取新的指令。

被調用函數返回后的棧幀

小結

這批函數棧幀分析為基礎 方便大家理解golang啟動過程中對棧幀的一系列操作,比如最騷的把goexit()塞入到newg的棧頂等過程~


免責聲明!

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



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