Languages: English | 日本語
A matching decompilation of the PlayStation game Legend of Mana. Both the North American and the Japanese releases are 100% matched.
The project reconstructs readable C source code that compiles down to the original MIPS machine code that exists on the disc, byte-for-byte. Two regional releases are targeted:
- North America -
SLUS_010.13(disc serial SLUS-01013). Complete: all 18 binaries are fully linked. - Japan -
SLPS_021.70(disc serial SLPS-02170). Complete: all 18 binaries are fully linked, built from the same C sources as the North American version.
Unless a section says otherwise, the build instructions, targets, and file names below refer to the North American version.
This is a decompilation project, not a PC port. The repository does not include the game executable, overlay binaries, artwork, audio, or other copyrighted game data. You must provide the required files from your own copy of the game.
The primary motivation for this project is to preserve the original game's logic and behavior for educational research and potential modding capabilities.
For both versions, every module - the main executable and all 17 overlays - is fully linked. A module is fully linked when two conditions hold:
- The build produces an ELF whose bytes match the original decompressed file, and
- Running the project's compressor on that ELF (stripped to a raw binary) reproduces an exact replica of the
.BINfile as it appears on the disc.
In other words, the round-trip original .BIN -> decompress -> C source -> compile -> ELF -> compress -> .BIN is bit-identical.
The main executable is not compressed, so for SLUS_010.13 and SLPS_021.70 condition 1 is the whole check: the linked ELF, converted to a raw binary, equals the disc file.
(Check out the compressor! It's honestly really amazing that it is bit identical and kind of extraneous, but cool nonetheless!)
Run make verify-bins to check every module, or make verify-bins VERSION=jp for the Japanese version.
-
✅ 100% matching - done. The main executable (
SLUS_010.13) and all 17 overlays are fully linked (see above). The Psy-Q SDK libraries are still linked from the original assembly. -
🚧 Cleanup and documentation - in progress. Remove decompilation artifacts and document functionality.
-
✅ NTSC-J version - done. The original Japanese release (
SLPS-02170) builds from the same source tree as the North American one, and all 18 of its binaries are fully linked too. -
💤 Modding and source port - build on the reconstructed source to make modding practical and to enable ports to other platforms.
| Item | North America | Japan |
|---|---|---|
| Status | ✅ Fully linked | ✅ Fully linked |
| Disc serial | SLUS-01013 |
SLPS-02170 |
| Main executable | SLUS_010.13 |
SLPS_021.70 |
| Main executable SHA-1 | d11dfdd50d412ac3fa3e2eb80fbde138da118f27 |
b067188a92e4de9a4db7bb7e5343c757e9884bfa |
Disc image (.bin) SHA-1 |
c1b536c99f0d390584eb30462a7e37f2bbef3902 |
7a314615be8a482cf3f81b4101cc19aaa738f36d |
| Architecture | 32-bit little-endian MIPS / PlayStation | 32-bit little-endian MIPS / PlayStation |
The getting-started steps below use the North American version. The Japanese version works the same way, with its files under disc/jp/ and VERSION=jp on the make command line. Other regional versions are not currently supported.
For the normal build you need:
- Git, including submodule support.
- Docker - Docker Desktop on Windows/macOS or Docker Engine on Linux.
- A legally obtained copy of Legend of Mana, North American or Japanese (see Supported game versions).
You do not need to install the historical PSX compilers, Psy-Q tools, Python packages, or a MIPS cross-compiler directly on your host. The development container provides them.
git clone --recursive https://github.com/celophi/lom-decomp.git
cd lom-decompIf you already cloned without submodules:
git submodule update --init --recursiveExtract the main executable and the game's BIN directory from your North American disc/image into disc/us/, so the repository contains the following (the Japanese release goes in disc/jp/ with the same layout):
disc/
`-- us/
|-- SLUS_010.13
`-- BIN/
|-- ADDHERO.BIN
|-- CARDA.BIN
|-- CHECKPS.BIN
|-- CLOAD.BIN
|-- FIELD.BIN
|-- GNAME.BIN
|-- GOLEM.BIN
|-- GOSUB.BIN
|-- GOVER.BIN
|-- MENU.BIN
|-- MOVIE.BIN
|-- NIKI.BIN
|-- SHOP.BIN
|-- TITLE.BIN
|-- WMAP.BIN
|-- WSEL.BIN
`-- ZUKAN.BIN
You do not need to copy the rest of the disc into the repository.
To confirm the main executable is the expected version:
sha1sum disc/us/SLUS_010.13Expected:
d11dfdd50d412ac3fa3e2eb80fbde138da118f27 disc/us/SLUS_010.13
The splat configs also contain expected SHA-1 hashes for the overlay files.
disc/is gitignored. Never commit original game files.
The project uses multiple historical GCC variants. Build the four local compiler images using the old-gcc submodule:
docker build -t old-gcc/gcc-2.8.0-psx -f tools/external/old-gcc/gcc-2.8.0-psx.Dockerfile tools/external/old-gcc
docker build -t old-gcc/gcc-2.7.2-cdk -f tools/external/old-gcc/gcc-2.7.2-cdk.Dockerfile tools/external/old-gcc
docker build -t old-gcc/gcc-2.6.0-psx -f tools/external/old-gcc/gcc-2.6.0-psx.Dockerfile tools/external/old-gcc
docker build -t old-gcc/gcc-2.7.2-psx-gnu -f dockerfiles/gnu-as.dockerfile tools/external/old-gccThis is normally a one-time setup step. The development Dockerfile uses these local images; no access to a private compiler image is required.
Run this from the repository root using dockerfiles/dev.dockerfile:
docker build -t lom-dev -f dockerfiles/dev.dockerfile .The image contains the compilers, Psy-Q tooling, MIPS binutils, splat, maspsx, the pinned objdiff CLI, and Python dependencies used by the project.
Run this from the repository root.
PowerShell, bash, or zsh:
docker run --rm -it -v "${PWD}:/lom" lom-devWindows Command Prompt (cmd.exe):
docker run --rm -it -v "%cd%:/lom" lom-devThe remaining setup commands are run inside the container.
make splatThis generates local build inputs such as asm/us/, linker/us/, and extracted assets under assets/us/. These files are intentionally not all stored in Git.
Run make splat again after changing splat configs, segment boundaries, symbol maps, or relocation overrides.
Build the main executable:
makeOutput:
build/us/SLUS_010.13.elf
To also produce a flat binary:
make binBuild one registered overlay:
make field
make menu
make checkpsBuild all overlays currently registered in mk/overlay-registry.mk:
make overlaysBuild the main executable and all registered overlays:
make everythingmk/overlay-registry.mk is the authoritative list of overlays currently wired into the linkable build.
After the initial setup, you generally do not need to clean the project after every edit:
edit source on host
|
v
make <smallest relevant target> inside lom-dev
|
v
inspect objdiff / diff output
|
v
edit and repeat
The Makefile automatically stages changed inputs before compiling. If the staged copy ever appears stale, run:
make recopyUse make clean only when you actually want to remove build/us/ and the /staging copy.
The repository is mounted into Docker at /lom, but historical compilation happens from /staging, a native Linux filesystem inside the container.
Some legacy 32-bit compiler/preprocessor binaries cannot safely stat() files on Windows-backed Docker bind mounts and may fail with:
Value too large for defined data type
The Makefile solves this by copying required inputs to /staging and normalizing text files to LF line endings before compiling.
For that reason, do not bypass the build system and invoke the old compiler directly against files under /lom.
| Target | Purpose |
|---|---|
make |
Build the main SLUS_010.13 ELF. |
make bin |
Also produce build/us/SLUS_010.13.bin. |
make <overlay> |
Build one registered overlay, such as make field. |
make overlays |
Build all registered overlays. |
make everything |
Build the main executable and all registered overlays. |
make splat |
Split the main executable and all overlay configs. |
make objdiff-objects |
Build target and reconstructed objects for objdiff. |
make objdiff-config |
Regenerate objdiff.json. |
make progress |
Generate build/us/progress.json. |
make diff-all |
Run objdiff across all configured units. |
make diff-text |
Generate compact text reports under build/us/diffs/. |
make dump-objs |
Disassemble built objects for code-generation analysis. |
make validate-assets |
Round-trip and validate format-aware assets. |
make verify-main |
Check that the linked main executable equals disc/us/SLUS_010.13 (verify-slus is an alias). |
make verify-bins |
Run verify-main and all registered whole-overlay SHA-1 checks. |
make verify-compressor |
Verify the compressor against the 17 original overlay files of the selected version. |
make recopy |
Force source/config files to be copied to /staging again. |
make clean |
Remove build output and /staging. |
Every target builds the North American version by default. Add VERSION=<name> to select another release, e.g. make VERSION=jp; see Version layout.
The project uses objdiff for local function and object comparison.
Build both sides and generate the objdiff config:
make objdiff-objects
make objdiff-configThen open objdiff and point it at the repository root.
For a command-line workflow:
make diff-all
make diff-textThe compact reports are written below build/us/diffs/.
You can also use decomp.me for collaborative matching. Existing source comments contain links to many decomp.me scratches; preserve those references when editing a function.
A critical detail of this project is that not every source file uses the same compiler configuration. Honestly, It was a lot of "fun" dealing with this. Especially the GNU one let me tell you.
The build defines 7 pipeline variants across four historical compiler builds. Compiler and assembler flags live in mk/toolchains.mk. Source routing and per-file overrides are in mk/main.mk and mk/overlay-registry.mk; mk/overlays.mk applies the overlay variants.
| Pipeline | Compiler flags | Assembly path |
|---|---|---|
| GCC 2.8.0 G0 (default) | -O2 -G0 -gcoff -fsigned-char |
maspsx, ASPSX 2.77, expanded division |
| GCC 2.8.0 G0, unoptimized | -O0 -G0 -gcoff -fsigned-char |
maspsx, ASPSX 2.77, expanded division |
| GCC 2.8.0 G4 | -O2 -G4 -gcoff -fsigned-char |
maspsx, ASPSX 2.77, expanded division |
| GCC 2.8.0 G4, no division expansion | -O2 -G4 -gcoff -fsigned-char |
maspsx, ASPSX 2.77, bare division |
| GCC 2.7.2 CDK G0 | -O2 -G0 -msoft-float -gcoff |
maspsx, ASPSX 2.67, expanded division |
| GCC 2.7.2 GNU G0 | -O2 -G0 |
Historical GNU as with -O -EL |
| GCC 2.6.0 G0 | -O2 -G0 -gcoff -msoft-float |
maspsx, ASPSX 2.34, expanded division |
Some executable/overlay ranges contain artwork, text, layouts, and other copyrighted data that should not be committed.
The project uses a hybrid approach:
- understood program data can be represented as typed C;
- understood binary formats can use byte-exact extractors/builders;
- unknown or creative data can remain as named local
databin/rodatabinassets referenced with.incbin.
One C source tree builds every regional release. Anything that comes from a particular disc lives in a per-version folder, and VERSION=<name> on the make command line picks which one to build.
VERSION |
Release | Status |
|---|---|---|
us (default) |
North America, SLUS-01013 |
Fully linked |
jp |
Japan, SLPS-02170 |
Fully linked |
| Shared by all versions | Per version |
|---|---|
src/, include/, mk/, tools/, docs/ |
disc/<version>/, config/<version>/, and the generated asm/<version>/, linker/<version>/, assets/<version>/, build/<version>/ |
Where the code differs between releases, the shared C source uses #if defined(VERSION_JP) / #if defined(VERSION_US) blocks; the build defines exactly one of them (see mk/version.mk and include/version.h). Symbol names are shared, but addresses are not, so each version has its own config/<version>/symbols/ files.
Each version gets its own objdiff progress report, and CI builds both (SLUS_010.13_report and SLPS_021.70_report). Every module builds from the shared C sources in both versions. config/jp/asm_units.txt can still route a file to assembly for JP only, for example while porting a unit whose code differs, but it's empty now.
lom-decomp/
|-- src/ # Reconstructed C source
| |-- overlays/ # Overlay source trees
| `-- psyq/ # Reconstructed Psy-Q library code
|-- include/ # Project and Psy-Q headers/macros
|-- config/<version>/ # Splat configs, symbols, relocations
|-- mk/ # Build rules and toolchain routing
|-- tools/ # Decompilation, compiler, diff, and asset tools
|-- docs/ # Architecture and matching documentation
|-- disc/<version>/ # Your local original game files (gitignored)
|-- assets/<version>/ # Local/generated asset data where required
|-- asm/<version>/ # Splat-generated target assembly (gitignored)
|-- linker/<version>/ # Splat-generated linker files (gitignored)
|-- build/<version>/ # Objects, ELFs, maps, diffs, and reports
|-- dockerfiles/ # Development and CI containers
|-- Makefile
`-- requirements.txt
Useful places to start exploring:
src/- reconstructed game and Psy-Q code.asm/us/nonmatchings/andasm/us/overlays/*/nonmatchings/- generated target assembly for unmatched functions.config/us/symbols/- known function/global addresses.config/us/relocations/- relocation overrides used when splat needs help reconstructing symbolic references.mk/overlay-registry.mk- overlay source/toolchain assignments.
Browse the documentation index for architecture guides and project references. Useful starting points include:
- Tools index - asset tools, scene extraction and test commands.
make splat reports a missing file or SHA-1 mismatch
Make sure the files are at disc/us/SLUS_010.13 and disc/us/BIN/*.BIN (or disc/jp/SLPS_021.70 and disc/jp/BIN/*.BIN for the Japanese version), without renaming them.
Docker cannot find an old-gcc/... image
Initialize the Git submodules and build the four historical compiler images from the setup section before building lom-dev.
GCC reports Value too large for defined data type
Use the Makefile instead of compiling directly from /lom. Run make recopy if the staged tree needs to be refreshed.
A symbol/config change is not reflected in generated assembly
Run make splat again. Do not edit generated asm/ or linker/ files manually.
A function matches with another compiler but not in the project build
Check its routing in mk/main.mk or mk/overlay-registry.mk. The configured historical toolchain is the authoritative one.
objdiff reports 100%, but whole-overlay verification fails
Check data/rodata jump table or case targets, relocation addends, linker section order, the overlay segment's align: key, and generated assets.
This project was created independently by analyzing the publicly released retail version of Legend of Mana and reconstructing its behavior and machine code through disassembly, decompilation, binary comparison, runtime analysis, and publicly available technical documentation and tools.
No leaked or otherwise non-public Legend of Mana source code, debug symbol files, internal symbol maps, developer documentation, or other confidential materials from Square or Square Enix have been used in the creation of this project.
Function names, variable names, data structures, translation-unit boundaries, and other source-level details are reconstructed or inferred from the retail binaries and observed behavior unless otherwise documented. They should not be assumed to be the names or organization used by the original developers.
This repository will never include leaked source code, private debug symbols, confidential documentation, or other non-public materials from the original game's development.
See LICENSE and THIRD_PARTY_NOTICES for licensing details.
The MIT License applies to original material authored for this project to the extent that the contributors hold the rights necessary to license that material. It does not grant rights to preexisting copyrighted material originating from the original game or from third-party SDKs, libraries, or development software.
This repository is an independent reverse-engineering and preservation project. It is not affiliated with or endorsed by Square, Square Enix, Sony, or any other rights holder.
No original game executable, overlay binaries, artwork, audio, or other copyrighted game data should be committed to this repository. You must supply required data from your own legally obtained copy of the game.
Legend of Mana and related names and assets are the property of their respective owners.
Thanks to Squaresoft and everyone who worked on Legend of Mana. The art, the music, and all the strange little ideas make this a game worth coming back to. You can tell the team was willing to try things, and that's a big part of what makes it interesting.
Figuring out how it all works has been a lot of fun. There's still plenty to understand, but hopefully this project helps preserve that work and gives other people a chance to explore it too.
This project builds on tools and research from the wider decompilation community, including: