Matching decompilation
A matching decompilation is C or C++ source code that, compiled with the original compiler and settings, produces a program identical byte for byte to the original. Community projects have done this for many console games, among them Super Mario 64, The Legend of Zelda: Ocarina of Time and Majora's Mask, and Paper Mario. For games written in assembly, the same idea gives a matching disassembly that assembles to the identical ROM, as pret's Pokémon Red does. This page describes how these projects work and when to choose this route.
How it works
- Identify the compiler. Find the exact compiler and version the game was built with: SGI IDO 5.3 or 7.1 for many N64 games, GCC 2.x versions from the PsyQ SDK for the PlayStation, Metrowerks CodeWarrior versions for the GameCube, Microsoft's for the Xbox. Compiler signatures in the code, library versions and leftover strings help to identify it.
- Split the program. Tools (splat, decomp-toolkit) split the ROM or executable into files of code, data and assets, following a configuration of addresses. The project builds them back into an identical program from disassembly at first.
- Decompile one function at a time. For each function, write C that compiles to the same instructions. Tools give a first draft (m2c), and decomp.me lets many people try candidate C against the original compiler in a browser. asm-differ and objdiff show where the output still differs.
- Replace the assembly. When a function matches, its C replaces its assembly in the build. The build still produces the identical program, which proves the match.
- Name and document. Matching code starts with generic names. The project then names variables, structures and functions, as in any reverse engineering.
What it gives
- A proof of behaviour. The match shows that the C behaves exactly like the original, including every bug.
- A base for ports. Once the code is C, it can be built for other systems with a new hardware layer (as the SM64 PC port did).
- A complete map of the program. Later projects on the same game can use it.
What it costs
- Matching is slow. Compilers of the time are sensitive to the order of statements, the types of temporary variables and the use of registers. Some functions take days to match.
- It needs the original compiler, which often runs only in an emulator or an old system.
- The resulting source is derived from the original program. Projects have different views of what may be published. The law differs by country. The user decides whether to publish such code (Legal).
When to choose it
| Situation | Route |
|---|---|
| The game is in C, the compiler is known and available, and a community already started a decompilation | Contribute to or use the decompilation's documents |
| You need a port that is exactly the original, bugs included, and can accept the legal position | Matching decompilation |
| The game is mostly hand-written assembly (most 8-bit and 16-bit games) | Matching proves less when the source was assembly; disassemble, document and reimplement |
| You want new code you can publish freely | Reimplementation, using decompilation projects' documents as references |
How GameFrame fits in
GameFrame's playbook applies to every route. Its toolkit helps a matching project with tasks the matching tools do not cover:
decomp_query.pyand the Ghidra export for searching the whole program as text.- Emulated ground truth (
re-emulate) to check a ported function's results on many inputs before it matches byte for byte. seqdiff.pyto compare random draws or events between the original and a build.- The evidence labels and documents, for knowledge that the C code alone does not record.