news 2026/4/23 0:50:42

[从零构建操作系统]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/4/23 10:11:01

LLC谐振变换器恒压恒流双竞争闭环Simulink仿真探索

LLC谐振变换器恒压恒流双竞争闭环simulink仿真&#xff08;附说明文档&#xff09; 1.采用电压电流双环竞争控制&#xff08;恒压恒流&#xff09; 2.附双环竞争仿真文件&#xff08;内含仿真介绍&#xff0c;波形分析&#xff0c;增益曲线计算.m代码&#xff09; 仿真参数&…

作者头像 李华
网站建设 2026/4/23 10:11:16

【Java方法】--递归的正确使用方法,告别栈溢出

个人主页 目录前言&#x1f4a1;1.什么是递归&#xff1f;1.1 递归的两个关键要素1.2 递归结构&#xff1a;2.经典的递归2.1 案例一&#xff1a;阶乘计算2.2 案例二&#xff1a;斐波那契数列2.3 目录遍历3.深入理解递归为什么会栈溢出3.1 什么是栈&#xff1f;Java 虚拟机栈结合…

作者头像 李华
网站建设 2026/4/22 20:50:34

视觉色选机:如何挑选技术可靠与服务完善的设备厂家

现今&#xff0c;于粮食加工行业里&#xff0c;视觉色选机成了保障产品品质的关键设备&#xff0c;它能提升附加值&#xff0c;还能实现自动化生产。它借助高分辨率相机捕捉物料图像&#xff0c;运用智能算法实时识别颜色&#xff0c;识别形状&#xff0c;识别内部缺陷&#xf…

作者头像 李华
网站建设 2026/4/17 12:45:01

Labview模拟温度检测报警系统 1、通过设定上下限温度,通过比较温度来到达指示灯的闪烁情况

Labview模拟温度检测报警系统 1、通过设定上下限温度&#xff0c;通过比较温度来到达指示灯的闪烁情况。 若超过了设定的温度上限&#xff0c;指示灯的闪烁会闪烁&#xff1b;若低于设定的温度下限&#xff0c;指示灯同样会闪烁。 2、设定上下限温度、模拟温度、最高温度、最低…

作者头像 李华
网站建设 2026/4/23 11:31:34

Ubuntu下Qt/C++程序终止全攻略

在Ubuntu系统中&#xff0c;结合Qt和C开发的应用程序可通过以下多种方式安全或强制终止&#xff0c;具体可分为系统级、Qt框架、C标准及线程管理四大类&#xff1a;系统级方法终端命令kill/pkill/killall&#xff1a;通过进程ID或名称发送信号&#xff08;如SIGTERM正常终止&am…

作者头像 李华