堆栈调用,局部变量
时间:2007-02-13 来源:wxz20032003
堆栈调用,局部变量
一:在分析汇编代码时总是要遇到无数的Call,对于这些Call,尽量要根据Call之前传递的参数和Call的返回值来判断Call的功能。传递参数的工作必须由函数调用者和函数本身来协调,计算机提供了一种被称为栈的数据结构来支持参数传递。
当参数个数多于一个时,按照什么顺序把参数压入堆栈。函数调用后,由谁来把堆栈恢复。在高级语言中,通过函数调用约定来说明这两个问题。常见的调用约定有:
二:堆栈框架也称为活动记录,它为程序的返回地址,传递进来的参数,保存的寄存器喝局部变量保存的堆栈空间。堆栈框架是按以下的步骤创建的。
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)
}
三: 其堆栈调用示意图:(编译原理的教程中说的更清楚)
四:例子
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。