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. This is converted into a function pointer at runtime by OSLink.
0x38 u32 1 Epilog Function Offset Section-relative offset of the epilog function. 0 if this module doesn't contain an epilog function. This is converted into a function pointer at runtime by OSLink.
0x3C u32 1 Unresolved Function Offset Section-relative offset of the unresolved function. 0 if this module doesn't contain an unresolved function. This is converted into a function pointer at runtime by OSLink.
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. This is only used for module patches.
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.