详解:16字节x86代码,让矩阵雨变成声音

Hacker News Top 工具

摘要

一篇详细的解析,关于一个16字节的x86实模式DOS演示程序,它在视频内存中生成无限的谢尔宾斯基分形,同时产生音频输出,展现了demoscene传统中极致的算法密度。

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

缓存时间: 2026/05/18 03:52

# 醒来!16b 来源:https://hellmood.111mb.de/wake_up_16b_writeup.html 于 2026 年 5 月在荷兰奥门的 Outline Demoparty 发布 探索 16 字节 x86 汇编中的算法密度。 在演示场景中,探索极端限制下能实现什么是极具回报的技术挑战。以下 **16 字节** x86 实模式 DOS 汇编代码代表了算法密度方面的一次精心尝试。执行时,它利用计算机的视频内存作为计算空间,绘制无限分形谢尔宾斯基三角形,同时将该几何结构解释为音频数据。 `` int 10h ; 2 字节 mov bh, 0xb8 ; 2 字节 mov ds, bx ; 2 字节 L: lodsb ; 1 字节 sub si, byte 57 ; 3 字节 xor [si], al ; 2 字节 out 61h, al ; 2 字节 jmp short L ; 2 字节 `` ## 1. 画布:一个准备好的虚空 代码以标准 BIOS 中断 `int 10h` 开始。这将初始化视频模式 0,建立 40x25 文本模式网格。随后的指令将数据段(`DS`)指向 `0xB800`,即 VGA/CGA 文本缓冲区的物理内存地址。 当 BIOS 在此中断期间清屏时,它不会用绝对零填充内存。在文本模式下,每个字符空间由两个字节组成:ASCII 字符和颜色属性。BIOS 统一初始化所有 2000 个字符槽位:ASCII 字节设置为 **`0x20`**(空格字符),颜色字节设置为 **`0x07`**(黑底浅灰文本)。虽然屏幕看起来完全是空的,但实际上它是一块已用统一数据模式准备好的画布。 **统一性的重要性:** 我们将要探索的数学进程依赖于一个可预测的环境。如果内存包含随机的伪影数据,算法计算将会处理这些差异。在元胞自动机中,一个意外的位可能会破坏模式。一个相当统一的内存空间为分形清晰出现提供了基础。 ## 2. 引擎:加法前缀和 为了理解分形的纯数学,让我们暂时隔离变量。我们将模拟一个完全归零的状态,而不是基础的 `0x20` 初始化。此外,我们将用 `add` 替换 `xor`,并以 **16 字节** 步长遍历此内存,假设累加器 `AL` 加载了值 **2**。 一个实模式 DOS 段恰好跨越 65,536 字节。每次迭代前进 16 字节,需要恰好 **4,096 步** 遍历整个段(\( 65536 / 16 = 4096 \))。当 `SI` 寄存器超过 `0xFFFF` 时,它会干净地回绕到 `0x0000`。 随着循环进行,它将累加器的当前值加到内存单元,然后将更新后的值读回累加器。这实际上创建了一个运行中的前缀和。因为 4096 是 256(我们 8 位寄存器的容量)的倍数,数学进位在段回绕时对齐,每次完整扫描结束时干净地将 `AL` 重置为 2。 段上第 \( p \) 次扫描中第 \( k \) 个被修改单元的值遵循二项式系数序列,按我们初始值 2 缩放: $$A^{(p)}[k] \equiv 2 \binom{k+p}{p-1} \pmod{256}$$ 下表展示了跨 16 个内存单元的前 16 步计算,说明值如何逐行累积: ## 3. 结晶:XOR 与谢尔宾斯基移位 这些十进制值中存在更深的模式。执行二进制加法时,位平面会进位到相邻位置。然而,如果我们丢弃算术进位,严格按模 2 执行加法,得到的就是 **异或(XOR)** 运算。 通过使用 `xor` 而不是 `add`,算法隔离了位平面。因为我们的模拟起始值为 2(二进制 `00000010`),**只有位 1** 受到此特定计算的影响。级联的十进制数变成 `0x00` 和 `0x02` 之间的纯切换。这种演进完美映射到 Stephen Wolfram 基本元胞自动机的**规则 60**: $$Cell^{(p)}[k] = Cell^{(p-1)}[k] \oplus Cell^{(p)}[k-1]$$ 根据卢卡斯定理,这种 XOR 关系在数学上保证与加法表中位 1 的状态匹配。我们可以通过可视化二进制传播(其中 '2' 表示位 1 被设置)来验证: ## 4. 机器的声音:将数据转换为音频 指令 `out 61h, al` 包含一个非常优雅的细节。 端口 `61h` 与内部 PC 扬声器接口。该端口的**位 1** 直接控制扬声器音盆,设置为 1 时推出,设置为 0 时收回。我们的例程通过 XOR 计算分形,更新内存,并立即将该字节发送到扬声器端口。 由于算法专门隔离和切换位 1,**谢尔宾斯基三角形的几何结构直接充当扬声器音盆的指令集。** CPU 的执行速度决定了功能的采样率。 分形产生的 1 和 0 模式产生独特的方波,在脉冲宽度和频率上自然变化。以下图表将上表中的状态可视化为音频波形: 当分形产生交替行(例如,第 2 次扫描)时,它输出更高频率的方波。当结构引入较大的零块(三角形内的空白区域,例如第 4 次扫描)时,扬声器音盆保持静止,导致有节奏的停顿。生成的音频是数学结构的直接声音表示。 ## 5. 56 字节步长:八度移位与对角线剪切 回到实际代码,我们注意到它并不是按 16 步进。指令 `sub si, byte 57` 与 `lodsb` 的递增相结合,导致每次迭代净移动 **\-56 字节**。例程反向遍历内存。 这种调整既改变了听觉频率,也改变了输出的视觉布局。 ### 音频:7 次回绕扫描与频率减半 虽然 16 字节步长恰好需要 4,096 次迭代完成一次段扫描,但 56 不能整除 65,536(\( \gcd(56, 65536) = 8 \))。循环只访问 8 的倍数的偏移量,需要 **8,192 次迭代** 才能命中所有可用地址,并在返回 `0x0000` 之前绕段回绕 7 次。 由于 8192 可被 256 整除,谢尔宾斯基序列的数学连续性得以保持。然而,因为宏周期现在是 8192 步而非 4096 步,完成一次扫描需要两倍的 CPU 周期。这使系统的基本频率减半,将听觉节奏降低**一个八度**,产生更慢、更深的音调。 正是在这里,例程的双重目的性真正闪耀。算法直接写入 ASCII 字符字节,其中位 1 专门负责切换扬声器音盆。同时,其余七个位变异成伪随机 ASCII 字符的级联,提供了作品混乱的视觉纹理。值得注意的是,将这个包含混合数据的完整字节直接发送到系统端口 `61h`(历史上管理各种低级主板控制)不会破坏系统。在标准 DOS 环境和现代模拟器中,将这些额外位推到端口实际上是无害的。这种优雅的巧合允许视觉字符数据安全地兼作音频信号,而不会导致硬件崩溃。 ### 视觉:对角线结构 我们还可以观察 \-56 字节步长如何映射到 40 字符(80 字节)的屏幕宽度: - 向后步进 56 字节在空间上等价于在 80 字节网格上前进 24 字节(\( -56 \equiv 24 \pmod{80} \))。 - 鉴于每个字符空间占用 2 字节,24 字节移位正好等于 **12 列**。 每步序列向上移动 1 行并向右移动 12 列。要确定访问的不同列数,我们计算最大公约数:\( \gcd(12, 40) = 4 \)。 算术确保循环正好访问四分之一的列(\( 40 / 4 = 10 \))。因此,分形不是作为连续图像渲染;相反,空间偏移将其对角剪切为 10 个均匀间隔的垂直列,向上攀登屏幕。 ## 6. 关于内存依赖性的最终观察 如果我们想象这个例程在经典的单色绿色显示器上运行,我们会观察到十个不同的闪烁上升字符柱,伴随着反映模式几何密度的电子音调。 然而,有必要承认一个关于硬件初始状态的实际现实。理论模型假设一个完美初始化、可预测的环境。实际上,在 BIOS 中断 `10h` 之后,不同的系统配置、不同的 VGA BIOS 实现以及现代模拟器(如 DOSBox 或 PCem)可能会在 RAM 的上层区域留下略微不同的伪影或默认值。因为我们的算法不断读取内存中已有的内容并进行 XOR,它将直接与这些现有位交互。 因此,效果对其环境高度敏感。显示的视觉字符和声音的音色可能会根据执行代码的特定机器或模拟器而发生显著变化。 为了保证每个硬件配置上完全相同的统一输出,只需添加一个简短的设置例程来显式清除或预设整个内存段。虽然这将确保理论上的完美,但它自然需要比严格的 16 字节限制稍大的空间。最终,这些内存环境中的任何一个都可以在具有稍多代码空间的任何其他系统上重现,但接受机器自然状态的微妙不可预测性正是在如此严格限制下工作的魅力所在。感谢您的阅读。

相似文章

矩阵转置的实现要点

Hacker News Top

一篇深入的技术博客文章,解释如何使用现代x86_64 CPU上的SIMD指令高效地转置矩阵,重点介绍类似_mm256_shuffle_epi8的AVX2内联函数。

80386 微码反汇编

Hacker News Top

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

用 x86_64 汇编写成的 Linux 桌面

Lobsters Hottest

一位开发者借助 Claude Code,用纯 x86_64 汇编重建了完整的 Linux 桌面栈——从 shell、终端、窗口管理器到各种工具,实现微秒级启动,并延长数小时续航。

Soul Player C64 – 在 1 MHz Commodore 64 上运行的真正 Transformer

Hacker News Top

# gizmo64k/soulplayer-c64 来源:[https://github.com/gizmo64k/soulplayer-c64](https://github.com/gizmo64k/soulplayer-c64) # Soul Player C64 **一款在 1 MHz Commodore 64 上运行的真实 Transformer。** ``` .-------. | O O | | V | |..|---|..| # SOUL PLAYER C64 2.5万个参数。 2 层网络。 真实的 Transformer。 从软盘加载运行。 你> 嗨 C64> 你好!这声音不错。真神奇! ``` 一个 2 层仅解码器(Decoder-Only)Transformer —— 与 ChatGPT、Claude 和 Gemini 背后的架构相同 —— 采用手写 6502/