1
0
Fork 0
mirror of https://github.com/zeldaret/oot.git synced 2024-11-10 19:20:13 +00:00

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"
This commit is contained in:
EllipticEllipsis 2022-02-11 20:09:27 +00:00 committed by GitHub
parent eadc477187
commit 6fd0f3cff2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 977 additions and 34 deletions

View file

@ -6,7 +6,7 @@
[subrepo] [subrepo]
remote = git@github.com:EllipticEllipsis/fado.git remote = git@github.com:EllipticEllipsis/fado.git
branch = master branch = master
commit = 43c339a597dfd308f14540b1151dc289f6cdb786 commit = a0fa828089353ba48e378b281c23100c247b1c92
parent = a5ed690de0e30b4a0355481bbabecb83b99bc102 parent = eadc477187888e1ae078d021b4a00b1366f0c9a4
method = merge method = merge
cmdver = 0.4.3 cmdver = 0.4.3

View file

@ -1,6 +1,7 @@
DEBUG ?= 0 DEBUG ?= 0
LLD ?= 0 LLD ?= 0
ASAN ?= 0 ASAN ?= 0
EXPERIMENTAL?= 0
ELF := fado.elf ELF := fado.elf
@ -30,6 +31,10 @@ ifneq ($(LD),ld)
endif endif
endif endif
ifneq ($(EXPERIMENTAL),0)
CFLAGS += -DEXPERIMENTAL
endif
# GCC is too stupid to be trusted with these warnings # GCC is too stupid to be trusted with these warnings
ifeq ($(CC),gcc) ifeq ($(CC),gcc)
WARNINGS += -Wno-implicit-fallthrough -Wno-maybe-uninitialized WARNINGS += -Wno-implicit-fallthrough -Wno-maybe-uninitialized
@ -52,7 +57,7 @@ clean:
$(RM) -r build $(ELF) $(RM) -r build $(ELF)
format: format:
clang-format-11 -i $(C_FILES) $(H_FILES) clang-format-11 -i $(C_FILES) $(H_FILES) lib/fairy/*
.PHONY: all clean format .PHONY: all clean format

View file

@ -3,9 +3,75 @@
<!-- Nice backronym... --> <!-- Nice backronym... -->
Contains Contains
- **Fairy** a library for reading N64 ELF files (big-endian) - **Fairy** a library for reading relocatable MIPS ELF object files (big-endian, suitable for Nintendo 64 games)
- **Fado** a program for generating the `.ovl`/relocation section for Zelda64 overlay files - **Fado** a program for generating the `.ovl`/relocation section for Zelda64 overlay files
- **Mido** an automatic dependency file generator
Compatible with both IDO and GCC. Compatible with both IDO and GCC (although [see below](N_B)).
Format is the standard .ovl section, with the relocs divided by section. It will also print the name the associated variable if it can find it in the ELF (for IDO, this is only if it is not static, whereas GCC sometimes seems to retain all of them). Format is the standard "Zelda64" .ovl section, with the relocs divided by section, as used by
- *The Legend of Zelda: Ocarina of Time* (all Nintendo 64/Gamecube/iQue releases)
- *The Legend of Zelda: Majora's Mask* (all Nintendo 64/Gamecube releases)
In theory it will also work for other Nintendo 64 games that use this system, such as *Yoshi's Story*, but has yet to be tested with these.
## Explanation
The overlay relocation sections used by Zelda64 is described [here](z64_relocation_section_format.md). Fado will produce a `.ovl` section compatible with this format, although as noted there, some compilers need persuasion to produce compatible objects.
## How to use
Compile by running `make`.
A standalone invocation of Fado would look something like
```sh
./fado.elf z_en_hs2.o -n ovl_En_Hs2 -o ovl_En_Hs2_reloc.s
```
This takes as input the compiled object file from the C file (e.g. [this one](https://github.com/zeldaret/oot/blob/eadc477187888e1ae078d021b4a00b1366f0c9a4/src/overlays/actors/ovl_En_Hs2/z_en_hs2.c)), the name of the overlay (`ovl_En_Hs2`) and will output an assembly file `ovl_En_Hs2_reloc.s` containing the relocation section. An example output is included in the repo [here](ovl_En_Hs_reloc.s). Fado will print information from the object file to assist with debugging, by splitting relocs by section, and for each, printing the type, offset, and associated symbol (or section if static):
```mips
# TEXT RELOCS
.word 0x45000084 # R_MIPS_HI16 0x000084 .data
.word 0x4600008C # R_MIPS_LO16 0x00008C .data
.word 0x450000B4 # R_MIPS_HI16 0x0000B4 .rodata
.word 0x460000BC # R_MIPS_LO16 0x0000BC .rodata
.word 0x450000C0 # R_MIPS_HI16 0x0000C0 func_80A6F1A4
.word 0x460000C4 # R_MIPS_LO16 0x0000C4 func_80A6F1A4
```
If invoking in a makefile, you will probably want to generate these from a predefined filelist, and with the appropriate dependencies. [The Ocarina of Time decomp repository](http://github.com/zeldaret/oot) contains an example of how to do this using a supplementary program to parse the `spec` format.
More information can be obtained by running
```sh
./fado.elf --help
```
which contains information on the various options, such as automatic dependency file generation, etc.
## N.B.
- Fado expects the linker script to output symbols for the section sizes, and for them to be declared separately, in the format
```
_SEGMENTNAMESegmentSECTIONSize
```
e.g.
```
_ovl_En_Hs2SegmentTextSize
```
etc.
- By default Fado expects sections to be 0x10-aligned, as is usual for IDO. Some versions of GCC like to align sections to smaller widths, which Fado will handle appropriately, but the linker script must also address this, and at least the default settings seem unable to size the sections correctly due ot placing `fill`s in the wrong places. For now it is recommended to manually align sections to 0x10 if the compiler does not automatically.
- The experimental flag `--alignment`/`-a` can be passed to Fado, and it will use the alignment declared by each section in the elf file instead of padding them to 0x10 bytes, It should be noted this option has not been fully tested because currently we don't have any linker script tool that can properly address the incorrect placing of `fill`s. Fado must be rebuilt passing `EXPERIMENTAL=1` to be able to use this flag.
- To prevent GCC producing non-compliant HI/LOs, you must pass *both* of the following compiler flags: `-mno-explicit-relocs -mno-split-addresses`. See [here](z64_relocation_section_format.md#hilo) for more details.
- It is recommended, though not strictly required, that `-fno-merge-constants` is used for GCC, to avoid unpredictable section sizes, and comply with the Zelda64 relocation format's expectation of at most one rodata section. See [here](z64_relocation_section_format.md#rodata) for more details.

View file

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
for i in "${@:2}" for i in "${@:2}"
do do

View file

@ -21,4 +21,5 @@ extern size_t helpTextWidth;
extern size_t helpDtIndent; extern size_t helpDtIndent;
extern size_t helpDdIndent; extern size_t helpDdIndent;
void Help_PrintHelp(const char* prologue, size_t posArgCount, const PosArgInfo* posArgInfo, size_t optCount, const OptInfo* optInfo, const char* epilogue); void Help_PrintHelp(const char* prologue, size_t posArgCount, const PosArgInfo* posArgInfo, size_t optCount,
const OptInfo* optInfo, const char* epilogue);

View file

@ -8,6 +8,8 @@
#define ARRAY_COUNT(arr) (signed long long)(sizeof(arr) / sizeof(arr[0])) #define ARRAY_COUNT(arr) (signed long long)(sizeof(arr) / sizeof(arr[0]))
#define ARRAY_COUNTU(arr) (unsigned long long)(sizeof(arr) / sizeof(arr[0])) #define ARRAY_COUNTU(arr) (unsigned long long)(sizeof(arr) / sizeof(arr[0]))
#define ALIGN(val, align) (((val) + (align - 1)) / (align) * (align))
/* Mathematical macros */ /* Mathematical macros */
#define ABS(x) ((x) < 0 ? -(x) : (x)) #define ABS(x) ((x) < 0 ? -(x) : (x))

View file

@ -0,0 +1,651 @@
/* This file contains enough of the ELF format definitions for MIPS to enable Fairy and Fado to work. More may need to
* be added later. The content is excerpted directly from elf.h from the GNU C Library, and therefore: */
/* Copyright (C) 1995-2020 Free Software Foundation, Inc. */
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#ifndef MIPS_ELF_H
#define MIPS_ELF_H
#include <stdint.h>
/* Type for a 16-bit quantity. */
typedef uint16_t Elf32_Half;
/* Types for signed and unsigned 32-bit quantities. */
typedef uint32_t Elf32_Word;
typedef int32_t Elf32_Sword;
/* Types for signed and unsigned 64-bit quantities. */
typedef uint64_t Elf32_Xword;
typedef int64_t Elf32_Sxword;
/* Type of addresses. */
typedef uint32_t Elf32_Addr;
/* Type of file offsets. */
typedef uint32_t Elf32_Off;
/* Type for section indices, which are 16-bit quantities. */
typedef uint16_t Elf32_Section;
/* The ELF file header. This appears at the start of every ELF file. */
#define EI_NIDENT (16)
typedef struct {
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
Elf32_Half e_type; /* Object file type */
Elf32_Half e_machine; /* Architecture */
Elf32_Word e_version; /* Object file version */
Elf32_Addr e_entry; /* Entry point virtual address */
Elf32_Off e_phoff; /* Program header table file offset */
Elf32_Off e_shoff; /* Section header table file offset */
Elf32_Word e_flags; /* Processor-specific flags */
Elf32_Half e_ehsize; /* ELF header size in bytes */
Elf32_Half e_phentsize; /* Program header table entry size */
Elf32_Half e_phnum; /* Program header table entry count */
Elf32_Half e_shentsize; /* Section header table entry size */
Elf32_Half e_shnum; /* Section header table entry count */
Elf32_Half e_shstrndx; /* Section header string table index */
} Elf32_Ehdr;
/* Fields in the e_ident array. The EI_* macros are indices into the
array. The macros under each EI_* macro are the values the byte
may have. */
#define EI_MAG0 0 /* File identification byte 0 index */
#define ELFMAG0 0x7f /* Magic number byte 0 */
#define EI_MAG1 1 /* File identification byte 1 index */
#define ELFMAG1 'E' /* Magic number byte 1 */
#define EI_MAG2 2 /* File identification byte 2 index */
#define ELFMAG2 'L' /* Magic number byte 2 */
#define EI_MAG3 3 /* File identification byte 3 index */
#define ELFMAG3 'F' /* Magic number byte 3 */
/* Conglomeration of the identification bytes, for easy testing as a word. */
#define ELFMAG "\177ELF"
#define SELFMAG 4
#define EI_CLASS 4 /* File class byte index */
#define ELFCLASSNONE 0 /* Invalid class */
#define ELFCLASS32 1 /* 32-bit objects */
#define ELFCLASS64 2 /* 64-bit objects */
#define ELFCLASSNUM 3
#define EI_DATA 5 /* Data encoding byte index */
#define ELFDATANONE 0 /* Invalid data encoding */
#define ELFDATA2LSB 1 /* 2's complement, little endian */
#define ELFDATA2MSB 2 /* 2's complement, big endian */
#define ELFDATANUM 3
#define EI_VERSION 6 /* File version byte index */
/* Value must be EV_CURRENT */
#define EI_OSABI 7 /* OS ABI identification */
#define ELFOSABI_NONE 0 /* UNIX System V ABI */
#define ELFOSABI_SYSV 0 /* Alias. */
#define ELFOSABI_HPUX 1 /* HP-UX */
#define ELFOSABI_NETBSD 2 /* NetBSD. */
#define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */
#define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */
#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */
#define ELFOSABI_AIX 7 /* IBM AIX. */
#define ELFOSABI_IRIX 8 /* SGI Irix. */
#define ELFOSABI_FREEBSD 9 /* FreeBSD. */
#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */
#define ELFOSABI_MODESTO 11 /* Novell Modesto. */
#define ELFOSABI_OPENBSD 12 /* OpenBSD. */
#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */
#define ELFOSABI_ARM 97 /* ARM */
#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
#define EI_ABIVERSION 8 /* ABI version */
#define EI_PAD 9 /* Byte index of padding bytes */
/* Legal values for e_type (object file type). */
#define ET_NONE 0 /* No file type */
#define ET_REL 1 /* Relocatable file */
#define ET_EXEC 2 /* Executable file */
#define ET_DYN 3 /* Shared object file */
#define ET_CORE 4 /* Core file */
#define ET_NUM 5 /* Number of defined types */
#define ET_LOOS 0xfe00 /* OS-specific range start */
#define ET_HIOS 0xfeff /* OS-specific range end */
#define ET_LOPROC 0xff00 /* Processor-specific range start */
#define ET_HIPROC 0xffff /* Processor-specific range end */
/* Legal values for e_machine (architecture). */
#define EM_NONE 0 /* No machine */
#define EM_M32 1 /* AT&T WE 32100 */
#define EM_SPARC 2 /* SUN SPARC */
#define EM_386 3 /* Intel 80386 */
#define EM_68K 4 /* Motorola m68k family */
#define EM_88K 5 /* Motorola m88k family */
#define EM_IAMCU 6 /* Intel MCU */
#define EM_860 7 /* Intel 80860 */
#define EM_MIPS 8 /* MIPS R3000 big-endian */
#define EM_S370 9 /* IBM System/370 */
#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */
/* reserved 11-14 */
#define EM_PARISC 15 /* HPPA */
/* reserved 16 */
#define EM_VPP500 17 /* Fujitsu VPP500 */
#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
#define EM_960 19 /* Intel 80960 */
#define EM_PPC 20 /* PowerPC */
#define EM_PPC64 21 /* PowerPC 64-bit */
#define EM_S390 22 /* IBM S390 */
#define EM_SPU 23 /* IBM SPU/SPC */
/* reserved 24-35 */
#define EM_V800 36 /* NEC V800 series */
#define EM_FR20 37 /* Fujitsu FR20 */
#define EM_RH32 38 /* TRW RH-32 */
#define EM_RCE 39 /* Motorola RCE */
#define EM_ARM 40 /* ARM */
#define EM_FAKE_ALPHA 41 /* Digital Alpha */
#define EM_SH 42 /* Hitachi SH */
#define EM_SPARCV9 43 /* SPARC v9 64-bit */
#define EM_TRICORE 44 /* Siemens Tricore */
#define EM_ARC 45 /* Argonaut RISC Core */
#define EM_H8_300 46 /* Hitachi H8/300 */
#define EM_H8_300H 47 /* Hitachi H8/300H */
#define EM_H8S 48 /* Hitachi H8S */
#define EM_H8_500 49 /* Hitachi H8/500 */
#define EM_IA_64 50 /* Intel Merced */
#define EM_MIPS_X 51 /* Stanford MIPS-X */
#define EM_COLDFIRE 52 /* Motorola Coldfire */
#define EM_68HC12 53 /* Motorola M68HC12 */
#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator */
#define EM_PCP 55 /* Siemens PCP */
#define EM_NCPU 56 /* Sony nCPU embeeded RISC */
#define EM_NDR1 57 /* Denso NDR1 microprocessor */
#define EM_STARCORE 58 /* Motorola Start*Core processor */
#define EM_ME16 59 /* Toyota ME16 processor */
#define EM_ST100 60 /* STMicroelectronic ST100 processor */
#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam */
#define EM_X86_64 62 /* AMD x86-64 architecture */
#define EM_PDSP 63 /* Sony DSP Processor */
#define EM_PDP10 64 /* Digital PDP-10 */
#define EM_PDP11 65 /* Digital PDP-11 */
#define EM_FX66 66 /* Siemens FX66 microcontroller */
#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */
#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */
#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */
#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */
#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */
#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */
#define EM_SVX 73 /* Silicon Graphics SVx */
#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */
#define EM_VAX 75 /* Digital VAX */
#define EM_CRIS 76 /* Axis Communications 32-bit emb.proc */
#define EM_JAVELIN 77 /* Infineon Technologies 32-bit emb.proc */
#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */
#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */
#define EM_MMIX 80 /* Donald Knuth's educational 64-bit proc */
#define EM_HUANY 81 /* Harvard University machine-independent object files */
#define EM_PRISM 82 /* SiTera Prism */
#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */
#define EM_FR30 84 /* Fujitsu FR30 */
#define EM_D10V 85 /* Mitsubishi D10V */
#define EM_D30V 86 /* Mitsubishi D30V */
#define EM_V850 87 /* NEC v850 */
#define EM_M32R 88 /* Mitsubishi M32R */
#define EM_MN10300 89 /* Matsushita MN10300 */
#define EM_MN10200 90 /* Matsushita MN10200 */
#define EM_PJ 91 /* picoJava */
#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */
#define EM_ARC_COMPACT 93 /* ARC International ARCompact */
#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */
#define EM_VIDEOCORE 95 /* Alphamosaic VideoCore */
#define EM_TMM_GPP 96 /* Thompson Multimedia General Purpose Proc */
#define EM_NS32K 97 /* National Semi. 32000 */
#define EM_TPC 98 /* Tenor Network TPC */
#define EM_SNP1K 99 /* Trebia SNP 1000 */
#define EM_ST200 100 /* STMicroelectronics ST200 */
#define EM_IP2K 101 /* Ubicom IP2xxx */
#define EM_MAX 102 /* MAX processor */
#define EM_CR 103 /* National Semi. CompactRISC */
#define EM_F2MC16 104 /* Fujitsu F2MC16 */
#define EM_MSP430 105 /* Texas Instruments msp430 */
#define EM_BLACKFIN 106 /* Analog Devices Blackfin DSP */
#define EM_SE_C33 107 /* Seiko Epson S1C33 family */
#define EM_SEP 108 /* Sharp embedded microprocessor */
#define EM_ARCA 109 /* Arca RISC */
#define EM_UNICORE 110 /* PKU-Unity & MPRC Peking Uni. mc series */
#define EM_EXCESS 111 /* eXcess configurable cpu */
#define EM_DXP 112 /* Icera Semi. Deep Execution Processor */
#define EM_ALTERA_NIOS2 113 /* Altera Nios II */
#define EM_CRX 114 /* National Semi. CompactRISC CRX */
#define EM_XGATE 115 /* Motorola XGATE */
#define EM_C166 116 /* Infineon C16x/XC16x */
#define EM_M16C 117 /* Renesas M16C */
#define EM_DSPIC30F 118 /* Microchip Technology dsPIC30F */
#define EM_CE 119 /* Freescale Communication Engine RISC */
#define EM_M32C 120 /* Renesas M32C */
/* reserved 121-130 */
#define EM_TSK3000 131 /* Altium TSK3000 */
#define EM_RS08 132 /* Freescale RS08 */
#define EM_SHARC 133 /* Analog Devices SHARC family */
#define EM_ECOG2 134 /* Cyan Technology eCOG2 */
#define EM_SCORE7 135 /* Sunplus S+core7 RISC */
#define EM_DSP24 136 /* New Japan Radio (NJR) 24-bit DSP */
#define EM_VIDEOCORE3 137 /* Broadcom VideoCore III */
#define EM_LATTICEMICO32 138 /* RISC for Lattice FPGA */
#define EM_SE_C17 139 /* Seiko Epson C17 */
#define EM_TI_C6000 140 /* Texas Instruments TMS320C6000 DSP */
#define EM_TI_C2000 141 /* Texas Instruments TMS320C2000 DSP */
#define EM_TI_C5500 142 /* Texas Instruments TMS320C55x DSP */
#define EM_TI_ARP32 143 /* Texas Instruments App. Specific RISC */
#define EM_TI_PRU 144 /* Texas Instruments Prog. Realtime Unit */
/* reserved 145-159 */
#define EM_MMDSP_PLUS 160 /* STMicroelectronics 64bit VLIW DSP */
#define EM_CYPRESS_M8C 161 /* Cypress M8C */
#define EM_R32C 162 /* Renesas R32C */
#define EM_TRIMEDIA 163 /* NXP Semi. TriMedia */
#define EM_QDSP6 164 /* QUALCOMM DSP6 */
#define EM_8051 165 /* Intel 8051 and variants */
#define EM_STXP7X 166 /* STMicroelectronics STxP7x */
#define EM_NDS32 167 /* Andes Tech. compact code emb. RISC */
#define EM_ECOG1X 168 /* Cyan Technology eCOG1X */
#define EM_MAXQ30 169 /* Dallas Semi. MAXQ30 mc */
#define EM_XIMO16 170 /* New Japan Radio (NJR) 16-bit DSP */
#define EM_MANIK 171 /* M2000 Reconfigurable RISC */
#define EM_CRAYNV2 172 /* Cray NV2 vector architecture */
#define EM_RX 173 /* Renesas RX */
#define EM_METAG 174 /* Imagination Tech. META */
#define EM_MCST_ELBRUS 175 /* MCST Elbrus */
#define EM_ECOG16 176 /* Cyan Technology eCOG16 */
#define EM_CR16 177 /* National Semi. CompactRISC CR16 */
#define EM_ETPU 178 /* Freescale Extended Time Processing Unit */
#define EM_SLE9X 179 /* Infineon Tech. SLE9X */
#define EM_L10M 180 /* Intel L10M */
#define EM_K10M 181 /* Intel K10M */
/* reserved 182 */
#define EM_AARCH64 183 /* ARM AARCH64 */
/* reserved 184 */
#define EM_AVR32 185 /* Amtel 32-bit microprocessor */
#define EM_STM8 186 /* STMicroelectronics STM8 */
#define EM_TILE64 187 /* Tileta TILE64 */
#define EM_TILEPRO 188 /* Tilera TILEPro */
#define EM_MICROBLAZE 189 /* Xilinx MicroBlaze */
#define EM_CUDA 190 /* NVIDIA CUDA */
#define EM_TILEGX 191 /* Tilera TILE-Gx */
#define EM_CLOUDSHIELD 192 /* CloudShield */
#define EM_COREA_1ST 193 /* KIPO-KAIST Core-A 1st gen. */
#define EM_COREA_2ND 194 /* KIPO-KAIST Core-A 2nd gen. */
#define EM_ARC_COMPACT2 195 /* Synopsys ARCompact V2 */
#define EM_OPEN8 196 /* Open8 RISC */
#define EM_RL78 197 /* Renesas RL78 */
#define EM_VIDEOCORE5 198 /* Broadcom VideoCore V */
#define EM_78KOR 199 /* Renesas 78KOR */
#define EM_56800EX 200 /* Freescale 56800EX DSC */
#define EM_BA1 201 /* Beyond BA1 */
#define EM_BA2 202 /* Beyond BA2 */
#define EM_XCORE 203 /* XMOS xCORE */
#define EM_MCHP_PIC 204 /* Microchip 8-bit PIC(r) */
/* reserved 205-209 */
#define EM_KM32 210 /* KM211 KM32 */
#define EM_KMX32 211 /* KM211 KMX32 */
#define EM_EMX16 212 /* KM211 KMX16 */
#define EM_EMX8 213 /* KM211 KMX8 */
#define EM_KVARC 214 /* KM211 KVARC */
#define EM_CDP 215 /* Paneve CDP */
#define EM_COGE 216 /* Cognitive Smart Memory Processor */
#define EM_COOL 217 /* Bluechip CoolEngine */
#define EM_NORC 218 /* Nanoradio Optimized RISC */
#define EM_CSR_KALIMBA 219 /* CSR Kalimba */
#define EM_Z80 220 /* Zilog Z80 */
#define EM_VISIUM 221 /* Controls and Data Services VISIUMcore */
#define EM_FT32 222 /* FTDI Chip FT32 */
#define EM_MOXIE 223 /* Moxie processor */
#define EM_AMDGPU 224 /* AMD GPU */
/* reserved 225-242 */
#define EM_RISCV 243 /* RISC-V */
#define EM_BPF 247 /* Linux BPF -- in-kernel virtual machine */
#define EM_CSKY 252 /* C-SKY */
#define EM_NUM 253
/* Old spellings/synonyms. */
#define EM_ARC_A5 EM_ARC_COMPACT
/* If it is necessary to assign new unofficial EM_* values, please
pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
chances of collision with official or non-GNU unofficial values. */
#define EM_ALPHA 0x9026
/* Legal values for e_version (version). */
#define EV_NONE 0 /* Invalid ELF version */
#define EV_CURRENT 1 /* Current version */
#define EV_NUM 2
/* Section header. */
typedef struct {
Elf32_Word sh_name; /* Section name (string tbl index) */
Elf32_Word sh_type; /* Section type */
Elf32_Word sh_flags; /* Section flags */
Elf32_Addr sh_addr; /* Section virtual addr at execution */
Elf32_Off sh_offset; /* Section file offset */
Elf32_Word sh_size; /* Section size in bytes */
Elf32_Word sh_link; /* Link to another section */
Elf32_Word sh_info; /* Additional section information */
Elf32_Word sh_addralign; /* Section alignment */
Elf32_Word sh_entsize; /* Entry size if section holds table */
} Elf32_Shdr;
/* Special section indices. */
#define SHN_UNDEF 0 /* Undefined section */
#define SHN_LORESERVE 0xff00 /* Start of reserved indices */
#define SHN_LOPROC 0xff00 /* Start of processor-specific */
#define SHN_BEFORE 0xff00 /* Order section before all others (Solaris). */
#define SHN_AFTER 0xff01 /* Order section after all others (Solaris). */
#define SHN_HIPROC 0xff1f /* End of processor-specific */
#define SHN_LOOS 0xff20 /* Start of OS-specific */
#define SHN_HIOS 0xff3f /* End of OS-specific */
#define SHN_ABS 0xfff1 /* Associated symbol is absolute */
#define SHN_COMMON 0xfff2 /* Associated symbol is common */
#define SHN_XINDEX 0xffff /* Index is in extra table. */
#define SHN_HIRESERVE 0xffff /* End of reserved indices */
/* Legal values for sh_type (section type). */
#define SHT_NULL 0 /* Section header table entry unused */
#define SHT_PROGBITS 1 /* Program data */
#define SHT_SYMTAB 2 /* Symbol table */
#define SHT_STRTAB 3 /* String table */
#define SHT_RELA 4 /* Relocation entries with addends */
#define SHT_HASH 5 /* Symbol hash table */
#define SHT_DYNAMIC 6 /* Dynamic linking information */
#define SHT_NOTE 7 /* Notes */
#define SHT_NOBITS 8 /* Program space with no data (bss) */
#define SHT_REL 9 /* Relocation entries, no addends */
#define SHT_SHLIB 10 /* Reserved */
#define SHT_DYNSYM 11 /* Dynamic linker symbol table */
#define SHT_INIT_ARRAY 14 /* Array of constructors */
#define SHT_FINI_ARRAY 15 /* Array of destructors */
#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */
#define SHT_GROUP 17 /* Section group */
#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */
#define SHT_NUM 19 /* Number of defined types. */
#define SHT_LOOS 0x60000000 /* Start OS-specific. */
#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */
#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */
#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */
#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */
#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */
#define SHT_SUNW_move 0x6ffffffa
#define SHT_SUNW_COMDAT 0x6ffffffb
#define SHT_SUNW_syminfo 0x6ffffffc
#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */
#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */
#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */
#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */
#define SHT_HIOS 0x6fffffff /* End OS-specific type */
#define SHT_LOPROC 0x70000000 /* Start of processor-specific */
#define SHT_HIPROC 0x7fffffff /* End of processor-specific */
#define SHT_LOUSER 0x80000000 /* Start of application-specific */
#define SHT_HIUSER 0x8fffffff /* End of application-specific */
/* Symbol table entry. */
typedef struct {
Elf32_Word st_name; /* Symbol name (string tbl index) */
Elf32_Addr st_value; /* Symbol value */
Elf32_Word st_size; /* Symbol size */
unsigned char st_info; /* Symbol type and binding */
unsigned char st_other; /* Symbol visibility */
Elf32_Section st_shndx; /* Section index */
} Elf32_Sym;
/* How to extract and insert information held in the st_info field. */
#define ELF32_ST_BIND(val) (((unsigned char)(val)) >> 4)
#define ELF32_ST_TYPE(val) ((val)&0xf)
#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type)&0xf))
/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */
#define ELF64_ST_BIND(val) ELF32_ST_BIND(val)
#define ELF64_ST_TYPE(val) ELF32_ST_TYPE(val)
#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO((bind), (type))
/* Legal values for ST_BIND subfield of st_info (symbol binding). */
#define STB_LOCAL 0 /* Local symbol */
#define STB_GLOBAL 1 /* Global symbol */
#define STB_WEAK 2 /* Weak symbol */
#define STB_NUM 3 /* Number of defined types. */
#define STB_LOOS 10 /* Start of OS-specific */
#define STB_GNU_UNIQUE 10 /* Unique symbol. */
#define STB_HIOS 12 /* End of OS-specific */
#define STB_LOPROC 13 /* Start of processor-specific */
#define STB_HIPROC 15 /* End of processor-specific */
/* Legal values for ST_TYPE subfield of st_info (symbol type). */
#define STT_NOTYPE 0 /* Symbol type is unspecified */
#define STT_OBJECT 1 /* Symbol is a data object */
#define STT_FUNC 2 /* Symbol is a code object */
#define STT_SECTION 3 /* Symbol associated with a section */
#define STT_FILE 4 /* Symbol's name is file name */
#define STT_COMMON 5 /* Symbol is a common data object */
#define STT_TLS 6 /* Symbol is thread-local data object*/
#define STT_NUM 7 /* Number of defined types. */
#define STT_LOOS 10 /* Start of OS-specific */
#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */
#define STT_HIOS 12 /* End of OS-specific */
#define STT_LOPROC 13 /* Start of processor-specific */
#define STT_HIPROC 15 /* End of processor-specific */
/* Symbol table indices are found in the hash buckets and chain table
of a symbol hash table section. This special index value indicates
the end of a chain, meaning no further symbols are found in that bucket. */
#define STN_UNDEF 0 /* End of a chain. */
/* How to extract and insert information held in the st_other field. */
#define ELF32_ST_VISIBILITY(o) ((o)&0x03)
/* For ELF64 the definitions are the same. */
#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY(o)
/* Symbol visibility specification encoded in the st_other field. */
#define STV_DEFAULT 0 /* Default symbol visibility rules */
#define STV_INTERNAL 1 /* Processor specific hidden class */
#define STV_HIDDEN 2 /* Sym unavailable in other modules */
#define STV_PROTECTED 3 /* Not preemptible, not exported */
/* Relocation table entry without addend (in section of type SHT_REL). */
typedef struct {
Elf32_Addr r_offset; /* Address */
Elf32_Word r_info; /* Relocation type and symbol index */
} Elf32_Rel;
/* How to extract and insert information held in the r_info field. */
#define ELF32_R_SYM(val) ((val) >> 8)
#define ELF32_R_TYPE(val) ((val)&0xff)
#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type)&0xff))
/* MIPS R3000 specific definitions. */
/* Legal values for e_flags field of Elf32_Ehdr. */
#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used. */
#define EF_MIPS_PIC 2 /* Contains PIC code. */
#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence. */
#define EF_MIPS_XGOT 8
#define EF_MIPS_64BIT_WHIRL 16
#define EF_MIPS_ABI2 32
#define EF_MIPS_ABI_ON32 64
#define EF_MIPS_FP64 512 /* Uses FP64 (12 callee-saved). */
#define EF_MIPS_NAN2008 1024 /* Uses IEEE 754-2008 NaN encoding. */
#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level. */
/* Legal values for MIPS architecture level. */
#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */
#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */
#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */
#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */
#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */
#define EF_MIPS_ARCH_32 0x50000000 /* MIPS32 code. */
#define EF_MIPS_ARCH_64 0x60000000 /* MIPS64 code. */
#define EF_MIPS_ARCH_32R2 0x70000000 /* MIPS32r2 code. */
#define EF_MIPS_ARCH_64R2 0x80000000 /* MIPS64r2 code. */
/* The following are unofficial names and should not be used. */
#define E_MIPS_ARCH_1 EF_MIPS_ARCH_1
#define E_MIPS_ARCH_2 EF_MIPS_ARCH_2
#define E_MIPS_ARCH_3 EF_MIPS_ARCH_3
#define E_MIPS_ARCH_4 EF_MIPS_ARCH_4
#define E_MIPS_ARCH_5 EF_MIPS_ARCH_5
#define E_MIPS_ARCH_32 EF_MIPS_ARCH_32
#define E_MIPS_ARCH_64 EF_MIPS_ARCH_64
/* Special section indices. */
#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols. */
#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */
#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */
#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols. */
#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols. */
/* Legal values for sh_type field of Elf32_Shdr. */
#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link. */
#define SHT_MIPS_MSYM 0x70000001
#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols. */
#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes. */
#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */
#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging info. */
#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information. */
#define SHT_MIPS_PACKAGE 0x70000007
#define SHT_MIPS_PACKSYM 0x70000008
#define SHT_MIPS_RELD 0x70000009
#define SHT_MIPS_IFACE 0x7000000b
#define SHT_MIPS_CONTENT 0x7000000c
#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */
#define SHT_MIPS_SHDR 0x70000010
#define SHT_MIPS_FDESC 0x70000011
#define SHT_MIPS_EXTSYM 0x70000012
#define SHT_MIPS_DENSE 0x70000013
#define SHT_MIPS_PDESC 0x70000014
#define SHT_MIPS_LOCSYM 0x70000015
#define SHT_MIPS_AUXSYM 0x70000016
#define SHT_MIPS_OPTSYM 0x70000017
#define SHT_MIPS_LOCSTR 0x70000018
#define SHT_MIPS_LINE 0x70000019
#define SHT_MIPS_RFDESC 0x7000001a
#define SHT_MIPS_DELTASYM 0x7000001b
#define SHT_MIPS_DELTAINST 0x7000001c
#define SHT_MIPS_DELTACLASS 0x7000001d
#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */
#define SHT_MIPS_DELTADECL 0x7000001f
#define SHT_MIPS_SYMBOL_LIB 0x70000020
#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */
#define SHT_MIPS_TRANSLATE 0x70000022
#define SHT_MIPS_PIXIE 0x70000023
#define SHT_MIPS_XLATE 0x70000024
#define SHT_MIPS_XLATE_DEBUG 0x70000025
#define SHT_MIPS_WHIRL 0x70000026
#define SHT_MIPS_EH_REGION 0x70000027
#define SHT_MIPS_XLATE_OLD 0x70000028
#define SHT_MIPS_PDR_EXCEPTION 0x70000029
#define SHT_MIPS_XHASH 0x7000002b
/* Legal values for sh_flags field of Elf32_Shdr. */
#define SHF_MIPS_GPREL 0x10000000 /* Must be in global data area. */
#define SHF_MIPS_MERGE 0x20000000
#define SHF_MIPS_ADDR 0x40000000
#define SHF_MIPS_STRINGS 0x80000000
#define SHF_MIPS_NOSTRIP 0x08000000
#define SHF_MIPS_LOCAL 0x04000000
#define SHF_MIPS_NAMES 0x02000000
#define SHF_MIPS_NODUPE 0x01000000
/* Symbol tables. */
/* MIPS specific values for `st_other'. */
#define STO_MIPS_DEFAULT 0x0
#define STO_MIPS_INTERNAL 0x1
#define STO_MIPS_HIDDEN 0x2
#define STO_MIPS_PROTECTED 0x3
#define STO_MIPS_PLT 0x8
#define STO_MIPS_SC_ALIGN_UNUSED 0xff
/* MIPS specific values for `st_info'. */
#define STB_MIPS_SPLIT_COMMON 13
/* MIPS relocs. */
#define R_MIPS_NONE 0 /* No reloc */
#define R_MIPS_16 1 /* Direct 16 bit */
#define R_MIPS_32 2 /* Direct 32 bit */
#define R_MIPS_REL32 3 /* PC relative 32 bit */
#define R_MIPS_26 4 /* Direct 26 bit shifted */
#define R_MIPS_HI16 5 /* High 16 bit */
#define R_MIPS_LO16 6 /* Low 16 bit */
#define R_MIPS_GPREL16 7 /* GP relative 16 bit */
#define R_MIPS_LITERAL 8 /* 16 bit literal entry */
#define R_MIPS_GOT16 9 /* 16 bit GOT entry */
#define R_MIPS_PC16 10 /* PC relative 16 bit */
#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */
#define R_MIPS_GPREL32 12 /* GP relative 32 bit */
#define R_MIPS_SHIFT5 16
#define R_MIPS_SHIFT6 17
#define R_MIPS_64 18
#define R_MIPS_GOT_DISP 19
#define R_MIPS_GOT_PAGE 20
#define R_MIPS_GOT_OFST 21
#define R_MIPS_GOT_HI16 22
#define R_MIPS_GOT_LO16 23
#define R_MIPS_SUB 24
#define R_MIPS_INSERT_A 25
#define R_MIPS_INSERT_B 26
#define R_MIPS_DELETE 27
#define R_MIPS_HIGHER 28
#define R_MIPS_HIGHEST 29
#define R_MIPS_CALL_HI16 30
#define R_MIPS_CALL_LO16 31
#define R_MIPS_SCN_DISP 32
#define R_MIPS_REL16 33
#define R_MIPS_ADD_IMMEDIATE 34
#define R_MIPS_PJUMP 35
#define R_MIPS_RELGOT 36
#define R_MIPS_JALR 37
#define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */
#define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */
#define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */
#define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */
#define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */
#define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */
#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */
#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */
#define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */
#define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */
#define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */
#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */
#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */
#define R_MIPS_GLOB_DAT 51
#define R_MIPS_COPY 126
#define R_MIPS_JUMP_SLOT 127
/* Keep this the last entry. */
#define R_MIPS_NUM 128
#endif /* MIPS_ELF_H */

View file

@ -1,13 +1,11 @@
/** /**
* Functions for working with N64 ELF files. * Functions for working with N64 ELF files.
* For now relies on (GNU) elf.h, but may move away from this in future.
*/ */
/* Copyright (C) 2021 Elliptic Ellipsis */ /* Copyright (C) 2021 Elliptic Ellipsis */
/* SPDX-License-Identifier: AGPL-3.0-only */ /* SPDX-License-Identifier: AGPL-3.0-only */
#include "fairy.h" #include "fairy.h"
#include <assert.h> #include <assert.h>
#include <endian.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
@ -16,10 +14,12 @@
#include <string.h> #include <string.h>
#include "vc_vector/vc_vector.h" #include "vc_vector/vc_vector.h"
#include "macros.h"
VerbosityLevel gVerbosity = VERBOSITY_NONE; VerbosityLevel gVerbosity = VERBOSITY_NONE;
bool gUseElfAlignment = false;
int Fairy_DebugPrintf(const char* file, int line, const char* func,VerbosityLevel level, const char* fmt, ...) { int Fairy_DebugPrintf(const char* file, int line, const char* func, VerbosityLevel level, const char* fmt, ...) {
if (gVerbosity >= level) { if (gVerbosity >= level) {
int ret = 0; int ret = 0;
va_list args; va_list args;
@ -57,8 +57,8 @@ static uint32_t Fairy_Swap32(uint32_t x) {
return ((x & 0xFF) << 0x18) | ((x & 0xFF00) << 0x8) | ((x & 0xFF0000) >> 0x8) | ((x & 0xFF000000) >> 0x18); return ((x & 0xFF) << 0x18) | ((x & 0xFF00) << 0x8) | ((x & 0xFF0000) >> 0x8) | ((x & 0xFF000000) >> 0x18);
} }
/* "Re-encode/Re-endianise", i.e. byteswap if required */ /* Both GCC and Clang define these, so we can avoid an endian header altogether */
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define REEND16(x) Fairy_Swap16(x) #define REEND16(x) Fairy_Swap16(x)
#define REEND32(x) Fairy_Swap32(x) #define REEND32(x) Fairy_Swap32(x)
#else #else
@ -108,17 +108,27 @@ FairyFileHeader* Fairy_ReadFileHeader(FairyFileHeader* header, FILE* file) {
assert(fread(header, 0x34, 1, file) != 0); assert(fread(header, 0x34, 1, file) != 0);
if (!Fairy_VerifyMagic(header->e_ident)) { if (!Fairy_VerifyMagic(header->e_ident)) {
fprintf(stderr, "Not a valid ELF file\n"); fprintf(stderr, "Not a valid ELF file.\n");
return NULL; return NULL;
} }
if (header->e_ident[EI_CLASS] != ELFCLASS32) { if (header->e_ident[EI_CLASS] != ELFCLASS32) {
fprintf(stderr, "Not a 32-bit ELF file\n"); fprintf(stderr, "Not a 32-bit ELF file.\n");
return NULL; return NULL;
} }
header->e_type = REEND16(header->e_type); header->e_type = REEND16(header->e_type);
if (header->e_type != ET_REL) {
fprintf(stderr, "Not a relocatable object file.\n");
return NULL;
}
header->e_machine = REEND16(header->e_machine); header->e_machine = REEND16(header->e_machine);
if (header->e_machine != EM_MIPS) {
fprintf(stderr, "Not a MIPS object file.\n");
return NULL;
}
header->e_version = REEND32(header->e_version); header->e_version = REEND32(header->e_version);
header->e_entry = REEND32(header->e_entry); header->e_entry = REEND32(header->e_entry);
header->e_phoff = REEND32(header->e_phoff); header->e_phoff = REEND32(header->e_phoff);
@ -246,16 +256,45 @@ void Fairy_InitFile(FairyFileInfo* fileInfo, FILE* file) {
switch (currentSection.sh_type) { switch (currentSection.sh_type) {
case SHT_PROGBITS: case SHT_PROGBITS:
assert(vc_vector_push_back(fileInfo->progBitsSections, &currentIndex)); assert(vc_vector_push_back(fileInfo->progBitsSections, &currentIndex));
if (strcmp(&shstrtab[currentSection.sh_name + 1], "text") == 0) {
fileInfo->progBitsSizes[FAIRY_SECTION_TEXT] += currentSection.sh_size; {
FAIRY_DEBUG_PRINTF("text section size: 0x%X\n", fileInfo->progBitsSizes[FAIRY_SECTION_TEXT]); FairySection sectionType = FAIRY_SECTION_OTHER;
} else if (strcmp(&shstrtab[currentSection.sh_name + 1], "data") == 0) { const char* sectionName = &shstrtab[currentSection.sh_name + 1];
fileInfo->progBitsSizes[FAIRY_SECTION_DATA] += currentSection.sh_size; size_t alignedSize;
FAIRY_DEBUG_PRINTF("data section size: 0x%X\n", fileInfo->progBitsSizes[FAIRY_SECTION_DATA]);
} else if (Fairy_StartsWith(&shstrtab[currentSection.sh_name + 1], "rodata")) { /* May be several */ /* Ignore the leading "." */
fileInfo->progBitsSizes[FAIRY_SECTION_RODATA] += currentSection.sh_size; if (strcmp(sectionName, "text") == 0) {
FAIRY_DEBUG_PRINTF("rodata section size: 0x%X\n", fileInfo->progBitsSizes[FAIRY_SECTION_RODATA]); sectionType = FAIRY_SECTION_TEXT;
} else if (strcmp(sectionName, "data") == 0) {
sectionType = FAIRY_SECTION_DATA;
} else if (Fairy_StartsWith(sectionName, "rodata")) { /* May be several */
sectionType = FAIRY_SECTION_RODATA;
}
if (sectionType != FAIRY_SECTION_OTHER) {
if (gUseElfAlignment) {
/* Ensure the next file will start at its correct alignment */
fileInfo->progBitsSizes[sectionType] =
ALIGN(fileInfo->progBitsSizes[sectionType], currentSection.sh_addralign);
alignedSize = ALIGN(currentSection.sh_size, currentSection.sh_addralign);
FAIRY_DEBUG_PRINTF("%s section alignment: 0x%X\n", sectionName,
currentSection.sh_addralign);
FAIRY_DEBUG_PRINTF("%s section size before align: 0x%X\n", sectionName,
currentSection.sh_size);
FAIRY_DEBUG_PRINTF("%s section size after align: 0x%X\n", sectionName, alignedSize);
fileInfo->progBitsSizes[sectionType] += alignedSize;
} else {
fileInfo->progBitsSizes[sectionType] += ALIGN(currentSection.sh_size, 0x10);
}
FAIRY_DEBUG_PRINTF("%s section size: 0x%X\n", sectionName,
fileInfo->progBitsSizes[sectionType]);
}
} }
break; break;
case SHT_SYMTAB: case SHT_SYMTAB:
@ -281,6 +320,7 @@ void Fairy_InitFile(FairyFileInfo* fileInfo, FILE* file) {
{ {
FairySection relocSection = FAIRY_SECTION_OTHER; FairySection relocSection = FAIRY_SECTION_OTHER;
/* Ignore the first 5 chars, which will always be ".rel." */
if (strcmp(&shstrtab[currentSection.sh_name + 5], "text") == 0) { if (strcmp(&shstrtab[currentSection.sh_name + 5], "text") == 0) {
relocSection = FAIRY_SECTION_TEXT; relocSection = FAIRY_SECTION_TEXT;
FAIRY_DEBUG_PRINTF("%s", "Found rel.text section\n"); FAIRY_DEBUG_PRINTF("%s", "Found rel.text section\n");
@ -313,7 +353,7 @@ void Fairy_InitFile(FairyFileInfo* fileInfo, FILE* file) {
void Fairy_DestroyFile(FairyFileInfo* fileInfo) { void Fairy_DestroyFile(FairyFileInfo* fileInfo) {
size_t i; size_t i;
for (i = 0; i < 3; i++) { for (i = 0; i < ARRAY_COUNTU(fileInfo->relocTablesInfo); i++) {
if (fileInfo->relocTablesInfo[i].sectionData != NULL) { if (fileInfo->relocTablesInfo[i].sectionData != NULL) {
FAIRY_DEBUG_PRINTF("Freeing reloc section %zd data\n", i); FAIRY_DEBUG_PRINTF("Freeing reloc section %zd data\n", i);
free(fileInfo->relocTablesInfo[i].sectionData); free(fileInfo->relocTablesInfo[i].sectionData);
@ -322,7 +362,7 @@ void Fairy_DestroyFile(FairyFileInfo* fileInfo) {
vc_vector_release(fileInfo->progBitsSections); vc_vector_release(fileInfo->progBitsSections);
FAIRY_DEBUG_PRINTF("%s","Freeing symtab data\n"); FAIRY_DEBUG_PRINTF("%s", "Freeing symtab data\n");
free(fileInfo->symtabInfo.sectionData); free(fileInfo->symtabInfo.sectionData);
FAIRY_DEBUG_PRINTF("%s", "Freeing strtab data\n"); FAIRY_DEBUG_PRINTF("%s", "Freeing strtab data\n");

View file

@ -4,7 +4,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <elf.h> #include "mips_elf.h"
#include "vc_vector/vc_vector.h" #include "vc_vector/vc_vector.h"
@ -18,6 +18,7 @@ typedef enum {
} VerbosityLevel; } VerbosityLevel;
extern VerbosityLevel gVerbosity; extern VerbosityLevel gVerbosity;
extern bool gUseElfAlignment;
typedef Elf32_Ehdr FairyFileHeader; typedef Elf32_Ehdr FairyFileHeader;
typedef Elf32_Shdr FairySecHeader; typedef Elf32_Shdr FairySecHeader;

View file

@ -1,7 +1,7 @@
/* Copyright (C) 2021 Elliptic Ellipsis */ /* Copyright (C) 2021 Elliptic Ellipsis */
/* SPDX-License-Identifier: AGPL-3.0-only */ /* SPDX-License-Identifier: AGPL-3.0-only */
#include "fairy.h" #include "fairy.h"
#include <elf.h> #include "mips_elf.h"
// clang-format off // clang-format off
static const FairyDefineString stTypes[] = { static const FairyDefineString stTypes[] = {

View file

@ -0,0 +1,46 @@
.section .ovl
# ovl_En_Hs2OverlayInfo
.word _ovl_En_Hs2SegmentTextSize
.word _ovl_En_Hs2SegmentDataSize
.word _ovl_En_Hs2SegmentRoDataSize
.word _ovl_En_Hs2SegmentBssSize
.word 28 # relocCount
# TEXT RELOCS
.word 0x45000084 # R_MIPS_HI16 0x000084 .data
.word 0x4600008C # R_MIPS_LO16 0x00008C .data
.word 0x450000B4 # R_MIPS_HI16 0x0000B4 .rodata
.word 0x460000BC # R_MIPS_LO16 0x0000BC .rodata
.word 0x450000C0 # R_MIPS_HI16 0x0000C0 func_80A6F1A4
.word 0x460000C4 # R_MIPS_LO16 0x0000C4 func_80A6F1A4
.word 0x450001DC # R_MIPS_HI16 0x0001DC func_80A6F1A4
.word 0x460001E0 # R_MIPS_LO16 0x0001E0 func_80A6F1A4
.word 0x4500022C # R_MIPS_HI16 0x00022C func_80A6F164
.word 0x46000230 # R_MIPS_LO16 0x000230 func_80A6F164
.word 0x44000238 # R_MIPS_26 0x000238 func_80A6F0B4
.word 0x450003D0 # R_MIPS_HI16 0x0003D0 .rodata
.word 0x460003D8 # R_MIPS_LO16 0x0003D8 .rodata
.word 0x45000460 # R_MIPS_HI16 0x000460 .data
.word 0x46000464 # R_MIPS_LO16 0x000464 .data
.word 0x4500049C # R_MIPS_HI16 0x00049C EnHs2_OverrideLimbDraw
.word 0x460004B4 # R_MIPS_LO16 0x0004B4 EnHs2_OverrideLimbDraw
.word 0x450004A0 # R_MIPS_HI16 0x0004A0 EnHs2_PostLimbDraw
.word 0x460004B0 # R_MIPS_LO16 0x0004B0 EnHs2_PostLimbDraw
# DATA RELOCS
.word 0x82000010 # R_MIPS_32 0x000010 EnHs2_Init
.word 0x82000014 # R_MIPS_32 0x000014 EnHs2_Destroy
.word 0x82000018 # R_MIPS_32 0x000018 EnHs2_Update
.word 0x8200001C # R_MIPS_32 0x00001C EnHs2_Draw
# RODATA RELOCS
.word 0xC2000020 # R_MIPS_32 0x000020 .text
.word 0xC2000024 # R_MIPS_32 0x000024 .text
.word 0xC2000028 # R_MIPS_32 0x000028 .text
.word 0xC200002C # R_MIPS_32 0x00002C .text
.word 0xC2000030 # R_MIPS_32 0x000030 .text
.word 0
.word 0
.word 0x00000090 # ovl_En_Hs2OverlayInfoOffset

View file

@ -123,7 +123,7 @@ static const FairyDefineString relSectionNames[] = {
{ 0 }, { 0 },
}; };
/* Taken from elf.h */ /* Taken from elf.h/mips_elf.h */
static const FairyDefineString relTypeNames[] = { static const FairyDefineString relTypeNames[] = {
FAIRY_DEF_STRING(, R_MIPS_NONE), /* No reloc */ FAIRY_DEF_STRING(, R_MIPS_NONE), /* No reloc */
FAIRY_DEF_STRING(, R_MIPS_16), /* Direct 16 bit */ FAIRY_DEF_STRING(, R_MIPS_16), /* Direct 16 bit */

View file

@ -114,7 +114,7 @@ void Help_PrintHelp(const char* prologue, size_t posArgCount, const PosArgInfo*
if (posArgCount != 0) { if (posArgCount != 0) {
printf("\nPositional Argument\n"); printf("\nPositional Argument\n");
for (i = 0; i < optCount; i++) { for (i = 0; i < posArgCount; i++) {
if (posArgInfo[i].helpArg == 0) { if (posArgInfo[i].helpArg == 0) {
break; break;
} }

View file

@ -55,7 +55,7 @@ char* GetOverlayNameFromFilename(const char* src) {
return ret; return ret;
} }
#define OPTSTR "M:n:o:v:hV" #define OPTSTR "M:n:o:v:ahV"
#define USAGE_STRING "Usage: %s [-hV] [-n name] [-o output_file] [-v level] input_files ...\n" #define USAGE_STRING "Usage: %s [-hV] [-n name] [-o output_file] [-v level] input_files ...\n"
#define HELP_PROLOGUE \ #define HELP_PROLOGUE \
@ -75,6 +75,8 @@ static const OptInfo optInfo[] = {
{ { "output-file", required_argument, NULL, 'o' }, "FILE", "Output to FILE. Will use stdout if none is specified" }, { { "output-file", required_argument, NULL, 'o' }, "FILE", "Output to FILE. Will use stdout if none is specified" },
{ { "verbosity", required_argument, NULL, 'v' }, "N", "Verbosity level, one of 0 (None, default), 1 (Info), 2 (Debug)" }, { { "verbosity", required_argument, NULL, 'v' }, "N", "Verbosity level, one of 0 (None, default), 1 (Info), 2 (Debug)" },
{ { "alignment", no_argument, NULL, 'a' }, NULL, "Experimental. Use the alignment declared by each section in the elf file instead of padding to 0x10 bytes. NOTE: It has not been properly tested because the tools we currently have are not compatible non 0x10 alignment" },
{ { "help", no_argument, NULL, 'h' }, NULL, "Display this message and exit" }, { { "help", no_argument, NULL, 'h' }, NULL, "Display this message and exit" },
{ { "version", no_argument, NULL, 'V' }, NULL, "Display version information" }, { { "version", no_argument, NULL, 'V' }, NULL, "Display version information" },
@ -82,7 +84,7 @@ static const OptInfo optInfo[] = {
}; };
// clang-format on // clang-format on
static size_t posArgCount = ARRAY_COUNT(optInfo); static size_t posArgCount = ARRAY_COUNT(posArgInfo);
static size_t optCount = ARRAY_COUNT(optInfo); static size_t optCount = ARRAY_COUNT(optInfo);
static struct option longOptions[ARRAY_COUNT(optInfo)]; static struct option longOptions[ARRAY_COUNT(optInfo)];
@ -142,6 +144,13 @@ int main(int argc, char** argv) {
} }
break; break;
case 'a':
#ifndef EXPERIMENTAL
goto not_experimental_err;
#endif
gUseElfAlignment = true;
break;
case 'h': case 'h':
printf(USAGE_STRING, argv[0]); printf(USAGE_STRING, argv[0]);
Help_PrintHelp(HELP_PROLOGUE, posArgCount, posArgInfo, optCount, optInfo, HELP_EPILOGUE); Help_PrintHelp(HELP_PROLOGUE, posArgCount, posArgInfo, optCount, optInfo, HELP_EPILOGUE);
@ -226,4 +235,12 @@ int main(int argc, char** argv) {
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
goto not_experimental_err; // silences a warning
not_experimental_err:
fprintf(
stderr,
"Experimental option '-%c' passed in a non-EXPERIMENTAL build. Rebuild with 'make EXPERIMENTAL=1' to enable.\n",
opt);
return EXIT_FAILURE;
} }

View file

@ -1,5 +1,5 @@
/* Copyright (C) 2021 Elliptic Ellipsis */ /* Copyright (C) 2021 Elliptic Ellipsis */
/* SPDX-License-Identifier: AGPL-3.0-only */ /* SPDX-License-Identifier: AGPL-3.0-only */
const char versionNumber[] = "1.1.1"; const char versionNumber[] = "1.2.1";
const char credits[] = "Written by Elliptic Ellipsis\n Special Thanks: AngheloAlf"; const char credits[] = "Written by Elliptic Ellipsis\nand AngheloAlf";
const char repo[] = "https://github.com/EllipticEllipsis/fado/"; const char repo[] = "https://github.com/EllipticEllipsis/fado/";

View file

@ -0,0 +1,114 @@
# 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.