首先我們要了解一些概念。
1.棧(stack)
由編譯器自動分配釋放,存放為執行函式而分配的區域性變數、函式引數、返回函式、返回位址等。操作方式類似於資料結構中的棧。
棧向下生成(先定義的位址高,後定義的位址低)
2.堆(heap)
由程式設計師分配釋放
,若程式設計師不釋放,程式結束時可能由os**。分配方式類似於鍊錶。
堆向上生成(先定義的位址低,後定義的位址高)
3.文字常量區
(唯讀)
常量字串存放處。程式結束後
由系統釋放
。執行時檢測。
4.程式**區
(唯讀)
存放函式體(類成員函式和全域性函式)的二進位制**
5.全域性區(static)
分為已初始化全域性資料區(init data)和未初始化全域性資料區(uninit data)
存放全域性變數、靜態資料、常量。程式結束後
由系統釋放
。具體情況如下圖:
接下來我們來具體了解棧幀,來看一段**:
由上圖我們可以看出,
main函式並不是函式啟動開始第乙個被呼叫的函式,但它是應用邏輯中的入口函式。
函式的呼叫過程要為函式開闢棧空間,用於函式的呼叫中臨時變數的儲存、現場保護。我們把這塊空間成為
函式棧幀。
我們需要了解一些暫存器:
ebp暫存器:基址暫存器,存放了函式棧幀
棧底的位址
esp暫存器:棧頂暫存器,存放了函式棧幀
棧頂的位址 s:static
eip(pc、ip):程式計數器,程式計數器裡儲存的內容永遠是當前正在執行指令的
(永遠指向下一條指令)
eax暫存器:利用eax進行函式的返回
對main()函式進行反彙編,反彙編**如下:
int main()
0022149a pop edi //出棧
0022149b pop esi //出棧
0022149c pop ebx //出棧,使esp向下移動
0022149d mov esp,ebp //將ebp賦值給esp
0022149f pop ebp //出棧,將出棧的內容儲存到ebp回到main函式的棧幀
002214a0 ret //ret指令會使得出棧一次,並將出棧的內容當做位址,將程式執行跳轉至此處
繼續執行會跳轉至main函式中:
總結
在最後,總結一下上述過程中出現過的彙編指令及其作用:
1.call:
通過修改ip實現函式的跳轉()
從右往左壓棧。
2. pop:出棧
eg:pop ebp 出棧至ebp
3.ret:調棧,棧頂回退,從myfunction回退到main。彈出棧頂返回值,將彈出的棧頂返回值存到eip
假如存入a,b,c,d,e
則在a的上面是b,c,d,e
a的下面是返回值的位址
函式的呼叫過程,棧幀的建立和銷毀
我們大家學習c語言肯定都知道函式,但大家可能都只會用函式,對它的了解只是上層的,並不知道它的呼叫過程,今天我們就一起來深入的研究一下函式的呼叫過程。首先,我們要知道的是,在函式呼叫時,程式將使用乙個執行時堆疊,它裡邊存區域性變數和返回位址,執行時堆疊由ebp 存放維護這個棧的棧底指標 和esp 存放...
函式的呼叫過程之棧幀的建立和銷毀
1.cpu中的暫存器 通用暫存器 eax,ebx,ecx,edx 程式計數器 eip pc 存放當前正在執行的指令的下一條指令的位址。棧頂 esp暫存器 棧底 ebp暫存器 2.將記憶體中的指令複製到cpu中 讀取指令 分析指令 執行指令 3.什麼是棧?棧是一種特殊的鍊錶形式的資料結構,只允許在鍊錶...
C語言 函式的呼叫過程及棧幀的建立和銷毀
一 說起函式呼叫,我們可能很快就想到 程式從main函式走起,遇到呼叫函式的語句,就跳轉到此函式所在的語句塊執行此函式,執行完之後再返回main函式繼續執行程式。但是這只是籠統的描述,其實在函式內部,函式呼叫要經過一系列的複雜的過程,下面為大家一一詳細敘述。1.說到函式呼叫,我們不可避免的要說到棧幀...