Improved reloc pairing

This commit is contained in:
Mr-Wiseguy 2024-04-20 20:00:48 -04:00
parent 50d55bd171
commit 47c9033b61

View file

@ -546,8 +546,12 @@ std::unordered_set<std::string> renamed_funcs{
"sqrtf", "sqrtf",
"memcpy", "memcpy",
"memset", "memset",
"strcmp",
"strcat",
"strcpy",
"strchr", "strchr",
"strlen", "strlen",
"strtok",
"sprintf", "sprintf",
"bzero", "bzero",
"bcopy", "bcopy",
@ -571,6 +575,9 @@ std::unordered_set<std::string> renamed_funcs{
"truncf", "truncf",
"vsprintf", "vsprintf",
"__assert", "__assert",
"malloc",
"free",
"realloc",
}; };
bool read_symbols(RecompPort::Context& context, const ELFIO::elfio& elf_file, ELFIO::section* symtab_section, uint32_t entrypoint, bool has_entrypoint, bool use_absolute_symbols) { bool read_symbols(RecompPort::Context& context, const ELFIO::elfio& elf_file, ELFIO::section* symtab_section, uint32_t entrypoint, bool has_entrypoint, bool use_absolute_symbols) {
@ -650,6 +657,7 @@ bool read_symbols(RecompPort::Context& context, const ELFIO::elfio& elf_file, EL
name = name + "_recomp"; name = name + "_recomp";
ignored = false; ignored = false;
} }
if (section_index < context.sections.size()) { if (section_index < context.sections.size()) {
auto section_offset = value - elf_file.sections[section_index]->get_address(); auto section_offset = value - elf_file.sections[section_index]->get_address();
const uint32_t* words = reinterpret_cast<const uint32_t*>(elf_file.sections[section_index]->get_data() + section_offset); const uint32_t* words = reinterpret_cast<const uint32_t*>(elf_file.sections[section_index]->get_data() + section_offset);
@ -670,6 +678,11 @@ bool read_symbols(RecompPort::Context& context, const ELFIO::elfio& elf_file, EL
} }
} }
// Suffix local symbols to prevent name conflicts.
if (bind == ELFIO::STB_LOCAL) {
name = fmt::format("{}_{:08X}", name, rom_address);
}
if (num_instructions > 0) { if (num_instructions > 0) {
context.section_functions[section_index].push_back(context.functions.size()); context.section_functions[section_index].push_back(context.functions.size());
} }
@ -931,6 +944,8 @@ ELFIO::section* read_sections(RecompPort::Context& context, const RecompPort::Co
section_out.relocs.resize(rel_accessor.get_entries_num()); section_out.relocs.resize(rel_accessor.get_entries_num());
// Track whether the previous reloc was a HI16 and its previous full_immediate // Track whether the previous reloc was a HI16 and its previous full_immediate
bool prev_hi = false; bool prev_hi = false;
// Track whether the previous reloc was a LO16
bool prev_lo = false;
uint32_t prev_hi_immediate = 0; uint32_t prev_hi_immediate = 0;
uint32_t prev_hi_symbol = std::numeric_limits<uint32_t>::max(); uint32_t prev_hi_symbol = std::numeric_limits<uint32_t>::max();
@ -977,9 +992,10 @@ ELFIO::section* read_sections(RecompPort::Context& context, const RecompPort::Co
if (reloc_out.type == RecompPort::RelocType::R_MIPS_LO16) { if (reloc_out.type == RecompPort::RelocType::R_MIPS_LO16) {
if (prev_hi) { if (prev_hi) {
if (prev_hi_symbol != rel_symbol) { if (prev_hi_symbol != rel_symbol) {
fmt::print(stderr, "[WARN] Paired HI16 and LO16 relocations have different symbols\n" fmt::print(stderr, "Paired HI16 and LO16 relocations have different symbols\n"
" LO16 reloc index {} in section {} referencing symbol {} with offset 0x{:08X}\n", " LO16 reloc index {} in section {} referencing symbol {} with offset 0x{:08X}\n",
i, section_out.name, reloc_out.symbol_index, reloc_out.address); i, section_out.name, reloc_out.symbol_index, reloc_out.address);
return nullptr;
} }
uint32_t rel_immediate = instr.getProcessedImmediate(); uint32_t rel_immediate = instr.getProcessedImmediate();
uint32_t full_immediate = (prev_hi_immediate << 16) + (int16_t)rel_immediate; uint32_t full_immediate = (prev_hi_immediate << 16) + (int16_t)rel_immediate;
@ -989,12 +1005,33 @@ ELFIO::section* read_sections(RecompPort::Context& context, const RecompPort::Co
section_out.relocs[i - 1].target_address = full_immediate; section_out.relocs[i - 1].target_address = full_immediate;
reloc_out.target_address = full_immediate; reloc_out.target_address = full_immediate;
} }
else {
if (prev_lo) {
uint32_t rel_immediate = instr.getProcessedImmediate();
uint32_t full_immediate;
if (prev_hi_symbol != rel_symbol) {
fmt::print(stderr, "[WARN] LO16 reloc index {} in section {} referencing symbol {} with offset 0x{:08X} follows LO16 with different symbol\n",
i, section_out.name, reloc_out.symbol_index, reloc_out.address);
}
full_immediate = (prev_hi_immediate << 16) + (int16_t)rel_immediate;
reloc_out.target_address = full_immediate;
}
else {
fmt::print(stderr, "Unpaired LO16 reloc index {} in section {} referencing symbol {} with offset 0x{:08X}\n",
i, section_out.name, reloc_out.symbol_index, reloc_out.address);
return nullptr;
}
}
prev_lo = true;
} else { } else {
if (prev_hi) { if (prev_hi) {
fmt::print(stderr, "Unpaired HI16 reloc index {} in section {} referencing symbol {} with offset 0x{:08X}\n", fmt::print(stderr, "Unpaired HI16 reloc index {} in section {} referencing symbol {} with offset 0x{:08X}\n",
i - 1, section_out.name, section_out.relocs[i - 1].symbol_index, section_out.relocs[i - 1].address); i - 1, section_out.name, section_out.relocs[i - 1].symbol_index, section_out.relocs[i - 1].address);
return nullptr; return nullptr;
} }
prev_lo = false;
} }
if (reloc_out.type == RecompPort::RelocType::R_MIPS_HI16) { if (reloc_out.type == RecompPort::RelocType::R_MIPS_HI16) {
@ -1321,29 +1358,28 @@ int main(int argc, char** argv) {
std::vector<uint32_t> section_statics{}; std::vector<uint32_t> section_statics{};
section_statics.assign(statics_set.begin(), statics_set.end()); section_statics.assign(statics_set.begin(), statics_set.end());
size_t closest_func_index = 0;
for (size_t static_func_index = 0; static_func_index < section_statics.size(); static_func_index++) { for (size_t static_func_index = 0; static_func_index < section_statics.size(); static_func_index++) {
uint32_t static_func_addr = section_statics[static_func_index]; uint32_t static_func_addr = section_statics[static_func_index];
// Search for the closest function
while (section_funcs[closest_func_index] < static_func_addr && closest_func_index < section_funcs.size()) {
closest_func_index++;
}
// Determine the end of this static function // Determine the end of this static function
uint32_t cur_func_end = static_cast<uint32_t>(section.size + section.ram_addr); uint32_t cur_func_end = static_cast<uint32_t>(section.size + section.ram_addr);
// Search for the closest function
size_t closest_func_index = 0;
while (section_funcs[closest_func_index] < static_func_addr && closest_func_index < section_funcs.size()) {
closest_func_index++;
}
// Check if there's a nonstatic function after this one // Check if there's a nonstatic function after this one
if (closest_func_index < section_funcs.size()) { if (closest_func_index < section_funcs.size()) {
// If so, use that function's address as the end of this one // If so, use that function's address as the end of this one
cur_func_end = section_funcs[closest_func_index]; cur_func_end = section_funcs[closest_func_index];
} }
uint32_t next_static_index = static_func_index + 1; // Check for any known statics after this function and truncate this function's size to make sure it doesn't overlap.
// Check if there's a known static function after this one for (uint32_t checked_func : statics_set) {
if (next_static_index < section_statics.size()) { if (checked_func > static_func_addr && checked_func < cur_func_end) {
// If so, check if it's before the current end address cur_func_end = checked_func;
if (section_statics[next_static_index] < cur_func_end) {
cur_func_end = section_statics[next_static_index];
} }
} }
@ -1366,6 +1402,8 @@ int main(int argc, char** argv) {
"void {}(uint8_t* rdram, recomp_context* ctx);\n", func.name); "void {}(uint8_t* rdram, recomp_context* ctx);\n", func.name);
bool result; bool result;
size_t prev_num_statics = static_funcs_by_section[func.section_index].size();
if (config.single_file_output) { if (config.single_file_output) {
result = RecompPort::recompile_function(context, config, func, single_output_file, static_funcs_by_section, false); result = RecompPort::recompile_function(context, config, func, single_output_file, static_funcs_by_section, false);
} }
@ -1373,6 +1411,19 @@ int main(int argc, char** argv) {
result = recompile_single_function(context, config, func, config.output_func_path / (func.name + ".c"), static_funcs_by_section); result = recompile_single_function(context, config, func, config.output_func_path / (func.name + ".c"), static_funcs_by_section);
} }
// Add any new static functions that were found while recompiling this one.
size_t cur_num_statics = static_funcs_by_section[func.section_index].size();
if (cur_num_statics != prev_num_statics) {
for (size_t new_static_index = prev_num_statics; new_static_index < cur_num_statics; new_static_index++) {
uint32_t new_static_vram = static_funcs_by_section[func.section_index][new_static_index];
if (!statics_set.contains(new_static_vram)) {
statics_set.emplace(new_static_vram);
section_statics.push_back(new_static_vram);
}
}
}
if (result == false) { if (result == false) {
fmt::print(stderr, "Error recompiling {}\n", func.name); fmt::print(stderr, "Error recompiling {}\n", func.name);
std::exit(EXIT_FAILURE); std::exit(EXIT_FAILURE);
@ -1423,10 +1474,6 @@ int main(int argc, char** argv) {
const auto& section = context.sections[section_index]; const auto& section = context.sections[section_index];
const auto& section_funcs = context.section_functions[section_index]; const auto& section_funcs = context.section_functions[section_index];
if (section.name == ".cosection") {
fmt::print("");
}
if (!section_funcs.empty()) { if (!section_funcs.empty()) {
std::string_view section_name_trimmed{ section.name }; std::string_view section_name_trimmed{ section.name };