0x01.棧在計算機中的應用
- 在計算機系統中,棧也可以稱之爲棧內存是一個具有動態內存區域,存儲函數內部(包括main函數)的局部變量和方法調用和函數參數值,是由系統自動分配的,一般速度較快;存儲地址是連續且存在有限棧容量,會出現溢出現象,程序可以將數據壓入棧中,也可以將數據從棧頂彈出。壓棧操作使得棧增大,而彈出操作使棧減小。
- 棧用於維護函數調用的上下文,離開了棧,函數調用就沒法實現。
- 棧是從高地址向低地址延伸。
0x02.棧幀和棧幀的結構
每一次函數的調用,都會在調用棧(call stack)上維護一個獨立的棧幀(stack frame)。
一個函數的棧幀用ebp 和 esp 這兩個寄存器來劃定範圍。
棧幀包括:
- 函數的返回地址和參數。
- 臨時變量。 包括函數的非靜態局部變量以及編譯器自動生成的其他臨時變量。
- 棧幀狀態值:ebp (幀指針),指向當前的棧幀的底部;esp(棧指針) 始終指向棧幀的頂部;
棧幀從低到上依次是(從高地址到低地址的方向):
- 參數
- 返回地址
- ebp
- 局部變量
- esp
0x03.函數的調用過程
調用約定:
- 函數調用約定描述了函數傳遞參數方式和棧幀同工作的技術細節。不同的操作系統、不同的語言、不同的編譯器在實現函數調用時的原理雖然基本相同,但具體的調用約定還是有差別的。這包括參數傳遞方式,參數入棧順序是從右向左還是從左向右,函數返回時恢復堆棧平衡的操作在子函數中進行還是在母函數中進行。
- 同一段代碼用不同的編譯選項、不同的編譯器編譯鏈接後,得到的可執行文件會有很多不同。
調用過程:
- 參數入棧。將參數按照一定的順序入棧。
- 返回地址入棧。將當前代碼區調用指令的下一條指令地址壓入棧中,供函數返回時繼續執行。
- 代碼區跳轉。處理器從當前代碼區跳轉到被調用函數的入口處。
- 棧幀處理步驟:EBP入棧,保存當前棧幀狀態值,已備後面恢復本棧幀時使用。push ebp
- 棧幀處理步驟:ESP值賦給EBP,更新棧幀底部。mov ebp,esp
- 棧幀處理步驟:給新棧幀分配空間。sub esp,xxx
0x04.函數的返回過程
- 保存被調用函數的返回值到 eax 寄存器中。mov eax,xxx
- 恢復 esp 同時回收局部變量空間。mov ebp, esp
- 將當前棧幀底部保存的前棧幀EBP值彈入EBP寄存器,恢復出上一個棧幀。pop ebp
- 彈出當前棧頂元素,從棧中取到返回地址,並跳轉到該位置
ret
0x05.圖示
(圖片轉載自https://www.cnblogs.com/clover-toeic/p/3755401.html)