(转)栈帧

转自:http://blog.youkuaiyun.com/yxysdcl/article/details/5569351

首先应该明白,栈是从高地址向低地址延伸的。每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着所需要的各种信息。寄存器ebp指向当前的栈帧的底部(高地址),寄存器esp指向当前的栈帧的顶部(地址地)。下图为典型的存取器安排,观察栈在其中的位置

 

入栈操作:push eax; 等价于 esp=esp-4,eax->[esp];如下图

出栈操作:pop eax; 等价于 [esp]->eax,esp=esp+4;如下图

我们来看下面这个C程序在执行过程中,栈的变化情况

void func(int m, int n) {

    int a, b;

    a = m;

    b = n;

}

main() {

...

    func(m, n);

L:  下一条语句

...

 

在main调用func函数前,栈的情况,也就是说main的栈帧:

从低地址esp到高地址ebp的这块区域,就是当前main函数的栈帧。当main中调用func时,写成汇编大致是:

push m

push n; 两个参数压入栈

call func; 调用func,将返回地址填入栈,并跳转到func

当跳转到了func,来看看func的汇编大致的样子:

__func:

        push ebp; 这个很重要,因为现在到了一个新的函数,也就是说要有自己的栈帧了,那么,必须把上面的函数main的栈帧底部保存起                        ; 来,栈顶是不用保存的,因为上一个栈帧的顶部讲会是func的栈帧底部。(两栈帧相邻的)

        mov ebp, esp; 上一栈帧的顶部,就是这个栈帧的底部

        ;暂时先看现在的栈的情况

                 ;到这里,新的栈帧开始了

                 sub esp, 8   ;  int a, b 这里声明了两个int,所以esp减小8个字节来为a,b分配空间

                 mov dword ptr [esp+4], [ebp+12];   a=m

                 mov dword ptr [esp], [ebp+8]; b=n         

   这样,栈的情况变为:

                    ret 8     ;  返回,然后8是什么意思呢,就是参数占用的字节数,当返回后,esp-8,释放参数m,n的空间

 

由此可见,通过ebp,能够很容易定位到上面的参数。当从func函数返回时,首先esp移动到栈帧底部(即释放局部变量),然后把上一个函数的栈帧底部指针弹出到ebp,再弹出返回地址到cs:ip上,esp继续移动划过参数,这样,ebp,esp就回到了调用函数前的状态,即现在恢复了原来的main的栈帧。

转载于:https://www.cnblogs.com/buptlyn/p/3978184.html

在 Java 程序运行过程中,每当调用一个方法时,JVM 会在当前线程的(Stack)中创建一个新的记录项来保存该方法的状态信息,这就是所谓的**(Stack Frame)**是实现函数调用的关键结构之一,在程序执行期间承担着重要的职责。下面我们将详细解释的作用及其组成部分。 ### 的功能 每次方法被调用的时候都会生成对应的一个新的,并按照先进后出的原则组织成 LIFO 结构——即最后进入的方法最先返回。每个都包含了执行该段代码所需的所有局部环境数据和控制信息,主要包括以下几个方面: 1. **局部变量表(Local Variables Table)** - 存储了方法内部声明的各种类型的局部变量、形式参数以及一些临时操作数等基本信息。 - 局部变量的位置由字节码指令指明,通常以索引来标识具体的槽位。 2. **操作数(Operand Stack)** - 可视作一个小的工作空间,用于暂存中间计算结果或者传递给下一组命令的操作数值。 - 当遇到诸如算术运算符这样的二元操作时,会先从顶弹出两个元素参与运算然后再把得到的结果压回去备用。 3. **动态链接(Dynamic Linking Information)** - 包含返回地址 Return Address (指向调用者所在位置),以便于 JVM 能够准确无误地找到应当跳回哪里继续往下走; - 同时也维护了一个对上层父级引用 Parent Frame Reference 的追踪链路方便后续访问外部作用域内的成员属性或其它上下文内容。 4. **常量池引用(Constant Pool References)** - 如果涉及到静态字段加载或是字符串拼接之类的动作那么就需要借助于此处存放的相关符号引用进行解析映射至实际物理内存地址上去获取对应的值。 5. **异常处理器表(Exception Handler Table)** - 描述了本层次内发生的错误情况该如何捕获并处理的信息列表,规定了一旦抛出了特定种类未被捕获异常则立即向指定标签处开始一段特殊流程。 6. **正常退出状态与非正常退出状态** - 正常情况下,当方法体被执行完毕之后便可以直接销毁对应的恢复之前的状态; - 若中途遇到了意外状况如 throw 出 Exception 对象,则依据预先设定好的规则寻找匹配项实施相应措施直至恢复正常运作为止。 综上所述,可以说每一个活跃中的方法都有且仅有一个与其关联独一无二的相伴相随,它们共同构成了我们熟知的过程抽象机制的核心部分,保证了各层级之间清晰独立又彼此协调工作的可能性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值