zoukankan      html  css  js  c++  java
  • 对于栈内存的理解

    1、栈

    堆栈非常重要,因为它跟踪程序中运行的函数,而函数又是软件的基本组成模块。当调用一个函数时,将创建一个栈桢来支持该函数的执行。栈桢包含函数的局部变量和调用者传递给函数的参数。栈桢还包含管理信息,允许被调用的函数(被调用方)安全地返回给调用方。(saved ebp、 return address)

    2、与栈相关的寄存器

    • 堆栈指针(esp)指向堆栈的顶部。顶部总是被最后一个被压入到堆栈上但尚未弹出的项目所占据,就像在现实世界中的一堆盘子。存储在esp中的地址随着栈的内容的压入和弹出而不断变化,因此它总是指向最后一项
    • 跟踪堆栈的第二个寄存器是ebp,即基指针或帧指针。它指向当前运行的函数的栈桢中的一个固定位置,并为访问函数参数和本地变量提供一个稳定的参考点(基)。ebp仅在函数调用开始或结束时更改。因此,我们可以很容易地将堆栈中的每个项作为ebp的偏移量来处理。与esp不同,ebp主要由程序代码维护,很少受到CPU干扰。有时候,完全抛弃ebp会带来性能上的好处,这可以通过编译器标志来实现。Linux内核就是这样做的一个例子。
    • eax寄存器用于将大多数C数据类型的返回值传输回调用方。
    • pc寄存器用来确定cpu下一条执行的指令

    3、一个简单函数的栈内存的管理

    int add(int a, int b)
    {
            int result = a + b;
            return result;
    }
    int main(int argc)
    {
            int answer;
            answer = add(40, 2);
    }
    

    (1)该函数栈内存的变化时序图

    在这里插入图片描述当main发起函数调用(调用add函数)时:

    • 首先要将函数的返回地址保存下来(pc 下一条执行指令的地址)
    • 其次,要将上一个栈帧的的栈底地址保存起来(即main函数栈帧的栈底地址)。

    当函数返回时,该栈的内容将会全部弹出,然后将函数的返回值保存在eax寄存器中。

    上述函数弹出的具体顺序是

    • result 保存在eax后,弹出。此时esp指向saved ebp。
    • saved ebp 的内容存到复制到ebp寄存器中(即这时ebp返回指向到main的栈底),然后saved ebp这块内存弹出。此时esp指向return address 这块内存中。
    • return address通过一个操作系统指令(ret指令),将其内容拷贝到pc寄存器中,然后这块内容弹出。这时,pc寄存器指向调用函数后面的语句。而此时esp则指向了a。

    这样就完成了函数的返回。add函数的栈帧完全消失。

    从上述图片可以看出:

    • 调用函数add时,add栈内部中,并不保存调用add所传递过来的参数,因为这两个参数保存在寄存器中。add函数是可以访问到这两个参数的,所以也可以认为它被保存到栈中了。
  • 相关阅读:
    PL/SQL Developer使用技巧、快捷键(转发)
    Java 获取随机日期
    jsonArray和Java List对象互转,日期处理
    ExtJs grid单选,多选
    ExtJs 下拉单联动,次级下拉框查询模式
    ExtJs 日期相加,Grid表格列可编辑
    转:Java阳历转农历
    转:Java 计算2个时间相差多少年,多少个月,多少天的几种方式
    钥匙计数之一
    LianLianKan
  • 原文地址:https://www.cnblogs.com/lasnitch/p/12764139.html
Copyright © 2011-2022 走看看