Synth Daily

Z80 Sans——把反汇编塞进字体里的神操作(2024)

Z80 Sans 是一款将反汇编功能集成在字体文件中的创新实验项目。通过深度挖掘 OpenType 的字形替换与定位技术,它能够将输入的十六进制字符序列实时转化为可读的 Z80 汇编指令。这不仅展示了字体排版技术的潜力,也解决了一系列如指令操作数乱序、小端序转换等复杂的技术挑战。

核心概念:字体即工具

通常情况下,字体只负责显示字符。但 Z80 Sans 突破了这一界限,通过 OpenType 的 GSUB(字形替换表)GPOS(字形定位表),它能对输入的字符流进行逻辑判断。

"你最喜欢的反汇编器是哪个?我的是一个字体。"

当你输入一串小写的十六进制代码时,字体内部的替换规则会自动匹配这些字节,并将其替换为对应的 Z80 汇编助记符

复杂的技术挑战

相比于普通的字体设计,将 CPU 指令集塞进字体面临着极高的逻辑复杂度:

  • 海量的组合: Z80 指令包含 16 位地址和寄存器操作数,单个指令可能存在多达 458,752 种可能的组合,手动定义规则几乎不可能。
  • 操作数乱序: 十六进制字节的编码顺序有时与反汇编后的显示顺序完全相反。
  • 小端序地址: 必须先处理低位字节,再处理高位字节,这要求字体具备“回溯”或“前瞻”的能力。
  • 带符号偏移量: 0x80..0xff 范围内的偏移量需要被渲染为负的补码形式。

解决方案与实现路径

为了处理这些复杂逻辑,作者放弃了手动编写,转而采用 程序化生成 的方案:

  • 递归下降解析器: 用于自动评估编码中的表达式,并生成所有可能的字形。
  • 上下文链式规则: 这是解决大部分问题的关键。通过定义复杂的匹配环境,字体可以根据前后的字符来决定当前的显示内容。
  • 字形压缩与优化: 为了将字形数量控制在 65,536 个 的限制之内,作者将数字编码为特定的字形变体,并使用连字(Ligature)技术减少冗余。

实验性现状与未来

虽然 Z80 Sans 已经实现了基础功能,但仍处于实验阶段:

  • 已知缺陷: 部分指令(如 LD (IX+o),r)在渲染时会产生微小的格式错误。
  • 工具链依赖: 生成该字体需要复杂的 Ruby 和 Python 环境,并对 FontForge 进行补丁处理。
  • 后续方向: 作者提到,未来可能会尝试使用 Harfbuzz WASM 等更先进的技术来处理复杂度更高的指令集。

资源与授权

该项目基于 Droid Sans MonoNoto Sans Mono 构建,遵循开源协议:

  • 代码: 采用 MIT 许可证。
  • 指令数据: 适配自 maziac/z80-instruction-set
  • 字体底图: 遵循 Apache 与 Open Font 许可证。