摘要:同時,和所指示的位置會隨著函數棧幀的創建和銷毀而不斷的發生改變。再次執行函數棧幀的創建操作。函數的返回值會存在一個寄存器中當函數棧幀釋放后,返回值不會隨之消失。二函數棧幀的銷毀將一些函數調用中使用的寄存器彈出棧。
一般來說,計算機中的寄存器有六種
分別是:eax, ebx, ecx,edx,ebp,esp
而ebp,esp這兩個寄存器中存放的是地址,與此同時,這兩個地址是來維護函數棧幀的。
每一個函數的調用,都需要在棧區為其開辟一個空間,這塊為其開辟的空間就是函數棧幀。
ebp:棧底指針
esp:棧頂指針
對于棧這種數據結構一共有兩種棧操作
1.pop 出棧
2. push 壓棧
如上圖所示,當main函數創建是便是會為其開辟函數棧幀,而其函數棧幀的地址范圍則由棧頂指針:esp,棧底指針:ebp來標識。同時,ebp和esp所指示的位置會隨著函數棧幀的創建和銷毀而不斷的發生改變。
需要明白的是,在VS編譯器中,main函數也是由其他函數調用的
在main函數的棧幀創建完成之后呢,就會用一個特定值將函數棧幀內的空間覆蓋,這個特定值就是0xcccccccc(十六進制表示)。
相信大家在跑代碼的時候都遇到過打印好多“燙燙燙燙燙燙燙燙燙”的情況,這其實是訪問的內存越界了,而錯誤訪問的內存中存放的正好就是上面那個特定值。
函數棧幀創建好以后,在函數中創建的變量便可以存放在函數棧幀中了。
1.如果調用的函數有參數的話,先要將參數壓棧,這里的參數是實參的一份臨時拷貝。
2.同時將調用函數結束之后的下一步操作的地址壓棧。(根據這個地址,我們們就可以在內存中找到相應的操作)
3.將調用之前的函數棧幀對應的ebp地址壓棧,這是為了方便我們在函數調用結束之后找到對應的函數棧幀的地址。
4.再次執行函數棧幀的創建操作。
函數形參并不是在函數棧幀中創建的,而是在函數棧幀創建之前就已經在棧中創建了(對應第一步),當要使用時,就可以從相應位置找到。
5.函數的返回值會存在一個寄存器中(當函數棧幀釋放后,返回值不會隨之消失)。
1.將一些函數調用中使用的寄存器彈出棧。
2.修改相應的ebp,esp的值,使其還原為函數調用前所指向的位置。具體為:出棧操作后,esp將指向當前ebp所指向的位置,之后彈出棧中所存儲的ebp的地址,讓ebp也指向正確的位置。這也是為何要在函數調用之前存儲當前ebp的地址。同時,因為出棧操作,esp的位置也相應的發生改變。
3.此時的棧頂元素對應的是函數調用之后的下一條指令的地址(在調用函數之前我們就將其壓棧了),根據地址我們就可以執行相應的操作。之后出棧,變更esp地址。
4.執行完第三步操作后,esp所指向的地址發生改變。同時釋放形參的空間,函數也相應的結束了。
這是函數棧幀的創建和銷毀,這里只是簡單的介紹,如果要理解的更透徹的話,可以查看匯編的代碼,更能幫助我們理解。如果有問題,歡迎大家在評論區探討。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/124083.html
摘要:語言深層理解函數中棧幀的創建與銷毀引言引言問題一引言問題二引言問題三一棧的簡單認識內存的簡單了解棧的簡單了解棧的定義棧的結構二寄存器與簡單的匯編指令寄存器的定義寄存器的分類簡單的匯編指令三棧幀的創建于銷毀調試調用堆棧調 ...
摘要:下文將從字節碼的角度,分析中基本類型傳參和對象傳參。主函數執行時,操作棧會推入主函數棧幀,其中包含了主函數的局部變量表,字節碼,返回值等信息。主函數的棧幀會被推入棧,成為當前操作棧。 個人網站地址: http://kailuncen.me/2017/06/0... 一個小問題 在開源中國看到這樣一則問題 https://www.oschina.net/quest...,其中的變量a前...
閱讀 713·2023-04-25 19:43
閱讀 3907·2021-11-30 14:52
閱讀 3784·2021-11-30 14:52
閱讀 3852·2021-11-29 11:00
閱讀 3783·2021-11-29 11:00
閱讀 3869·2021-11-29 11:00
閱讀 3557·2021-11-29 11:00
閱讀 6105·2021-11-29 11:00