Custom agent imported from jaytheham/body-harvest-decompilation (
.github/agents/Data.agent.md). Copyright stays with the author.
Overview
This is a matching decompilation project for Body Harvest (N64). The goal is to create C code that compiles to the exact same assembly as the original game ROM.
You will be tasked with updating the yaml and C files so .data and .rodata sections are defined in C code and compile to match the original ROM. C89 code, compiler IDO 5.3 -O2 -mips2 -32.
Project Structure
asm/nonmatchings: Readonly, git-ignored - target assembly of unmatched functions.asm/matchings: Readonly, git-ignored - target assembly of functions with a matching C implementation, for reference.src.us/: C source files.include/: Header files for variables, functions, and structs.build/: Readonly, git-ignored - compiled object files and the final ROM image.bh.ld: Readonly, git-ignored - Linker script defining the layout of the ROM, including the .data and .rodata sections.baserom.us.z64Readonly, git-ignored - original ROM image, used as a reference for the target assembly and data.bh.us.yaml- Defines the layout of sections within the ROM, including the .data and .rodata sections.
Tools
These powershell tools exist to assist you:
- Extract the data from the original ROM and rebuild the linker script:
.\tools\extract.ps1. This will read the layout defined inbh.us.yaml. - Build the ROM:
.\tools\make.ps1. Important: This is the only correct way to build your C code, it ensures all symbols are correctly linked.
Workflow
- You will be given a ROM address section to work on e.g.
- [0x14AA40, bin]. - Search for variables defined in this section e.g.
D_8013BA94_14AA44, variables are namedD_<RAM address>_<ROM address>or sometimes without the ROM addressD_<RAM address>. There may be many variables defined in the same section, so you should focus on the first few variables in the section to start with. - Search for references to these variables in .c and .s files to determine which C file this data belongs to. Note that some of the original C files may currently be combined into a single file, so you may need to split an existing C file into multiple files to match the original layout of the ROM.
Not all functions in C are decompiled yet so you may need to search for variable references in the .s assembly files in
asm/nonmatchingsto determine the correct C file. - Update the yaml file to define the target section e.g.
- [0x14A8A0, .data, overlay_gameplay/outside/F6A50], the third argument of the section must be the path of the c section this data belongs to. If the targetbinsection appears to contain data for multiple C files split it into multiple sections - leaving a un-namedbinsection for the remaining data - and focus on just the data from the first section. Note that data sections are always aligned to 0x10 bytes. - Add definitions for these variables in the appropriate existing C file, make sure to use the correct types as determined by definitions in
variables.us.hand load/store instructions in.sfiles, order, and initial values as in the original ROM. Define the variables before the first function in the C file. - Run the extract script to rebuild the linker script from the changed yaml file, then run the build script to compile the ROM. You must run extract any time the yaml file is changed, and build after making code changes.
- Compare the built ROM against the original ROM and identify any differences in the output for the data section. You can also look at the linker script to see which order it is putting the sections into, but you cannot change the order of sections in the linker script as it is auto-generated, you must change the yaml and C code to match the original ROM.
Then continue updating the C code to fix any differences in the output until the built ROM matches the original ROM, this may require changing the types of variables, their order, their initial values, or the layout of data sections. Note the linker script adds padding between sections in some circumstances.
Update any D_<RAM address> style variables to D_<RAM address>_<ROM address> style as you work on them.
There are some already decompiled data sections in the yaml for reference.
When working with .rodata sections:
all rodata symbols need to be declared as const.
single f32 & f64 values also need to be defined as an array or the compiler doesnt treat them as const.
identify and name jump tables, see jtbl_801411A8_150158 as an example
Once you start working on rodata, any remaining data that hasn't been extracted to a C file needs to be defined as rodatabin instead of bin in the yaml so that the linker will place it in the correct location.
Do not cheat by adding all the remaining bin data as a variable in the last defined non-bin section's C file, you must add variables to the C files which reference them, and split the yaml sections so each data section corresponds to the correct C file as needed to match the original ROM layout.
Don't skip any data, if unable to determine where some data belongs, add it as a variable in the first C file you find with a reference to the same section of data, and then move it later if needed.
If the build script returns build/bh.us.z64: OK then the built ROM perfectly matches the original ROM.