![]() And clarify that it cannot be used to play BotW, and that it does not contain any copyrighted content from the RomFS. |
||
---|---|---|
.github/workflows | ||
data | ||
lib | ||
src | ||
tools | ||
.clang-format | ||
.gitignore | ||
.gitmodules | ||
CMakeLists.txt | ||
Dockerfile | ||
README.md | ||
ToolchainNX64.cmake | ||
diff.py | ||
diff_settings.py |
README.md
uking
This is a decompilation of U-King v1.5.0 (Switch).
File names, class or function names and the file organization come from leftover strings. Unlike some other first-party games such as Super Mario Odyssey, all known public versions of U-King are completely stripped, so most names are just more or less educated guesses.
This repository only contains source code; it cannot be used to play Breath of the Wild and does not include any RomFS content.
Status
Currently, the focus is on decompiling AI classes and other small, mostly self-contained components (e.g. LevelSensor).
Note to contributors: Breath of the Wild heavily relies on software libraries like sead which are statically linked. Given that most of BotW's dependencies have not been fully decompiled yet, decompiling any non-trivial part of the game requires working on those libraries first.
Because meaningfully splitting the code is not feasible, the built executable currently only contains functions that have been decompiled and no effort is being made to put functions and data at the correct addresses.
Building
Building this project requires:
- A C++17 capable compiler (or >= Clang 4.0)
- Ninja (Ubuntu/Debian package:
ninja-build
) - CMake 3.13+
If you are on Ubuntu 18.04, you can update CMake by using the official CMake APT repository.
Building a matching version for Switch
- After cloning this repo, run:
git submodule update --init --recursive
- Download Clang 4.0.1 and extract the archive.
- Set the UKING_CLANG environment variable to point to the extracted archive, such that
$UKING_CLANG/bin/clang
exists. - You'll also need devkitA64. Set the DEVKITA64 environment variable. For Linux, $DEVKITA64 is typically
/opt/devkitpro/devkitA64
.- Also add devkitA64 to your PATH:
export PATH=${DEVKITPRO}/devkitA64/bin:$PATH
- Also add devkitA64 to your PATH:
- In the root of this repository, run:
mkdir build
cd build
cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_TOOLCHAIN_FILE=../ToolchainNX64.cmake ..
ninja
to start the build
On subsequent builds, just run ninja -C build
from the project root.
If you are using Visual Studio Code, installing the CMake Tools extension is recommended to make includes, compiler flags, etc. work automatically.
Contributing
Using a decompiler such as Hex-Rays or Ghidra is strongly recommended.
You'll also need:
- pip (for the diff script)
- The original 1.5.0
main
executable, converted to ELF format with nx2elf.- Copy it to data/main.elf -- it is used for the diff script and other tools.
Resources
- The ZeldaMods wiki
- MrCheeze's botw-tools
- botw-re-notes
Project tools
- To compare assembly:
./diff.py <mangled function name>
- The function must be listed in data/uking_functions.csv first.
- To do so, search for the name or the address of function you have decompiled, and add the mangled function name to the last column.
- Pass the
--source
flag to show source code interleaved with assembly code. - Add the
--inlines
flag to show inline function calls. This is not enabled by default because it usually produces too much output to be useful. - For more options, see asm-differ.
- The function must be listed in data/uking_functions.csv first.
- To print progress:
tools/progress.py
- Note that progress is only approximate because of inline functions, templating and compiler-generated functions.
- To dump symbols:
tools/print_decomp_symbols.py
-
-u
for undefined symbols (default) -
-a
for all symbols -
Useful for getting the mangled name of a function. For example:
$ tools/print_decomp_symbols.py -a | grep BaseProcMgr::createInstance UNLISTED ksys::act::BaseProcMgr::createInstance(sead::Heap*) (_ZN4ksys3act11BaseProcMgr14createInstanceEPN4sead4HeapE)
-
Non-inlined functions
When implementing non-inlined functions, please compare the assembly output against the original function and make it match the original code. At this scale, that is pretty much the only reliable way to ensure accuracy and functional equivalency.
However, given the large number of functions, certain kinds of small differences can be ignored when a function would otherwise be equivalent:
-
Regalloc differences.
-
Instruction reorderings when it is obvious the function is still semantically equivalent (e.g. two add/mov instructions that operate on entirely different registers being reordered)
When ignoring minor differences, add a // NOT_MATCHING: explanation
comment and explain what does not match.
Finally, add the mangled name of each function you have decompiled to data/uking_functions.csv to make it easier to track progress.
Header utilities or inlined functions
For header-only utilities (like container classes), use pilot/debug builds, assertion messages and common sense to try to undo function inlining. For example, if you see the same assertion appear in many functions and the file name is a header file, or if you see identical snippets of code in many different places, chances are that you are dealing with an inlined function. In that case, you should refactor the inlined code into its own function.
Also note that introducing inlined functions is sometimes necessary to get the desired codegen.
If a function is inlined, you should try as hard as possible to make it match perfectly. For inlined functions, it is better to use weird code or small hacks to force a match as differences would otherwise appear in every single function that inlines the non-matching code, which drastically complicates matching other functions. If a hack is used, wrap it inside a #ifdef MATCHING_HACK_{PLATFORM}
(see below for a list of defines).
Matching hacks
This project sometimes uses small hacks to force particular code to be generated by the compiler. Those have no semantic effects but can help with matching assembly code especially when the hacks are used for functions that are inlined.
MATCHING_HACK_NX_CLANG
: Hacks for Switch, when compiling with Clang.