生化危机4(Resident Evil 4)在任天堂(Nintendo)的 GameCube(GameCube)平台上的 G4BE08 debug build(2004年11月25日原型,含两张光盘)完整字节一致反编译项目,其 Bio4.sym 文件列出每个函数名。构建仓库可精确复现 main.dol 与全部 114 个 REL 重载文件(校验于 config/G4BE08/build.sha1)。仓库不含游戏资源,需自备调试盘镜像构建,原文件在配置时从盘读取。
正文
完整、字节一致的任天堂 GameCube《生化危机4》反编译:G4BE08 调试版("2004 年 11 月 25 日"原型,双碟),其 Bio4.sym 文件为每个函数命名。构建仓库可精确复现 main.dol 和全部 114 个 REL overlay(config/G4BE08/build.sha1,每次构建都会校验)。
| | |
| --- | --- |
| 对象 | 1083 个(DOL 中 675 个,114 个 REL 中共 408 个),全部字节一致;15641 个函数 |
| 源码 | 约 55.5 万行 C/C++(src/),约 3.3 万行头文件(include/);无汇编文件 |
| 游戏代码 | SN Systems ProDG 3.9.3 — GCC 2.95.3 "SN BUILD v1.79",从 SN 的 GPL 源码本地构建 |
| CRI 中间件(src/lib/adx_*、sfd_*、mpv_* 等) | Metrowerks CodeWarrior 2.4.7(GC/2.7),即 CRI 发布这些库时所用的编译器 |
| 任天堂 SDK(src/lib/OS*、GX* 等) | Metrowerks CodeWarrior GC/1.2.5n,源码来自 dolsdk2004 |
仓库不含任何游戏资源,也没有从光盘复制的代码或数据。构建需要自备调试碟镜像(碟 1 提供 main.dol 和大多数 REL,碟 2 提供四个岛屿关卡 REL);原始文件在配置阶段从镜像中读取。
构建
Linux、Python 3、ninja。编译器和工具(decomp-toolkit、objdiff、wibo、CodeWarrior 各版本)由首次 configure 运行时下载,原生 SN GCC 除外。
第一步,构建原生 cc1/cc1plus(只需一次),需要 SN 的 GPL 源码,见 tools/sn-gcc/build.sh:
SNGCCSRC=/path/to/NGCGNUSRC/NGC tools/sn-gcc/build.sh
第二步,放入自己的光盘镜像(碟 1:main.dol + 110 个 REL;碟 2:四个岛屿关卡 REL st30..st33):
cp re4debugdisc1.iso re4debugdisc2.gcm orig/G4BE08/
第三步,构建并校验:
python3 configure.py && ninja
ninja 结束时给出进度报告(DOL 和各个 REL 模块 100% 匹配并链接);build/tools/dtk shasum -c config/G4BE08/build.sha1 会打印 115 行 OK。要研究某个单元,python3 tools/bytecmp.py game/foo 把它编译出的对象与原版逐字比较,python3 tools/fdiff.py game/foo <symbol> 显示单个函数。
目录结构
src/game/— 游戏本体(C++;少量 newlib C 单元)。src/em*/敌人,src/wep*/武器,src/pl*/玩家角色,src/st*/房间(每个房间一个 REL),src/t_*/、src/Tools/、src/tools/是游戏内调试编辑器,src/Sscrn/子画面,src/lib/是 SDK、CRI 和运行时。include/— 头文件,其中包括重建的结构体布局。config/G4BE08/— 单元列表(objects.py、modules.py)、symbols.txt、splits.txt、链接脚本、各模块 REL 数据(modules/<mod>/)、build.sha1。tools/— 构建生成器(project.py)、ProDG 驱动(ngccc.py)、REL 重建(make_rel.py、link_rel.py)、比较工具、sn-gcc/(原生编译器构建)、research/(编译器分析套件)、motion_export.py+motion/(把动画导出为 glTF/BVH,用游戏自身的代码求值,并与 Dolphin 中运行的游戏核对)。docs/overview.md— 引擎如何组织:按子系统阅读src/的指南。docs/matching.md— 匹配是怎么做的:编译器来源、编译器机制目录及复现它们的源码写法、两个编译器的经验规则。docs/unit-notes.md— 逐单元笔记。docs/research/— 逐轮研究日志。
这里的"匹配"指什么
每个单元都用原编译器编译成与原版相同的字节。当编译器需要某种特定源码写法才能复现某个寄存器选择或指令调度,而找不到自然写法时,该构造会用 // COMPILER-DIFF: 注释标记(共 644 处:死测试、空的 asm("") 洗白与锚点、register T x asm("rN") 固定、填充语句)。它们都不发出指令:python3 tools/asmcheck.py --all 会把每个 GCC 单元连同其 asm 模板标记一起编译,列出源自模板的指令——唯一的命中是下面的硬件内核(TOTAL 231;八个汇编单元单独一行报告,不计入该数字)。这棵树早先的状态在游戏代码里有约 100 条手置指令(asm("li %0,0")、asm("lis/addi")、asm("mr")),在 CRI 库里有约 100 个寄存器固定 asm { } 块;2026-09-17 被改写为 C(docs/research/compiler.md 的 "Asm-removal pass" 一节记录了每一处的配方与编译器机制)。每个标记的机制都记录在 docs/matching.md 和 docs/research/ 中。
保留下来的汇编,都是原作者当年也非用汇编不可的代码,因为他们的编译器没有别的表达方式:
- GCC 2.95 游戏代码:paired-single 内核(
math_sub中的SINF/COSF/RSQRT/LIMIT_ANGLE,trans、shape、dbmodule中的矩阵内核,Espgen42/espgen45中量化的psq_l),main/scheduler中的 GQR 设置,以及 libsnsndvd异常处理器。 - MWCC 的 CRI 库:paired-single / cache / SPR 内核(
mpv_umc、mpv_mc、dct_fsri、cftyp422_ppc、mpv_lib),SDK 的mtx/vec/quat/GX内建函数,以及dct_ac中的一个寄存器引导块(dctac_Init:厂商编译器版本会合并.bss但不合并该函数的 8 字节字面量,我们的两者都合并)。27 处仍保留不产生代码的asm { mr r11, x; mr x, r11 }固定(两个 move 都会被分配器删除;它们把着色寄存器集合缩小一个)和asm { mr v, v }自拷贝(一个不透明的第二次定义)。 - 八个以汇编为主体的单元:crt0(
__start)、eabi、SN 的tealeaf/fileserver/ppcdown/proview(src/lib/<name>.c),以及 Capcom 的memset_2和yz2asm(src/game/<name>.cpp)。原版就是汇编(SN 的 libsn/crt0 对象和 Capcom 自己的汇编;字节里没有编译器惯用法),所以每一个都是一个 C 文件,其函数写成整函数顶层asm()主体,采用 GAS 语法(.globl/.type/label/.size、局部.L_标签、.4byte/.float/.skip数据),由与其余部分相同的 ProDG 驱动编译(include/asm_regs.h以.set常量提供r3/f1/GQR0名字;NgcAs 接受裸数字)。tools/asmcheck.py把它们列为asm-bodied。
命名
函数名是 Capcom 的,来自调试版的 Bio4.sym 文件;名字经过 C++ 修饰,这也是游戏代码用 C++、而 SDK、CRI 和 newlib 单元用 C 的原因。文件名和单元边界来自断言留在二进制里的 D:/Bio4/Prog/<file>.cpp 字符串。结构体与字段名分三类:厂商的,来自 PS2 调试版的类型信息(用 tools/ps2sym.py 对应到 GameCube 布局);我们命名的,按用途命名并如实标注;以及占位符 xNN(十六进制偏移,含义不明)。厂商名保留厂商的拼写,所以这棵树有意混用不同约定。#line 指令复现厂商在断言字符串里的行号。docs/naming.md 有完整说明和计数。
贡献
CONTRIBUTING.md:构建、三项校验、规则(字节永不改变、不发出指令的 asm、命名),以及如何带证据提出重命名。
法律
重建的游戏与 SDK 源码属于各自所有者(Capcom、Nintendo、CRI Middleware)的知识产权,仅为研究与保存而发布。为本项目编写的构建脚本、工具和文档以 CC0 发布(LICENSE)。
评论
讨论整体对这份反编译成果抱有热情,但分歧集中在两点:字节级一致到底算不算真正还原了游戏源码,以及给一份受版权保护的作品套 CC0 许可是否成立。AI 是否参与则是贯穿全程的暗线,多数人已把它当作默认前提而非争论焦点。
认为 CC0 用在反编译作品上根本不成立
- 反编译产物是原作的衍生作品,版权随原作继承,原作者不会因为重写了一遍就放弃权利;反编译历来是灰色地带,最终只看版权方是否愿意追究。(较多人)
- 有人补一句,只能寄希望于 Capcom 已经不在乎了。(少数人) > 你继承的是原作的版权,因为这是衍生作品。(@shakna)
认为为了字节一致硬塞编译器伪指令,恰恰说明没还原对
- 项目里有 644 处 COMPILER-DIFF 注释,用空汇编洗白、寄存器钉死、填充语句等手段逼编译器吐出同样的机器码。作者认为反编译的价值从来不是复刻原始字节——原始字节本来就在手里——而是用人类可读的源码重建对游戏的理解;字节一致只是"你做对了"的旁证,需要靠一堆杂质去凑,反而是做错了的信号,也是古德哈特定律在 AI 时代的一次示范。(较多人)
- 反讽的是,这个项目本身依赖泄露的调试版本和其中的符号表,这正说明保存社区搜集、分发这些材料的价值。(少数人)
认为这只是用可编译的 C 语法模拟行为,不是恢复原程序
- 随机打开一个文件,看到的是把一批数组下标逐个赋常量或 ARC 索引,形似机器翻译出来的中间层,而不是当年的编程思路。(较多人) > 这更像是在用能编译的 C 语法模拟行为,而不是恢复游戏原本的编程。(@groundzeros2015)
觉得纠结 AI 参与与否正在变得没有意义
- 有人从 README 的行文推测是 AI 辅助,但认为项目好就是好,用过 AI 的人不必向绝对的怀疑论者解释自己。(较多人)
- 有人指出"字节一致"是 Claude 的口头禅,暗示这套写法有很强的模型味。(少数人)
- 也有人明确表态:尽管复古游戏圈对 AI 敌意不小,这类项目和模拟器依然让人兴奋,模拟器要求对源系统有极深理解,优化水平另属一个量级。(少数人) > 项目好就是好。(@mw888)
对成果既钦佩又心情复杂
- 一位 Quake 爱好者说,这些反编译大多集中在早期 3D 主机游戏上,低分辨率贴图加双线性模糊的组合很难让人真心喜欢,可能只是代际差异。(少数人)
有价值的补充
- 真正的技术分水岭是可重定位性:如果增删字节后程序仍能正确运行,说明还原程度到了另一个层次,否则只是固定布局的复刻。
- 有评论直接问用了多少 token、哪些模型,侧面说明围观者已默认这是模型产出的工程。
- 另一个被提到的下游价值是无障碍:已有盲人开发者在做反编译游戏的可访问改造,这条路或许能让视障玩家玩到这一作。
- 一句调侃被顺手留下:Capcom 把《生化危机 4》移植到一切平台上的执念,让这次反编译成了保存意义上最没用的作品之一。(玩笑)