A tool for linking modules against botw
This tool is a wrapper for make
. It generates a linker script that binds symbols to addresses, calls make
to build your module, then checks the binary for dynamically linked symbols that doesn't exist (and are supposed to be statically linked)
make
and objdump
are required for the program to work, both of which should be already installed if you are running your project in a linux or WSL environment.
│
│
┌──▼───────────────┐
│ Initialize │
└──┬───────────────┘
│
FAIL┌──▼───────────────┐ ┌──────────────────┐
┌─┤ Linker Script ◄──────┤ Prepare Relink ◄─┬──────┐
│ └──┬───────────────┘ └──────────────────┘ │ │
│ │ │ │OK
FAIL┌──▼───────────────┐ ┌──────────────────┐ │ ┌──┴───────────────┐
├─┤ Run Make ◄──────┤ Prepare Rebuild │ │ │ Botw Symbol Scan │
│ └──┬───────────────┘ └──▲───────────────┘ │ └──▲───┬───────────┘
│ │OK │1st │OK │ │FAIL
│ ┌──▼───────────────┐ │ 2+┌─────────────┴────┐ │ │
│ │ Check Binary ├─────────┴───► Configure Linker ├─┘ │
│ └──┬───────────────┘-c / FAIL └──────────────────┘FAIL │
│ │OK │
│ ┌──▼───────────────┐ │
└─► Cleanup ◄──────────────────────────────────────┘
└──┬───────────────┘
│
▼
Initialize: Read config files, run tasks
Linker Script: Generate linker script from config
Run Make: call make and objdump
Check Binary: Check if the elf contains unlinked symbols
Prepare Rebuild: Remove existing linker script and binary
Configure Linker: Change linker config based on missing symbols
Botw Symbol Scan: Scan botw symbol listing for missing symbols
Prepare Relink: Removing binary to relink
Cleanup: Save config files, cleanup tasks
- Include this repo as a submodule to your project. Replace LOCAL_PATH with where you want to clone this tool
git submodule add git@github.com:iTNTPiston/botw-link LOCAL_PATH
- Install the dependencies
cd path/to/botw-link pip install -r requirements.txt
- Optionally, add the BotW decomp project as a submodule as well so you have access to the headers. Replace LOCAL_PATH where you want to clone the botw code
git submodule add git@github.com:zeldaret/botw LOCAL_PATH
- Later, to update to the latest version of the tool:
In collab scenarios, to update your copy of the tool to whatever the repo uses:
cd path/to/botw-link git checkout main git pull cd path/to/your/repo git add path/to/botw-link git commit -m "Update botw-link" git push
git submodule update
Follow the steps below to see how to make your code interact with BotW and how to change your build system to use this tool.
You can call functions or use data in BotW with the headers from the decomp project or declare your own and link them later.
This is the recommended way to make your module interact with BotW.
- Add the decomp project to your include path
Note: do not add the source
path/to/botw/src
*.cpp
files. Just the headers would be enough. However, in rare situations you might want to use the decompiled source code if you can't find the function address. - Locate the header that contains the function/class you want to use and
#include
it in your source. The function does not need to be decompiled to be used. For example:Make sure the include path is set correctly in your IDE and your makefile if you see include errors.#include <KingSystem/System/SystemTimers.h>
- Call the function or data just like any regular c++ function
In this case we are using the data symbol
const auto pSystemTimers = ksys::SystemTimers::getInstance();
_ZN4ksys12SystemTimers9sInstanceE
. Since this is listed in the decomp project, the build tool will automatically find it and link it for you - If you need to get the raw address of a member function (for example for hooking), see the Glue API. Do not use member function pointers directly as static function pointers. The compiler will likely stop you anyway.
Sometimes the symbol isn't in the decomp project. You can either:
- Declare it in a header by yourself and link the symbol manually by editing the
.yaml
config file this tool uses. - Contribute to the decomp project by adding the header and the symbol listing
With this tool, you can target the same code against both BotW 1.5.0 and 1.6.0 versions at build time. However, whatever symbols you are using must be present in the listing of the corresponding version.
Sometimes it's needed to target code only for a specific version. To do that, you can use preprocessor macros:
#if BOTW_VERSION == 150
word_only_on_150();
#endif
The tool will define BOTW_VERSION
as either 150
or 160
based on the args and pass it to make
.
You need to apply some changes to the makefile and other files in the build system to use this tool
- Decide a place to put the generated linker script in your project. For example
config/linker/syms.ld
- In your linker specs (the
.specs
file passed in from the ld flag-specs=
), add this file to the command. For exampleThe path should be relative to your build directory// OLD: %(old_link) -T ../libs/exlaunch/misc/link.ld --shared --export-dynamic // NEW: %(old_link) -T ../libs/exlaunch/misc/link.ld ../config/linker/syms.ld --shared --export-dynamic
- In your
makefile
, includeBOTW_VERSION_DEFINES
in the compiler flags. For example:CLFAGS=$(CLFAGS) $(BOTW_VERSION_DEFINES)
- When calling the tool, specify the linker script output location
--output config/linker/syms.ld
The tool uses command line arguments to accept inputs so it doesn't depend on external tooling for argument parsing. You can make a script or use a script runner like Just to avoid typing them out every time.
You should invoke the tool by calling it from python with the directory path to make sure it works properly, for example:
python path/to/botw-link path/to/config.toml -V 150
You can see an example of the build config in example.toml
--version/-V VERSION
Version of BotW to link against. VERSION must be either "150" or "160". This will affect what symbol data is used and output/input file names. The same string will be passed to the makefile through the BOTW_VERSION variable.
--clean/-c
This will clean the symbols defined in the linker config .yaml
files and make sure they are up-to-date. Also cleans internal caches used by this tool. The default behavior is only clean when unlinked symbols are found
--update/-u
This will fetch the latest CSV symbol listing for BotW 1.5.0 from the decomp project. The default behavior is only fetch if missing
--verbose/-v
Show more output
If the tool tells you that it can't find a symbol. Follow the following steps.
Try searching for the symbols in listing/150.txt
or listing/160.txt
depending on your version
If the symbol is found in the txt but the tool still can't find it, please open an issue.
If the symbol is missing in the txt
file, follow Add new Symbols below
For 1.5.0:
See if the function is already in the decomp project. If so, use the same signature, or just use the headers from the decomp project.
If not, you must find the address of the symbol yourself, then follow Add new Symbols below
If the symbol is still missing, you must find the address of the symbol yourself, then you can add it to this tool by:
- 1.5.0: see here for how to add a symbol listing to 1.5.0. You need to make a PR to the decomp project
- 1.6.0: Make a PR to this repo updating
listing/160.txt
For testing, you can add the listing to manual
section of the local .yaml
file generated by this tool