1. 程式人生 > >棧幀——組合語言詳解

棧幀——組合語言詳解

原來我以為在C語言中指標已經是非常麻煩了,沒想到棧幀給我甜蜜一擊,但最後一路學習下來也不是多麼麻煩的事。

首先我們得明確為什麼有函式,其作用是:在面向過程語言的重要組成成分,它將具有相同功能的語句組合到一塊,便於我們使用,提高程式可讀性,減少程式碼量。

以main函式為例,在使用過程中首先呼叫__tmainCRTStartup函式,然後又呼叫mainCRTStartup函式,而每一次的函式呼叫就是一個過程——函式的呼叫過程;在這個過程中我們要為函式開闢棧空間,用於臨時變數的儲存、現場的保護(函式的返回值和引數、呼叫前暫存器的狀態,呼叫前棧幀的頂部和底部的地址),這塊棧空間我們稱之為函式

棧幀。

由C語言的記憶體分佈空間可得,在不斷地函式過程中,棧向下增長,那麼具體的呼叫過程是怎麼樣的嘞?舉一段程式碼表示說明(本次程式碼在vc++6.0環境下執行):


很簡單的一段程式碼,將其對應彙編程式碼一步步開始進行分析,在此之前我們瞭解一下關於彙編的基本知識:

暫存器:esp棧頂指標、ebp是存取堆疊底指標——存取某時刻的棧頂指標,以方便對棧的操作;

pc(程式計數器)當前正在執行的指令的下一條指令的地址;

eax是"累加器"(accumulator), 它是很多加法乘法指令的預設暫存器、ebx 是"基地址"(base)暫存器, 在記憶體定址時存放基地址、ecx是計數器(counter), 是重複(REP)字首指令和LOOP指令的內定計數器、edx則總是被用來放整數除法產生的餘數。

指令:push入棧、pop出棧、ret當前儲存的暫存器地址出棧,其值賦給IP暫存器。

一、main函式棧幀的創立:


一個函式的棧幀用ebp和esp這兩個暫存器劃定範圍。暫存器esp始終指向棧的頂部,也即指向當前函式棧幀的頂部。而ebp暫存器指向函式棧幀的一個固定位置,所以ebp暫存器又被稱為幀指標。這兩個暫存器的詳細操作方式為:函式呼叫時上一級呼叫者的幀底被壓入當前ebp內容所指的地址,也就是當前幀的幀底位置儲存了上一級呼叫者的ebp指標值(幀底),而每個ebp的前一個單元存放的就是當前函式的返回地址(它是由呼叫者在call指令中入的棧)。這樣就可以根據當前ebp的值回溯出整個任務的呼叫棧(呼叫過程)。

二、add函式的呼叫,首先形參例項化(具體過程不表,但具體要用到call命令跳轉至add函式的程式碼執行處);

call:將當前的彙編指令地址儲存,以便於恢復,jmp(修改eip)跳轉至目標函式的地址處。


整個函式呼叫到這裡就結束了,以後將繼續完善~