From 198de1b5cf6e58415948588584750c51562d58dd Mon Sep 17 00:00:00 2001 From: Wiseguy <68165316+Mr-Wiseguy@users.noreply.github.com> Date: Thu, 30 Jan 2025 02:54:27 -0500 Subject: [PATCH] Move handling of HI16/LO16 relocs for non-relocatable reference sections into elf parsing by patching the output binary (fixes patch regeneration) (#127) --- src/elf.cpp | 32 +++++++++++++++++++++++++++++++- src/recompilation.cpp | 11 +---------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/elf.cpp b/src/elf.cpp index 25f84da..787ceea 100644 --- a/src/elf.cpp +++ b/src/elf.cpp @@ -104,10 +104,10 @@ bool read_symbols(N64Recomp::Context& context, const ELFIO::elfio& elf_file, ELF if (section_index < context.sections.size()) { auto section_offset = value - elf_file.sections[section_index]->get_address(); - const uint32_t* words = reinterpret_cast(elf_file.sections[section_index]->get_data() + section_offset); uint32_t vram = static_cast(value); uint32_t num_instructions = type == ELFIO::STT_FUNC ? size / 4 : 0; uint32_t rom_address = static_cast(section_offset + section.rom_addr); + const uint32_t* words = reinterpret_cast(context.rom.data() + rom_address); section.function_addrs.push_back(vram); context.functions_by_vram[vram].push_back(context.functions.size()); @@ -551,6 +551,36 @@ ELFIO::section* read_sections(N64Recomp::Context& context, const N64Recomp::ElfP return a.address < b.address; } ); + + // Patch the ROM word for HI16 and LO16 reference symbol relocs to non-relocatable sections. + for (size_t i = 0; i < section_out.relocs.size(); i++) { + auto& reloc = section_out.relocs[i]; + if (reloc.reference_symbol && (reloc.type == N64Recomp::RelocType::R_MIPS_HI16 || reloc.type == N64Recomp::RelocType::R_MIPS_LO16)) { + bool target_section_relocatable = context.is_reference_section_relocatable(reloc.target_section); + if (!target_section_relocatable) { + uint32_t reloc_rom_addr = reloc.address - section_out.ram_addr + section_out.rom_addr; + uint32_t reloc_rom_word = byteswap(*reinterpret_cast(context.rom.data() + reloc_rom_addr)); + + uint32_t ref_section_vram = context.get_reference_section_vram(reloc.target_section); + uint32_t full_immediate = reloc.target_section_offset + ref_section_vram; + + uint32_t imm; + + if (reloc.type == N64Recomp::RelocType::R_MIPS_HI16) { + imm = (full_immediate >> 16) + ((full_immediate >> 15) & 1); + } + else { + imm = full_immediate & 0xFFFF; + } + + *reinterpret_cast(context.rom.data() + reloc_rom_addr) = byteswap(reloc_rom_word | imm); + // Remove the reloc by setting it to a type of NONE. + reloc.type = N64Recomp::RelocType::R_MIPS_NONE; + reloc.reference_symbol = false; + reloc.symbol_index = (uint32_t)-1; + } + } + } } } diff --git a/src/recompilation.cpp b/src/recompilation.cpp index 8720837..5cfe8e5 100644 --- a/src/recompilation.cpp +++ b/src/recompilation.cpp @@ -184,19 +184,10 @@ bool process_instruction(GeneratorType& generator, const N64Recomp::Context& con reloc_reference_symbol = reloc.symbol_index; // Don't try to relocate special section symbols. if (context.is_regular_reference_section(reloc.target_section) || reloc_section == N64Recomp::SectionAbsolute) { + // TODO this may not be needed anymore as HI16/LO16 relocs to non-relocatable sections is handled directly in elf parsing. bool ref_section_relocatable = context.is_reference_section_relocatable(reloc.target_section); // Resolve HI16 and LO16 reference symbol relocs to non-relocatable sections by patching the instruction immediate. if (!ref_section_relocatable && (reloc_type == N64Recomp::RelocType::R_MIPS_HI16 || reloc_type == N64Recomp::RelocType::R_MIPS_LO16)) { - uint32_t ref_section_vram = context.get_reference_section_vram(reloc.target_section); - uint32_t full_immediate = reloc.target_section_offset + ref_section_vram; - - if (reloc_type == N64Recomp::RelocType::R_MIPS_HI16) { - imm = (full_immediate >> 16) + ((full_immediate >> 15) & 1); - } - else if (reloc_type == N64Recomp::RelocType::R_MIPS_LO16) { - imm = full_immediate & 0xFFFF; - } - // The reloc has been processed, so set it to none to prevent it getting processed a second time during instruction code generation. reloc_type = N64Recomp::RelocType::R_MIPS_NONE; reloc_reference_symbol = (size_t)-1;