函数栈桢

在做面试题的时候,我遇到了这样一道题:

    #include <stdio.h>

    void fun()
    {
        int tmp=10;
        int* p=(int*)(*(&tmp+1));
        *(p-1)=20;
    }

    int main()
    {
        int a=0;
        fun();
        printf("%d",a);
        return 0;
    }

一眼看去,a的值好像并未发生改变。但是实际上并不是我们看到的这么简单哦~

正文

在解这道题时,我们需要搞懂函数调用是怎么实现的???

接下来我就来一步一步讲解

函数栈桢地址使用

函数栈桢的使用是由高地址向低地址使用的

函数压栈

函数压栈:在栈顶处不断放入数据

函数调用时使用的寄存器
  • esp:函数栈顶的地址,随着压栈的进行,esp会向低地址处移动

  • ebp:函数栈底的地址

在调用main函数之前,还调用了一个函数叫做mainCRTStart()

mainCRTStart是用来调用main函数的一个函数

接下来,我将以下面的代码为例,来讲解函数调用过程

    #include <stdio.h>

    int Add(int x,int y)
    {
        int z = 0;
        z = x + y;
        return z;
    }

    int main()
    {
        int a = 10;
        int b = 20;
        int ret = 0;
        ret = Add(a,b);
        printf("%d",ret);
        return 0;
    }

代码分析

调用mainCRTStart()

以调用mainCRTStart()来调用main函数,此时ebp在栈底,esp在栈顶。

用汇编代码来看

这里写图片描述

注意:函数栈桢图中的序号与步骤号对应,汇编代码前的红色数字与步骤号也是对应的,一个步骤可能执行多条语句

第一步

将ebp的值压在栈顶上(红色方框),esp由esp1移到esp2的位置

第二步

将esp的值赋给ebp,即ebp由ebp1的位置移到ebp2的位置

第三步

esp-4Ch:esp由esp2的位置移到esp3的位置,此时为esp与ebp维护的空间是为main函数开辟了空间

第四步

将ebx、esi、edi依次压入栈中,esp随着每次压栈向低地址处移动,则esp由esp3的位置移到esp4的位置

第五步

将edi放到ebp-4Ch的位置上,即将edi移动到edi1的位置,

将eax的内容拷贝ecx存放内容次,放到edi向下的内容中去。将为main函数开辟的空间全部初始化成随机值

第六步

为ebp-4地址处赋值,为10(a)

第七步

为ebp-8地址处赋值,为20(b)

第八步

为ebp-12地址处赋值,为0(ret)

第九步

将ebp-8地址处的值赋给寄存器eax,并将eax压入栈中(_b)

将ebp-4地址处的值赋给寄存器ecx,并将ecx压入栈中(_a)

将call指令下一条指令的地址压入栈中

该过程进行完,esp由esp4的位置移动到esp5的位置

第十步

进入Add函数中,将main函数的ebp位置压入栈中,esp由esp5位置移到esp5的位置

第十一步

将ebp移动到esp的位置,即将ebp由ebp2的位置移到ebp3的位置

第十二步

esp-44h:为Add函数开辟空间

第十三步

依次将ebx、esi、edi压入栈中,则esp由esp7的位置移到esp8的位置

第十四步

将edi移动到edi1的位置(橙色),并将Add函数开辟的空间初始化为随机值

第十五步

将ebp3-4的位置初始化成0(z)

第十六步

将ebp+8的位置的值(a)放入eax寄存器中

将eax(x)中的值加ebp+0Ch(y),将结果放在eax寄存器中

将eax中的值,赋给ebp-4(z)

第十七步

将ebp-4(z)中的值放入eax寄存器中

第十八步

将edi、esi、ebx弹出栈,将esp由eap8的位置移动到esp7的位置

第十九步

将esp放在ebp的位置,即esp由esp7的位置移动到esp9的位置

第二十步

将ebp弹出,ebp移动至main函数的栈底位置,即esp2的位置

第二十一步

将寄存器eax中存放的值,赋给ebp-0Ch(ret)

面试题解答

其实a的值是在调用函数fun时,通过指针赋值发生的改变

转载请注明原地址:Lucky-pxx的博客 » 点击阅读原文,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值