函数调用过程中栈帧的创建与销毁
开始之前需要对汇编语言中的一些指令进行解释:
esp 栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。
ebp 基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。
mov 将“,”后面的 地址赋给“,”前面的。
push push reg/mem/seg;sp<-sp-2,ss<-reg/mem/seg
进栈指令先使堆栈指令sp减2,然后把一个字操作数存入堆栈顶部。堆栈操作的对象只能是字操作数,进栈时底字节存放于低地址,高字节存放于高地址,sp相应向低地址移动两个字节单元。
pop pop reg/seg/mem;reg/seg/mem<-ss:[sp],sp<-sp+2
出栈指令把栈顶的一个字传送至指定的目的操作数,然后堆栈指针sp加2。目的操作数应为字操作数,字从栈顶弹出时,低地址字节送低字节,高地址字节送高字节。
call 1. 保存当前指令的下一个指令的地址 2. 跳转到指定函数处通过jmp
sub 不带借位的减法指令。指令格式:SUB OP1,OP2 指令功能:(OP1)←(OP1)-(OP2),将OP1-OP2的值,保存在OP1中,如:SUB [EAX],1 以EAX寄存器为内存地址,将该地址的值减1,
rep stos
lea edi,[ebp-0C0h]
mov ecx,30h
mov eax,0CCCCCCCCh
rep stos dword ptr es:[edi]
rep指令的目的是重复其上面的指令.ECX的值是重复的次数. stos指令的作用是将eax中的值拷贝到es:edi指向的地址.
对一个简单的比较两个个数最大值的函数进行分析:
开始逐行运行,并通过反汇编来查看函数调用的原理:
调用开始的反汇编:
对形参进行实例化,通过指令实现:
当call指令执行时:
0A11361h :跳转到0A116F0h
0A116F0h:
开始执行具体的操作:
push ebp 首先将esp指针下移,然后把ebp寄存器的内容(main函数的栈底地址)存到fun函数的当前栈顶(当前esp指向的地址);
mov ebp, esp 把esp的内容赋给ebp;fun函数的栈底。
sub esp,0D0h 给esp减去一个随机值,指向一个新的fun函数栈顶。
从array中返回:
首先 将d的内容存在eax中;
之后进行返回操作:
mov esp, ebp 把esp指向ebp的内容,形成新的栈顶
pop ebp 将栈顶的内容(main:ebp)弹出来放在ebp,把esp指针上移。
ret 把main:retaddr返回给pc ,esp上移;使pc指向main函数的下一 条指令;
add esp,8 fun函数返回后a和b就会被释放,所以这里给esp加两个整形的字节,使esp恢复到形参实例化前的位置,即从栈向上两个整形的字节字节
dword ptr [w],eax 将返回值赋值给主函数里面的w;