浅析C++程序栈


读《深入理解计算机系统》第三章 程序的机器级表示   有感(发篇博文加强自己对知识的理解吐舌头,有不对的地方敬请指正)

我们知道C++程序运行时变量的存储区域分为堆区,栈区,静态存储区,今天我们就来浅析一下所谓的栈区

我们知道,程序运行的时候,临时变量是存储在栈上的,当一个函数调用完成时程序会自动清除临时对象,然而这个栈到底是如何运行的呢?看下文

 

一个函数调用包括将数据(以参数和返回值的形式)和控制从代码的一部分传递到另一个部分,它还必须为临时变量分配空间,并在退出的时候释放这些空间。大多数机器包括IA32只提供转译控制到函数和从函数中转移出控制这种简单的指令。数据传递,局部变量的分配和释放通过操纵程序栈来实现     --《深入理解计算3.7-过程》

 

上图就是所谓的栈,这个栈由许多个帧组成。栈上分配给单个函数的那部分就叫做一个帧。




          (注意:上图中灰色部分是多分配的内存,即使未被使用,因为这涉及到数据访问的严格对齐,请读者自行查找资料)

调用swap_add之前:

先看左图:先调用caller(),如上图,程序会把caller()里的临时变量arg1arg2按照声明的顺序依次存储在帧指针(帧底指针)ebp - 4 的位置ebp - 8的位置(int4个字节),然后运行到caller的第三行准备调用swap_add,在调用之前程序会程序会先把swap_add的函数按照参数声明的顺序以相对于栈顶指针esp的顺序先后压入caller()的帧中(下面会解释为什么要这样),调用前的最后一步就是栈顶指针esp - 4,然把返回地址压入栈中,(可以参考右图),

返回地址就是程序从被调用函数里返回后应该继续执行的地方,这里继续执行的语句就是把swap_add的函数返回值赋给变量diff(注意此时ebp还是指向左图中的那个位置,esp是指向右图+4即指向返回地址)

 

调用swap_add:

在刚进入swap_add时第一步就是在程序栈上建立swap_add的帧(一帧对应一个函数,可以回去看一下最开始的那张图caller就是调用者,swap_add就是当前者)   

 

建栈:而建帧的第一步就是保存上一个帧的帧底指针ebp的值,然后把ebp移到esp的位置开始一个新的帧(注意此时右图中此时还未把ebx的值压入栈中)。说了这么多,保存帧底指针是为了什么呢?保存上一个帧的帧底指针就是为了当当前的帧调用完成时通过保存的这个值能够回到上一个帧的帧底,然后以此类推

 

ebx我们忽略不讲,可以把它看成一个变量的值

 

 

那么swap_add如何取得他的参数呢,其实很简单(ebp,esp 的位置如右图) ebp+8不就是 参数arg1的地址么,ebp+12不就是arg2的地址么。接下来swap_add的帧就像caller一样了 保存临时变量,因为swap_add没有调用其它函数,所以当执行到swap_add的最后一条语句时就要返回。

 

退栈:

Swap_add调用完了就要返回。此时,程序栈会把上一个帧的帧底指针的值取出来 即 保存在当前ebp中的那个old ebp的的值 ,然后把old ebp的值赋给ebp,再把返回地址弹出来,让程序跳到返回地址所指的地方继续执行(caller里的第3行),esp在退回去到左图的位置时会依次调用临时变量的析构函数(如果有的话),这就是出了函数作用域临时变量就不再有效的原因,接着程序栈就又回到了左图的状态。

然后接着完成对caller的调用,然后再返回上层函数调用,最后回到main,然后程序结束。


最后读者可以自行验证一下(注意,程序栈还会包含一块未使用的区域,所以c和a之间的地址会相差很大,但总体来看还是符合上面的分析的。)


仔细对比一下你会发现a和x的地址是一样的,说明程序栈是固定的(我说的固定是相对于我的编译器,且再未开启栈随机化优化功能的情况下,至于栈随机化,那是为了抵抗缓冲区溢出攻击而发明的一种方法,然而还是能被攻击。)


 

《深入理解计算机》吐血推荐大家阅读,读完后程序员质的飞跃

下一篇:

C++函数调用栈与尾递归。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值