摘要:當函數返回時,系統棧會彈出該函數所對應的棧幀。四寄存器與函數棧幀每一個函數獨占自己的棧幀空間。棧幀調整具體包括。
棧是函數執行的內存區域,是C語言運行時最重要的元素之一
寄存器是CPU內部用來存放數據的一些小型存儲區域,用來暫時存放參與運算的數據和運算結果。
寄存器有eax,ebx,ecx,edx,還有ebp,esp。本文主要介紹最后兩個,由于寄存器不是本次博客的重點,其他請自行了解!
ESP | 棧指針寄存器(extended stack pointer),其內存放著一個指針,該指針永遠指向系統棧最上面一個棧幀的棧頂 |
---|---|
EBP | 基址指針寄存器(extended base pointer),其內存放著一個指針,該指針永遠指向系統棧最上面一個棧幀的底部 |
想要了解函數棧幀,就必須先了解好這兩個地址。
ebp,esp這兩個寄存器中存放的是地址,且這兩個地址是用來維護函數棧幀的
棧區:
用于動態地存儲函數之間的調用關系,以保證被調用函數在返回時恢復到母函數中繼續執行。
棧的最常見操作有兩種:
壓棧(push)
彈棧(pop)
用于標識棧的屬性也有兩個:
棧頂(top)
棧底( base)。
什么意思?
可以把棧想象成一摞撲克牌。
push | 為棧增加一個元素的操作叫做推,相當于在這摞撲克牌的最上面再放上一張。 |
---|---|
pop | 從棧中取出一個元素的操作叫做流行,相當于從這摞撲克牌取出最上面的一張。 |
pop | 從棧中取出一個元素的操作叫做流行,相當于從這摞撲克牌取出最上面的一張。 |
---|---|
base | 標識棧底位置,它記錄著撲克牌最下面一張的位置。base用于防止棧空后繼續彈棧(牌發完時就不能再去揭了)。很明顯,一般情況下,base是不會變動的。 |
以下面代碼為例:
#define _CRT_SECURE_NO_WARNINGS 1#include int Add(int x, int y){ int z = 0; z = x + y; return z;}int main(){ int a = 10; int b = 20; int c = 0; c = Add(a, b); printf("%d/n", c); return 0;}
當中央處理器在執行調用Add函數的時候,會從代碼區中
主要函數對應的機器指令的區域跳轉到Add函數對應的機器指令區域,在那里取指并執行;當Add函數執行完閉,需要返回的時候,又會跳回到主要函數對應的指令區域,緊接著調用Add后面的指令繼續執行主要函數的代碼。
如下圖:
那么中央處理器是怎么知道要去Add函數的代碼區取指,
在執行完Add后又是怎么知道跳回到主要函數(而不是其他未知的代碼區)的呢?
這是因為
當函數被調用時,系統棧會為這個函數開辟一個新的棧幀,并把它壓入棧中。這個棧幀中的內存空間被它所屬的函數獨占,正常情況下是不會和別的函數共享的。當函數返回時,系統棧會彈出該函數所對應的棧幀。
每一個函數獨占自己的棧幀空間。當前正在運行的函數的棧幀總是在棧頂。
函數棧幀:
esp和ebp之間的內存空間為當前棧幀,esp標識了當前棧幀的頂部,ebp標識了當前棧幀的底部。
函數調用大致包括以下幾個步驟。
(1)參數入棧:將參數從右向左依次壓入系統棧中。 (2)返回地址入棧:將當前代碼區調用指令的下一條指令地址壓入棧中,供函數返回時繼續執行。
(3)代碼區跳轉:處理器從當前代碼區跳轉到被調用函數的入口處。
(4)棧幀調整:具體包括。保存當前棧幀狀態值,已備后面恢復本棧幀時使用(ebp入棧);將當前棧幀切換到新棧幀(將esp值裝入ebp,更新棧幀底部);給新棧幀分配空間(把esp減去所需空間的大小,抬高棧頂);
將上面的代碼轉到反匯編模式查看
對應觀察:
1.函數返回過程
(1)保存返回值:通常將函數的返回值保存在寄存器EAX中。
(2)彈出當前棧幀,恢復上一個棧幀。
1.在堆棧平衡的基礎上,給esp加上棧幀的大小,降低棧頂,回收當前棧幀的空間。
2.將當前棧幀底部保存的前棧幀ebp值彈入ebp寄存器,
復出上一個棧幀。
3.將函數返回地址彈給ebi寄存器。
(3)跳轉:按照函數返回地址跳回母函數中繼續執行。
本文內容來自于《oday安全軟件漏洞分析技術》第2版與自己學習筆記所,本文僅記述自己學習歷程與僅供自己學習,復習用,不做任何商業用途。
若有興趣深入了解函數棧幀,請自行查閱王清主編的《Oday安全:軟件漏洞分析技術(第2版)》一書。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/121674.html
摘要:這里分塊講解六函數棧幀的銷毀過程一解析的作用是將棧頂的數據彈出,彈出數據儲存到相應寄存器中。 ?前言? 讀完這篇博客,你可以明白什么? ①局部變量到底是怎么在棧上創建的? ②為什么局部變量不初始化為隨機值? ③函數是怎么傳參的?傳參的先后順序是什么? ④形參和實參是什么關系? ⑤函數調用是怎...
摘要:是那些可能在虛擬機正常運行期間拋出的異常的超類。運行時異常定義及其子類都被稱為運行時異常。對于語言中的關鍵字和,虛擬機中并沒有特殊的字節碼指令去支持它們,都是通過編譯器生成字節碼片段以及不同的異常處理器來實現。 前言 在一些傳統的編程語言,如C語言中,并沒有專門處理異常的機制,程序員通常用方法的特定返回值來表示異常情況,并且程序的正常流程和異常流程都采用同樣的流程控制語句。Java語言...
閱讀 2068·2021-11-24 09:39
閱讀 774·2021-09-30 09:48
閱讀 974·2021-09-22 15:29
閱讀 2409·2019-08-30 14:17
閱讀 1885·2019-08-30 13:50
閱讀 1336·2019-08-30 13:47
閱讀 977·2019-08-30 13:19
閱讀 3418·2019-08-29 16:43