函数调用时程序堆栈的变化

这个主要写一点关于在C里面,堆栈是怎么保存数据的,以及调用函数时,堆栈指针的变化。

很多人都知道,在程序里面,局部变量是在栈里面保存的,局部变量是有作用域的,这些,其实都是通过栈来实现的。

下面,通过一些简单的程序,来看看程序的栈,到底是怎么一回事,栈是怎么实现保存函数调用前后的信息的,为什么递归容易爆栈的问题。


首先说明两个寄存器

1.rbp:栈帧指针,具体应该是指向当前函数栈的栈底,是不动的。实际的作用应该就是类似于一个基址,通过这个基址上栈中变量的寻址。

2.rsp:栈顶指针。

3.rip:指令寄存器。存储cpu读取指令的地址


首先,写了一个比较简单的C程序:

#include <stdio.h>
#include <stdlib.h>


int add(int a, int b)
{
    int c=a+b;
    return c;
}


int main()
{
    int a=0x1;
    int b=0x10;
    int c=0x100;
    int sum=add(a,b);
    sum=add(sum,c);
    return 0;
}

经过反汇编之后,得到的main的汇编程序如下:

push   %ebp
%esp,%ebp
sub    $0x18,%esp
movl   $0x1,-0x10(%ebp)
movl   $0x10,-0xc(%ebp)
movl   $0x100,-0x8(%ebp)
mov    -0xc(%ebp),%eax
mov    %eax,0x4(%esp)
mov    -0x10(%ebp),%eax
mov    %eax,(%esp)
call   80483b4 <add>
mov    %eax,-0x4(%ebp)
mov    -0x8(%ebp),%eax
mov    %eax,0x4(%esp)
mov    -0x4(%ebp),%eax
mov    %eax,(%esp)
call   80483b4 <add>
mov    %eax,-0x4(%ebp)
mov    $0x0,%eax
leave  
ret   


通过这个,可以画出main函数的栈:



通过看main的栈的结构,有一点需要注意,而传入函数add的参数a和b,都在main栈的最后两个位置里面。在mian函数里面调用的函数,其参数的拷贝是在main函数的栈里面的,而不是拷贝在add函数的栈里面。

所以函数add(a,b),通过在main的栈里面添加一个a,b的副本,来传递给add函数,所以传递的是参数的一个拷贝,而不是直接把参数传递进去。


接下里看add的汇编程序:

080483b4 <add>:
push   %ebp
mov    %esp,%ebp
sub    $0x10,%esp
mov    0xc(%ebp),%eax
mov    0x8(%ebp),%edx
add    %edx,%eax
mov    %eax,-0x4(%ebp)
mov    -0x4(%ebp),%eax
leave  
ret    


通过汇编,可以得到程序第一次调用add的栈信息:

<
  • 4
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值