栈帧

关于栈帧 我觉得这两篇文章讲的不错了,至少我看完能 明白了。

http://www.cnblogs.com/haolujun/archive/2011/03/26/1996525.html

http://blog.csdn.net/zsy2020314/article/details/9429707

写的很详细,我不打算和他们一样的从头分析这个栈帧了 。

 通过理解栈帧这个概念我觉得能够理解 函数中的变量为什么会有局部性,一层层的函数调用是怎么实现的 又 是怎么正确返回的等等。 然后在思考函数调用时栈的结构时发现一个问题。

先简单写两个函数

#include<stdio.h>
#include<unistd.h>
int foo()
{
	printf("where i  am\n");
	exit(0);
}
int fun(int a,int b)
{
	int c=5;
	int *p = &a;
	*(p-1)= foo;
	return c;
}
int main()
{
	int a = 0;
	int b = 1;
	int ret = fun(a,b);
	return 0;
}


画图水平不行 从上边文章中盗个图改改


在main中调用fun时   在汇编角度也就是call  fun时  call指令 会将 下一句指令的地址入栈,以备函数返回时继续执行,从fun返回是 ret    相当于 pop IP    IP就指向了先前有call入栈的fun的下一句的地址。

也就是说从fun中能正确返回到main中 靠的是 图中在 变量a下一个位置存储的“返回地址” 而 a 是被调用函数的第一个参数,我们在fun中完全能找到它,那么我既然能找到a 也就能找到“返回地址”所存储的位置,当然也就能修改它了

int *p = &a;
*(p-1)= foo;
这两个语句 将“返回地址”修改成了foo函数,所以当程序执行时 fun结束,就不能争取返回到main中了,而是跑到了foo中~~~~


结果会输出 where i  am

如果foo中 不exit的话   那程序也无法正常返回到main中结束了,因为之前的修改已经打乱了 层层调用的这种栈帧结构,程序会出错。由此例考虑,利用这个栈帧 应该还能做很多有意思的事情



学习了栈帧这个货之后,我突然想到了前段时间调试程序时一个解释不了的bug,原程序解释起来比较啰嗦,我就举个同理的例子好了。简单说就是在用gdb调程序时,比如我刚走到第五行,然后打印第十行的变量,发现它的值已经被计算出来了,这gdb你也太不老实了,还没到那一行呢 值怎么就出来了呢?当时令我有些困惑,但看完栈帧后,似乎知道为什么了。 先写个程序测试一下。


简单看  在main中两次调用fun 用gdb调试,当进入到第二个fun时,跑到第五行

int  c = 3;

这是后 打印 后边的变量 d   f  竟然已经有了 正确的值, 我明明还没跑到那句呢?  然后发现调试进入第一个fun调用的话,就不会发生这种现象。

然后  想-----------       应该是两次都调用了同一个函数,当第一个函数返回后 紧接着调用第二个,因为是同一个函数,那么 栈帧,及内部临时变量分配的存储地址,都是一样的

,所以当我在第二个fun中打印后边变量的内容时,并不是已经执行到了那一句,而是 d  f 内容应是内存中的随机值,而这个内存中的随机值就正好是上一次调用fun时 临时变量的值。

再来验证一下上边的想法, 把函数改一下



这次就能很容易的看出 在第二次调用 fun时 跑第五行,打印后边的变量,这些变量的内容是第一次调用函数时那些变量的值,d=2  f=3   而不是像最初所想的那样,它提前算出来了(d= 6  f =11)

那再改一下



可以看到 虽然是不同的函数  但函数结构 变量个数顺序什么的都一样, 栈帧结构也是相同的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值