news 2026/6/23 19:51:11

[从零构建操作系统]08 函数调用时栈的底层行为解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
[从零构建操作系统]08 函数调用时栈的底层行为解析


第一步:在kernel_init里安家(黄色区域)

代码位置: 右上角 kernel_init 函数开头

栈图对应: 左侧黄色的 “局部变量和数据”

  1. sub $0x10, %esp

    • 动作:也就是把栈顶指针esp往下拉 16 个字节,给kernel_init这个函数划出一块地盘(栈帧)。

  2. movl $0x1, -0x4(%ebp)

    • 动作:把数值1放入ebp往下 4 字节的地方。

    • 对应:这就是代码里的int a = 1。图中黄色区域的a=1就存在这。

  3. movl $0x2, -0x8(%ebp)

    • 动作:把数值2放入ebp往下 8 字节的地方。

    • 对应:这就是代码里的int b = 2。图中黄色区域的b=2就存在这。


第二步:准备调用test,打包行李(橙色区域)

代码位置: 右上角 call 指令上面的两行 push

栈图对应: 左侧橙色的 “参数传递”

这里有一个关键知识点:C语言函数参数入栈顺序是从右往左。

我们要调用的是 test(a, b),所以先压 b,再压 a。

  1. push -0x8(%ebp)(对应代码push b)

    • 动作:把变量b(也就是2)压入栈中。

    • 对应:图中橙色区域上方的“参数:b”

  2. push -0x4(%ebp)(对应代码push a)

    • 动作:把变量a(也就是1)压入栈中。

    • 对应:图中橙色区域下方的“参数:a”

注意:此时栈顶(esp)已经指到了“参数 a”的位置。


第三步:跳过去执行(蓝色区域)

代码位置: 右上角 10033: call 1000c <test>

栈图对应: 左侧蓝色的 “返回地址”

  1. call ...

    • 动作:CPU要去别的地方执行代码了,但它得记得回来之后该从哪接着干。所以 CPU 会自动把“下一条指令的地址”(也就是add $0x8, %esp这一行的地址)压入栈。

    • 对应:图中蓝色的“返回地址”。此时esp指向这里(图中标注的esp1)。


第四步:进入test函数,建立新家(绿色区域)

代码位置: 右下角 test 函数的开头

栈图对应: 左侧绿色的 “之前ebp”

  1. push %ebp(test函数的第一行代码)

    • 动作:test函数说:“我也要用ebp来定位我的地盘,但我不能把kernel_initebp弄丢了。” 所以先把kernel_initebp值压入栈保存起来。

    • 对应:图中绿色的“之前的ebp”

  2. mov %esp, %ebp

    • 动作:把当前的栈顶位置赋值给ebp

    • 对应:此时ebpesp都指向了绿色格子的最下沿(图中标注的ebp / esp2)。


终极解密:为什么要这么折腾?

请看右下角test函数如何取参数:

现在的ebp指向绿色的“之前ebp”。

  • 往上(高地址)走 4 个字节,是蓝色的“返回地址”。

  • 再往上走 4 个字节(+8),就是橙色的“参数 a”

  • 再往上走 4 个字节(+120xc),就是橙色的“参数 b”

对照右下角代码:

  • mov 0x8(%ebp), %edx-> 取出了a

  • mov 0xc(%ebp), %eax-> 取出了b

总结

这张图画的就是:

  1. 黄色:调用者自己存的私房钱(局部变量)。

  2. 橙色:调用者打包给被调用者的礼物(参数)。

  3. 蓝色:回家的路标(返回地址)。

  4. 绿色:被调用者用来定位的基准桩(旧 ebp)。

被调用者(test)站在绿色的位置,往回伸手(ebp + 偏移),就能拿到别人传给它的参数。

补充:x86编译器对各字段的分类

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/23 19:48:13

力扣hot100:搜索插入位置

题目描述&#xff1a;题目分析&#xff1a;本题是一个二分查找&#xff0c;核心思路是通过计算中心点和目标值的大小关系&#xff0c;以此在一个while循环里不断更新左右端点&#xff0c;知道左端点大于右端点。代码&#xff1a;class Solution {public int searchInsert(int[]…

作者头像 李华
网站建设 2026/6/23 19:43:57

Java冷启动全指南:从原理到实战优化

一、Java冷启动问题概述 Java冷启动是指应用从启动到达到最佳性能状态的过程&#xff0c;包括JVM初始化、类加载、解释执行、JIT编译等多个阶段。在传统单机部署场景中&#xff0c;冷启动问题并不明显&#xff0c;但在云原生、Serverless架构下&#xff0c;冷启动时间直接影响…

作者头像 李华
网站建设 2026/6/22 17:23:17

测试 - 单元测试(JUnit)

JUnit 官网 Mockito 官网 一、概念 1.1 注解 Test标记一个函数为测试方法。BeforeEach、AfterEach在每个测试方法 前/后 执行&#xff0c;用于 准备/清理 运行环境。BeforeAll、AfterAll在所有测试 前/后 执行&#xff08;必须是静态方法&#xff09;&#xff0c;用于 执行…

作者头像 李华
网站建设 2026/6/23 12:59:42

C++中多态

文章目录前言一、多态的概念二、多态的定义以及实现三、抽象类四、多态的原理1. 虚函数表2. 多态的原理3. 动态绑定与静态绑定前言 本文中的代码都是在X64环境下编译运行的&#xff0c;涉及的指针都是8bytes&#xff0c;切换其他平台需要考虑指针问题。 一、多态的概念 多态是…

作者头像 李华
网站建设 2026/6/23 18:23:45

c++经典练习题-多分支

目录 1304. 冷饮的价格&#xff08;2&#xff09; 1044. 找出最经济型的包装箱型号 1039. 求三个数的最大数 1035. 判断成绩等级 1300. 小明暑假的零花钱 1322. 求数的量级&#xff1f; 1049. 汉译英 1391. 公交卡充值问题&#xff1f; 1668. 运动会成绩统计 1669. 上…

作者头像 李华
网站建设 2026/6/22 18:40:19

qt为什么转向用cmake放弃qmake

Qt 从 qmake 转向 CMake 是其构建系统战略的重大转型&#xff0c;这一转变在 Qt6 中全面落地。下面从 技术、生态、工程实践 三个维度&#xff0c;系统解释&#xff1a; 一、Qt 使用 CMake 的核心好处 1. 强大的跨平台与多编译器支持 CMake 原生支持&#xff1a; Windows&…

作者头像 李华