mirror of
https://github.com/zeldaret/oot.git
synced 2024-12-05 01:06:37 +00:00
463 lines
16 KiB
C
463 lines
16 KiB
C
|
/**
|
||
|
* Functions for printing various sections of an N64 ELF file using the functions in Fairy, similarly to readelf
|
||
|
*/
|
||
|
/* Copyright (C) 2021 Elliptic Ellipsis */
|
||
|
/* SPDX-License-Identifier: AGPL-3.0-only */
|
||
|
#include "fairy.h"
|
||
|
|
||
|
#include <assert.h>
|
||
|
#include <stdbool.h>
|
||
|
#include <stddef.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "fairy_data.inc"
|
||
|
|
||
|
void Fairy_PrintSymbolTable(FILE* inputFile) {
|
||
|
FairyFileHeader fileHeader;
|
||
|
FairySecHeader* sectionTable;
|
||
|
size_t shstrndx;
|
||
|
char* shstrtab;
|
||
|
FairySym* symbolTable = NULL;
|
||
|
size_t symbolTableNum = 0;
|
||
|
char* strtab = NULL;
|
||
|
|
||
|
Fairy_ReadFileHeader(&fileHeader, inputFile);
|
||
|
sectionTable = malloc(fileHeader.e_shentsize * fileHeader.e_shnum);
|
||
|
shstrndx = fileHeader.e_shstrndx;
|
||
|
|
||
|
Fairy_ReadSectionTable(sectionTable, inputFile, fileHeader.e_shoff, fileHeader.e_shnum);
|
||
|
|
||
|
shstrtab = malloc(sectionTable[shstrndx].sh_size * sizeof(char));
|
||
|
|
||
|
fseek(inputFile, sectionTable[shstrndx].sh_offset, SEEK_SET);
|
||
|
assert(fread(shstrtab, sectionTable[shstrndx].sh_size, 1, inputFile) != 0);
|
||
|
|
||
|
{
|
||
|
size_t currentIndex;
|
||
|
size_t strtabndx = 0;
|
||
|
for (currentIndex = 0; currentIndex < fileHeader.e_shnum; currentIndex++) {
|
||
|
FairySecHeader currentHeader = sectionTable[currentIndex];
|
||
|
|
||
|
switch (currentHeader.sh_type) {
|
||
|
case SHT_SYMTAB:
|
||
|
if (strcmp(&shstrtab[currentHeader.sh_name], ".symtab") == 0) {
|
||
|
printf("symtab found\n");
|
||
|
symbolTableNum = currentHeader.sh_size / sizeof(FairySym);
|
||
|
symbolTable = malloc(currentHeader.sh_size);
|
||
|
Fairy_ReadSymbolTable(symbolTable, inputFile, currentHeader.sh_offset, currentHeader.sh_size);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SHT_STRTAB:
|
||
|
if (strcmp(&shstrtab[currentHeader.sh_name], ".strtab") == 0) {
|
||
|
strtabndx = currentIndex;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (symbolTable == NULL) {
|
||
|
puts("No symtab found.");
|
||
|
free(sectionTable);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (strtabndx != 0) {
|
||
|
printf("strtab found\n");
|
||
|
printf("Size: %X bytes\n", sectionTable[strtabndx].sh_size);
|
||
|
strtab = malloc(sectionTable[strtabndx].sh_size);
|
||
|
printf("and mallocked\n");
|
||
|
fseek(inputFile, sectionTable[strtabndx].sh_offset, SEEK_SET);
|
||
|
printf("file offset sought: %X\n", sectionTable[strtabndx].sh_offset);
|
||
|
assert(fread(strtab, sectionTable[strtabndx].sh_size, 1, inputFile) != 0);
|
||
|
printf("file read\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
{
|
||
|
size_t currentIndex;
|
||
|
printf("Symbol table\n");
|
||
|
printf(" Num: Value Size Type Bind Vis Ndx Name\n");
|
||
|
for (currentIndex = 0; currentIndex < symbolTableNum; currentIndex++) {
|
||
|
FairySym currentSymbol = symbolTable[currentIndex];
|
||
|
printf("%4zd: ", currentIndex);
|
||
|
printf("%08X ", currentSymbol.st_value);
|
||
|
printf("%4X ", currentSymbol.st_size);
|
||
|
printf("%-11s ", Fairy_StringFromDefine(stTypes, ELF32_ST_TYPE(currentSymbol.st_info)));
|
||
|
printf("%-10s ", Fairy_StringFromDefine(stBinds, ELF32_ST_BIND(currentSymbol.st_info)));
|
||
|
printf("%-11s ", Fairy_StringFromDefine(stVisibilities, ELF32_ST_VISIBILITY(currentSymbol.st_other)));
|
||
|
|
||
|
if (currentSymbol.st_shndx != 0) {
|
||
|
printf("%3X ", currentSymbol.st_shndx);
|
||
|
} else {
|
||
|
printf("UND ");
|
||
|
}
|
||
|
|
||
|
if (strtab != NULL) {
|
||
|
printf("%s", &strtab[currentSymbol.st_name]);
|
||
|
} else {
|
||
|
printf("%4X ", currentSymbol.st_name);
|
||
|
}
|
||
|
putchar('\n');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
free(sectionTable);
|
||
|
free(symbolTable);
|
||
|
if (strtab != NULL) {
|
||
|
free(strtab);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Fairy_PrintRelocs(FILE* inputFile) {
|
||
|
FairyFileHeader fileHeader;
|
||
|
FairySecHeader* sectionTable;
|
||
|
FairyRel* relocs;
|
||
|
size_t shstrndx;
|
||
|
char* shstrtab;
|
||
|
size_t currentSection;
|
||
|
|
||
|
Fairy_ReadFileHeader(&fileHeader, inputFile);
|
||
|
sectionTable = malloc(fileHeader.e_shentsize * fileHeader.e_shnum);
|
||
|
shstrndx = fileHeader.e_shstrndx;
|
||
|
|
||
|
Fairy_ReadSectionTable(sectionTable, inputFile, fileHeader.e_shoff, fileHeader.e_shnum);
|
||
|
|
||
|
shstrtab = malloc(sectionTable[shstrndx].sh_size * sizeof(char));
|
||
|
|
||
|
fseek(inputFile, sectionTable[shstrndx].sh_offset, SEEK_SET);
|
||
|
assert(fread(shstrtab, sectionTable[shstrndx].sh_size, 1, inputFile) != 0);
|
||
|
|
||
|
for (currentSection = 0; currentSection < fileHeader.e_shnum; currentSection++) {
|
||
|
if (sectionTable[currentSection].sh_type != SHT_REL) {
|
||
|
continue;
|
||
|
}
|
||
|
printf("Section size: %d\n", sectionTable[currentSection].sh_size);
|
||
|
|
||
|
relocs = malloc(sectionTable[currentSection].sh_size * sizeof(char));
|
||
|
|
||
|
Fairy_ReadRelocs(relocs, inputFile, sectionTable[currentSection].sh_offset,
|
||
|
sectionTable[currentSection].sh_size);
|
||
|
|
||
|
// fseek(inputFile, sectionTable[currentSection].sh_offset, SEEK_SET);
|
||
|
// assert(fread(relocs, sectionTable[currentSection].sh_size, 1, inputFile) != 0);
|
||
|
|
||
|
printf("Relocs in section [%2zd]: %s:\n", currentSection, shstrtab + sectionTable[currentSection].sh_name);
|
||
|
printf("Offset Info Type Symbol\n");
|
||
|
{
|
||
|
size_t currentReloc;
|
||
|
for (currentReloc = 0; currentReloc < sectionTable[currentSection].sh_size / sizeof(*relocs);
|
||
|
currentReloc++) {
|
||
|
|
||
|
printf("%08X,%08X ", relocs[currentReloc].r_offset, relocs[currentReloc].r_info);
|
||
|
|
||
|
switch (ELF32_R_TYPE(relocs[currentReloc].r_info)) {
|
||
|
case R_MIPS_NONE:
|
||
|
printf("%-15s", "R_MIPS_NONE");
|
||
|
break;
|
||
|
case R_MIPS_16:
|
||
|
printf("%-15s", "R_MIPS_16");
|
||
|
break;
|
||
|
case R_MIPS_32:
|
||
|
printf("%-15s", "R_MIPS_32");
|
||
|
break;
|
||
|
case R_MIPS_REL32:
|
||
|
printf("%-15s", "R_MIPS_REL32");
|
||
|
break;
|
||
|
case R_MIPS_26:
|
||
|
printf("%-15s", "R_MIPS_26");
|
||
|
break;
|
||
|
case R_MIPS_HI16:
|
||
|
printf("%-15s", "R_MIPS_HI16");
|
||
|
break;
|
||
|
case R_MIPS_LO16:
|
||
|
printf("%-15s", "R_MIPS_LO16");
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
printf("%X", ELF32_R_SYM(relocs[currentReloc].r_info));
|
||
|
|
||
|
putchar('\n');
|
||
|
}
|
||
|
putchar('\n');
|
||
|
}
|
||
|
putchar('\n');
|
||
|
|
||
|
free(relocs);
|
||
|
}
|
||
|
free(sectionTable);
|
||
|
free(shstrtab);
|
||
|
}
|
||
|
|
||
|
void Fairy_PrintSectionTable(FILE* inputFile) {
|
||
|
FairyFileHeader fileHeader;
|
||
|
FairySecHeader* sectionTable;
|
||
|
size_t shstrndx;
|
||
|
char* shstrtab;
|
||
|
size_t currentSection;
|
||
|
|
||
|
Fairy_ReadFileHeader(&fileHeader, inputFile);
|
||
|
sectionTable = malloc(fileHeader.e_shentsize * fileHeader.e_shnum);
|
||
|
shstrndx = fileHeader.e_shstrndx;
|
||
|
|
||
|
Fairy_ReadSectionTable(sectionTable, inputFile, fileHeader.e_shoff, fileHeader.e_shnum);
|
||
|
|
||
|
shstrtab = malloc(sectionTable[shstrndx].sh_size * sizeof(char));
|
||
|
|
||
|
fseek(inputFile, sectionTable[shstrndx].sh_offset, SEEK_SET);
|
||
|
assert(fread(shstrtab, sectionTable[shstrndx].sh_size, 1, inputFile) != 0);
|
||
|
|
||
|
printf("[Nr] Name Type Addr Off Size ES Flg Lk Inf Al\n");
|
||
|
for (currentSection = 0; currentSection < fileHeader.e_shnum; currentSection++) {
|
||
|
FairySecHeader entry = sectionTable[currentSection];
|
||
|
printf("[%2zd] ", currentSection);
|
||
|
printf("%-15s", shstrtab + entry.sh_name);
|
||
|
|
||
|
printf("%-15s", Fairy_StringFromDefine(shTypes, entry.sh_type));
|
||
|
|
||
|
// printf("%08X ", entry.sh_type);
|
||
|
printf("%08X ", entry.sh_addr);
|
||
|
printf("%06X ", entry.sh_offset);
|
||
|
printf("%06X ", entry.sh_size);
|
||
|
printf("%02X ", entry.sh_entsize);
|
||
|
// printf("%08X ", entry.sh_flags);
|
||
|
|
||
|
{
|
||
|
char flagChars[] = { 'W', 'A', 'X', 'M', 'S', 'I', 'L', 'O', 'G', 'T', 'C', 'x', 'o', 'E', 'p' };
|
||
|
uint32_t flags = entry.sh_flags;
|
||
|
size_t shift;
|
||
|
int pad = 4;
|
||
|
for (shift = 0; shift < sizeof(flagChars); shift++) {
|
||
|
if ((flags >> shift) & 1) {
|
||
|
putchar(flagChars[shift]);
|
||
|
pad--;
|
||
|
}
|
||
|
}
|
||
|
if (pad > 0) {
|
||
|
printf("%*s", pad, "");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
printf("%2X ", entry.sh_link);
|
||
|
printf("%3X ", entry.sh_info);
|
||
|
printf("%2X", entry.sh_addralign);
|
||
|
putchar('\n');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
typedef enum { REL_SECTION_NONE, REL_SECTION_TEXT, REL_SECTION_DATA, REL_SECTION_RODATA } FairyOverlayRelSection;
|
||
|
|
||
|
const char* relSectionStrings[] = {
|
||
|
NULL,
|
||
|
".text",
|
||
|
".data",
|
||
|
".rodata",
|
||
|
};
|
||
|
|
||
|
static uint32_t Fairy_PackReloc(FairyOverlayRelSection sec, FairyRel rel) {
|
||
|
return (sec << 0x1E) | (ELF32_R_TYPE(rel.r_info) << 0x18) | rel.r_offset;
|
||
|
}
|
||
|
|
||
|
void Fairy_PrintSectionSizes(FairySecHeader* sectionTable, FILE* inputFile, size_t tableSize, char* shstrtab) {
|
||
|
size_t number = tableSize / sizeof(FairySecHeader);
|
||
|
FairySecHeader currentHeader;
|
||
|
char* sectionName;
|
||
|
size_t relocSectionsCount = 0;
|
||
|
size_t* relocSectionIndices;
|
||
|
int* relocSectionSection;
|
||
|
size_t currentRelocSection = 0;
|
||
|
FairySecHeader symtabHeader;
|
||
|
FairySym* symtab;
|
||
|
FairySecHeader strtabHeader;
|
||
|
char* strtab = NULL;
|
||
|
// size_t symtabSize;
|
||
|
|
||
|
uint32_t textSize = 0;
|
||
|
uint32_t dataSize = 0;
|
||
|
uint32_t rodataSize = 0;
|
||
|
uint32_t bssSize = 0;
|
||
|
uint32_t relocCount = 0;
|
||
|
|
||
|
size_t currentSection;
|
||
|
bool symtabFound = false;
|
||
|
bool strtabFound = false;
|
||
|
/* Count the reloc sections */
|
||
|
for (currentSection = 0; currentSection < number; currentSection++) {
|
||
|
if (sectionTable[currentSection].sh_type == SHT_REL) {
|
||
|
relocSectionsCount++;
|
||
|
}
|
||
|
}
|
||
|
printf("relocSectionsCount: %zd\n", relocSectionsCount);
|
||
|
|
||
|
relocSectionIndices = malloc(relocSectionsCount * sizeof(int));
|
||
|
relocSectionSection = malloc(relocSectionsCount * sizeof(int));
|
||
|
|
||
|
/* Find the section sizes and the reloc sections */
|
||
|
for (currentSection = 0; currentSection < number; currentSection++) {
|
||
|
currentHeader = sectionTable[currentSection];
|
||
|
sectionName = &shstrtab[currentHeader.sh_name + 1]; /* ignore the initial '.' */
|
||
|
switch (currentHeader.sh_type) {
|
||
|
case SHT_PROGBITS:
|
||
|
if (Fairy_StartsWith(sectionName, "rodata")) {
|
||
|
printf("rodata\n");
|
||
|
rodataSize += currentHeader.sh_size;
|
||
|
break;
|
||
|
}
|
||
|
if (Fairy_StartsWith(sectionName, "data")) {
|
||
|
printf("data\n");
|
||
|
dataSize += currentHeader.sh_size;
|
||
|
break;
|
||
|
}
|
||
|
if (Fairy_StartsWith(sectionName, "text")) {
|
||
|
printf("text\n");
|
||
|
textSize += currentHeader.sh_size;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SHT_NOBITS:
|
||
|
if (Fairy_StartsWith(sectionName, "bss")) {
|
||
|
printf("bss\n");
|
||
|
bssSize += currentHeader.sh_size;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SHT_REL:
|
||
|
relocSectionIndices[currentRelocSection] = currentSection;
|
||
|
sectionName += 4; /* ignore the "rel." part */
|
||
|
if (Fairy_StartsWith(sectionName, "rodata")) {
|
||
|
printf(".rel.rodata\n");
|
||
|
relocSectionSection[currentRelocSection] = REL_SECTION_RODATA;
|
||
|
} else if (Fairy_StartsWith(sectionName, "data")) {
|
||
|
printf(".rel.data\n");
|
||
|
relocSectionSection[currentRelocSection] = REL_SECTION_DATA;
|
||
|
} else if (Fairy_StartsWith(sectionName, "text")) {
|
||
|
printf(".rel.text\n");
|
||
|
relocSectionSection[currentRelocSection] = REL_SECTION_TEXT;
|
||
|
}
|
||
|
|
||
|
currentRelocSection++;
|
||
|
break;
|
||
|
|
||
|
case SHT_SYMTAB:
|
||
|
if (Fairy_StartsWith(sectionName, "symtab")) {
|
||
|
symtabHeader = currentHeader;
|
||
|
symtabFound = true;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SHT_STRTAB:
|
||
|
if (Fairy_StartsWith(sectionName, "strtab")) {
|
||
|
strtabHeader = currentHeader;
|
||
|
strtabFound = true;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
/* Can use symbols here too */
|
||
|
puts(".section .ovl");
|
||
|
printf("# OverlayInfo\n");
|
||
|
printf(".word 0x%08X # .text size\n", textSize);
|
||
|
printf(".word 0x%08X # .data size\n", dataSize);
|
||
|
printf(".word 0x%08X # .rodata size\n", rodataSize);
|
||
|
printf(".word 0x%08X # .bss size\n\n", bssSize);
|
||
|
|
||
|
if (!symtabFound) {
|
||
|
fprintf(stderr, "Symbol table not found");
|
||
|
return;
|
||
|
}
|
||
|
/* Obtain the symbol table */
|
||
|
symtab = malloc(symtabHeader.sh_size);
|
||
|
|
||
|
// TODO: Consider replacing this with a lighter-weight read: sufficient to get the name, shndx
|
||
|
Fairy_ReadSymbolTable(symtab, inputFile, symtabHeader.sh_offset, symtabHeader.sh_size);
|
||
|
|
||
|
if (!strtabFound) {
|
||
|
fprintf(stderr, "String table not found");
|
||
|
} else {
|
||
|
/* Obtain the string table */
|
||
|
strtab = malloc(strtabHeader.sh_size);
|
||
|
fseek(inputFile, strtabHeader.sh_offset, SEEK_SET);
|
||
|
assert(fread(strtab, strtabHeader.sh_size, 1, inputFile) != 0);
|
||
|
}
|
||
|
|
||
|
/* Do single-file relocs */
|
||
|
{
|
||
|
FairyRel* relocs;
|
||
|
for (currentSection = 0; currentSection < relocSectionsCount; currentSection++) {
|
||
|
size_t currentReloc;
|
||
|
size_t sectionRelocCount;
|
||
|
currentHeader = sectionTable[relocSectionIndices[currentSection]];
|
||
|
sectionRelocCount = currentHeader.sh_size / sizeof(FairyRel);
|
||
|
relocs = malloc(currentHeader.sh_size);
|
||
|
Fairy_ReadRelocs(relocs, inputFile, currentHeader.sh_offset, currentHeader.sh_size);
|
||
|
|
||
|
for (currentReloc = 0; currentReloc < sectionRelocCount; currentReloc++) {
|
||
|
FairySym symbol = symtab[ELF32_R_SYM(relocs[currentReloc].r_info)];
|
||
|
if (symbol.st_shndx == SHN_UNDEF) {
|
||
|
continue; // TODO: this is where multifile has to look elsewhere
|
||
|
}
|
||
|
|
||
|
printf(".word 0x%08X", Fairy_PackReloc(relocSectionSection[currentSection], relocs[currentReloc]));
|
||
|
printf(" # %X (%s), %X, 0x%06X", relocSectionSection[currentSection], &shstrtab[currentHeader.sh_name],
|
||
|
ELF32_R_TYPE(relocs[currentReloc].r_info), relocs[currentReloc].r_offset);
|
||
|
if (strtab != NULL) {
|
||
|
printf(", %s", &strtab[symbol.st_name]);
|
||
|
}
|
||
|
putchar('\n');
|
||
|
|
||
|
relocCount++;
|
||
|
}
|
||
|
|
||
|
free(relocs);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
printf(".word %d # relocCount\n", relocCount);
|
||
|
|
||
|
{
|
||
|
uint32_t ovlSectionSize = ((relocCount + 8) & ~0x03) * sizeof(uint32_t);
|
||
|
|
||
|
printf("\n.word 0x%08X # Overlay section size\n", ovlSectionSize);
|
||
|
}
|
||
|
|
||
|
free(relocSectionIndices);
|
||
|
free(relocSectionSection);
|
||
|
if (strtab != NULL) {
|
||
|
free(strtab);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void PrintZeldaReloc(FILE* inputFile) {
|
||
|
FairyFileHeader fileHeader;
|
||
|
FairySecHeader* sectionTable;
|
||
|
size_t shstrndx;
|
||
|
char* shstrtab;
|
||
|
|
||
|
Fairy_ReadFileHeader(&fileHeader, inputFile);
|
||
|
sectionTable = malloc(fileHeader.e_shentsize * fileHeader.e_shnum);
|
||
|
shstrndx = fileHeader.e_shstrndx;
|
||
|
|
||
|
Fairy_ReadSectionTable(sectionTable, inputFile, fileHeader.e_shoff, fileHeader.e_shnum);
|
||
|
|
||
|
shstrtab = malloc(sectionTable[shstrndx].sh_size * sizeof(char));
|
||
|
|
||
|
fseek(inputFile, sectionTable[shstrndx].sh_offset, SEEK_SET);
|
||
|
assert(fread(shstrtab, sectionTable[shstrndx].sh_size, 1, inputFile) != 0);
|
||
|
|
||
|
Fairy_PrintSectionSizes(sectionTable, inputFile, fileHeader.e_shentsize * fileHeader.e_shnum, shstrtab);
|
||
|
|
||
|
free(sectionTable);
|
||
|
free(shstrtab);
|
||
|
}
|