栈帧%ebp,%esp详解

本文详细解析了函数调用时栈帧的创建、参数传递及返回过程。通过示例程序展示了main函数调用func函数时栈的变化,包括esp和ebp寄存器的作用,以及如何通过它们来定位参数和局部变量。内容涵盖了栈的入栈、出栈操作,以及函数返回时栈帧的清理过程。
摘要由CSDN通过智能技术生成

首先应该明白,栈是从高地址向低地址延伸的。每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着所需要的各种信息。寄存器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的栈帧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值