mirror of
https://github.com/N64Recomp/N64Recomp.git
synced 2025-05-20 02:14:55 +00:00
Symbol file toml update (#52)
* Symbol input file mechanism * Migration to new toml lib --------- Co-authored-by: dcvz <david@dcvz.io>
This commit is contained in:
parent
26c5c2cbb8
commit
e0e52d1fc3
10 changed files with 748 additions and 367 deletions
236
src/main.cpp
236
src/main.cpp
|
@ -1018,7 +1018,6 @@ ELFIO::section* read_sections(RecompPort::Context& context, const RecompPort::Co
|
|||
reloc_out.address = rel_offset;
|
||||
reloc_out.symbol_index = rel_symbol;
|
||||
reloc_out.type = static_cast<RecompPort::RelocType>(rel_type);
|
||||
reloc_out.needs_relocation = false;
|
||||
|
||||
std::string rel_symbol_name;
|
||||
ELFIO::Elf64_Addr rel_symbol_value;
|
||||
|
@ -1033,12 +1032,6 @@ ELFIO::section* read_sections(RecompPort::Context& context, const RecompPort::Co
|
|||
|
||||
reloc_out.target_section = rel_symbol_section_index;
|
||||
|
||||
bool rel_needs_relocation = false;
|
||||
|
||||
if (rel_symbol_section_index < context.sections.size()) {
|
||||
rel_needs_relocation = context.sections[rel_symbol_section_index].relocatable;
|
||||
}
|
||||
|
||||
// Reloc pairing, see MIPS System V ABI documentation page 4-18 (https://refspecs.linuxfoundation.org/elf/mipsabi.pdf)
|
||||
if (reloc_out.type == RecompPort::RelocType::R_MIPS_LO16) {
|
||||
if (prev_hi) {
|
||||
|
@ -1212,6 +1205,79 @@ bool recompile_single_function(const RecompPort::Context& context, const RecompP
|
|||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::string> reloc_names {
|
||||
"R_MIPS_NONE ",
|
||||
"R_MIPS_16",
|
||||
"R_MIPS_32",
|
||||
"R_MIPS_REL32",
|
||||
"R_MIPS_26",
|
||||
"R_MIPS_HI16",
|
||||
"R_MIPS_LO16",
|
||||
"R_MIPS_GPREL16",
|
||||
};
|
||||
|
||||
void dump_context(const RecompPort::Context& context, const std::filesystem::path& path) {
|
||||
std::ofstream context_file {path};
|
||||
|
||||
for (size_t section_index = 0; section_index < context.sections.size(); section_index++) {
|
||||
const RecompPort::Section& section = context.sections[section_index];
|
||||
const std::vector<size_t>& section_funcs = context.section_functions[section_index];
|
||||
if (!section_funcs.empty()) {
|
||||
fmt::print(context_file,
|
||||
"# Autogenerated from an ELF via N64Recomp\n"
|
||||
"[[section]]\n"
|
||||
"name = \"{}\"\n"
|
||||
"rom = 0x{:08X}\n"
|
||||
"vram = 0x{:08X}\n"
|
||||
"size = 0x{:X}\n"
|
||||
"\n",
|
||||
section.name, section.rom_addr, section.ram_addr, section.size);
|
||||
|
||||
if (!section.relocs.empty()) {
|
||||
fmt::print(context_file, "relocs = [\n");
|
||||
|
||||
for (const RecompPort::Reloc& reloc : section.relocs) {
|
||||
if (reloc.target_section == section_index || reloc.target_section == section.bss_section_index) {
|
||||
// TODO allow MIPS32 relocs for TLB mapping support.
|
||||
if (reloc.type == RecompPort::RelocType::R_MIPS_HI16 || reloc.type == RecompPort::RelocType::R_MIPS_LO16) {
|
||||
fmt::print(context_file, " {{ type = \"{}\", vram = 0x{:08X}, target_vram = 0x{:08X} }},\n",
|
||||
reloc_names[static_cast<int>(reloc.type)], reloc.address, reloc.target_address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt::print(context_file, "]\n\n");
|
||||
}
|
||||
|
||||
fmt::print(context_file, "functions = [\n");
|
||||
|
||||
for (const size_t& function_index : section_funcs) {
|
||||
const RecompPort::Function& func = context.functions[function_index];
|
||||
fmt::print(context_file, " {{ name = \"{}\", vram = 0x{:08X}, size = 0x{:X} }},\n",
|
||||
func.name, func.vram, func.words.size() * sizeof(func.words[0]));
|
||||
}
|
||||
|
||||
fmt::print(context_file, "]\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<uint8_t> read_file(const std::filesystem::path& path) {
|
||||
std::vector<uint8_t> ret;
|
||||
|
||||
std::ifstream file{ path, std::ios::binary};
|
||||
|
||||
if (file.good()) {
|
||||
file.seekg(0, std::ios::end);
|
||||
ret.resize(file.tellg());
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
file.read(reinterpret_cast<char*>(ret.data()), ret.size());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
auto exit_failure = [] (const std::string& error_str) {
|
||||
fmt::vprint(stderr, error_str, fmt::make_format_args());
|
||||
|
@ -1230,7 +1296,6 @@ int main(int argc, char** argv) {
|
|||
exit_failure(fmt::format("Failed to load config file: {}\n", config_path));
|
||||
}
|
||||
|
||||
ELFIO::elfio elf_file;
|
||||
RabbitizerConfig_Cfg.pseudos.pseudoMove = false;
|
||||
RabbitizerConfig_Cfg.pseudos.pseudoBeqz = false;
|
||||
RabbitizerConfig_Cfg.pseudos.pseudoBnez = false;
|
||||
|
@ -1248,52 +1313,118 @@ int main(int argc, char** argv) {
|
|||
std::unordered_set<std::string> relocatable_sections{};
|
||||
relocatable_sections.insert(relocatable_sections_ordered.begin(), relocatable_sections_ordered.end());
|
||||
|
||||
if (!elf_file.load(config.elf_path.string())) {
|
||||
exit_failure("Failed to load provided elf file\n");
|
||||
RecompPort::Context context{};
|
||||
|
||||
if (!config.elf_path.empty() && !config.symbols_file_path.empty()) {
|
||||
exit_failure("Config file cannot provide both an elf and a symbols file\n");
|
||||
}
|
||||
|
||||
if (elf_file.get_class() != ELFIO::ELFCLASS32) {
|
||||
exit_failure("Incorrect elf class\n");
|
||||
// Build a context from the provided elf file.
|
||||
if (!config.elf_path.empty()) {
|
||||
ELFIO::elfio elf_file;
|
||||
|
||||
if (!elf_file.load(config.elf_path.string())) {
|
||||
exit_failure("Failed to load provided elf file\n");
|
||||
}
|
||||
|
||||
if (elf_file.get_class() != ELFIO::ELFCLASS32) {
|
||||
exit_failure("Incorrect elf class\n");
|
||||
}
|
||||
|
||||
if (elf_file.get_encoding() != ELFIO::ELFDATA2MSB) {
|
||||
exit_failure("Incorrect endianness\n");
|
||||
}
|
||||
|
||||
context = { elf_file };
|
||||
context.relocatable_sections = std::move(relocatable_sections);
|
||||
|
||||
// Read all of the sections in the elf and look for the symbol table section
|
||||
ELFIO::section* symtab_section = read_sections(context, config, elf_file);
|
||||
|
||||
// Search the sections to see if any are overlays or TLB-mapped
|
||||
analyze_sections(context, elf_file);
|
||||
|
||||
// If no symbol table was found then exit
|
||||
if (symtab_section == nullptr) {
|
||||
exit_failure("No symbol table section found\n");
|
||||
}
|
||||
|
||||
// Manually sized functions
|
||||
for (const auto& func_size : config.manual_func_sizes) {
|
||||
context.manually_sized_funcs.emplace(func_size.func_name, func_size.size_bytes);
|
||||
}
|
||||
|
||||
// Read all of the symbols in the elf and look for the entrypoint function
|
||||
bool found_entrypoint_func = read_symbols(context, elf_file, symtab_section, config.entrypoint, config.has_entrypoint, config.use_absolute_symbols);
|
||||
|
||||
// Add any manual functions
|
||||
add_manual_functions(context, elf_file, config.manual_functions);
|
||||
|
||||
if (config.has_entrypoint && !found_entrypoint_func) {
|
||||
exit_failure("Could not find entrypoint function\n");
|
||||
}
|
||||
}
|
||||
// Build a context from the provided symbols file.
|
||||
else if (!config.symbols_file_path.empty()) {
|
||||
if (config.rom_file_path.empty()) {
|
||||
exit_failure("A ROM file must be provided when using a symbols file\n");
|
||||
}
|
||||
|
||||
std::vector<uint8_t> rom = read_file(config.rom_file_path);
|
||||
if (rom.empty()) {
|
||||
exit_failure("Failed to load ROM file: " + config.rom_file_path.string() + "\n");
|
||||
}
|
||||
|
||||
if (!RecompPort::Context::from_symbol_file(config.symbols_file_path, std::move(rom), context)) {
|
||||
exit_failure("Failed to load symbols file\n");
|
||||
}
|
||||
|
||||
auto rename_function = [&context](size_t func_index, const std::string& new_name) {
|
||||
RecompPort::Function& func = context.functions[func_index];
|
||||
|
||||
context.functions_by_name.erase(func.name);
|
||||
func.name = new_name;
|
||||
context.functions_by_name[func.name] = func_index;
|
||||
};
|
||||
|
||||
for (size_t func_index = 0; func_index < context.functions.size(); func_index++) {
|
||||
RecompPort::Function& func = context.functions[func_index];
|
||||
if (reimplemented_funcs.contains(func.name)) {
|
||||
rename_function(func_index, func.name + "_recomp");
|
||||
func.reimplemented = true;
|
||||
func.ignored = true;
|
||||
} else if (ignored_funcs.contains(func.name)) {
|
||||
rename_function(func_index, func.name + "_recomp");
|
||||
func.ignored = true;
|
||||
} else if (renamed_funcs.contains(func.name)) {
|
||||
rename_function(func_index, func.name + "_recomp");
|
||||
func.ignored = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (config.has_entrypoint) {
|
||||
bool found_entrypoint = false;
|
||||
|
||||
for (uint32_t func_index : context.functions_by_vram[config.entrypoint]) {
|
||||
auto& func = context.functions[func_index];
|
||||
if (func.rom == 0x1000) {
|
||||
rename_function(func_index, "recomp_entrypoint");
|
||||
found_entrypoint = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_entrypoint) {
|
||||
exit_failure("No entrypoint provided in symbol file\n");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
exit_failure("Config file must provide either an elf or a symbols file\n");
|
||||
}
|
||||
|
||||
if (elf_file.get_encoding() != ELFIO::ELFDATA2MSB) {
|
||||
exit_failure("Incorrect endianness\n");
|
||||
}
|
||||
|
||||
RecompPort::Context context{ elf_file };
|
||||
context.relocatable_sections = std::move(relocatable_sections);
|
||||
|
||||
// Read all of the sections in the elf and look for the symbol table section
|
||||
ELFIO::section* symtab_section = read_sections(context, config, elf_file);
|
||||
|
||||
// Search the sections to see if any are overlays or TLB-mapped
|
||||
analyze_sections(context, elf_file);
|
||||
|
||||
// If no symbol table was found then exit
|
||||
if (symtab_section == nullptr) {
|
||||
exit_failure("No symbol table section found\n");
|
||||
}
|
||||
|
||||
// Functions that weren't declared properly and thus have no size in the elf
|
||||
//context.manually_sized_funcs.emplace("guMtxF2L", 0x64);
|
||||
//context.manually_sized_funcs.emplace("guScaleF", 0x48);
|
||||
//context.manually_sized_funcs.emplace("guTranslateF", 0x48);
|
||||
//context.manually_sized_funcs.emplace("guMtxIdentF", 0x48);
|
||||
//context.manually_sized_funcs.emplace("sqrtf", 0x8);
|
||||
//context.manually_sized_funcs.emplace("guMtxIdent", 0x4C);
|
||||
for (const auto& func_size : config.manual_func_sizes) {
|
||||
context.manually_sized_funcs.emplace(func_size.func_name, func_size.size_bytes);
|
||||
}
|
||||
|
||||
// Read all of the symbols in the elf and look for the entrypoint function
|
||||
bool found_entrypoint_func = read_symbols(context, elf_file, symtab_section, config.entrypoint, config.has_entrypoint, config.use_absolute_symbols);
|
||||
|
||||
// Add any manual functions
|
||||
add_manual_functions(context, elf_file, config.manual_functions);
|
||||
|
||||
if (config.has_entrypoint && !found_entrypoint_func) {
|
||||
exit_failure("Could not find entrypoint function\n");
|
||||
}
|
||||
|
||||
fmt::print("Function count: {}\n", context.functions.size());
|
||||
|
||||
|
@ -1312,6 +1443,11 @@ int main(int argc, char** argv) {
|
|||
|
||||
std::vector<std::vector<uint32_t>> static_funcs_by_section{ context.sections.size() };
|
||||
|
||||
// TODO expose a way to dump the context from the command line. Make sure not to rename functions when doing so.
|
||||
//fmt::print("Dumping context\n");
|
||||
//dump_context(context, "dump.toml");
|
||||
//return 0;
|
||||
|
||||
fmt::print("Working dir: {}\n", std::filesystem::current_path().string());
|
||||
|
||||
// Stub out any functions specified in the config file.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue