80386 微码反汇编

Hacker News Top 新闻

摘要

一篇博客文章,详细介绍了成功反汇编和分析 Intel 80386 微码的过程,揭示了215条指令入口点以及其复杂的内部架构。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/05/23 12:30

# 80386 微码反汇编 « Reenigne 博客 来源:https://www.reenigne.org/blog/80386-microcode-disassembled/ 在我发布了《8086 微码反汇编》(https://www.reenigne.org/blog/8086-microcode-disassembled/)之后,Ken Shirriff(https://www.righto.com/)给我发了一张 80386 微码 ROM 的高分辨率图片。我原本没指望能对它做什么,原因有二:一是它比 8086 的微码 ROM(10752 比特)大得多(94720 比特),所以(即使借助 bitract 或类似工具)手动转码和校验也会极其繁琐。二是完全不知从何入手——至少对于 8086,有相关专利提供了大致框架和一些可搜索的代码片段。而 80386 则是一个完全的黑盒。我知道它的功能,也大致了解它的工作原理,但要将其转化为可在二进制大块中搜索的模式,似乎是一个难以逾越的挑战。 几年后,我在 Discord 上与 GloriousCow 和 Smartest Blob(可能还有其他一些人)聊天时,他们提到如果能获得 80386 芯片的高分辨率图像并尝试提取其中的微码,会很有意思。我表示第一部分已经完成了,但将图像转为二进制大块,再从中解读出可理解的微码似乎太难了。好吧,他们可能把这当成了挑战——他们运用了各种图像处理、人工智能和人工辅助自动化手段,几天后便从图像中提取出了二进制大块并进行了交叉校验。 不过,反汇编它依然挑战巨大!我们发现了各种模式,逐渐搞清楚了如何将其重新排列成以 μ 操作(μ-op)为一轴、以 μ 操作位为另一轴的矩阵,然后是读取 μ 操作的顺序(一端未使用的 μ 操作区块帮了大忙),以及如何将 μ 操作位划分成字段。基于对 8086 微码的研究,我推测其中两个字段会是源寄存器和目的寄存器。我还知道 80386 可以在两个周期内完成一个 ALU 操作,这意味着必须有一个字段来指定 ALU 的第二个输入,以便这些操作的微码能在第一个周期将两个操作数加载到 ALU,然后在第二个周期将结果输出到目的地。此外,还有一个规律性出现的模式,我们怀疑它可能表示指令的结束(事实证明我们是对的)。 Ken 也提供了帮助,他在 80386 芯片上追踪了各种线路和逻辑位,使我们能够了解各部分是如何连接的。逐渐地,整个图景变得更加清晰。每当我们弄清楚一个问题,就会为理解使用相同结构的其他微码块的含义提供线索。与此同时,我们还在解码指令解码器(由多个较小的 PLA 组成)和保护测试 PLA。最终,我们达到了能够将 386 指令与微码块关联起来的程度,事情变得豁然开朗。 就大多数指令而言,80386 每个周期的执行速度比 8086 快得多,这是通过投入更多晶体管实现的——在 8086 中由微码实现的许多算法,在 80386 中基本上是“硬件加速”的,因此我很早就意识到,80386 微码更多的部分将是设置这些加速器,而不是直接体现算法。弄清楚加速器(如乘除硬件、桶形移位器和保护测试单元)与微码之间的接口,占据了工作的一大部分。 **根据微码,80386 有多少条不同的指令?它们分别是什么?** 微码有 215 个来自解码 ROM 的入口点——相较于 8086 的 60 个,这是一个相当大的增长!部分原因是新增了指令,另一部分原因是指令会根据操作数是寄存器还是内存、CPU 处于实模式还是保护模式、是否带有 REP 前缀等不同情况,由不同的例程处理。我不会在此全部列出,但如果你感兴趣,可以在 fields.txt 文件中找到它们(以及所有子例程和共享代码)。列出顶层微码例程的大小意义不大,因为许多例程只做少量工作,然后跳转到与其他入口点共享的例程。同样,列出每个入口点处理的操作码数量也没有意义,因为指令解码器不仅仅根据操作码来决定使用哪个例程。 **是否有任何指令不由微码处理?** 出人意料的是,没有!与 8086(以及现代 CPU)不同,80386 始终在执行 μ 操作,每条指令都有对应的微码。 **微码中是否包含任何不起作用的“垃圾代码”?** 从 0x849 到 0x856(含)的例程(在微码反汇编中标记为“未使用?”)似乎没有任何与之关联的入口点。我不完全确定它的功能,但它与 #PF(PAGE_FAULT)例程(0x8e9-0x8f5)有很多共同点——两者最终都执行中断 0x0e,错误码设置为来自分页单元的上次错误码。但这个例程将 CR2 设置为来自分页单元的某个神秘值,而不是故障线性地址。所有其他微码似乎都是为了实现 CPU 的文档化行为(或者在处理与 ICE(在线仿真器)硬件交互的例程情况下,实现未文档化行为)。 **微码是否包含任何尚未被记录的隐藏功能、操作码或彩蛋?** 我不完全确定,因为我手头没有真实的 386 机器来进行测试,但我可能发现了一个 I/O 权限位图处理中的缺陷,该位图被一些保护模式操作系统用来授予用户模式进程有限的 I/O 端口访问权限(按照现代标准,这种做法可能被视为极不安全)。当发生 4 字节端口访问时,微码似乎只检查前 3 个地址的权限位。因此,如果这样的访问发生在进程拥有权限的 I/O 端口空间边界处,访问的最后一个字节可能会错误地成功,从而可能访问到操作系统预期不应让用户可访问的某个硬件寄存器。这是一个相当隐蔽的 bug,因此没有微码反汇编的话,它被忽略并不太令人惊讶。然而,在这种无处不在的硬件中存在安全漏洞,且 40 多年来未被发现,实属罕见!有可能它只出现在某些版本的 CPU 中,或者是我误解了该例程的工作方式,实际上它其实是正确的。不过,这份微码似乎并非来自早期版本的 80386——解码器中没有任何 XBTS/IBTS 指令的痕迹。 **如何学习理解微码反汇编?** **在哪里可以下载反汇编结果?** 你可以在 GitHub 上的 x86 微码仓库(https://github.com/reenigne/x86_microcode/tree/main/80386)中找到它。先从 parts.txt 文件开始,该文件说明了所有其他文件的作用;或者直接进入 microcode_10.txt 查看反汇编。 **致谢** 感谢 Daniel Balsom (gloriouscow)(https://martypc.blogspot.com/)、Smartest Blob、nand2mario(https://nand2mario.github.io/)和 Ken Shirriff(https://www.righto.com/)。 本文发布于 2026 年 5 月 23 日星期六上午 11:06,归类于计算机(https://www.reenigne.org/blog/category/computer/)、硬件(https://www.reenigne.org/blog/category/hardware/)。你可以通过 RSS 2.0 订阅(https://www.reenigne.org/blog/80386-microcode-disassembled/feed/)来关注本文的任何回应。你也可以在此处留言(https://www.reenigne.org/blog/80386-microcode-disassembled/#respond),或从你的网站进行回溯引用(https://www.reenigne.org/blog/80386-microcode-disassembled/trackback/)。

相似文章

Intel 8087浮点芯片的指令解码

Ken Shirriff

对Intel 8087浮点协处理器指令解码的详细逆向工程分析,解释主CPU与协处理器之间的交互、微码ROM的使用以及总线接口单元。

z386:基于原始微码构建的开源80386

Hacker News Top

本文详述了z386,一款基于原始Intel微码构建的开源FPGA 80386 CPU。它能引导DOS 6/7、运行保护模式程序,并玩经典游戏如Doom,既是一种教育性重构,也是一个可用的FPGA CPU。