主程序 结果见上图
.386
.model flat,stdcall
option casemap:none
include <windows.inc>
include <user32.inc>
includelib <user32.lib>
include <kernel32.inc>
includelib <kernel32.lib>
.code
start:
call test2
test2 proc
local @loc1:dword,@loc2:word
local @loc3:byte
mov eax,@loc1
mov ax,@loc2
mov al,@loc3
leave
ret
test2 endp
end start
反汇编后内存如下:
我们经过分析发现:
主程序的地址是call 处的那个
子程序过程;
1.保护现场 入栈
2.执行程序
3.返回断点 出栈
因为根据局部变量(包括函数形参)入堆栈的原理,我们发现,要先保存ebp这个寄存器(因为访问堆栈就是用的这个寄存器,esp只是用来标识堆栈栈顶位置的)
push ebp ; 把原来ebp寄存器的值保存起来; mov ebp,esp ; 把esp寄存器的值复制到ebp寄存器中,供存取局部变量时做指针用; add esp,FFFFFFF8 ; 在堆栈中预留(注意是预留,局部变量用完自动出栈,所以还要把esp的值重新赋值回来)出空间(即重新设置堆栈指针),由于堆栈是向下增长,所以要把esp加上一个负值。-8不是-7,因为dword访问内存更快 一条leave指令就实现了mov esp,ebp和pop ebp两条指令的功能。 esp用完要返回初始值,因为局部变量自动出栈。
.386
.model flat,stdcall
option casemap:none
include <windows.inc>
include <user32.inc>
includelib <user32.lib>
include <kernel32.inc>
includelib <kernel32.lib>
.code
start:
call test2
test2 proc
local @loc1:dword,@loc2:word
local @loc3:byte
mov eax,@loc1
mov ax,@loc2
mov al,@loc3
leave
ret
test2 endp
end start