天天看点

对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的尤其是这样。 

粗浅分析,不当之处还请指出。