想要深刻理解函式的呼叫過程,就必須了解c,c++程式的記憶體,cpu,以及棧幀的建立與釋放。
我們知道函式的每一次呼叫都是乙個過程,即我們要討論的函式呼叫過程,這個過程要為函式開闢棧空間,用於本次函式呼叫中的臨時變數的儲存、現場保護。這塊棧空間我們稱之為函式棧幀。
1:下面是記憶體,我們以圖的形式形象的展示出來,然後將棧區放大,如下圖
對於棧區,我們先了解一下它的結構:
棧(stack):入棧(push)和出棧(pop),棧遵循「先進後出」或「後進先出」;
2:cpu
作用:讀取指令-->分析指令-->執行指令
cpu中的暫存器:
eax、ebx、ecx、edx-->通用暫存器
eip(pc)-->程式計數器(存放當前指令的下一條指令的位址)
esp(棧頂)ebp(棧底)
注:esp和ebp之間就是乙個函式的棧幀。函式在呼叫過程中會形成臨時變數,而這個臨時變數的呼叫和被呼叫就在棧幀之間。呼叫函式會形成棧幀,釋放函式就會釋放棧幀。
3:棧幀的建立和釋放,我們在vc6.0下來實現它,我們先來用乙個簡單的**看一下
#include#includeint myadd(int _a,int _b)
int main()
接下來我們按fn加f10進行除錯,在view下檢視a,b變數,如下:
接下來我們按f11進入myadd函式,我們呼叫myadd函式,其實是呼叫main函式,然後呼叫myadd函式,那接下來我們看一下(1):main函式的呼叫過程
在main函式當中,第乙個被調的函式是maincrtstartup函式。
接下來我們檢視一下暫存器,在view->debug windows->regiest下檢視,如下:
我們要研究的是main函式的呼叫過程,必須得對應彙編**,上面一些就是簡單的操作,我們記錄一下,接下來,從main函式的地方開始,要展開main函式的呼叫就得為main函式建立棧幀,那我們先來看一下main函式棧幀的建立。
此時我們看一下暫存器中的值,b,a入棧,先入b,再入a
接下來按f10單步執行至call命令處,f11,進入myadd函式
(2)myadd函式的棧幀建立和main函式的棧幀建立與初始化是相同的
(2)跳轉至目標函式的位址處(jmp跳轉)。
再按f11,就進入myadd函式的執行**處,
我們注意暫存器的值的變化:如下圖
此時我們單步執行到ebp出棧,察看暫存器的值:
(3)剩下的就是函式返回部分:
f10單步執行至ret指令,然後f11,進入main函式返回部分,如下圖
(2)用彈出來的資料修改eip;
函式呼叫過程(棧幀)
眾所周知,程式每呼叫乙個函式,系統都會為其開闢一塊空間,當它返回時,才收回這塊空間。程式崩潰有一部分原因就是因為無限制的呼叫函式,卻沒有及時返回,導致記憶體空間不夠。為了更好的維護這一塊空間 通常稱為棧空間 我們需要了解兩個暫存器,乙個為 esp 指向棧頂的指標 乙個為 ebp 指向棧底的指標 棧空...
函式棧幀(呼叫過程)
函式棧幀就是在呼叫函式是為其在棧空間上開闢了一段空間,指向過程呼叫,乙個過程呼叫包括將資料 以過程引數和返回值的形式 和控制從 的一部分傳遞到另一部分。我們以以下 為例講解整個函式呼叫過程 int my add int x,int y int main 一 呼叫main 函式 我們從main 函式的...
函式的呼叫過程 棧幀
在談棧幀之前,我們必須要先知道c c 程式記憶體的分配情況。乙個由c c 編譯的程式占用的記憶體分為以下幾個部分 1 棧區 stack 由編譯器自動分配釋放 存放為執行函式而分配的局 部變數 函式引數 返回資料 返回位址等。其操作方式類似於資料結構中的 棧。2 堆區 heap 一般由程式設計師分配釋...