REL (File Format)
The REL format is the file format for relocatable modules for GameCube games. This is essentially the GameCube's equivalent of a DLL file, allowing for code modules to be dynamically linked at runtime and unlinked when not in use to save memory.
Format
Header
Offset | Type | Count | Name | Notes | V1 | V2 | V3 |
---|---|---|---|---|---|---|---|
0x0 | u32 | 1 | Module ID | Unique ID identifying this module. The main DOL file is module 0, so REL modules will start from ID 1. | ✔ | ✔ | ✔ |
0x4 | u32 | 1 | Next Module Link | Pointer to the next module, forming a linked list. Always 0, filled in at runtime. | ✔ | ✔ | ✔ |
0x8 | u32 | 1 | Previous Module Link | Pointer to the previous module, forming a linked list. Always 0, filled in at runtime. | ✔ | ✔ | ✔ |
0xC | u32 | 1 | Section Count | Number of sections contained in the file. | ✔ | ✔ | ✔ |
0x10 | u32 | 1 | Section Info Offset | Offset to the section info table. | ✔ | ✔ | ✔ |
0x14 | u32 | 1 | Module Name Offset | Offset to the module name. Can be 0, in which case this module doesn't contain a name string. | ✔ | ✔ | ✔ |
0x18 | u32 | 1 | Module Name Size | Size of the module name string. | ✔ | ✔ | ✔ |
0x1C | u32 | 1 | Module Version | Module version number. Can be 1, 2, or 3. | ✔ | ✔ | ✔ |
0x20 | u32 | 1 | BSS Size | Size of the BSS section, which is allocated at runtime (not included in the file). | ✔ | ✔ | ✔ |
0x24 | u32 | 1 | Relocation Table Offset | Absolute offset of the relocation table. | ✔ | ✔ | ✔ |
0x28 | u32 | 1 | Import Table Offset | Absolute offset of the import table. | ✔ | ✔ | ✔ |
0x2C | u32 | 1 | Import Table Size | Size of the import table. | ✔ | ✔ | ✔ |
0x30 | u8 | 1 | Prolog Section | Section index of the prolog function, which is called when the module is linked. 0 if this module doesn't contain a prolog function. | ✔ | ✔ | ✔ |
0x31 | u8 | 1 | Epilog Section | Section index of the epilog function, which is called when the module is unlinked. 0 if this module doesn't contain an epilog function. | ✔ | ✔ | ✔ |
0x32 | u8 | 1 | Unresolved Section | Section index of the unresolved function, which is called if the module attempts to call an unlinked function. 0 if this module doesn't contain an unresolved function. | ✔ | ✔ | ✔ |
0x33 | u8 | 1 | Padding | Padding to align the file to 4 bytes. | ✔ | ✔ | ✔ |
0x34 | u32 | 1 | Prolog Function Offset | Section-relative offset of the prolog function. 0 if this module doesn't contain a prolog function. | ✔ | ✔ | ✔ |
0x38 | u32 | 1 | Epilog Function Offset | Section-relative offset of the epilog function. 0 if this module doesn't contain an epilog function. | ✔ | ✔ | ✔ |
0x3C | u32 | 1 | Unresolved Function Offset | Section-relative offset of the unresolved function. 0 if this module doesn't contain an unresolved function. | ✔ | ✔ | ✔ |
0x40 | u32 | 1 | Module Alignment | ✖ | ✔ | ✔ | |
0x44 | u32 | 1 | BSS Alignment | ✖ | ✔ | ✔ | |
0x48 | u32 | 1 | Unknown | ✖ | ✖ | ✔ |
Section Info Table
This data is pointed to by the Section Info Offset value in the header. It specifies the layout of the file. The structure loops once for each section in the file, as specified by the Section Count in the header. Any compiler-generated sections that are unused (such as the symbol table or the section name table) are nulled out and listed with a size/offset of 0. The first section is always null. The BSS section is listed with a valid size but an offset of 0 (as the BSS section is not included in the file, but instead has space allocated at runtime).
Offset | Type | Count | Name | Notes |
---|---|---|---|---|
0x0 | u32 | 1 | Offset | Absolute offset of the section. The 0x1 bit is toggled to indicate whether this section contains executable code. AND out that bit to get the correct offset. |
0x4 | u32 | 1 | Size | Size of the section. |
0x8 | End of section info |
Import Table
This data is pointed to by the Import Table Offset value in the header. You can get the number of imports by dividing the Import Table Size value by 0x8 (the size of one import entry). An import is basically an offset into the relocation table, pointing to the relocations used for a specific module.
Offset | Type | Count | Name | Notes |
---|---|---|---|---|
0x0 | u32 | 1 | Module ID | The module ID for this import. A module ID of 0 refers to the main DOL executable. |
0x4 | u32 | 1 | Relocations Offset | Absolute offset of the relocations for the import, pointing into the relocation table. |
0x8 | End of import |
Relocation Table
This data is pointed to by the Relocation Table Offset value in the header. Since modules have space allocated at runtime and therefore do not have a fixed memory address, the relocations table is needed to ensure all data and function addresses in the REL are correct; this includes both symbols within the REL itself, which don't have a fixed address until the REL is linked in, and symbols within the DOL, which need corrections due to the usage of relative offsets in branch instructions. The relocation table describes the location of every instruction that needs to be patched, and how to patch it.
There are multiple distinct groups of relocations, with each one being pointed to by an entry in the import table. To read the relocations for a given module, you need to iterate over all relocation entries until you hit an R_DOLPHIN_END directive. Each relocation is 0x8 bytes.
Offset | Type | Count | Name | Notes |
---|---|---|---|---|
0x0 | u16 | 1 | Offset | Offset of this relocation, relative to the offset of the last relocation entry. (Basically, for each entry you skip ahead by this many bytes.) |
0x2 | u8 | 1 | Relocation Type | Type of the relocation. See the below table for a list of possible types. |
0x3 | u8 | 1 | Section Index | The section index of the symbol being patched to. |
0x4 | u32 | 1 | Symbol Offset | The section-relative offset of the symbol being patched to. For module patches, add this offset to the address of the section. For DOL patches, this offset is the full raw address, and Section Index is unused. |
0x8 | End of relocation |
These are the possible relocation types. The "used" column indicates whether this relocation type is used by any of the modules in any of Retro's games.
Value | Name | Description | Used? |
---|---|---|---|
0 | R_PPC_NONE | Do nothing. | ✖ |
1 | R_PPC_ADDR32 | Write the full, 32-bit address of the symbol. | ✔ |
2 | R_PPC_ADDR24 | Write the 24-bit address of the symbol. Leave the existing value of the bottom two bits intact. | ✖ |
3 | R_PPC_ADDR16 | Write the 16-bit address of the symbol. | ✖ |
4 | R_PPC_ADDR16_LO | Write the low 16 bits of the symbol address. | ✔ |
5 | R_PPC_ADDR16_HI | Write the high 16 bits of the symbol address. | ✔ |
6 | R_PPC_ADDR16_HA | Write the high 16 bits of the symbol address, plus 0x10000. This is used for cases where the bottom half is >= 0x8000, in which case a subtract operation is used to load the lower half of the address. | ✔ |
7 | R_PPC_ADDR14 | Write the 14-bit address of the symbol. Leave the existing value of the bottom two bits intact. This is used for conditional branch instructions. | ✖ |
8 | R_PPC_ADDR14_BRTAKEN | Write the 14-bit address of the symbol. Leave the existing value of the bottom two bits intact. Note: Needs a proper check on differences between this and ADDR14 | ✖ |
9 | R_PPC_ADDR14_BRNTAKEN | Write the 14-bit address of the symbol. Leave the existing value of the bottom two bits intact. Note: Needs a proper check on differences between this and ADDR14 | ✖ |
10 | R_PPC_REL24 | Write a 24-bit offset from the address of this instruction to the address of the symbol. This is used for branch instructions. | ✔ |
11 | R_PPC_REL14 | Write a 14-bit offset from the address of this instruction to the address of the symbol. | ✖ |
201 | R_DOLPHIN_NOP | Do nothing. This is used when the offset from one relocation to the next is larger than 0xFFFF bytes. | ✔ |
202 | R_DOLPHIN_SECTION | Change the current section to Section Index and reset the current offset to 0. | ✔ |
203 | R_DOLPHIN_END | This marks the end of the relocations for this import. | ✔ |