-
Notifications
You must be signed in to change notification settings - Fork 13
Port docs from PH #90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
1fe0f8e
1890bff
1682e68
f0ed89f
99efe76
46de45d
1b26e1a
a5a2494
b549770
1d4a241
a8de8f5
8d3814a
5b7b3c7
3273dcc
64e0dac
78e20ce
69d676b
a891122
fc4236d
2feacff
6471adb
a9183f5
f49eafa
32b7819
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,104 @@ | ||||||||||
| # Decompiling | ||||||||||
| This document describes how you can start decompiling code and contribute to the project. Feel free to ask for help if you get | ||||||||||
| stuck or need assistance. | ||||||||||
| - [Pick a source file](#pick-a-source-file) | ||||||||||
| - [Decompiling a source file](#decompiling-a-source-file) | ||||||||||
| - [Decompiling a function](#decompiling-a-function) | ||||||||||
| - [Decompiling `.init` functions](#decompiling-init-functions) | ||||||||||
| - [The Ghidra project](#the-ghidra-project) | ||||||||||
|
|
||||||||||
| ## Pick a source file | ||||||||||
| A reservation sheet exists for a list of delinked source files that are ready to be decompiled. This list grows as more source files are delinked from the rest of the base ROM. You can request access to the sheet in the ZeldaRet discord [channels for ST](https://discord.com/channels/688807550715560050/1453177153502969977) (you can join the server with [this invite link](https://discord.gg/6tjntnU8hC)). | ||||||||||
|
Mityno marked this conversation as resolved.
Outdated
|
||||||||||
|
|
||||||||||
| You can claim a source file (called an "actor") by filling in the "Reserved by" column. Once you started decompilation, create a PR on the ST repository for the actor you're decompiling. The decomp-dev bot will follow your PR and give information about the decompilation progress of your code. | ||||||||||
|
|
||||||||||
| <!-- TODO --> | ||||||||||
| If you want to unclaim the file, <!-- leave another comment so we can be certain that the source file is available to be claimed again. --> | ||||||||||
| Remember to make a pull request of any progress you made on the source file, whether it is just header files or partially decompiled code. | ||||||||||
|
Mityno marked this conversation as resolved.
Outdated
|
||||||||||
|
|
||||||||||
| ## Decompiling a source file | ||||||||||
| We use the object diffing tool [`objdiff`](https://github.com/encounter/objdiff) to track differences between our decompiled C++ code and the base ROM's code. | ||||||||||
| 1. [Download the latest release.](https://github.com/encounter/objdiff/releases/latest) | ||||||||||
| 1. Run `configure.py <eur|usa>` and `ninja` to generate `objdiff.json` in the repository root (don't forget to follow the instructions in [INSTALL.md](../INSTALL.md) first). | ||||||||||
|
Mityno marked this conversation as resolved.
Outdated
|
||||||||||
| 1. In `objdiff`, set the project directory to the repository root (it should load `objdiff.json` itself). | ||||||||||
| 1. [WSL only] If you're using WSL (which is possible), navigate to the project directory with window's directory picker tool and select | ||||||||||
| 1. Select your source file in the left sidebar: | ||||||||||
|
Mityno marked this conversation as resolved.
|
||||||||||
|  | ||||||||||
|
Mityno marked this conversation as resolved.
Outdated
|
||||||||||
| 1. See the list of functions and data to decompile: | ||||||||||
|  | ||||||||||
|
|
||||||||||
| > [!NOTE] | ||||||||||
| > If a source file is missing in `objdiff`, or `objdiff` fails to build a file, first rerun `ninja` to update `objdiff.json`. | ||||||||||
| > If the problem persists, feel free to ask for help. | ||||||||||
|
|
||||||||||
| ## Decompiling a function | ||||||||||
| Once you've opened a source file in `objdiff`, you can choose to decompile the functions in any order. We recommend starting | ||||||||||
| with a small function if you're unfamiliar with decompilation. Here's an example: | ||||||||||
|
|
||||||||||
|  | ||||||||||
|
|
||||||||||
| As a starting point, we look at the decompiler output in Ghidra. You can request access to our shared Ghidra project [in this section](#the-ghidra-project). | ||||||||||
|
|
||||||||||
|  | ||||||||||
|
|
||||||||||
| Looking at this output, we might try writing something like this: | ||||||||||
| ```cpp | ||||||||||
| ARM bool Actor::Drop(Vec3p *vel) { | ||||||||||
|
Mityno marked this conversation as resolved.
Outdated
|
||||||||||
| if (mGrabbed) { | ||||||||||
| mVel = *vel; | ||||||||||
| mGrabbed = false; | ||||||||||
| return true; | ||||||||||
| } | ||||||||||
| return false; | ||||||||||
| } | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| Now we can go back to `objdiff` and look at the result: | ||||||||||
|
|
||||||||||
|  | ||||||||||
|
|
||||||||||
| Success! Note that this was a simple example and that you'll sometimes get stuck on a function. In that case, try the | ||||||||||
| following: | ||||||||||
| - Decompile a different function and come back later. | ||||||||||
| - Export to [decomp.me](https://decomp.me/): | ||||||||||
| 1. Press the `decomp.me` button in `objdiff`. | ||||||||||
| 1. Once you're sent to `decomp.me`, go to "Options" and change the preset to "Phantom Hourglass". | ||||||||||
| 1. Paste your code into the "Source code" tab. | ||||||||||
| 1. Share the link with us! | ||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh yeah also, as I learned yesterday, if you have inlines in a header and #include the header outside of the region it will use ARM, but if you do include it inside the thumb region it will use thumb
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I tried to include that in the description if that's what you wanted, let me know how it works for you |
||||||||||
|
|
||||||||||
| ## Decompiling `.init` functions | ||||||||||
| > [!NOTE] | ||||||||||
| > This section will be updated as we learn more about global objects. Feel free to contribute or provide us with more | ||||||||||
| > information! | ||||||||||
|
|
||||||||||
| Functions in the `.init` section are static initializers. Their purpose is to call C++ constructors on global objects, and to | ||||||||||
| register destructors so the global objects can be destroyed when their overlay unloads. | ||||||||||
|
|
||||||||||
| Static initializers are generated implicitly and do not require us to write any code ourselves. So, to generate one, you must | ||||||||||
| define a global variable by using a constructor. | ||||||||||
|
|
||||||||||
| If the static initializer calls `__register_global_object`, that means the global object has a destructor. This means you'll | ||||||||||
| have to declare a destructor if it doesn't exist already. | ||||||||||
|
|
||||||||||
| Another consequence of having a destructor is that a `DestructorChain` object will be added to the `.bss` section. This struct | ||||||||||
| is 12 (`0xc`) bytes long and is also implicit, so we don't need to define it ourselves. | ||||||||||
|
|
||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. to this I'd like to add that if you have multiple ctors in the same file they will all end up in the same static initializer function, meaning the order of the declarations will change the order of the code from the sinit function (also something else to know is that you only have one sinit per source file)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm unsure how to formulate that since I don't fully understand what is going on, I'll leave that small comment to you if you have time |
||||||||||
| > [!IMPORTANT] | ||||||||||
| > An important thing to keep in mind is that a static initializer can construct multiple global objects. | ||||||||||
|
|
||||||||||
| ## Decompiling data | ||||||||||
| > [!NOTE] | ||||||||||
| > Under construction! It's not fully clear how data is decompiled, as the compiler is strict on how it orders global variables. | ||||||||||
| > Feel free to contribute to this section or provide us with more information! | ||||||||||
|
|
||||||||||
| Other than `.text` and `.init` which contain code, there are the following sections for data: | ||||||||||
| - `.rodata`: Global or static constants | ||||||||||
| - `.data`: Global or static variables | ||||||||||
| - `.bss`/`.sbss`: Global or static uninitialized variables | ||||||||||
|
Mityno marked this conversation as resolved.
Outdated
|
||||||||||
|
|
||||||||||
| You can see examples of these data sections in the [compilation section in `build_system.md`](/docs/build_system.md#compiling-code). | ||||||||||
|
|
||||||||||
| ## The Ghidra project | ||||||||||
| We use a shared Ghidra project to analyze the game and decompile functions. To gain access to the project, install | ||||||||||
| [Ghidra version 11.2.1](https://github.com/NationalSecurityAgency/ghidra/releases/tag/Ghidra_11.2.1_build) and request access | ||||||||||
| from @aetias on Discord. | ||||||||||
Uh oh!
There was an error while loading. Please reload this page.