x86仿真器团队曾遇到一段代码糟糕到他们在仿真过程中直接修复
摘要
一个关于Windows x86仿真器团队的故事:他们遇到一个程序,其初始化循环完全展开了64KB(65,536条指令),于是添加了特殊优化,将其替换为一个紧凑循环。
<p><a href="https://lobste.rs/s/mjkp4m/time_x86_emulator_team_found_code_so_bad">评论</a></p>
查看缓存全文
缓存时间: 2026/06/16 11:32
# x86 模拟器团队发现代码质量太差,以至于在模拟过程中直接修复了它 - 《老古董新事》
来源:https://devblogs.microsoft.com/oldnewthing/20260615-00?p=112419
在一次讲故事交流中,我的一位同事讲述了一个过去的趣闻。那时,Windows 还在原生运行其他处理器的系统上,包含了一个模拟 x86-32 的处理器模拟器。(这种事情发生过很多次。至于具体是哪个处理器,恕我不知,这个故事的版本并不明确。)
这个特定的模拟器采用了二进制翻译技术,生成本地代码来执行原始 x86-32 代码的等价操作。相比解释执行,这种方式带来了显著的性能提升。你可以把 x86-32 想象成一种字节码,模拟器就是 JIT 编译器。
总之,我同事发现有一个程序需要在栈上分配大约 64KB 的内存并将其初始化。标准的做法是先进行堆栈探测,确保有 64KB 内存可用(https://devblogs.microsoft.com/oldnewthing/20260311-00/?p=112134),然后从栈指针减去 65536,最后通过一个小而紧凑的循环初始化内存。
然而,编译这段代码的编译器觉得用循环来初始化内存太乏味了。它没有生成循环来逐个字节初始化缓冲区,而是“优化”成了展开的循环——变成了 65536 个独立的“写字节到内存”指令,每条指令长度为 4 字节。
总而言之,这个程序花了 256KB 的代码来初始化 64KB 的数据。
这着实让团队难以容忍,于是他们给翻译器添加了特殊代码:只要检测到这段糟糕的函数,就直接将其替换为等价的紧凑循环。
### 分类
### 主题
## 作者
Raymond Chen
Raymond 参与 Windows 的演变已有 30 多年。2003 年,他创办了名为《老古董新事》的网站,其受欢迎程度远超他最狂野的想象——这一发展至今仍让他感到毛骨悚然。该网站还派生出一本书,恰巧书名也是《老古董新事》(Addison Wesley, 2007)。他偶尔会出现在 Windows 开发者文档的 Twitter 账号上,讲述一些毫无实际用途的故事。
相似文章
模拟器调试:Area 5150 的 Lake Effect
本文详细介绍了在MartyPC模拟器上调试Area5150演示中“Lake”效应的过程,解释了需要特定标题hack的原因,以及通过总线嗅探和动态时钟实现周期精确CGA模拟的后续修复方法。
让 stinkarm 减少臭味还是增加臭味?
关于改进一个最小化 ARMv7 模拟器的更新,重点优化内存翻译,从复杂的 B-tree 映射转向简化的 4 GiB slab 方法以提高效率。
Linux/x86-64上使用内存间接调用(徒劳?)的系统调用检测,第一部分
一篇技术博文,讨论在Linux/x86-64上检测系统调用的技术,包括指令双关、E9Patch、zpoline以及短指令修补的挑战。
80386 早期启动内存访问
本文解释了 Intel 80386 中的早期启动内存访问技术,该技术通过将地址生成与前一条指令的最后一个周期重叠来隐藏内存延迟。文章描述了该技术在 z386 FPGA 核心中的实现,达到了 ao486 级别的性能,并在 Doom FPS 上提升了 39%。
更多模拟器佳品,一个能启动Windows的Intel Itanium (IA-64)模拟器
来自Yufeng Gao和gdwnldsKSC的一款新的Intel Itanium (IA-64)模拟器能够启动Windows Server 2003和Windows XP 64位版,但运行速度非常慢。代码预计将在后续开源。