汇编网首页登录博客注册
masmaster的学习博客
博客首页博客互动【做检测题】论坛求助

我的博客

个人首页 |  我的文章 |  我的相册 |  我的好友 |  最新访客 |  文章收藏 |  论坛提问 |  友情链接 |  给我留言  
图片载入中
文章收藏

[2010-07-30 18:43] 关于堆栈框架(2)

堆栈参数的访问:
在调用函数时,C程序使用标准的方法初始化和访问参数。 C中的函数以序言开始,序言部分的代码保存了EBP寄存器,并使EBP指向当时堆栈的顶部,函数还有可能把一些寄存器入栈, 这些寄存器的值将在函数返回的时候恢复。函数以收尾代码结束,在这部分代码中,EBP被恢复, ret指令从函数返回。如:
subproc    proc
           push  ebp  ;序言部分将EBP入栈保存。
然后,将ESP/SP的值设为EBP/BP的值,所以EBP/BP开始作为堆栈的基址指针使用了。
subproc    proc
           push ebp
           mov ebp,esp
这两条指令完成后, 堆栈框架如下图:(用32位寄存器表示)
------------
|parameter1|    ;[EBP+12]
------------
|parameter2|    ;[EBP+8]
------------
|返回地址  |    ;[EBP+4]
------------
|  EBP     |    ;EBP,ESP
------------
函数还会将其他的寄存器入栈保存,但不会改变栈中参数的地址相对于EBP的偏移,随后的代码中,ESP可能会变, 而EBP通常不变。

访问堆栈参数:
在堆栈架构中使用相对基址寻址方式访问堆栈参数,EBP作为基址寄存器,偏移是一个常量。如:
supproc      proc
             push ebp         ;EBP入栈并保存返回地址
             mov ebp,esp      ;堆栈基址指针
             mov eax,[ebp+12] ;第二个参数
             add eax,[ebp+8]  ;第一个参数
             pop ebp          ;恢复EBP取得返回地址
             ret              ;返回
supproc      endp

堆栈的清理:
在子例程返回时, 必须用某种方法清除堆栈中的参数, 否则就会导致内存泄露以及堆栈的破坏。
对于这个问题, 简单的方法是在call指令后使用一条add指令给ESP加上一个值,使得ESP指向正确的返回地址。

处理堆栈清理问题的另一种方法是使用stdcall调用约定。 可以在子例程中ret指令后提供一个整数参数以修复ESP的值,这个整数值必须等于堆栈参数消耗的堆栈空间的字数。,比如:
subpurc      proc
             push ebp
             mov ebp,esp
             mov eax,[ebp+12]
             add eax,[ebp+8]
             pop ebp
             ret 8             ;消耗了8字节的空间
subproc      endp
评论次数(0)  |  浏览次数(413)  |  类型(汇编语言笔记) |  收藏此文  | 
 
 请输入验证码  (提示:点击验证码输入框,以获取验证码