读书人

子程序的压栈形式

发布时间: 2012-08-21 13:00:21 作者: rapoo

子程序的压栈方式

当指定子程序的语言模式,或者使用.model中指定的语言模式时,如stdcall、pascal等,子程序的参数压栈方式是不同的,例如stdcall模式下,参数是从右向左压栈,而在pascal模式下,参数是从左向右压栈。

?

下面,以stdcall模式为例,说明调用一个子程序时,是如何压栈的,假设压栈前,esp的值为addr:

?

addr……addr - 4ebp + 16参数三addr?- 8ebp + 12参数二addr - 12ebp + 8参数一addr - 16ebp + 4返回地址addr - 20ebp保存原ebp值,并且mov ebp, espaddr - 24ebp - 4局部变量1addr - 28ebp - 8局部变量2……

?

如上表所示,如果栈是向下生长的,则在将参数和返回地址进栈后,需要保存当前的ebp,并且将当前的esp值赋予ebp,从而可以用ebp访问参数或者局部变量。同时,编译器在编译时,会在ret前,加上leave这条指令, 实现mov esp,ebp, pop ebp的功能。

?

而在子程序中如果要用uses或是pushad/popad对实现环境变量保存时,如果返回结果是保存在eax中,则一定要记得将返回结果保存起来,否则eax中的值会被重置为调用前的值,如下列代码所示:

?

.386  .model flat, stdcall    include    windows.inc  include    kernel32.inc  includelib kernel32.lib include   user32.incincludelib user32.libinclude    masm32.inc includelib masm32.lib  include    debug.inc includelib debug.lib    .data  ddResult  dd  ?    .code  calc proc one, two, three      pushad          mov eax, one      add eax, two      add eax, three        mov ddResult, eax ;如果不在这里保存,返回的eax会是原来的值            PrintDec eax      PrintLine        popad          PrintDec eax      PrintLine    ret  calc endp    start proc      invoke calc, 1, 2, 3      PrintDec ddResult  ; 6          PrintLine    PrintDec eax  ;          ret  start endp    end start

?输出结果:


子程序的压栈形式

读书人网 >编程

热点推荐