任何程式在執行過程中都需要使用堆疊,作業系統為每乙個程式(程序及執行緒)設定乙個堆疊。在使用高階語言程式設計時,源程式中使用的函式呼叫、區域性變數都要用到堆疊,由編譯器來負責生成有關的機器指令。我的理解,堆疊就是維護當前執行緒中執行狀態的乙個資料結構,這種狀態包括:需要傳遞的變數,函式的返回位址,區域性變數等等。
與堆疊相關的 3 個暫存器是:ss, esp, ebp。
esp 暫存器中的內容作為堆疊的當前指標。push, pop, call, ret 等指令都與堆疊有關,使用 ss:esp 指向堆疊單元。
ebp 暫存器中的內容作為堆疊的「基準」指標。ss:ebp 指向的位址作為基準位址。在函式(子程式)內部,可以使用 [ebp+立即數] 的形式來取得主程式傳遞的引數,使用 [ebp-立即數] 的形式來訪問區域性變數。
從上述的描述可以看出,整個堆疊的是乙個經典的先入後出的棧結構,在棧中還存在著「棧幀」這樣的結構,用來表示當前函式執行的環境,裡面存放著當前函式的區域性變數,所需的返回位址。棧幀由 ebp 所指出,ebp 和 esp 之間即為當前函式幀,呼叫函式和被呼叫函式的棧幀是相鄰存放,這樣即可通過 ebp加減固定的數,來獲取主調函式所傳遞的函式引數。
上述的堆疊結構如下:
堆疊是經過精心設計的結構,使得程式設計人員能夠方便的設計函式來實現結構化設計,高階語言也得益於這種結構,c 語言基本上就是彙編的一種簡單的翻譯。這裡要強調的是,在用匯編寫程式的時候,完全可以不按這種結構來設計,比如引數我們可以放到指定的記憶體區,被呼叫的函式到指定的記憶體區去取出傳遞給它的引數;也可以讓函式引數全部通過暫存器來傳送,尤其是在 arm 這種暫存器特別多,而且每個暫存器的地位都相同的處理器之中。之所以要設計出堆疊,就是為了能夠以統一的方式來編寫程式。
對於 c 語言,函式有好幾種呼叫規則。最常見的是兩種,cdecl 方式和 stdcall 方式。
cdecl 方式
(1)使用堆疊傳遞引數
(2)主程式按從右向左的順序將引數逐個壓棧,最後乙個引數先入棧。每乙個引數壓棧一次。
(3)在子程式中,使用 [ebp+x] 的方式來訪問引數。x=8 代表第 1 個引數;x=12 代表第二個引數,依次類推
(4)子程式用 ret 指令返回。
(5)由主程式執行「add esp, n」指令調整 esp,達到堆疊平衡。
(6)一般返回值放在 eax 中
stdcall 方式
與cdecl的不同是,堆疊的平衡不是由主程式完成,而是由子程式通過呼叫「ret n」指令主動平衡。
這些呼叫規則,都是針對 c 語言來說的,在 c 語言和彙編需要互相呼叫的情況;c 語言編寫的不通的二進位制函式庫之間,都要注意函式的呼叫規則。
下面舉乙個普通的例子
[plain]view plain
copy
addproc1 proc ; cdecl方式
mov ebp, esp
mov eax, dword ptr [ptr+8] ; 取第乙個引數
add eax, dword ptr [ptr+12] ; 取第二個引數
pop ebp ; 恢復棧幀為呼叫者,但這時候堆疊還未平衡
ret
addproc1 endp
addproc2 proc ; stdcall
push ebp
mov ebp, esp
mov eax, dword ptr [ptr+8]
add eax, dword ptr [ptr+12]
pop ebp
ret 8 ; 和前面一樣,唯一不同是,直接由子程式恢復堆疊,8 正好是兩個引數的長度
addproc2 endp
start:
push 20
push 10
call addproc1
add esp, 8 ; 由主調函式恢復堆疊
push 50
push 60
call addproc2
ret
end start
記憶體中的堆疊 堆疊平衡
1 記憶體中的堆疊使用是先從 高位的位址 到 低位的位址 使用 儲存的。2 堆疊使用的時候,最後需要進行堆疊平衡,也就是去平衡esp中暫存器儲存的值 3 esp暫存器中儲存的值對應的就是當前堆疊使用的位置 4 如果當前的壓入的堆疊資料 不是通過push指令 後面不需要的話,一般就是在sub esp,...
彙編中的堆疊傳參
這個堆疊傳參,就好比你想吃糖,可是你左邊的口袋裡已經裝滿了瓜子,所以你只能,先把糖放入右邊口袋,當你需要吃糖的時候。在從右邊口袋裡把糖取出來,就這麼簡單,這就是堆疊傳參,左邊口袋是通用暫存器,右邊口袋就是堆疊。糖果就是引數,向口袋放糖和從口袋拿糖就是呼叫堆疊,吃糖這個動作就是執行程式。當我們在執行函...
組合語言 6 利用堆疊傳遞引數及堆疊的修正
一 呼叫子程式時資訊的保護與恢復方法 1 在子程式中進行 subroute proc push axpush bxpush cx.popcx popbx popax retsubroute endp 2 在主程式中進行 push axpush bxpush cxcall subroute popcx...