プログラミング
Resident Evil 4 (GameCube) – C/C++への完全なバイト同一デコンパイル
Resident Evil 4 (GameCube) – complete byte-identical decompilation to C/C++ (github.com)
要約
このプロジェクトは、ニンテンドーゲームキューブ版「バイオハザード4」のデバッグビルド(G4BE08)を、バイト単位で完全に一致するC/C++ソースコードにデコンパイルすることに成功しました。ビルドプロセスは、元のバイナリと完全に一致する実行ファイルを生成し、ゲームの構造とコンパイラの挙動に関する詳細なドキュメントも含まれています。
全文翻訳
Resident Evil 4 (GameCube) — デコンパイル
ニンテンドーゲームキューブ版「バイオハザード4」の完全なバイト同一デコンパイルです。G4BE08デバッグビルド(「2004年11月25日」プロトタイプ、両ディスク)で、Bio4.symファイルが全ての関数に名前を付けています。リポジトリをビルドすると、main.dolと114個全てのRELオーバーレイが完全に再現されます(config/G4BE08/build.sha1、ビルドごとにチェック)。オブジェクト1083個(DOLに675個、114個のRELに408個)、全てバイト同一です。関数数 約555,000行のC/C++(src/)、約33,000行のヘッダー(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がライブラリと共に配布したコンパイラ
Nintendo SDK(src/lib/OS*, GX*, …)
Metrowerks CodeWarrior GC/1.2.5n、dolsdk2004からのソース
リポジトリにはゲームアセットやディスクからコピーされたコードやデータは一切含まれていません。ビルドするには、独自のデバッグディスクイメージが必要です(ディスク1はmain.dolとほとんどのREL、ディスク2は4つのアイランドステージREL用)。元のファイルは設定時にそこから読み込まれます。
ビルドにはLinux、Python 3、ninjaが必要です。コンパイラとツール(decomp-toolkit, objdiff, wibo, CodeWarriorビルド)は、ネイティブSN GCCを除き、最初の設定実行時にダウンロードされます。
# 1. ネイティブcc1/cc1plus(一度だけ):SNのGPLソースドロップが必要です。tools/sn-gcc/build.shを参照してください。
SN_GCC_SRC=/path/to/NGC_GNU_SRC/NGC tools/sn-gcc/build.sh
# 2. ディスクイメージ(ディスク1:main.dol + 110個のREL、ディスク2:4つのアイランドステージREL st3_0..st3_3)
cp re4_debug_disc1.iso re4_debug_disc2.gcm orig/G4BE08/
# 3. ビルドと検証
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>で1つの関数を表示します。
レイアウト
src/game/ — ゲーム(C++、少数のnewlib Cユニット)。
src/em*/ 敵、src/wep*/ 武器、src/pl*/ プレイヤーキャラクター、src/st*/ ルーム(ルームごとに1つの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("")ラウンダーとアンカー、レジスタT x asm("rN")ピン、パディングステートメント)でマークされます。それらは命令を発行しません:python3 tools/asmcheck.py --allは、アセンブリテンプレートでマークされたGCCユニットを全てコンパイルし、テンプレートから来た命令をリストします。ヒットするのは以下のハードウェアカーネルのみです(合計231個。アセンブリ本体を持つ8つのユニットは独自の行で報告され、その数から除外されます)。このツリーの以前の状態には、ゲームコードに約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ゲームコード:ペア・シングルカーネル(math_subのSINF/COSF/RSQRT/LIMIT_ANGLE、trans, shape, dbmoduleの行列カーネル、Espgen42/espgen45のquantised psq_l)、main/schedulerのGQRセットアップ、libsn sndvd例外ハンドラ。
MWCC CRIライブラリ:ペア・シングル/キャッシュ/SPRカーネル(mpv_umc, mpv_mc, dct_fsri, cftyp422_ppc, mpv_lib)、SDKのmtx/vec/quat/GXイントリンジック、dct_acの1つのレジスタステアリングブロック(dctac_Init:ベンダーのコンパイラビルドは.bssをプールしましたが、関数の8バイトリテラルはプールしませんでした。我々のビルドは両方をプールします)。
Codeless asm { mr r11, x; mr x, r11 } ピン(両方の移動はアロケータによって削除されます。レジスタを1つ減らしてカラーセットを狭めます)とasm { mr v, v } 自己コピー(不透明な2番目の定義)は27箇所に残っています。
アセンブリ本体を持つ8つのユニット:crt0 (__start), eabi, SNのtealeaf/fileserver/ppcdown/proview (src/lib/<name>.c)、Capcomのmemset_2とyz2asm (src/game/<name>.cpp)。元はアセンブリでした(SNのlibsn/crt0オブジェクトとCapcom自身のasm。バイトにコンパイライディオムはありません)。そのため、それぞれがGAS構文の関数全体トップレベルasm()本体を持つCファイルです(.globl/.type/label/.size, ローカル.L_ラベル, .4byte/.float/.skipデータ)。残りのコードと同じProDGドライバでコンパイルされます(include/asm_regs.hはr3/f1/GQR0名を.set定数として供給します。NgcAsは生の数値を扱います)。tools/asmcheck.pyはそれらをasm-bodiedとしてリストします。
命名
関数名はCapcomのもので、デバッグビルドのBio4.symファイルから来ています。これらはC++でマンデリングされており、ゲームコードがC++である理由であり、SDK、CRI、newlibユニットがCである理由です。ファイル名とユニット境界は、アサートに残されたD:/Bio4/Prog/<file>.cpp文字列から来ています。構造体とフィールド名は3種類です:ベンダーのもの(PS2デバッグビルドの型情報から、tools/ps2sym.pyでゲームキューブレイアウトにマッチング)、我々のもの(使用法から名前を付け、そのようにマーク)、プレースホルダーxNN(16進数オフセット、不明)。ベンダー名はベンダーのスペルを保持するため、ツリーは意図的に規約を混在させています。#lineディレクティブは、アサート文字列内のベンダーの行番号を再現します。docs/naming.mdに完全な説明とカウントがあります。
貢献
CONTRIBUTING.md:ビルド、3つの検証チェック、ルール(バイトは変更しない、命令を発行しないasm、命名)、証拠と共にリネームを提案する方法。
法的
再構築されたゲームおよびSDKソースは、それぞれの所有者(Capcom, Nintendo, CRI Middleware)の知的財産であり、研究および保存目的でのみ公開されています。このプロジェクトのために書かれたビルドスクリプト、ツール、ドキュメントはCC0(LICENSE)の下でリリースされています。