4 Commits

Author SHA1 Message Date
Ethan Lafrenais
11faed1a80 Merge 91be352ee0 into d660733116 2025-02-13 16:12:59 -08:00
Wiseguy
d660733116 Implement reloc pairing GNU extension (#131) 2025-02-13 18:20:48 -05:00
Ethan Lafrenais
91be352ee0 Also apply reimplemented_funcs and ignored_funcs 2025-01-16 01:00:31 -05:00
Ethan Lafrenais
37dabfb295 Apply renamed_funcs to reference symbols 2025-01-16 01:00:31 -05:00
2 changed files with 46 additions and 11 deletions

View File

@@ -663,7 +663,15 @@ bool N64Recomp::Context::import_reference_context(const N64Recomp::Context& refe
// Copy the functions from the reference context into the reference context's function map.
for (const N64Recomp::Function& func_in: reference_context.functions) {
if (!add_reference_symbol(func_in.name, func_in.section_index, func_in.vram, true)) {
// Rename if necessary
std::string name = func_in.name;
if (N64Recomp::reimplemented_funcs.contains(name) ||
N64Recomp::ignored_funcs.contains(name) ||
N64Recomp::renamed_funcs.contains(name)) {
name = name + "_recomp";
}
if (!add_reference_symbol(name, func_in.section_index, func_in.vram, true)) {
return false;
}
}

View File

@@ -368,8 +368,8 @@ ELFIO::section* read_sections(N64Recomp::Context& context, const N64Recomp::ElfP
ELFIO::relocation_section_accessor rel_accessor{ elf_file, reloc_find->second };
// Allocate space for the relocs in this section
section_out.relocs.resize(rel_accessor.get_entries_num());
// Track whether the previous reloc was a HI16 and its previous full_immediate
bool prev_hi = false;
// Track consecutive identical HI16 relocs to handle the GNU extension to the o32 ABI.
int prev_hi_count = 0;
// Track whether the previous reloc was a LO16
bool prev_lo = false;
uint32_t prev_hi_immediate = 0;
@@ -416,6 +416,13 @@ ELFIO::section* read_sections(N64Recomp::Context& context, const N64Recomp::ElfP
// Check if the symbol is undefined and to know whether to look for it in the reference symbols.
if (rel_symbol_section_index == ELFIO::SHN_UNDEF) {
// Get renamed version of symbol name if necessary
if (N64Recomp::reimplemented_funcs.contains(rel_symbol_name) ||
N64Recomp::ignored_funcs.contains(rel_symbol_name) ||
N64Recomp::renamed_funcs.contains(rel_symbol_name)) {
rel_symbol_name = rel_symbol_name + "_recomp";
}
// Undefined sym, check the reference symbols.
N64Recomp::SymbolReference sym_ref;
if (!context.find_reference_symbol(rel_symbol_name, sym_ref)) {
@@ -462,7 +469,7 @@ ELFIO::section* read_sections(N64Recomp::Context& context, const N64Recomp::ElfP
uint32_t rel_immediate = reloc_rom_word & 0xFFFF;
uint32_t full_immediate = (prev_hi_immediate << 16) + (int16_t)rel_immediate;
reloc_out.target_section_offset = full_immediate + rel_symbol_offset - rel_section_vram;
if (prev_hi) {
if (prev_hi_count != 0) {
if (prev_hi_symbol != rel_symbol) {
fmt::print(stderr, "Paired HI16 and LO16 relocations have different symbols\n"
" LO16 reloc index {} in section {} referencing symbol {} with offset 0x{:08X}\n",
@@ -470,8 +477,12 @@ ELFIO::section* read_sections(N64Recomp::Context& context, const N64Recomp::ElfP
return nullptr;
}
// Set the previous HI16 relocs' relocated address.
section_out.relocs[i - 1].target_section_offset = reloc_out.target_section_offset;
// Set the previous HI16 relocs' relocated addresses.
for (size_t paired_index = i - prev_hi_count; paired_index < i; paired_index++) {
uint32_t hi_immediate = section_out.relocs[paired_index].target_section_offset;
uint32_t paired_full_immediate = hi_immediate + (int16_t)rel_immediate;
section_out.relocs[paired_index].target_section_offset = paired_full_immediate + rel_symbol_offset - rel_section_vram;
}
}
else {
// Orphaned LO16 reloc warnings.
@@ -495,7 +506,8 @@ ELFIO::section* read_sections(N64Recomp::Context& context, const N64Recomp::ElfP
}
prev_lo = true;
} else {
if (prev_hi) {
// Allow a HI16 to follow another HI16 for the GNU ABI extension.
if (reloc_out.type != N64Recomp::RelocType::R_MIPS_HI16 && prev_hi_count != 0) {
// This is an invalid elf as the MIPS System V ABI documentation states:
// "Each relocation type of R_MIPS_HI16 must have an associated R_MIPS_LO16 entry
// immediately following it in the list of relocations."
@@ -508,11 +520,26 @@ ELFIO::section* read_sections(N64Recomp::Context& context, const N64Recomp::ElfP
if (reloc_out.type == N64Recomp::RelocType::R_MIPS_HI16) {
uint32_t rel_immediate = reloc_rom_word & 0xFFFF;
prev_hi = true;
prev_hi_immediate = rel_immediate;
prev_hi_symbol = rel_symbol;
// First HI16, store its immediate.
if (prev_hi_count == 0) {
prev_hi_immediate = rel_immediate;
prev_hi_symbol = rel_symbol;
}
// HI16 that follows another HI16, ensure they reference the same symbol.
else {
if (prev_hi_symbol != rel_symbol) {
fmt::print(stderr, "HI16 reloc (index {} symbol {} offset 0x{:08X}) follows another HI16 reloc with a different symbol (index {} symbol {} offset 0x{:08X}) in section {}\n",
i, rel_symbol, section_out.relocs[i].address,
i - 1, prev_hi_symbol, section_out.relocs[i - 1].address,
section_out.name);
return nullptr;
}
}
// Populate the reloc temporarily, the full offset will be calculated upon pairing.
reloc_out.target_section_offset = rel_immediate << 16;
prev_hi_count++;
} else {
prev_hi = false;
prev_hi_count = 0;
}
if (reloc_out.type == N64Recomp::RelocType::R_MIPS_32) {