函数调用过程中的栈帧分析

说到函数栈帧,就不得不提到另外一个名词“”,栈的主要特点:先入后出,后入先出(就像叠罗汉一样),增长的方向,高地址向低地址生长,系统自动回收

那么栈帧是什么呢?

栈帧首先是存储在栈上,栈帧记录函数调用过程的一些信息的,例如变量、上一级栈帧的帧指针、函数的返回地址等,一个程序不止一个函数,很多时候都是函数的嵌套调用,那么栈上面肯定有多个栈帧(栈溢出因为栈空间不够,栈帧太多会消耗太多的栈空间,因为每个栈帧都要记录上一级栈帧的帧指针和返回地址),下图为栈帧的一般结构


可以看到上图有一个ebp,这个在x86中,指的是一个寄存器,还有另外一个寄存器esp和它一起使用

ebp(rbp):帧指针或基址指针,用来寻址,始终是指向栈帧的起始位置

esp(rsp):栈地址,会随着数据的入栈(push)和出栈(pop)移动,指向栈帧的顶部位置

eip(rip):指向cpu下一条指令的地址

举例之前,才来看一张图,这张图,对下面通过汇编分析函数的调用过程,有一定的作用


main.c的例子代码

int add(int a, int b)
{
        return (a + b);
}
int mul(int x, int y)
{
        return (x * y);
}
void fun(int x, int y)
{
        int sum = 0;
        int acc = 0;

        sum = add(x, y);
        acc = mul(x, y);
}
int main(int argc, char** argv)
{
        int a = 0;
        int b = 0;
        int ret = 0;
        a = 3;
        b = 4;
        fun(a, b);

        return 0;
}

这个程序的反汇编代码


分析这个例子的函数调用过程的栈帧

首先用gdb调试该程序,看一下调用fun函数之前,main函数的栈帧


进入fun函数的时候,栈帧的变化


进入add函数时,栈帧的变化


能把上面的入栈看懂,下面的出栈过程就简单了

首先是pop %rbp,这个主要是把上一级的栈帧送入rbp,就是让这个rbp这个帧指针指向原来的栈帧起始地址,rsp再向上移动8个字节

ret指令则是将栈顶的返回地址弹出到rip,然后按照rip此时指示的指令地址继续执行程序


leave指令主要是因为当前rsp和rbp指向的位置不一样,需要先将rsp = rbp,可以看到leave的指令都没有了pop %rbp这条指令,所以leave等价于:mov %rbp, %rsp ;pop %rbp

至此全部讲完,主要是借助了gdb来分析函数调用的栈帧

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值