#include #include #include #include "recomp.h" #include "../RecompiledFuncs/recomp_overlays.inl" constexpr size_t num_code_sections = ARRLEN(section_table); // SectionTableEntry sections[] defined in recomp_overlays.inl struct LoadedSection { int32_t loaded_ram_addr; size_t section_table_index; bool operator<(const LoadedSection& rhs) { return loaded_ram_addr < rhs.loaded_ram_addr; } }; std::vector loaded_sections{}; std::unordered_map func_map{}; void load_overlay(size_t section_table_index, int32_t ram) { const SectionTableEntry& section = section_table[section_table_index]; for (size_t function_index = 0; function_index < section.num_funcs; function_index++) { const FuncEntry& func = section.funcs[function_index]; func_map[ram + func.offset] = func.func; } loaded_sections.emplace_back(ram, section_table_index); section_addresses[section.index] = ram; } extern "C" { int32_t section_addresses[num_sections]; } extern "C" void load_overlays(uint32_t rom, int32_t ram_addr, uint32_t size) { // Search for the first section that's included in the loaded rom range // Sections were sorted by `init_overlays` so we can use the bounds functions auto lower = std::lower_bound(§ion_table[0], §ion_table[num_code_sections], rom, [](const SectionTableEntry& entry, uint32_t addr) { return entry.rom_addr < addr; } ); auto upper = std::upper_bound(§ion_table[0], §ion_table[num_code_sections], (uint32_t)(rom + size), [](uint32_t addr, const SectionTableEntry& entry) { return addr < entry.size + entry.rom_addr; } ); // Load the overlays that were found for (auto it = lower; it != upper; ++it) { load_overlay(std::distance(§ion_table[0], it), it->rom_addr - rom + ram_addr); } } extern "C" void unload_overlays(int32_t ram_addr, uint32_t size) { for (auto it = loaded_sections.begin(); it != loaded_sections.end();) { const auto& section = section_table[it->section_table_index]; // Check if the unloaded region overlaps with the loaded section if (ram_addr < (it->loaded_ram_addr + section.size) && (ram_addr + size) >= it->loaded_ram_addr) { // Check if the section isn't entirely in the loaded region if (ram_addr > it->loaded_ram_addr || (ram_addr + size) < (it->loaded_ram_addr + section.size)) { fprintf(stderr, "Cannot partially unload section\n" " rom: 0x%08X size: 0x%08X loaded_addr: 0x%08X\n" " unloaded_ram: 0x%08X unloaded_size : 0x%08X\n", section.rom_addr, section.size, it->loaded_ram_addr, ram_addr, size); std::exit(EXIT_FAILURE); } // Determine where each function was loaded to and remove that entry from the function map for (size_t func_index = 0; func_index < section.num_funcs; func_index++) { const auto& func = section.funcs[func_index]; uint32_t func_address = func.offset + it->loaded_ram_addr; func_map.erase(func_address); } // Reset the section's address in the address table section_addresses[section.index] = 0; // Remove the section from the loaded section map it = loaded_sections.erase(it); // Skip incrementing the iterator continue; } ++it; } } void init_overlays() { for (size_t section_index = 0; section_index < num_code_sections; section_index++) { section_addresses[section_table[section_index].index] = section_table[section_index].ram_addr; } // Sort the executable sections by rom address std::sort(§ion_table[0], §ion_table[num_code_sections], [](const SectionTableEntry& a, const SectionTableEntry& b) { return a.rom_addr < b.rom_addr; } ); } extern "C" recomp_func_t * get_function(int32_t addr) { auto func_find = func_map.find(addr); if (func_find == func_map.end()) { fprintf(stderr, "Failed to find function at 0x%08X\n", addr); std::exit(EXIT_FAILURE); } return func_find->second; }