Skip to content

Commit 0afeb08

Browse files
authored
Fix jump table handling in regenerated relocatable functions (#86)
1 parent 5360099 commit 0afeb08

File tree

3 files changed

+30
-17
lines changed

3 files changed

+30
-17
lines changed

librecomp/include/librecomp/mods.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ namespace recomp {
419419
class LiveRecompilerCodeHandle : public ModCodeHandle {
420420
public:
421421
LiveRecompilerCodeHandle(const N64Recomp::Context& context, const ModCodeHandleInputs& inputs,
422-
std::unordered_map<size_t, size_t>&& entry_func_hooks, std::unordered_map<size_t, size_t>&& return_func_hooks);
422+
std::unordered_map<size_t, size_t>&& entry_func_hooks, std::unordered_map<size_t, size_t>&& return_func_hooks, std::vector<size_t>&& original_section_indices, bool regenerated);
423423

424424
~LiveRecompilerCodeHandle() = default;
425425

librecomp/src/mods.cpp

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -420,9 +420,11 @@ recomp::mods::CodeModLoadError recomp::mods::DynamicLibraryCodeHandle::populate_
420420

421421
recomp::mods::LiveRecompilerCodeHandle::LiveRecompilerCodeHandle(
422422
const N64Recomp::Context& context, const ModCodeHandleInputs& inputs,
423-
std::unordered_map<size_t, size_t>&& entry_func_hooks, std::unordered_map<size_t, size_t>&& return_func_hooks)
423+
std::unordered_map<size_t, size_t>&& entry_func_hooks, std::unordered_map<size_t, size_t>&& return_func_hooks, std::vector<size_t>&& original_section_indices, bool regenerated)
424424
{
425-
section_addresses = std::make_unique<int32_t[]>(context.sections.size());
425+
if (!regenerated) {
426+
section_addresses = std::make_unique<int32_t[]>(context.sections.size());
427+
}
426428
base_event_index = inputs.base_event_index;
427429

428430
N64Recomp::LiveGeneratorInputs recompiler_inputs{
@@ -436,10 +438,12 @@ recomp::mods::LiveRecompilerCodeHandle::LiveRecompilerCodeHandle(
436438
.pause_self = pause_self,
437439
.trigger_event = inputs.recomp_trigger_event,
438440
.reference_section_addresses = inputs.reference_section_addresses,
439-
.local_section_addresses = section_addresses.get(),
441+
// Use the reference section addresses as the local section addresses if this is regenerated code so that jump tables work correctly.
442+
.local_section_addresses = regenerated ? inputs.reference_section_addresses : section_addresses.get(),
440443
.run_hook = run_hook,
441444
.entry_func_hooks = std::move(entry_func_hooks),
442-
.return_func_hooks = std::move(return_func_hooks)
445+
.return_func_hooks = std::move(return_func_hooks),
446+
.original_section_indices = std::move(original_section_indices)
443447
};
444448

445449
N64Recomp::LiveGenerator generator{ context.functions.size(), recompiler_inputs };
@@ -759,8 +763,10 @@ std::vector<recomp::mods::ModDetails> recomp::mods::ModContext::get_mod_details(
759763
struct RegeneratedSection {
760764
uint32_t rom_addr;
761765
uint32_t ram_addr;
766+
uint16_t original_index;
762767
size_t first_func_index;
763768
size_t first_reloc_index;
769+
bool relocatable;
764770
};
765771

766772
struct RegeneratedFunction {
@@ -824,7 +830,7 @@ N64Recomp::Context context_from_regenerated_list(const RegeneratedList& regenlis
824830
section_out.name = "patch_section_" + std::to_string(section_index);
825831
section_out.bss_section_index = 0;
826832
section_out.executable = true;
827-
section_out.relocatable = false;
833+
section_out.relocatable = section_in.relocatable;
828834
section_out.has_mips32_relocs = false;
829835

830836
std::vector<size_t>& section_funcs_out = ret.section_functions[section_index];
@@ -1127,31 +1133,29 @@ std::vector<recomp::mods::ModLoadErrorDetails> build_regen_list(
11271133

11281134
if constexpr (patched_regenlist) {
11291135
section_ram_addr = recomp::overlays::get_patch_section_ram_addr(section_index);
1136+
cur_section_relocs = recomp::overlays::get_patch_section_relocs(section_index);
11301137
}
11311138
else {
11321139
section_ram_addr = recomp::overlays::get_section_ram_addr(section_index);
1140+
cur_section_relocs = recomp::overlays::get_section_relocs(section_index);
11331141
}
11341142

11351143
// Allocate a new section.
11361144
auto& section_out = regenlist.sections.emplace_back(RegeneratedSection{
11371145
.rom_addr = cur_hook_def.section_rom,
11381146
.ram_addr = section_ram_addr,
1147+
.original_index = section_index,
11391148
.first_func_index = regenlist.functions.size(),
1140-
.first_reloc_index = regenlist.relocs.size()
1149+
.first_reloc_index = regenlist.relocs.size(),
1150+
// Patch sections are never relocatable, so a section is relocatable if it has any relocs and is not a base patch section.
1151+
.relocatable = !patched_regenlist && !cur_section_relocs.empty()
11411152
});
11421153

11431154
// Update the tracked section fields.
11441155
cur_section_rom = section_out.rom_addr;
11451156
cur_section_vram = section_out.ram_addr;
11461157
cur_section_index = section_index;
11471158
cur_section_reloc_index = 0;
1148-
1149-
if constexpr (patched_regenlist) {
1150-
cur_section_relocs = recomp::overlays::get_patch_section_relocs(cur_section_index);
1151-
}
1152-
else {
1153-
cur_section_relocs = recomp::overlays::get_section_relocs(cur_section_index);
1154-
}
11551159

11561160
// Reset the tracked function vram to prevent issues when two functions have the same vram in different sections.
11571161
cur_function_vram = 0xFFFFFFFF;
@@ -1292,7 +1296,15 @@ std::unique_ptr<recomp::mods::LiveRecompilerCodeHandle> apply_regenlist(Regenera
12921296
.do_break = do_break,
12931297
.reference_section_addresses = section_addresses,
12941298
};
1295-
regenerated_code_handle = std::make_unique<LiveRecompilerCodeHandle>(hook_context, handle_inputs, std::move(regenlist.entry_func_hooks), std::move(regenlist.return_func_hooks));
1299+
1300+
std::vector<size_t> original_section_indices{};
1301+
original_section_indices.resize(regenlist.sections.size());
1302+
for (size_t new_section_index = 0; new_section_index < regenlist.sections.size(); new_section_index++) {
1303+
original_section_indices[new_section_index] = regenlist.sections[new_section_index].original_index;
1304+
}
1305+
1306+
regenerated_code_handle = std::make_unique<LiveRecompilerCodeHandle>(hook_context, handle_inputs,
1307+
std::move(regenlist.entry_func_hooks), std::move(regenlist.return_func_hooks), std::move(original_section_indices), true);
12961308

12971309
if (!regenerated_code_handle->good()) {
12981310
return {};
@@ -1630,7 +1642,8 @@ recomp::mods::CodeModLoadError recomp::mods::ModContext::load_mod_code(uint8_t*
16301642
}
16311643
// Live recompiler code handle.
16321644
else {
1633-
mod.code_handle = std::make_unique<LiveRecompilerCodeHandle>(*mod.recompiler_context, handle_inputs, std::move(entry_func_hooks), std::move(return_func_hooks));
1645+
mod.code_handle = std::make_unique<LiveRecompilerCodeHandle>(*mod.recompiler_context, handle_inputs,
1646+
std::move(entry_func_hooks), std::move(return_func_hooks), std::vector<size_t>{}, false);
16341647

16351648
if (!mod.code_handle->good()) {
16361649
mod.code_handle.reset();

0 commit comments

Comments
 (0)