slf4j 如何返回堆栈_函数调用之堆栈原理(三)

c6da018bb75d8ca5dfd27e846cf98fde.png
原文: https:// manybutfinite.com/post/ journey-to-the-stack/
翻译:RobotCode俱乐部

上篇文章,我们看了函数堆栈是如何工作的,以及在函数“序言”期间栈帧是如何构建的。现在是时候看看逆过程了,栈帧在函数结束时被销毁。继续来看看add函数:

Simple Add Program - add.c
int add(int a, int b)
{
    int result = a + b;
    return result;
}

int main(int argc)
{
    int answer;
    answer = add(40, 2);
}

我们在执行第4行,就在a + b赋值到result之后。事情是这样的:

299385ae42ed403001133c06b8f01f32.png

d7546e60992dfc3b743f4d3d5d3ca368.png

5333f9ec7a81698a55eca2800f1b5ac8.png

2d4a81e16d4039fd5d5a21aaced963d2.png

第一个指令是冗余的,有点傻,因为我们知道eax已经等于result,但这是你优化关闭后的结果。然后leave指令运行,以一件事的代价做两件事:它重置esp以指向当前栈帧的起点,然后恢复保存的ebp值。这两个操作在逻辑上是不同的,因此在图中是分开的(图2,3所示),但是如果你使用调试器进行跟踪,它们就会自动发生。

在leave运行之后,将恢复前一个栈帧。add被调用的唯一痕迹,是堆栈顶部的返回地址。它包含add完成后必须运行的main指令的地址。ret指令负责处理它:它将返回地址弹出到eip寄存器中,该寄存器指向要执行的下一条指令。该程序现已返回main,如下:

33bba9ca8158163dc9fd1c38eebb73ad.png

b72dfe2d652047b650b0054689607043.png

553092ad2349a002b2754edda2276fc2.png

cd3519b896a7d17c48520cd7fac618f0.png

main将add的返回值复制到本地变量answer中,然后运行自己的“尾声”,这与任何其他栈桢被销毁的过程相同。main的唯一特性是保存的ebp为null,因为它是代码中的第一个栈帧。在最后一步中,执行流程转到C库(libc),返回到操作系统。这里有一个图,展示了函数调用的返回序列。

6707861ba8b88e31bda617bc472eaf69.png

现在你已经很好地掌握了堆栈的操作方式,下一篇中介绍堆栈缓冲区溢出。

由于本人水平有限,翻译必然有很多不妥的地方,欢迎指正。
同时,欢迎关注下方微信公众号,一起交流学习:)

f1d322b8c4e110bc98283aae607ece9b.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值