Fix crash from Kamek skip-return hooks (Item Rain crash) (#182) added every Kamek BranchLink patch target to lrContinuationCallTargets unconditionally, with no filter analogous to the RetroWfcHookSetsLinkRegister check already used for RetroWFC hooks. Since bl is the ordinary PowerPC call instruction, this made the codegen treat effectively every patched call in the mod as a potential skip-return hook, forcing conservative handling (full register reload, disabled resident-call fast paths, local LR-continuation dispatch tables) onto thousands of calls that just return normally. For Retro Rewind this inflated total translated mod size by +42% (1,414,327 -> 2,005,284 lines), concentrated in ~10 unrelated overlay functions that happened to call a patched target, and was enough to make one aggregate build shard pathologically slow to compile (hangs Linux CI). Instead, only mark a bl target as LR-continuation-aware if a lightweight discovery-only decode of its own body actually finds evidence of skip-return behavior via DiscoverLrRelativeIndirectJumpOffsets. Falls back to the conservative (old) behavior if a target can't be statically analyzed, so no skip-return case is silently missed. Verified against the real Retro Rewind mod: total mod size returns to 1,416,350 lines (+0.14% vs. pre-fix, down from +42%), all 6 genuinely new continuation functions from the original fix are preserved, zero functions lost, and all 609 existing translator tests still pass.
Wiicompiled Static Recompiler
The translator parses GameCube/Wii DOL files, decodes PowerPC instructions, lifts them through
IR/SSA and type inference, and emits C++ that is compiled into a native executable together with
a runtime in runtime/. Project-specific paths and addresses are supplied through a versioned
YAML manifest, so the translator itself contains no game-specific data.
Translating a DOL does not exempt you from owning the game it came from.
How translating a DOL works
A project manifest (YAML) names the input DOL and pins its layout; everything else is derived.
Translation is four commands:
-
translate-recursive <entry-point> --project <manifest>- walks the call graph from the entry point, decodes every reachable function, and emits C++ (plus JSON metadata describing what was emitted). -
generate-data-init --project <manifest>- writes the embedded.data/.rodata/.sdatasection initializer andRuntimeConfig.h. -
emit-build-shards --project <manifest>- emits the CMake build graph (shards.cmake) covering both generated sources andruntime/src. -
CMake + Ninja with Clang compiles
runtime/plus the generated output into one executable.
Discovery is purely recursive from the entry point unless the manifest provides an optional
function_map (one hexaddr name per line) that seeds additional function boundaries. Unsupported
instructions fail translation by default.
See projects/examples/generic-dol.yml for a minimal manifest driven by RECOMP_GENERIC_DOL.
Prerequisites
| Tool | Notes |
|---|---|
| .NET 8 SDK | Builds and runs the translator. |
| CMake ≥ 3.16 and Ninja | Configures and drives the native build. |
| Clang / LLVM | The shipped build uses LLVM-MinGW targeting x86-64-v3. MSVC is not the tested path. |
Build the CLI once and invoke the assembly directly:
dotnet build translator/src/Translator.Cli/Translator.Cli.csproj -c Release
$translator = 'translator/src/Translator.Cli/bin/Release/net8.0/Translator.Cli.dll'
Manifest essentials
inputs.dol.path- the DOL to translate; optional SHA-256 pinning rejects wrong revisions.memory.base/size- guest address space.memory.sda_base/sda2_base- the r13/r2 Small Data Area bases your DOL's boot code installs (lis/oripairs in__init_registers). Required by any command that writesRuntimeConfig.h; the translator does not guess them.translation.function_map.path- optional symbol map used as the discovery oracle.translation.allow_unsupported_instructions- off by default; enabling it emits runtime traps instead of failing, and such a build can never ship.
Relative paths resolve from workspace_root, which itself resolves from the manifest directory.
Commands
info [--project path]translate-recursive <address> --project pathgenerate-data-init --project pathemit-base-manifest --project pathemit-build-shards --project pathtranslate-mod --project path [--profile name] ...- static Kamek/Pulsar module translation
Any command prints its own option list with --help.
Test
dotnet test translator/Translator.sln -c Release