Resident Evil 4 (GameCube) – complete byte-identical decompilation to C/C++

Hacker News by 6 min read 114x views
Resident Evil 4 (GameCube) – complete byte-identical decompilation to C/C++

Share Post

A complete, byte-identical decompilation of Resident Evil 4 for the Nintendo GameCube: the G4BE08 debug build (the "Nov 25 2004" prototype, the two discs), whose Bio4.sym records name every function. Building the repository reproduces main.dol and all 114 REL overlays exactly (config/G4BE08/build.sha1, checked on all build).

Objects 1083 (675 in the DOL, 408 throughout the 114 RELs), all byte-identical; 15641 functions
Source ~555k lines of C/C++ (src/), ~33k lines of headers (include/); no gathering files
Game code SN Systems ProDG 3.9.3 — GCC 2.95.3 "SN BUILD v1.79", built natively from SN's GPL origin drop
CRI middleware (src/lib/adx_*, sfd_*, mpv_*, …) Metrowerks CodeWarrior 2.4.7 (GC/2.7), the compiler CRI shipped the libraries with
Nintendo SDK (src/lib/OS*, GX*, …) Metrowerks CodeWarrior GC/1.2.5n, sources from dolsdk2004

The repository contains no equivalent resources and no code or data copied from the discs. You need your own images of the debug discs to build (disc 1 for main.dol and most RELs, disc 2 for the four island-stage RELs); the first records are peruse from them at configure time.

Linux, Python 3, ninja. Compilers and tools (decomp-toolkit, objdiff, wibo, the CodeWarrior builds) are downloaded by the archetypal configure run, apart from the native SN GCC:

# 1. the native cc1/cc1plus (once): needs SN's GPL origin drop, see tools/sn-gcc/build.sh SN_GCC_SRC=/path/to/NGC_GNU_SRC/NGC tools/sn-gcc/build.sh # 2. your disc images (disc 1: main.dol + 110 RELs; disc 2: the four island-stage RELs st3_0..st3_3) cp re4_debug_disc1.iso re4_debug_disc2.gcm orig/G4BE08/ # 3. build and verify python3 configure.py && ninja

ninja ends alongside the advancement study (100% matched and connected for the DOL and the REL modules); build/tools/dtk shasum -c config/G4BE08/build.sha1 prints 115 OK lines. To activity on a unit, python3 tools/bytecmp.py game/foo compares its entity with the first term by term and python3 tools/fdiff.py game/foo <symbol> shows one function.

  • src/game/ — the equivalent (C++; a few newlib C units). src/em*/ enemies, src/wep*/ weapons, src/pl*/ participant characters, src/st*/ rooms (one REL per room), src/t_*/, src/Tools/, src/tools/ the in-game debug editors, src/Sscrn/ the sub-screens, src/lib/ SDK, CRI and runtime.
  • include/ — headers, including the reconstructed struct layouts.
  • config/G4BE08/ — component lists (objects.py, modules.py), symbols.txt, splits.txt, linker scripts, per-module REL data (modules/<mod>/), build.sha1.
  • tools/ — build generator (project.py), the ProDG controller (ngccc.py), REL rebuild (make_rel.py, link_rel.py), the difference tools, sn-gcc/ (native compiler build), research/ (compiler-analysis kit), motion_export.py + motion/ (animation export to glTF/BVH, evaluated alongside the game's own code and verified against the equivalent operating in Dolphin).
  • docs/overview.md — how the motor is put together: a study guide to src/ by subsystem.
  • docs/matching.md — how the matching was done: compiler provenance, the catalogue of compiler mechanisms and the origin shapes that reproduce them, rules of thumb for the two compilers. docs/unit-notes.md — per-unit notes. docs/research/ — the pass-by-pass investigation log.

What "matching" method here

Every component compiles to the first bytes alongside the first compilers. Where the compiler needed a particular origin form to reproduce a enroll choice or a agenda and no natural orthography was found, the build is marked alongside a // COMPILER-DIFF: comment (644 of them: deceased tests, empty asm("") launders and anchors, enroll T x asm("rN") pins, padding statements). None of them emits an instruction: python3 tools/asmcheck.py --all compiles all GCC component alongside its asm templates marked and lists the instructions that came from a template — the lone hits are the hardware kernels below (TOTAL 231; the eight asm-bodied units are reported on their own row and kept out of that number). An before province of this tree had ~100 hand-placed instructions (asm("li %0,0"), asm("lis/addi"), asm("mr")) in the equivalent code and ~100 register-pinning asm { } blocks in the CRI libraries; they were replaced by C on 2026-09-17 (docs/research/compiler.md, division "Asm-removal pass", records the recipe and the compiler scheme per site). Each tag's scheme is documented in docs/matching.md and docs/research/.

Assembly that remains, all of it code the first authors additionally wrote in gathering since their compilers had no another way to province it:

  • GCC 2.95 equivalent code: paired-single kernels (SINF/COSF/RSQRT/LIMIT_ANGLE in math_sub, the matrix kernels in trans, shape, dbmodule, quantised psq_l in Espgen42/espgen45), the GQR setup in main/scheduler, and the libsn sndvd elimination handler.
  • MWCC CRI libraries: the paired-single / cache / SPR kernels (mpv_umc, mpv_mc, dct_fsri, cftyp422_ppc, mpv_lib), the SDK's mtx/vec/quat/GX intrinsics, and one register-steering block in dct_ac (dctac_Init: the vendor's compiler build pooled .bss but not the function's 8-byte literals; ours pools both). Codeless asm { mr r11, x; mr x, r11 } pins (both moves are deleted by the allocator; they narrow the color set by one register) and asm { mr v, v } self copies (an opaque second definition) remain in 27 places.
  • Eight asm-bodied units: crt0 (__start), eabi, SN's tealeaf/fileserver/ppcdown/proview (src/lib/<name>.c), and Capcom's memset_2 and yz2asm (src/game/<name>.cpp). The originals were gathering (SN's libsn/crt0 objects and Capcom's own asm; no compiler idiom in the bytes), so each is a C document whose functions are whole-function top-level asm() bodies in GAS syntax (.globl/.type/label/.size, local .L_ labels, .4byte/.float/.skip data), compiled by the identical ProDG controller as the remainder (include/asm_regs.h supplies the r3/f1/GQR0 names as .set constants; NgcAs takes naked numbers). tools/asmcheck.py lists them as asm-bodied.

Function names are Capcom's, from the debug build's Bio4.sym files; they are C++-mangled, which is why the equivalent code is C++ and the SDK, CRI and newlib units are C. File names and component boundaries come from the D:/Bio4/Prog/<file>.cpp strings the asserts remaining in the binaries. Struct and site names are of three kinds: the vendor's, from the PS2 debug build's category data (matched to the GameCube layouts by tools/ps2sym.py); ours, named from use and marked as such; and placeholders xNN (offset in hex, definition unknown). Vendor names keep the vendor's spelling, so the tree mixes conventions on purpose. #line directives reproduce the vendor's row numbers in the province strings. docs/naming.md has the complete document and the counts.

CONTRIBUTING.md: build, the three verification checks, the rules (bytes never change, no instruction-emitting asm, naming), and how to propose a rename alongside evidence.

The reconstructed equivalent and SDK origin is the intelligent asset of its corresponding owners (Capcom, Nintendo, CRI Middleware) and is published for investigation and conservation only. The build scripts, tools and records written for this project are released under CC0 (LICENSE).

Other Article Hacker News
Close Right Ads
Close Left Ads