首先需要知道cpu所做的事就是不停地讀取程式,分析程式,執行程式。。。還有我們對記憶體的操作都是以位元組為單位。
既然讀取程式是從記憶體上讀取的
那麼也要知道記憶體是怎麼分配的,按照什麼原則分配。這裡先對記憶體做個初步介紹。
用一張**釋:
其中堆疊相對而生,堆區向上增長,棧區向下增長,棧區記憶體用完即銷,堆區需要程式設計師自己申請並自己釋放,若不釋放則會造成記憶體洩漏,或者程式結束時自動釋放(這就是為什麼有時候需要重啟程式或機器的原因)。
【什麼是棧幀結構?】
我的理解中棧幀結構就是在程式執行期間,在記憶體中的棧區開闢和釋放的空間。乙個程式中每個函式在被呼叫之時都會有自己的棧幀結構,當被呼叫完之後就會被釋放,這個棧幀結構由cpu中的ebp(棧底)和esp(棧頂)暫存器來維護。
【cpu中存在一些暫存器】
eap,ebp,ecp,exp這些都是通用暫存器
ebp:棧底暫存器 esp:棧頂暫存器
在呼叫乙個函式的時候用的是組合語言中的call命令,call命令的作用是儲存當前指令的下一條指令的位址,可能有人會問為什麼要儲存?那我想問問你出去玩完回不回家?他又問為什麼儲存的是下一條指令的位址?難道你剛回家就又要出去幹同樣一件事嗎?儲存在**請繼續往下看。
【下面用乙個簡單的程式來完整了解一下程式的呼叫過程】
#includeint add(int x,int y)
int main()
【在以往,我們都錯誤地以為main函式是入口函式】那麼我們呼叫堆疊看看:
由此得出maincrtstartup函式才是入口函式,而main函式只不過是被它呼叫的。
由於main函式實際上是被呼叫的所以它就有自己的棧幀結構。
【進入單步除錯,仔細研究函式的每乙個過程】
注:隨時開啟暫存器和記憶體注意觀察。
檢視程式的反彙編,按f11進入main函式,邊按f11邊觀察暫存器和記憶體的變化,在呼叫函式之前暫停一會,
觀察暫存器和記憶體:
找到指向棧頂和棧底的暫存器,再在記憶體中找到對應區間進行觀察
觀查匯程式設計序
【下面仔細觀察形參例項化環節】
先是形參例項化的過程,仔細觀察
在上面先是將a=10放到了ebp-4的記憶體上,然後給ebp-8這塊記憶體起個名字叫b,並且其內容為10
在這裡卻先是ebp-8,然後才是ebp-4。
原因很簡單,形參例項化的順序是從右往左的。
【call命令】
按一下f11
彙編:暫存器:
再按一下
彙編:暫存器:
再按
【被調函式的棧幀結構形成過程】
參考上文
【關於返回值的問題】
既然被調函式有返回值,但是返回值是區域性變數,隨著函式的呼叫結束棧幀結構不復存在,區域性變數也被銷毀,那麼返回值是怎麼返回到main函式中的?
發現了嗎?返回時是本身銷毀了,返回的是乙份拷貝,在被調函式中計算結果,將結果存入暫存器eax,而return 返回的時候返回的是暫存器中的值,簡而言之,返回值是通過暫存器返回的。
【總結】如圖
C語言函式棧幀解析
目錄 eax,ebx,ecx ebp 存放了指向函式棧幀棧底的位址 esp 存放了指向函式棧幀棧頂的位址 函式被呼叫時,系統會在棧區為該函式開闢一塊棧空間,這個棧空間就是該函式的函式棧幀。以main函式的呼叫為例 棧幀也叫過程活動記錄,是編譯器用來實現函式呼叫過程的一種資料結構。從邏輯上講,棧幀為乙...
C語言 深度理解函式 函式的棧幀
c語言函式是如何呼叫的呢?初學時我想當然地回答 從呼叫部分轉到函式部分逐句執行,就是那麼簡單啊,然而你有沒有想過 函式呼叫前需要做哪些準備工作?函式是如何傳參的?傳參後又是如何使用的?引數使用完後又是如何銷毀的?呼叫的整個過程是怎樣的呢?今天就通過下面這個簡單的 帶大家走進函式的世界,一 竟 inc...
C語言 函式呼叫過程(棧幀)
首先舉個栗子 include int add int x,int y int main 在這個程式裡,函式被呼叫才會發揮函式的功能,而函式的呼叫其實是乙個過程,在這個過程計算機要為函式開闢棧空間,用於本次函式臨時變數的儲存和現場保護,這塊空間稱為函式的棧幀。現場保護的作用是為了在呼叫完另乙個函式,返...