彙編中引數的傳遞和堆疊修正2

2021-04-13 01:06:41 字數 2368 閱讀 2718

在經典的組合語言教程中,函式呼叫時堆疊的使用都是著重講解的問題。如今隨著高階語言的越來越完善,單純使用彙編開發的程式已經不多了。但對函式呼叫時堆疊動向的了解仍有助於我們明晰程式的執行流程,從而在程式編寫和除錯的過程中有乙個清晰的思路。

一.呼叫約定

在win32中,有關函式的呼叫主要有兩種約定。

1._stdcall

以__stdcall方式呼叫的函式有以下特徵:

•  引數由右至左壓棧

• 呼叫返回時,堆疊由被調函式調整

2.__cdecl

__cdecl約定是c/c++函式的預設呼叫約定。它有以下特徵:

• 引數由右至左壓棧

• 呼叫返回時,堆疊由呼叫者調整

二.win32函式呼叫過程

1.    壓入引數

這裡依據以上的呼叫方式將呼叫者給出的引數一一壓入堆疊。

2.    壓入斷點

當程式執行到call指令的時候,當前語句的位址作為斷點位址壓入堆疊。

3.    跳轉

eip的值被重新設定為被調函式的起始位址。

4.    mov ebp, esp

這裡ebp被用來在堆疊中尋找呼叫者壓入的引數,同時作為呼叫者堆疊指標的乙個備份。在此前還應該執行一條:

push ebp

把ebp中原來的數值儲存。

5.    sub esp,n

這裡n是函式內區域性變數的總位元組數加上乙個整數,一般為40。此後esp即為被調函式的堆疊指標了。

6.    初始化esp ~ esp-n之間的n位元組空間

這是對堆疊中已分配給區域性變數使用的記憶體空間的初始化,一般全部設定為0xcc。

7.    順序執行函式內語句。

此時函式的堆疊位於所有區域性變數的記憶體空間之後,二者之間一般有40位元組的隔離帶。

8.返回

為保障呼叫的正常返回,函式內應當保證規範使用堆疊,使即將返回的時候esp的值恢復為執行第一條語句前的狀態。說明白點,就是每一條push都要有相應的pop。

呼叫返回的過程如下:

mov esp, ebp

執行後,esp恢復為呼叫者的堆疊指標,棧頂除斷點位址外,還存有原ebp的值和呼叫時壓入的引數。

然後依次彈出ebp的值和斷點位址。如果是__cdecl約定則直接返**用者,呼叫者將負責調整堆疊,丟棄調先前壓入的引數。如果是__stdcall則這個工作由被調函式來執行。

程式樣例如下:

……0040b8e8   push        1            壓入引數

0040b8ea   call        00401028        呼叫函式

……00401028   jmp         0040b7c0        跳轉到函式入口

……0040b7c0   push        ebp            儲存ebp

0040b7c1   mov         ebp,esp        

0040b7c3   sub         esp,44h        設定函式的堆疊指標,此函式中有4

;位元組的區域性變數

0040b7c6   push        ebx

0040b7c7   push        esi        

0040b7c8   push        edi

0040b7c9   lea         edi,[ebp-44h]    

0040b7cc   mov         ecx,11h

0040b7d1   mov         eax,0cccccccch

0040b7d6   rep stos    dword ptr [edi]    初始化區域性變數空間

0040b7d8   mov         eax,dword ptr [ebp+8]

0040b7db   mov         dword ptr [ebp-4],eax

……0040b7de   pop         edi            彈出曾壓棧的資料

0040b7df   pop         esi

0040b7e0   pop         ebx

0040b7e1   mov         esp,ebp        恢復呼叫者的堆疊

0040b7e3   pop         ebp            彈出原ebp值

0040b7e4   ret         4            返回並將堆疊向上調整4位元組。

;此處為__stdcall約定,所以由函式調

;整堆疊

相應的c**如下:

void __stdcall fun(int);

int main(void)

void __stdcall fun(int para)

組合語言 6 利用堆疊傳遞引數及堆疊的修正

一 呼叫子程式時資訊的保護與恢復方法 1 在子程式中進行 subroute proc push axpush bxpush cx.popcx popbx popax retsubroute endp 2 在主程式中進行 push axpush bxpush cxcall subroute popcx...

ESP,EBP 彙編關於引數的傳遞

參考了羅雲斌的一篇文章,很清晰 子程式如何訪問引數 因為預設對堆疊操作的暫存器有 esp 和 ebp,而 esp是堆疊指標,無法暫借使用,所以一般使用 ebp 來訪問堆疊,假定在乙個呼叫中有兩個引數,而且在 push 第乙個引數前的堆疊指標 esp 為 x,那麼壓入兩個引數後的 esp 為 x 8,...

ESP,EBP 彙編關於引數的傳遞

子程式如何訪問引數 因為預設對堆疊操作的暫存器有 esp 和 ebp,而esp是堆疊指標,無法暫借使用,所以一般使用 ebp 來訪問堆疊,假定在乙個呼叫中有兩個引數,而且在 push 第乙個引數前的堆疊指標 esp 為 x,那麼壓入兩個引數後的 esp 為 x 8,程式開始執行 call 指令,ca...