在不同的编译器下,函数调用过程中栈帧的创建是略有差异的,具体细节取决于编译器的实现
越高级的编译器,函数封装越复杂,越不容易观察和学习
寄存器
eax ebx ecx edx
ebp esp
这2个寄存器中存放的是地址,这2个地址是用来维护函数栈帧的
每一个函数调用,都要在栈区创建一个空间(函数栈帧)
edp存放函数栈帧的高地址端的地址(栈底指针)
内存由高地址向低地址使用 ebp+4是向下ebp-4是向上
esp存放函数栈帧的低地址端的地址 (栈顶指针)
edp和esp之间的空间就是该函数的函数栈帧
压栈出栈
压栈 push :给栈顶加上一个元素
出栈 pop :从栈顶删除一个元素
栈顶地址也会随之改变
函数栈帧的创建
先用ebp和esp开辟一块空间
push edx
push esi
push edi
这三个元素不用管
lea load effective address 加载有效地址
初始化edp到edx的空间
将变量存入初始化好的空间
将变量放入寄存器中并压栈
执行call指令,并将call指令的下一条指令的地址压栈到形参上方,以便call指令完成后返回
函数传参
实参压栈到栈顶作为形参参与下一个函数的调用
传参时实参从右往左传,使右侧实参的形参位于高地址,左侧实参的形参位于高地址
函数返回
先将结果存入eax寄存器保存起来,等回到主函数再进行使用
pop edi
pop esi
pop ebx
将栈顶指针esp移动到栈底指针epb的位置
pop epb 利用epb中所存的地址返回主函数的栈底
利用原epb下方存入的地址返回主函数call指令的下一条指令
返回后将原来存返回地址的空间和形参所占空间释放,esp也随之下移
局部变量的创建
为函数分配好栈帧空间后,初始一部分空间,在这一部分空间给局部变量分配空间