1
0
mirror of https://github.com/zeldaret/oot.git synced 2024-09-21 12:54:51 +00:00
oot/tools/fado/z64_relocation_section_format.md
EllipticEllipsis 6fd0f3cff2
git subrepo pull --force tools/fado (#1138)
subrepo:
  subdir:   "tools/fado"
  merged:   "a0fa82808"
upstream:
  origin:   "git@github.com:EllipticEllipsis/fado.git"
  branch:   "master"
  commit:   "a0fa82808"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo.git"
  commit:   "2f68596"
2022-02-11 15:09:27 -05:00

4.9 KiB

Zelda 64 overlay relocation section format

Both Zelda 64 titles use the same custom dynamic overlay relocation format, which is

All elements are 4 bytes in width.

Offset Description Notes
0x00 Size of overlay .text section
0x04 Size of overlay .data section
0x08 Size of overlay .rodata section
0x0C Size of overlay .bss section
0x10 Number of relocation entries
0x14- Relocation entries Must be sorted in increasing order by section, then offset
...
(zero padding of section to 0x10 alignment)
End - 4 Size of overlay .ovl section Also the offset from the end of the rest of the section sizes

Relocation entries

The only element that is not a single number are the relocation entries, which are bitpacked as follows:

0x1F..0x1E 0x1D..0x18 0x17..0x0
ss tttttt oooo oooo oooo oooo oooo oooo
Section Type Offset

Section

2 bits. Section where the instruction or data to be relocated is.

Value Section
1 .text
2 .data
3 .rodata

Type

6 bits. Four types of standard MIPS relocation are supported. They use the same values as the standard elf formats:

Value Type Description
2 R_MIPS_32 A full word address (such as a pointer in data or an address in a jumptable)
4 R_MIPS_26 26-bit direct relocation, for a J-type instruction
5 R_MIPS_HI16 High 16-bit, generally the top half of an address in an li/lui
6 R_MIPS_LO16 Low 16-bit, the bottom half of an address, such as in an addiu,ori,lh, etc.

Offset

0x18 bits. Offset in bytes from the start of the section where the relocation occurs.

Example

0x82000A30 = 0b1000 0010 0000 0000 0000 1010 0011 0000

This splits as

0b10, 0b000010, 0b0000 0000 0000 1010 0011 0000 = 0x2, 0x2, 0xA30

i.e. a full-word (R_MIPS_32) relocation at .data + 0xA30.

Compiler compatibility

HI/LO

The MIPS ELF format standard specifies that each LO be preceded by a unique HI associated to it (but multiple LOs may associate to the same HI), and the overlay relocation function acts based on this assumption.

IDO complies with this consistently, but GCC in its wisdom decided that it was appropriate to violate this by default, and allow multiple HIs to associate to the same LO. GCC also likes to reorder relocations in the .rel.* sections.

To prevent these you must pass both of the following compiler flags:

-mno-explicit-relocs -mno-split-addresses

(GNU do not document this behaviour themselves, although apparently it has been present for many years. It is also not even consistent between versions.)

rodata

It should be clear from the description above that this system expects a single rodata section. Again, IDO will only ever produce one rodata section, but GCC will produce several, albeit only one containing relocatable rodata: the others are for "mergeable" strings and floats/doubles. The cleanest way to deal with this is to pass

-fno-merge-constants

which will force GCC to generate a single combined rodata section. If, however, you really think you will benefit from merging constants, to obtain relocations correctly offset from the start of the entire rodata section(s), the actual .rodata section must be explicitly linked first.

For multi-file overlays, the situation is even more complicated, and Fado gets around this by adding up the sizes of all the rodata sections so that we may simply place one files' in one chunk: this means that each individual .rodata section should be linked before the others, i.e.

.text(1)
.text(2)
.data(1)
.data(2)
.rodata(1)
.rodata.cst4(1)
...
.rodata(2)
.rodata.cst4(2)

or similar.