首先,我们先来了解下栈帧和栈的基本知识:
    • 栈帧也常被称为“活动记录”(activation record),是编译器用来实现过程/函数调用的一种数据结构。
    • 从逻辑上讲,栈帧就是一个函数执行的环境,包含所有与函数调用相关的数据:主要包括函数参数、函数中的局部变量、函数执行完后的返回地址,被函数修改的需要恢复的任何寄存器的副本。
  另外,需要注意的是:栈是从高地址向低地址延伸的。每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着所需要的各种信息。寄存器ebp用来指向当前的栈帧的底部(高地址),寄存器esp用来指向当前的栈帧的顶部(低地址),即在函数调用执行过程中,寻找所需参数或变量信息时使用寄存器ebp来寻址,因为寄存器esp的值是经常变化的,而寄存器ebp的值对一个函数的栈帧来讲是不变的。
  栈是一种LIFO形式的数据结构,所有的数据都是后进先出。这种形式的数据结构正好满足我们调用函数的方式: 父函数调用子函数,父函数在前,子函数在后;返回时,子函数先返回,父函数后返回栈支持两种基本操作,push和pop。push将数据压入栈中,pop将栈中的数据弹出并存储到指定寄存器或者内存中。
  pop操作后,栈中的数据并没有被清空,只是该数据我们无法直接访问。栈的形式不一定必须时向下生长的,也可以向上生长,只是我们的系统调用栈(call stack)用到的是向下生长形式而已。
  有了上面的基础知识,让我们以一个实际的例子来讲解一下。
int Add(int a, int b)
{
int c;
c=a+b;
return c;
}
Main()
{
Add(10, 5);
printf("hello world!");
}

程序从main()函数开始执行,首先将main()函数压入系统调用栈(call stack)(下面如无特殊说明,用代指系统调用栈(call stack)),并给它分配一个栈帧用以保存所需信息。然后执行main函数中第一条语句,这是一条函数调用语句,在实际调用执行Add函数前需要做一些准备工作。

  首先将5和10两个参数压入栈,同时更新ESP指针的值,如下图所示:

 
  注意,参数5和10压入栈的顺序,应该是从右向左依次压入系统调用栈(call stack)。
  接下来我们需要搞清楚的是:当Add函数调用执行完毕之后,我们需通过某种方式返回到main函数中继续执行下面的指令,在本例中也就是执行print函数。解决这个问题的方式就是将下一条指令的地址压入栈中。
  以上准备工作就绪,下面开始调用执行Add函数。
  首先,我们需要将main函数用来寻址参数或变量信息的EBP寄存器值压入栈中保存,以便于从Add函数返回之后,从栈中取出EBP的值赋给EBP寄存器让main函数用来寻址参数或变量信息,同时更新ESP的值。为了Add函数能够寻址到所需信息,将此时的ESP寄存器的值赋值给EBP寄存器(图中的EBP-new)。此时将接着执行int c语句,为变量c开辟一段内存空间压入栈中,同时更新ESP的值。接下来执行c=a+b,然后返回c,但main函数中并没有声明变量来存储该返回值,故该返回值丢失。函数返回时将ESP更新为EBP-new,接着将EBP-old弹出赋值给EBP寄存器,让main函数拿来寻址所需信息,此时就从Add函数的栈帧恢复到了main函数的栈帧。接着弹出RET(Add函数的返回地址),对应的汇编代码中会有一条ret指令,该指令会将RET返回地址保存到EIP寄存器中,然后处理器根据这个地址无条件跳转到main函数的相应位置去取下一条指令即print函数继续执行。print函数调用执行过程中压栈出栈过程与Add函数类似,不再细说。
 

stack和stack frame的更多相关文章

  1. 栈帧示意图:stack pointer、frame pointer

    更多参考:http://www.embeddedrelated.com/usenet/embedded/show/31646-1.php 一: The calling convention descr ...

  2. Struts2(六.用标签显示用户列表及Value Stack和Stack Context)

    一.用Struts2标签显示用户列表 原理: 在struts中可以通过在action中将所有用户的信息存入到某个范围中,然后转向userlist.jsp,进行访问 原则: 在jsp网页上,尽量不要出现 ...

  3. java:stack栈: Stack 类表示后进先出(LIFO)的对象堆栈

    //Stack 类表示后进先出(LIFO)的对象堆栈 //它提供了通常的 push 和 pop 操作,以及取栈顶点的 peek 方法.测试堆栈是否为空的 empty 方法.在堆栈中查找项并确定到栈顶距 ...

  4. 155. Min Stack (stack)

    Design a stack that supports push, pop, top, and retrieving the minimum element in constant time. pu ...

  5. 自己理解BFC 和 stack context , stack order

    1. stack order 发生在BFC计算好了之后. 2.一个一个的BFC里面,不同的block 里面的stack context 会根据 stack order的顺序,进行堆叠.呈现互相遮盖的效 ...

  6. Java-JVM 栈帧(Stack Frame)

    一.概述 栈帧位置 JVM 执行 Java 程序时需要装载各种数据到内存中,不同的数据存放在不同的内存区中(逻辑上),这些数据内存区称作运行时数据区(Run-Time Data Areas). 其中 ...

  7. (android 源码下开发应用程序) 如何在 Android 各 level ( 包含 user space 與 kernel space ) 使用dump call stack的方法

    http://janbarry0914.blogspot.com/2014/07/androiddump-call-stack.html dump call stack [文章重點] 了解 Andro ...

  8. 聊一聊goroutine stack

    通过阅读这篇文章对内存的处理以及栈的扩容有了新的认识,我们在生产环境中也遇到了内存使用量超大的情况,现在怀疑也可能是由于栈扩容导致的 很好的一片文章: 推送在外卖订餐中扮演着重要的角色,为商家实时接单 ...

  9. pthread中如何追踪stack over flow

    通常在程序挂掉的时候我们会catch 他们挂掉的signal,然后在signal中打印出当时的一个stack,来方便问题调查, 但是在stack overflow的情况发生时,会没有拿到stack.s ...

随机推荐

  1. Backing up the tail

    The tail of the transaction log usually refers to the contents of the database's transaction log tha ...

  2. Xshell连接虚拟机突然被拒,提示再次输入密码。。。

    sudo vim /etc/ssh/sshd_config 将 # Authentication: LoginGraceTime 120 PermitRootLogin prohibit-passwo ...

  3. leetcode111

    /** * Definition for a binary tree node. * public class TreeNode { * public int val; * public TreeNo ...

  4. IOS上架截屏 屏幕快照

    IOS上架截屏,屏幕快照,4种屏幕尺寸,每种尺寸5张软件功能截图. 大小等于对应设备的屏幕的像素大小.使用模拟器,command +s截图就可以了虚拟机里的手机截屏就保存在mac 桌面上了.jpg,p ...

  5. Tomcat 实战-调优方案

    来自:  http://blog.csdn.net/u010028869/article/details/51793821 来自:  https://www.cnblogs.com/baihuites ...

  6. JAVA 非对称加密工具

    import java.io.File; import java.io.FileInputStream; import java.math.BigInteger; import java.securi ...

  7. 如何让自己的exe程序开机自启动

    方法一. ①鼠标右键自己的exe程序,创建快捷方式 ②win+R,打开运行对话框,输入shell:startup,如下图: 将exe文件的的快捷方式拷贝到这个目录下,然后下次重启的时候自己的应用程序就 ...

  8. The Process of Google Hiring

    [The Process of Google Hiring] 1.keynote 1: The Google hiring process is designed to hire the most t ...

  9. 05-SSH综合案例:环境搭建之配置文件的引入

    1.3 第三步导入相应配置文件 Struts框架中: * web.xml * 核心过滤器: <filter> <filter-name>struts2</filter-n ...

  10. redis的连接方法|连接池|操作

    1.先看下redis的连接 import redis # 连接服务端 r = redis.Redis(host="127.0.0.1",port=6379) #获取所有的key值 ...