函数调用栈帧的具体过程(汇编代码)

基础知识

ebp:存储栈底地址

esp:存储栈顶

ebp,esp作用:本次维护函数的栈帧

栈区由高地址向低地址延申,在栈开辟的时候,栈的大小即被确定


 main函数由谁调用?

__tmainCRTStartup

mainCRTStartup

越往下越是底层的调用者

在VS中,main函数由其他函数调用

栈区每一次调用都要分配空间

右击反汇编可以看对应的汇编代码

看具体地址则令其不显示符号名


以下为一个main函数调用add函数的汇编代码的例子

int Add (int x, int y)
{
    int z = 0 ;
    z= x + y ;
    return x + y;
}
int main()
{
    int a = 10;
    int b = 20;
    int c = 0;
    c=Add(a,b);
    return 0;
}

push:把一个值压入栈中

push ebp

把ebp压入栈之中 ,结果是esp地址变低(少了四个字节)

为什么不是八个字节呢?

原因:地址占用的字节数因具体的环境而不同,32位和64位系统占用大小不同

mov:把一个值赋给另一个值

mov ebp,esp:把esp的值赋给ebp

sub esp ,0E4h:把esp减去一个固定的值,即移到更低地址的地方去

至此,esp,ebp到达了一块新的空间。这块空间就是为main函数申请的空间

三次push(每次push之后esp自动变化)

push ebx

push esi

push edi

lea:load effective address加载有效地址

lea edi,[ebp-0E4h]

在edi之中把刚创建main时候的栈帧的esp存储

以下是把edi中存储的地址(先前的esp)到ebp的值全部修改为(初始化为)0CCCCCCCh的值

mov ecx,39h

ecx存具体次数

代表向下39h个地址

mov eax,0CCCCCCCh(著名的烫烫烫烫烫)

代表初始化的值

rep stos dword ptr es:[edi]

dword代表四个字节

把从创建main时候的esp向下39h地址全部初始化为eax之中的值

至此main的函数栈帧开辟完毕

准备执行代码

int a=10;

mov dword ptr [ebp-8],0Ah

把0Ah放入[ebp-8]的位置

int b=20;

mov dword ptr[ebp-14h],14h

发现地址差两个整型

连续创建两个变量空间不一定是连续分布的(依据编译器实现不同)

int c=0;

mov dword ptr [ebp-20h],0

add函数开始调用

c=Add(a,b);

把b的值20放入eax

mov eax,dword ptr[ebp-14h]

把寄存器eax值压入20

push eax

把a的值10放入寄存器

mov ecx,dword ptr[ebp-8] 

push ecx

call 00C210E1(按F11调试进入函数)00C210E1为被调用函数的地址

call指令的下一条指令的地址压入栈中方便以后寻找位置以便于下一条指令执行(00C21450)

然后执行跳转(jmp)

跳转到对应函数后

开辟新的栈帧

同样套路main的栈帧开辟一致

push

mov

sub

push

push

push

lea

mov

mov

rep stos

 至此add函数栈帧初始化完毕

int z=0;

mov dword ptr [ebp-8],0

z=x+y;

mov eax,dword ptr[ebp+8]

把对应地址的值移入eax,即使a的值(形参a)

add eax,dword ptr[ebp+0Ch](Ch代表12)

把eax与形参b的值加起来

mov dword ptr [ebp-8],eax

把加起来的值赋给对应c的位置

return z;

问:函数结束了,临时变量销毁了,为什么还能返回值z

答:值被存储到了寄存器里,z的销毁不影响寄存器的值

mov eax,dword ptr [ebp-8]

pop edi

pop esi

pop ebx

以上弹出该函数栈帧中寄存器中的值

mov esp,ebp

让栈顶指针移动到此时的栈底

pop ebp

把上次函数调用的栈底pop到ebp里

至此ebp和esp回到main函数里头(main的栈底还原)

ret

把call下一条指令读取(刚刚调用函数时jump到函数对应的指令,现在回到原来指令处)

此时指令从call的下一条指令执行(指令还原)

add esp,8

两个形参的空间释放(main栈帧恢复如初)

函数彻底调用完毕了

mov dword ptr [ebp-20h],eax

把和放入c中

函数作用彻底实现

main函数栈帧销毁同理

ps:函数栈帧创建最关键的三个部分

        1        形参压栈

        2        下一条指令的地址压栈

        3        上一个函数(main)函数的栈底压栈

        销毁的时候依次找到上一个栈帧的底部,下一条指令的位置,再去掉两个形参,找到顶部

        还原如初

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值