mirror of
https://github.com/N64Recomp/N64ModernRuntime.git
synced 2026-05-11 03:12:15 +00:00
Only create the regenerated code handle if any functions need to be regenerated
This commit is contained in:
parent
c3968de461
commit
11259826d7
1 changed files with 142 additions and 139 deletions
|
|
@ -1014,153 +1014,156 @@ std::vector<recomp::mods::ModLoadErrorDetails> recomp::mods::ModContext::load_mo
|
|||
}
|
||||
}
|
||||
|
||||
// Sort the unprocessed hooks by section and vram.
|
||||
std::sort(unprocessed_hooks.begin(), unprocessed_hooks.end(),
|
||||
[](const std::pair<recomp::mods::HookDefinition, size_t>& lhs, const std::pair<recomp::mods::HookDefinition, size_t>& rhs) {
|
||||
if (lhs.first.section_rom == rhs.first.section_rom) {
|
||||
return lhs.first.function_vram < rhs.first.function_vram;
|
||||
if (!unprocessed_hooks.empty()) {
|
||||
|
||||
// Sort the unprocessed hooks by section and vram.
|
||||
std::sort(unprocessed_hooks.begin(), unprocessed_hooks.end(),
|
||||
[](const std::pair<recomp::mods::HookDefinition, size_t>& lhs, const std::pair<recomp::mods::HookDefinition, size_t>& rhs) {
|
||||
if (lhs.first.section_rom == rhs.first.section_rom) {
|
||||
return lhs.first.function_vram < rhs.first.function_vram;
|
||||
}
|
||||
else {
|
||||
return lhs.first.section_rom < rhs.first.section_rom;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Collect the unprocessed hooks into a patch list.
|
||||
// Hooks have been sorted by their section address and function address at this point so they
|
||||
// can be gathered by section into the patch list.
|
||||
PatchedList patchlist{};
|
||||
uint32_t cur_section_rom = 0xFFFFFFFF;
|
||||
uint32_t cur_section_vram = 0xFFFFFFFF;
|
||||
uint16_t cur_section_index = 0xFFFF;
|
||||
uint32_t cur_function_vram = 0xFFFFFFFF;
|
||||
|
||||
// While scanning, also track the hook slot indices for recompilation and the native functions so they can be patched.
|
||||
std::vector<recomp_func_t*> func_ptrs{};
|
||||
// Maps function index within context to hook slot index.
|
||||
std::unordered_map<size_t, size_t> entry_func_hooks{};
|
||||
std::unordered_map<size_t, size_t> return_func_hooks{};
|
||||
|
||||
for (size_t hook_index = 0; hook_index < unprocessed_hooks.size(); hook_index++) {
|
||||
const auto& cur_hook = unprocessed_hooks[hook_index];
|
||||
const auto& cur_hook_def = cur_hook.first;
|
||||
size_t cur_hook_slot_index = cur_hook.second;
|
||||
|
||||
if (cur_hook_def.section_rom != cur_section_rom) {
|
||||
// Get the index of the section.
|
||||
auto find_section_it = section_vrom_map.find(cur_hook_def.section_rom);
|
||||
if (find_section_it == section_vrom_map.end()) {
|
||||
std::stringstream error_param_stream{};
|
||||
error_param_stream << std::hex <<
|
||||
"section: 0x" << cur_hook_def.section_rom <<
|
||||
" func: 0x" << std::setfill('0') << std::setw(8) << cur_hook_def.function_vram;
|
||||
ret.emplace_back(ModLoadErrorDetails{
|
||||
"", ModLoadError::FailedToLoadCode, error_to_string(CodeModLoadError::InvalidHook) + ":" + error_param_stream.str()
|
||||
});
|
||||
unload_mods();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t section_index = find_section_it->second;
|
||||
|
||||
// Allocate a new section.
|
||||
auto& section_out = patchlist.sections.emplace_back(PatchedSection{
|
||||
.rom_addr = cur_hook_def.section_rom,
|
||||
.ram_addr = recomp::overlays::get_section_ram_addr(section_index),
|
||||
.first_func_index = patchlist.functions.size()
|
||||
});
|
||||
|
||||
// Update the tracked section fields.
|
||||
cur_section_rom = section_out.rom_addr;
|
||||
cur_section_vram = section_out.ram_addr;
|
||||
cur_section_index = section_index;
|
||||
|
||||
// Reset the tracked function vram to prevent issues when two functions have the same vram in different sections.
|
||||
cur_function_vram = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
if (cur_hook_def.function_vram != cur_function_vram) {
|
||||
uint32_t function_section_offset = cur_hook_def.function_vram - cur_section_vram;
|
||||
FuncEntry func_entry{};
|
||||
bool found_func = recomp::overlays::get_func_entry_by_section_index_function_offset(cur_section_index, function_section_offset, func_entry);
|
||||
|
||||
if (!found_func) {
|
||||
std::stringstream error_param_stream{};
|
||||
error_param_stream << std::hex <<
|
||||
"section: 0x" << cur_hook_def.section_rom <<
|
||||
" func: 0x" << std::setfill('0') << std::setw(8) << cur_hook_def.function_vram;
|
||||
ret.emplace_back(ModLoadErrorDetails{
|
||||
"", ModLoadError::FailedToLoadCode, error_to_string(CodeModLoadError::InvalidHook) + ":" + error_param_stream.str()
|
||||
});
|
||||
unload_mods();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t function_rom_size = func_entry.rom_size;
|
||||
|
||||
// A size of 0 means the function can't be hooked (e.g. it's a native reimplemented function).
|
||||
if (function_rom_size == 0) {
|
||||
std::stringstream error_param_stream{};
|
||||
error_param_stream << std::hex <<
|
||||
"section: 0x" << cur_hook_def.section_rom <<
|
||||
" func: 0x" << std::setfill('0') << std::setw(8) << cur_hook_def.function_vram;
|
||||
ret.emplace_back(ModLoadErrorDetails{
|
||||
"", ModLoadError::FailedToLoadCode, error_to_string(CodeModLoadError::CannotBeHooked) + ":" + error_param_stream.str()
|
||||
});
|
||||
unload_mods();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Allocate a new function.
|
||||
patchlist.functions.emplace_back(PatchedFunction{
|
||||
.section_offset = function_section_offset,
|
||||
.size = function_rom_size
|
||||
});
|
||||
func_ptrs.push_back(func_entry.func);
|
||||
|
||||
// Update the tracked function address.
|
||||
cur_function_vram = cur_hook_def.function_vram;
|
||||
}
|
||||
|
||||
// Record the hooks in the function to hook mapping.
|
||||
size_t func_index = patchlist.functions.size() - 1;
|
||||
if (cur_hook_def.at_return) {
|
||||
return_func_hooks[func_index] = cur_hook_slot_index;
|
||||
}
|
||||
else {
|
||||
return lhs.first.section_rom < rhs.first.section_rom;
|
||||
entry_func_hooks[func_index] = cur_hook_slot_index;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Collect the unprocessed hooks into a patch list.
|
||||
// Hooks have been sorted by their section address and function address at this point so they
|
||||
// can be gathered by section into the patch list.
|
||||
PatchedList patchlist{};
|
||||
uint32_t cur_section_rom = 0xFFFFFFFF;
|
||||
uint32_t cur_section_vram = 0xFFFFFFFF;
|
||||
uint16_t cur_section_index = 0xFFFF;
|
||||
uint32_t cur_function_vram = 0xFFFFFFFF;
|
||||
// Generate the recompiler context.
|
||||
N64Recomp::Context hook_context = context_from_patched_function_list(patchlist, decompressed_rom);
|
||||
hook_context.use_lookup_for_all_function_calls = true;
|
||||
|
||||
// While scanning, also track the hook slot indices for recompilation and the native functions so they can be patched.
|
||||
std::vector<recomp_func_t*> func_ptrs{};
|
||||
// Maps function index within context to hook slot index.
|
||||
std::unordered_map<size_t, size_t> entry_func_hooks{};
|
||||
std::unordered_map<size_t, size_t> return_func_hooks{};
|
||||
|
||||
for (size_t hook_index = 0; hook_index < unprocessed_hooks.size(); hook_index++) {
|
||||
const auto& cur_hook = unprocessed_hooks[hook_index];
|
||||
const auto& cur_hook_def = cur_hook.first;
|
||||
size_t cur_hook_slot_index = cur_hook.second;
|
||||
|
||||
if (cur_hook_def.section_rom != cur_section_rom) {
|
||||
// Get the index of the section.
|
||||
auto find_section_it = section_vrom_map.find(cur_hook_def.section_rom);
|
||||
if (find_section_it == section_vrom_map.end()) {
|
||||
std::stringstream error_param_stream{};
|
||||
error_param_stream << std::hex <<
|
||||
"section: 0x" << cur_hook_def.section_rom <<
|
||||
" func: 0x" << std::setfill('0') << std::setw(8) << cur_hook_def.function_vram;
|
||||
ret.emplace_back(ModLoadErrorDetails{
|
||||
"", ModLoadError::FailedToLoadCode, error_to_string(CodeModLoadError::InvalidHook) + ":" + error_param_stream.str()
|
||||
});
|
||||
unload_mods();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t section_index = find_section_it->second;
|
||||
|
||||
// Allocate a new section.
|
||||
auto& section_out = patchlist.sections.emplace_back(PatchedSection{
|
||||
.rom_addr = cur_hook_def.section_rom,
|
||||
.ram_addr = recomp::overlays::get_section_ram_addr(section_index),
|
||||
.first_func_index = patchlist.functions.size()
|
||||
});
|
||||
|
||||
// Update the tracked section fields.
|
||||
cur_section_rom = section_out.rom_addr;
|
||||
cur_section_vram = section_out.ram_addr;
|
||||
cur_section_index = section_index;
|
||||
|
||||
// Reset the tracked function vram to prevent issues when two functions have the same vram in different sections.
|
||||
cur_function_vram = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
if (cur_hook_def.function_vram != cur_function_vram) {
|
||||
uint32_t function_section_offset = cur_hook_def.function_vram - cur_section_vram;
|
||||
FuncEntry func_entry{};
|
||||
bool found_func = recomp::overlays::get_func_entry_by_section_index_function_offset(cur_section_index, function_section_offset, func_entry);
|
||||
|
||||
if (!found_func) {
|
||||
std::stringstream error_param_stream{};
|
||||
error_param_stream << std::hex <<
|
||||
"section: 0x" << cur_hook_def.section_rom <<
|
||||
" func: 0x" << std::setfill('0') << std::setw(8) << cur_hook_def.function_vram;
|
||||
ret.emplace_back(ModLoadErrorDetails{
|
||||
"", ModLoadError::FailedToLoadCode, error_to_string(CodeModLoadError::InvalidHook) + ":" + error_param_stream.str()
|
||||
});
|
||||
unload_mods();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t function_rom_size = func_entry.rom_size;
|
||||
|
||||
// A size of 0 means the function can't be hooked (e.g. it's a native reimplemented function).
|
||||
if (function_rom_size == 0) {
|
||||
std::stringstream error_param_stream{};
|
||||
error_param_stream << std::hex <<
|
||||
"section: 0x" << cur_hook_def.section_rom <<
|
||||
" func: 0x" << std::setfill('0') << std::setw(8) << cur_hook_def.function_vram;
|
||||
ret.emplace_back(ModLoadErrorDetails{
|
||||
"", ModLoadError::FailedToLoadCode, error_to_string(CodeModLoadError::CannotBeHooked) + ":" + error_param_stream.str()
|
||||
});
|
||||
unload_mods();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Allocate a new function.
|
||||
patchlist.functions.emplace_back(PatchedFunction{
|
||||
.section_offset = function_section_offset,
|
||||
.size = function_rom_size
|
||||
});
|
||||
func_ptrs.push_back(func_entry.func);
|
||||
|
||||
// Update the tracked function address.
|
||||
cur_function_vram = cur_hook_def.function_vram;
|
||||
}
|
||||
|
||||
// Record the hooks in the function to hook mapping.
|
||||
size_t func_index = patchlist.functions.size() - 1;
|
||||
if (cur_hook_def.at_return) {
|
||||
return_func_hooks[func_index] = cur_hook_slot_index;
|
||||
}
|
||||
else {
|
||||
entry_func_hooks[func_index] = cur_hook_slot_index;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the recompiler context.
|
||||
N64Recomp::Context hook_context = context_from_patched_function_list(patchlist, decompressed_rom);
|
||||
hook_context.use_lookup_for_all_function_calls = true;
|
||||
|
||||
// Regenerate the functions using the live recompiler.
|
||||
ModCodeHandleInputs handle_inputs{
|
||||
.base_event_index = 0, // No events in vanilla functions, so this doesn't matter.
|
||||
.recomp_trigger_event = recomp_trigger_event,
|
||||
.get_function = get_function,
|
||||
.cop0_status_write = cop0_status_write,
|
||||
.cop0_status_read = cop0_status_read,
|
||||
.switch_error = switch_error,
|
||||
.do_break = do_break,
|
||||
.reference_section_addresses = section_addresses,
|
||||
};
|
||||
regenerated_code_handle = std::make_unique<LiveRecompilerCodeHandle>(hook_context, handle_inputs, std::move(entry_func_hooks), std::move(return_func_hooks));
|
||||
// Regenerate the functions using the live recompiler.
|
||||
ModCodeHandleInputs handle_inputs{
|
||||
.base_event_index = 0, // No events in vanilla functions, so this doesn't matter.
|
||||
.recomp_trigger_event = recomp_trigger_event,
|
||||
.get_function = get_function,
|
||||
.cop0_status_write = cop0_status_write,
|
||||
.cop0_status_read = cop0_status_read,
|
||||
.switch_error = switch_error,
|
||||
.do_break = do_break,
|
||||
.reference_section_addresses = section_addresses,
|
||||
};
|
||||
regenerated_code_handle = std::make_unique<LiveRecompilerCodeHandle>(hook_context, handle_inputs, std::move(entry_func_hooks), std::move(return_func_hooks));
|
||||
|
||||
if (!regenerated_code_handle->good()) {
|
||||
regenerated_code_handle.reset();
|
||||
ret.emplace_back(ModLoadErrorDetails{
|
||||
"", ModLoadError::FailedToLoadCode, error_to_string(CodeModLoadError::InternalError)
|
||||
});
|
||||
unload_mods();
|
||||
return ret;
|
||||
}
|
||||
if (!regenerated_code_handle->good()) {
|
||||
regenerated_code_handle.reset();
|
||||
ret.emplace_back(ModLoadErrorDetails{
|
||||
"", ModLoadError::FailedToLoadCode, error_to_string(CodeModLoadError::InternalError)
|
||||
});
|
||||
unload_mods();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Patch the functions that were regenerated.
|
||||
for (size_t patched_func_index = 0; patched_func_index < func_ptrs.size(); patched_func_index++) {
|
||||
patch_func(func_ptrs[patched_func_index], regenerated_code_handle->get_function_handle(patched_func_index));
|
||||
// Patch the functions that were regenerated.
|
||||
for (size_t patched_func_index = 0; patched_func_index < func_ptrs.size(); patched_func_index++) {
|
||||
patch_func(func_ptrs[patched_func_index], regenerated_code_handle->get_function_handle(patched_func_index));
|
||||
}
|
||||
}
|
||||
|
||||
active_game = mod_game_index;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue