天天看點

對call、retn的深入分析和認識

為了加深對call、retn的了解,我今天用delphi寫了一個小程式,在OD中跟蹤程式執行call及retn時堆棧的變化。

程式很簡單:

procedure summ(b: string);

var

a: string;

begin

a := b;

end;

procedure TForm2.Button3Click(Sender: TObject);

begin

summ('bbbbbbbb');

end;

對應的彙編代碼:

004A4D28   .  B8 3C4D4A00   mov     eax, 004A4D3C                    ;  ASCII "bbbbbbbb"

004A4D2D   .  E8 9EFFFFFF   call    004A4CD0

004A4D32   .  C3            retn

004A4CD0  /$  55            push    ebp

...........

004A4D21   .  59            pop     ecx

004A4D22   .  59            pop     ecx

004A4D23   .  5D            pop     ebp

004A4D24   .  C3            retn

執行到004A4D2D,esp=0013F630,F7進去後到達004A4CD0  也就是summ的第一句代碼,esp=0013F62C,也就是說執行call xx系統進行了一個壓棧操作!執行到 004A4D24時,esp=0013F62C(和執行到第一句代碼時相等),執行了retn後,esp=0013F630,也就是說retn進行了一個出棧的動作! 

另外,函數執行完畢的前後,不管是stdcall還是fastcall,都不保證寄存器不被修改!

總結:

1、執行到函數内的第一個語句時的esp值和到最後一個語句(也就是retn)的esp值是一樣的:

004A4CD0  /$  55            push    ebp  ;esp=0013F628

004A4CD1  |.  8BEC          mov     ebp, esp

004A4CD3  |.  5D            pop     ebp

004A4CD4  /.  C2 0400       retn    4 ;esp=0013F628 

2、retn 4表示pop 2次。

3、執行到call xx時的esp值與執行完xx時的esp值不一定相等,對stdcall的尤其是這樣。 

粗淺分析,不當之處還請指出。