子程序的压栈方式

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

 

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

 

addr ……
addr - 4 ebp + 16 参数三
addr - 8 ebp + 12 参数二
addr - 12 ebp + 8 参数一
addr - 16 ebp + 4 返回地址
addr - 20 ebp 保存原ebp值,并且mov ebp, esp
addr - 24 ebp - 4 局部变量1
addr - 28 ebp - 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.inc
includelib user32.lib

include    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

 输出结果:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值