C++基礎知識:c 函式呼叫過程原理及函式棧幀分析
阿新 • • 發佈:2019-02-06
1.關於棧
首先必須明確一點也是非常重要的一點,棧是向下生長的,所謂向下生長是指從記憶體高地址->地地址的路徑延伸,那麼就很明顯了,棧有棧底和棧頂,那麼棧頂的地址要比棧底低。對x86體系的CPU而言,其中
---> 暫存器ebp(base pointer )可稱為“幀指標”或“基址指標”,其實語意是相同的。
---> 暫存器esp(stack pointer)可稱為“ 棧指標”。
要知道的是:
---> ebp 在未受改變之前始終指向棧幀的開始,也就是棧底,所以ebp的用途是在堆疊中定址用的。
---> esp是會隨著資料的入棧和出棧移動的,也就是說,esp始終指向棧頂。
見下圖,假設函式A呼叫函式B,我們稱A函式為"呼叫者",B函式為“被呼叫者”則函式呼叫過程可以這麼描述:
(1)先將呼叫者(A)的堆疊的基址(ebp)入棧,以儲存之前任務的資訊。
(2)然後將呼叫者(A)的棧頂指標(esp)的值賦給ebp,作為新的基址(即被呼叫者B的棧底)。
(3)然後在這個基址(被呼叫者B的棧底)上開闢(一般用sub指令)相應的空間用作被呼叫者B的棧空間。
(4)函式B返回後,從當前棧幀的ebp即恢復為呼叫者A的棧頂(esp),使棧頂恢復函式B被呼叫前的位置;然後呼叫者A再從恢復後的棧頂可彈出之前的ebp值(可以這麼做是因為這個值在函式呼叫前一步被壓入堆疊)。這樣,ebp和esp就都恢復了呼叫函式B前的位置,也就是棧恢復函式B呼叫前的狀態。
這個過程在AT&T彙編中通過兩條指令完成,即:
leave
ret
這兩條指令更直白點就相當於:
mov %ebp , %esp
pop %ebp