程式的位址空間圖中,從下向上,位址不斷增長,從0x00000000到0xffffffff。
code:**區,儲存**
字元、串常量區:儲存不能被修改的常量
init,uninit:全域性區,分別為初始化全域性區,和未初始化全域性區,儲存全域性變數
heap:堆,使用malloc在堆申請空間,在堆上建立的變數使用完畢後要手動釋放空間
棧:在離堆較遠處的一塊空間叫做棧,用於存放臨時變數,函式呼叫時形成棧幀,函式呼叫完成時,銷毀棧幀
注:堆和棧相對而生,即棧底在較高位址處,在不斷的使用對空間,建立臨時變數時,棧頂向低位址處移動,堆則相反
棧幀:在函式呼叫的過程中,要為函式開闢空間,用於本次函式呼叫中臨時變數的儲存、現場保護,這塊棧空間稱為棧幀。
棧幀的維護離不開兩個暫存器,ebp,esp,當main函式開始執行時,形成main函式的棧幀,esp指向棧幀的棧頂,ebp指向棧幀的棧底,在這個過程中ebp和esp相當於指標
在c語言中,main函式被_tmaincrtsartup函式呼叫,當有如下**時:
當main函式呼叫時,要開闢棧空間,畫出棧幀圖:#include
int main()
為了清楚觀察這一過程,用vc6.0轉到匯程式設計序,可以清楚地看出,當開闢棧幀完成時,經過小麵兩行彙編**,用ebp完成a,b的建立並賦值,ebp-4和ebp-8的原因是整形變數需要四個位元組的空間,
如果在建立完成a,b之後,要進行add(a,b),完成a和b相加,並返回結果,**如下:
當開始調函式的時候,將a,b再次建立乙份放在main函式的棧幀外面,esp不斷移動,注意,先建立的b,即在add的引數裡,從右向左依次例項化,圖如下:
進來之後
將main的ebp存的值壓入棧內
ebp指向esp的位置
esp-44h
經過前兩條指令就形成了add函式的棧幀
add建立z的方式和在main函式中建立a,b的方式一致
棧幀圖如下:
接下來
然後通過ebp找到 形參a,b將a+b賦值給z
將z中的值放在eax通用暫存器中
此時,add函式已經執行完成
不斷進行pop指令,edp不斷向上移,即所指向位址不斷增加
然後將esp指向ebp所指向的位置
然後在進行pop指令將棧頂元素彈人ebp,因為這是棧頂的值是原來main函式ebp的值,所以ebp再次指向main函式的棧幀的底部,如圖:
最後進行ret指令,返回call的下一條指令除
call的功能:
1、彈出棧頂
2、彈出的值放入eip中
給esp+8,esp再次指向main函式的棧幀頂部,main函式的棧幀恢復完成
再把eax中的值(z即a+b)放在c內
函式呼叫完成,返回值收,列印
函式呼叫過程(棧幀)
眾所周知,程式每呼叫乙個函式,系統都會為其開闢一塊空間,當它返回時,才收回這塊空間。程式崩潰有一部分原因就是因為無限制的呼叫函式,卻沒有及時返回,導致記憶體空間不夠。為了更好的維護這一塊空間 通常稱為棧空間 我們需要了解兩個暫存器,乙個為 esp 指向棧頂的指標 乙個為 ebp 指向棧底的指標 棧空...
函式棧幀(呼叫過程)
函式棧幀就是在呼叫函式是為其在棧空間上開闢了一段空間,指向過程呼叫,乙個過程呼叫包括將資料 以過程引數和返回值的形式 和控制從 的一部分傳遞到另一部分。我們以以下 為例講解整個函式呼叫過程 int my add int x,int y int main 一 呼叫main 函式 我們從main 函式的...
棧幀與函式呼叫過程分析
乙個c c 編譯的程式占用的記憶體分為以下幾個部分 1.棧區 stack 由編譯器自動分配和釋放,存放函式的引數值,區域性變數的值,返回資料,返回位址等。操作方式類似於資料結構中的棧。2.堆區 heap 一般由程式設計師分配和釋放,若程式設計師不釋放,程式結束時可能由作業系統 與資料結構中的堆是兩碼...