堆栈调用,局部变量(更易理解,有图)

 
堆栈调用,局部变量 (2007-02-13 11:52)
分类: 汇编学习

堆栈调用,局部变量

一:在分析汇编代码时总是要遇到无数的Call,对于这些Call,尽量要根据Call之前传递的参数和Call的返回值来判断Call的功能。传递参数的工作必须由函数调用者和函数本身来协调,计算机提供了一种被称为栈的数据结构来支持参数传递。
   当参数个数多于一个时,按照什么顺序把参数压入堆栈。函数调用后,由谁来把堆栈恢复。在高级语言中,通过函数调用约定来说明这两个问题。常见的调用约定有:

<!--[if !vml]--><!--[endif]-->

二:堆栈框架也称为活动记录,它为程序的返回地址,传递进来的参数,保存的寄存器喝局部变量保存的堆栈空间。堆栈框架是按以下的步骤创建的。

1:参数被压入堆栈。

2:过程被调用,返回地址被压入堆栈。

3:过程开始执行时,EBP被压入堆栈。

4:使EBP和ESP的值相等,从这里开始,EBP就作为寻址参数的基址指针。

5:可以从ESP中减掉一个数值来给过程的局部变量创建空间。

 

【例】按__stdcall约定调用函数test2(Par1, Par2)   


        push par2  ; 参数2              ;参数被压入堆栈(从右向左)
        push par1  ; 参数1              ;
        call test2;                            ;过程被调用
        {                                ;过程开始执行
             push ebp                    ; EBP被压入堆栈,保护现场原先的EBP指针
             mov  ebp, esp            ;使EBP=ESP, 设置新的EBP指针,指向栈顶,

;从这里开始,EBP就作为寻址参数的基址指针。
             mov  eax, [ebp+0C]  ; 调用参数2
             mov  ebx, [ebp+08]   ; 调用参数1
             sub  esp, 8              ; 若函数要用局部变量,则要在堆栈中留出点空间

;从ESP中减掉一个数值来给过程的局部变量创建空间
             …
             add  esp, 8                 ; 释放局部变量占用的堆栈
             pop  ebp                    ; 恢复现场的ebp指针
             ret  8                      ; 返回(相当于ret; add esp,8)
        }

三: 其堆栈调用示意图:(编译原理的教程中说的更清楚)

<!--[if !vml]--><!--[endif]-->

四:例子

 

 

00401000  /$  6A 04        push    4               ; /Arg2 = 00000004

00401002  |.  6A 03         push    3                ; |Arg1 = 00000003

00401004  |.  E8 16000000   call    0040101F          ; \local.0040101F

00401009  |.  8BD8         mov     ebx, eax

0040100B  |.  6A 00         push    0                ; /ExitCode = 0

0040100D  \.  FF15 00204000 call    dword ptr [<&KERNEL32.ExitProces>; \ExitProcess

 

 

 

 

 

00401013      00            db      00

00401014      00            db      00

00401015      00            db      00

00401016      00            db      00

00401017      00            db      00

00401018      00            db      00

00401019      00            db      00

0040101A      00            db      00

0040101B      00            db      00

0040101C      00            db      00

0040101D      00            db      00

0040101E      00            db      00

 

 

 

 

 

 

0040101F  /$  55           push    ebp

00401020  |.  8BEC         mov    ebp, esp

;使EBP=ESP=0012FFB4

;设置新的EBP指针,指向栈顶,

;从这里开始,EBP就作为寻址参数的基址指针。

00401022  |.  83EC 04       sub     esp, 4

;扩展栈空间ESP=0012FFB0

00401025  |.  8B45 0C       mov    eax, dword ptr [ebp+C];

                                                               ;当前堆栈3个双字偏移的数值

                                                               ; ebp+C=0012FFB4+C=0012FFC0

                                                               ;EAX=[0012FFC0]=00000004

00401028  |.  8B5D 08       mov     ebx, dword ptr [ebp+8]

                                                               ;当前堆栈2个双字偏移的数值

                                                               ; ebp+8==0012FFB4+8=0012FFBC

                                                               ;EBX=[0012FFBC]=00000003

0040102B  |.  895D FC      mov     dword ptr [ebp-4], ebx

                                                               ;[ebp-4]就是局部变量=[0012FFB4-4]=[0012FFB0]

                                                               ;自动减4,也就是将EBX中的值00000003

;放入堆栈的0012FFB0地址处

;参数1放局部变量里

0040102E  |.  0345 FC       add     eax, dword ptr [ebp-4]

                                                               ;将局部变量与EAX相加后放入EAX中

                                                               ;EAX=00000007

                                                               ;参数2与局部变量相加

00401031  |.  83C4 04       add     esp, 4

                                                               ; 释放局部变量占用的堆栈,ESP: 0012FFB4

00401034  |.  5D            pop     ebp

                                                               ;恢复原有的EBP, ESP:0012FFB8

00401035  \.  C2 0800       retn    8

                                                               ; 返回(相当于ret; add esp,8)

                                                               ; ESP: 0012FFC4

 

 

 

堆栈的情况:

0012FFB0   00000003        ;局部变量

0012FFB4   0012FFF0              ;保存EBP, push    ebp

0012FFB8   00401009       ;压入返回地址

;返回到 local.<模块入口点>+9 来自 local.0040101F

0012FFBC   00000003        ; push    3,每次堆栈地址加32位,双字

0012FFC0   00000004        ; push    4

 

 

 

 

五:说明

Intel的堆栈是在内存中是向下扩展的。先进栈的数据内存地址最高,后进栈的数据内存地址减少。且数据是按小尾类型存储,例如:数值12345678H存放的形式(假设按字):先存1234,后存放5678。

 

原文地址:http://blog.chinaunix.net/space.php?uid=20399471&do=blog&id=1688004

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值