diff --git a/RecompModTool/main.cpp b/RecompModTool/main.cpp index d98c3d3..78441fe 100644 --- a/RecompModTool/main.cpp +++ b/RecompModTool/main.cpp @@ -39,7 +39,7 @@ static std::vector get_toml_path_array(const toml::array* return ret; } -static bool read_dependency_file(const std::filesystem::path& dependency_path, N64Recomp::Context& context, std::vector& import_symbol_mod_ids) { +static bool read_dependency_file(const std::filesystem::path& dependency_path, N64Recomp::Context& context, std::vector& dependencies, std::vector& import_symbol_dependency_indices) { toml::table toml_data{}; try { @@ -60,6 +60,30 @@ static bool read_dependency_file(const std::filesystem::path& dependency_path, N if (!dependency_node.is_table()) { throw toml::parse_error("Invalid dependency entry", dependency_node.source()); } + + size_t dependency_index = dependencies.size(); + + auto read_number = [](const toml::node& node, const std::string& key, const std::string& name, int64_t min_limit, int64_t max_limit) { + toml::node_view mod_id_node = node[toml::path{key}]; + if (!mod_id_node.is_number()) { + if (mod_id_node) { + throw toml::parse_error(fmt::format("Invalid {}", name).c_str(), mod_id_node.node()->source()); + } + else { + throw toml::parse_error(fmt::format("Dependency entry is missing {}", name).c_str(), node.source()); + } + } + int64_t number_value = mod_id_node.ref(); + if (number_value < min_limit || number_value > max_limit) { + throw toml::parse_error(fmt::format("Dependency {} out of range", name).c_str(), mod_id_node.node()->source()); + } + return number_value; + }; + + // Version number + uint8_t major_version = static_cast(read_number(dependency_node, "major_version", "major version", 0, std::numeric_limits::max())); + uint8_t minor_version = static_cast(read_number(dependency_node, "minor_version", "minor version", 0, std::numeric_limits::max())); + uint8_t patch_version = static_cast(read_number(dependency_node, "patch_version", "patch version", 0, std::numeric_limits::max())); // Mod ID toml::node_view mod_id_node = dependency_node[toml::path{"mod_id"}]; @@ -71,7 +95,14 @@ static bool read_dependency_file(const std::filesystem::path& dependency_path, N throw toml::parse_error("Dependency entry is missing mod id", dependency_node.source()); } } + const std::string& mod_id = mod_id_node.ref(); + dependencies.emplace_back(N64Recomp::Dependency{ + .major_version = major_version, + .minor_version = minor_version, + .patch_version = patch_version, + .mod_id = mod_id + }); // Symbol list toml::node_view functions_data = dependency_node[toml::path{"functions"}]; @@ -91,7 +122,7 @@ static bool read_dependency_file(const std::filesystem::path& dependency_path, N .is_function = true } ); - import_symbol_mod_ids.emplace_back(mod_id); + import_symbol_dependency_indices.emplace_back(dependency_index); } } else { @@ -199,7 +230,7 @@ static inline uint32_t round_up_16(uint32_t value) { return (value + 15) & (~15); } -N64Recomp::ModContext build_mod_context(const N64Recomp::Context& input_context, std::vector&& import_symbol_mod_ids, bool& good) { +N64Recomp::ModContext build_mod_context(const N64Recomp::Context& input_context, std::vector&& dependencies, std::vector&& import_symbol_dependency_indices, bool& good) { N64Recomp::ModContext ret{}; good = false; @@ -224,10 +255,15 @@ N64Recomp::ModContext build_mod_context(const N64Recomp::Context& input_context, // TODO avoid a copy here. ret.base_context.rom = input_context.rom; + ret.dependencies = std::move(dependencies); + ret.import_symbol_dependency_indices = std::move(import_symbol_dependency_indices); uint32_t rom_to_ram = (uint32_t)-1; size_t output_section_index = (size_t)-1; ret.base_context.sections.resize(1); + + size_t num_imports = ret.import_symbol_dependency_indices.size(); + size_t import_symbol_start_index = input_context.reference_symbols.size() - num_imports; // Iterate over the input sections in their sorted order. for (uint16_t section_index : section_order) { @@ -365,9 +401,11 @@ N64Recomp::ModContext build_mod_context(const N64Recomp::Context& input_context, continue; } // Reloc to an imported symbol. - if (cur_reloc.reference_symbol && cur_reloc.target_section == N64Recomp::SectionImport) { - // Copy the reloc as-is. - section_out.relocs.emplace_back(cur_reloc); + if (cur_reloc.target_section == N64Recomp::SectionImport) { + // Copy the reloc and set the target section offset to be the import symbol index. + N64Recomp::Reloc reloc_out = cur_reloc; + reloc_out.symbol_index = reloc_out.symbol_index - import_symbol_start_index; + section_out.relocs.emplace_back(reloc_out); } // Reloc to a reference symbol. else if (cur_reloc.reference_symbol) { @@ -383,6 +421,10 @@ N64Recomp::ModContext build_mod_context(const N64Recomp::Context& input_context, case N64Recomp::RelocType::R_MIPS_32: // Don't patch MIPS32 relocations, as they've already been patched during elf parsing. break; + case N64Recomp::RelocType::R_MIPS_26: + // Don't patch MIPS26 relocations, as there may be multiple functions with the same vram. Emit the reloc instead. + section_out.relocs.emplace_back(cur_reloc); + break; case N64Recomp::RelocType::R_MIPS_NONE: // Nothing to do. break; @@ -394,15 +436,6 @@ N64Recomp::ModContext build_mod_context(const N64Recomp::Context& input_context, reloc_word &= 0xFFFF0000; reloc_word |= reloc_target_address & 0xFFFF; break; - case N64Recomp::RelocType::R_MIPS_26: - if (reloc_target_address & 0x3) { - fmt::print("R_MIPS_26 reloc at address 0x{:08X} in section {} has a target address not divisible by 4!\n", - cur_reloc.address, cur_section.name); - return {}; - } - reloc_word &= 0xFC000000; - reloc_word |= (reloc_target_address >> 2) & 0x3FFFFFF; - break; default: fmt::print("Unsupported or unknown relocation type {} in reloc at address 0x{:08X} in section {}!\n", (int)cur_reloc.type, cur_reloc.address, cur_section.name); @@ -438,11 +471,7 @@ N64Recomp::ModContext build_mod_context(const N64Recomp::Context& input_context, } } - ret.import_symbol_mod_ids = std::move(import_symbol_mod_ids); - // Copy the import reference symbols from the end of the input context to this context. - size_t num_imports = ret.import_symbol_mod_ids.size(); - size_t import_symbol_start_index = input_context.reference_symbols.size() - num_imports; ret.base_context.reference_symbols.resize(num_imports); ret.base_context.reference_symbol_names.resize(num_imports); for (size_t import_symbol_index = 0; import_symbol_index < num_imports; import_symbol_index++) { @@ -461,6 +490,9 @@ N64Recomp::ModContext build_mod_context(const N64Recomp::Context& input_context, ret.base_context.reference_symbols_by_name[reference_symbol_name] = import_symbol_index; } + // Copy the reference sections from the input context as-is for resolving reference symbol relocations. + ret.base_context.reference_sections = input_context.reference_sections; + good = true; return ret; } @@ -503,10 +535,11 @@ int main(int argc, const char** argv) { } // Read the imported symbols, placing them at the end of the reference symbol list. - std::vector import_symbol_mod_ids{}; + std::vector dependencies{}; + std::vector import_symbol_dependency_indices{}; for (const std::filesystem::path& dependency_path : config.dependency_paths) { - if (!read_dependency_file(dependency_path, context, import_symbol_mod_ids)) { + if (!read_dependency_file(dependency_path, context, dependencies, import_symbol_dependency_indices)) { fmt::print(stderr, "Failed to read dependency file: {}\n", dependency_path.string()); return EXIT_FAILURE; } @@ -537,7 +570,7 @@ int main(int argc, const char** argv) { } bool mod_context_good; - N64Recomp::ModContext mod_context = build_mod_context(context, std::move(import_symbol_mod_ids), mod_context_good); + N64Recomp::ModContext mod_context = build_mod_context(context, std::move(dependencies), std::move(import_symbol_dependency_indices), mod_context_good); std::vector symbols_bin = N64Recomp::symbols_to_bin_v1(mod_context); std::ofstream output_syms_file{ config.output_syms_path, std::ios::binary }; diff --git a/include/n64recomp.h b/include/n64recomp.h index 6efc718..521421a 100644 --- a/include/n64recomp.h +++ b/include/n64recomp.h @@ -51,7 +51,7 @@ namespace N64Recomp { struct Reloc { uint32_t address; uint32_t target_section_offset; - uint32_t symbol_index; // Only used for reference symbols + uint32_t symbol_index; // Only used for reference symbols and import symbols uint16_t target_section; RelocType type; bool reference_symbol; @@ -164,13 +164,23 @@ namespace N64Recomp { ReplacementFlags flags; }; + struct Dependency { + uint8_t major_version; + uint8_t minor_version; + uint8_t patch_version; + std::string mod_id; + }; + struct ModContext { Context base_context; std::vector replacements; - // Mod id of every imported function (which exist at the end of `base_context.reference_symbols`). - std::vector import_symbol_mod_ids; // Indices of every exported function. std::vector exported_funcs; + // List of dependencies of this mod. + std::vector dependencies; + // Index of the dependency that each imported function belongs to. + // Imported symbols exist at the end of `base_context.reference_symbols`. + std::vector import_symbol_dependency_indices; }; enum class ModSymbolsError { Good, @@ -180,7 +190,7 @@ namespace N64Recomp { FunctionOutOfBounds, }; - ModSymbolsError parse_mod_symbols(std::span data, std::span binary, const std::unordered_map& sections_by_vrom, Context& context_out, ModContext& mod_context_out); + ModSymbolsError parse_mod_symbols(std::span data, std::span binary, const std::unordered_map& sections_by_vrom, const Context& reference_context, ModContext& mod_context_out); std::vector symbols_to_bin_v1(const ModContext& mod_context); } diff --git a/src/main.cpp b/src/main.cpp index d1c29e6..f681673 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -267,7 +267,7 @@ int main(int argc, char** argv) { }; // TODO expose a way to dump the context from the command line. - bool dumping_context = true;// false; + bool dumping_context = false; if (argc != 2) { fmt::print("Usage: {} [config file]\n", argv[0]); diff --git a/src/mod_symbols.cpp b/src/mod_symbols.cpp index 989044e..a6aedca 100644 --- a/src/mod_symbols.cpp +++ b/src/mod_symbols.cpp @@ -9,6 +9,7 @@ struct FileSubHeaderV1 { uint32_t num_sections; uint32_t num_replacements; uint32_t num_exports; + uint32_t num_dependencies; uint32_t num_imports; uint32_t string_data_size; }; @@ -27,11 +28,14 @@ struct FuncV1 { uint32_t size; }; +constexpr uint32_t SectionSelfVromV1 = 0xFFFFFFFF; +constexpr uint32_t SectionImportVromV1 = 0xFFFFFFFE; + struct RelocV1 { uint32_t section_offset; uint32_t type; - uint32_t target_section_offset; - uint32_t target_section_vrom; // 0 means current section + uint32_t target_section_offset; // If this reloc references an import symbol, this indicates the import symbol index instead + uint32_t target_section_vrom; }; struct ReplacementV1 { @@ -47,15 +51,20 @@ struct ExportV1 { uint32_t name_size; }; -struct ImportV1 { - uint32_t name_start; - uint32_t name_size; +struct DependencyV1 { + uint8_t major_version; + uint8_t minor_version; + uint8_t patch_version; + uint8_t reserved; uint32_t mod_id_start; uint32_t mod_id_size; }; -constexpr uint32_t SectionSelfVromV1 = 0xFFFFFFFF; -constexpr uint32_t SectionImportVromV1 = 0xFFFFFFFE; +struct ImportV1 { + uint32_t name_start; + uint32_t name_size; + uint32_t dependency; +}; template const T* reinterpret_data(std::span data, size_t& offset, size_t count = 1) { @@ -75,8 +84,13 @@ bool check_magic(const FileHeader* header) { return memcmp(header->magic, good_magic, sizeof(good_magic)) == 0; } -bool parse_v1(std::span data, const std::unordered_map& sections_by_vrom, N64Recomp::Context& ret, N64Recomp::ModContext& mod_context) { +static inline uint32_t round_up_4(uint32_t value) { + return (value + 3) & (~3); +} + +bool parse_v1(std::span data, const std::unordered_map& sections_by_vrom, N64Recomp::ModContext& mod_context) { size_t offset = sizeof(FileHeader); + N64Recomp::Context& base_context = mod_context.base_context; const FileSubHeaderV1* subheader = reinterpret_data(data, offset); if (subheader == nullptr) { return false; @@ -84,22 +98,44 @@ bool parse_v1(std::span data, const std::unordered_mapnum_sections; size_t num_replacements = subheader->num_replacements; + size_t num_exports = subheader->num_exports; + size_t num_dependencies = subheader->num_dependencies; + size_t num_imports = subheader->num_imports; + size_t string_data_size = subheader->string_data_size; - ret.sections.resize(num_sections); + if (string_data_size & 0b11) { + printf("String data size of %zu is not a multiple of 4\n", string_data_size); + return false; + } + + const char* string_data = reinterpret_data(data, offset, string_data_size); + if (string_data == nullptr) { + return false; + } + + size_t import_symbol_base_index = base_context.reference_symbols.size(); + + base_context.sections.resize(num_sections); mod_context.replacements.resize(num_replacements); + mod_context.exported_funcs.resize(num_exports); + mod_context.dependencies.resize(num_dependencies); + mod_context.import_symbol_dependency_indices.resize(num_imports); + base_context.reference_symbols.resize(import_symbol_base_index + num_imports); + base_context.reference_symbol_names.resize(import_symbol_base_index + num_imports); for (size_t section_index = 0; section_index < num_sections; section_index++) { const SectionHeaderV1* section_header = reinterpret_data(data, offset); if (section_header == nullptr) { return false; } - N64Recomp::Section& cur_section = ret.sections[section_index]; + N64Recomp::Section& cur_section = base_context.sections[section_index]; cur_section.rom_addr = section_header->file_offset; cur_section.ram_addr = section_header->vram; cur_section.size = section_header->rom_size; cur_section.bss_size = section_header->bss_size; cur_section.name = "mod_section_" + std::to_string(section_index); + cur_section.relocatable = true; uint32_t num_funcs = section_header->num_funcs; uint32_t num_relocs = section_header->num_relocs; @@ -116,8 +152,8 @@ bool parse_v1(std::span data, const std::unordered_map data, const std::unordered_map data, const std::unordered_mapsecond; + cur_reloc.reference_symbol = true; } } } @@ -180,15 +220,102 @@ bool parse_v1(std::span data, const std::unordered_map(replacements[replacement_index].flags); } + const ExportV1* exports = reinterpret_data(data, offset, num_exports); + if (exports == nullptr) { + printf("Failed to read exports (count: %zu)\n", num_exports); + return false; + } + + for (size_t export_index = 0; export_index < num_exports; export_index++) { + const ExportV1& export_in = exports[export_index]; + uint32_t func_index = export_in.func_index; + uint32_t name_start = export_in.name_start; + uint32_t name_size = export_in.name_size; + + if (func_index >= base_context.functions.size()) { + printf("Export %zu has a function index of %u, but the symbol file only has %zu functions\n", + export_index, func_index, base_context.functions.size()); + } + + if (name_start + name_size > string_data_size) { + printf("Export %zu has a name start of %u and size of %u, which extend beyond the string data's total size of %zu\n", + export_index, name_start, name_size, string_data_size); + } + + // Add the function to the exported function list. + mod_context.exported_funcs[export_index] = func_index; + // Populate the exported function's name from the string data. + base_context.functions[func_index].name = std::string_view(string_data + name_start, string_data + name_start + name_size); + } + + const DependencyV1* dependencies = reinterpret_data(data, offset, num_dependencies); + if (dependencies == nullptr) { + printf("Failed to read dependencies (count: %zu)\n", num_dependencies); + return false; + } + + for (size_t dependency_index = 0; dependency_index < num_dependencies; dependency_index++) { + const DependencyV1& dependency_in = dependencies[dependency_index]; + uint32_t mod_id_start = dependency_in.mod_id_start; + uint32_t mod_id_size = dependency_in.mod_id_size; + + if (mod_id_start + mod_id_size > string_data_size) { + printf("Dependency %zu has a name start of %u and size of %u, which extend beyond the string data's total size of %zu\n", + dependency_index, mod_id_start, mod_id_size, string_data_size); + } + + auto& dependency_out = mod_context.dependencies[dependency_index]; + dependency_out.major_version = dependency_in.major_version; + dependency_out.minor_version = dependency_in.minor_version; + dependency_out.patch_version = dependency_in.patch_version; + dependency_out.mod_id = std::string_view(string_data + mod_id_start, string_data + mod_id_start + mod_id_size); + } + + const ImportV1* imports = reinterpret_data(data, offset, num_imports); + if (imports == nullptr) { + printf("Failed to read imports (count: %zu)\n", num_imports); + return false; + } + + for (size_t import_index = 0; import_index < num_imports; import_index++) { + const ImportV1& import_in = imports[import_index]; + uint32_t name_start = import_in.name_start; + uint32_t name_size = import_in.name_size; + uint32_t dependency_index = import_in.dependency; + size_t reference_symbol_index = import_symbol_base_index + import_index; + + if (name_start + name_size > string_data_size) { + printf("Import %zu has a name start of %u and size of %u, which extend beyond the string data's total size of %zu\n", + import_index, name_start, name_size, string_data_size); + } + + if (dependency_index >= num_dependencies) { + printf("Import %zu belongs to dependency %u, but only %zu dependencies were specified\n", + import_index, dependency_index, num_dependencies); + } + + std::string_view import_name{ string_data + name_start, string_data + name_start + name_size }; + + base_context.reference_symbols[reference_symbol_index] = N64Recomp::ReferenceSymbol{ + .section_index = N64Recomp::SectionImport, + .section_offset = static_cast(import_index), + .is_function = true, + }; + base_context.reference_symbol_names[reference_symbol_index] = import_name; + base_context.reference_symbols_by_name[std::string{import_name}] = reference_symbol_index; + mod_context.import_symbol_dependency_indices[import_index] = dependency_index; + } + return offset == data.size(); } -N64Recomp::ModSymbolsError N64Recomp::parse_mod_symbols(std::span data, std::span binary, const std::unordered_map& sections_by_vrom, Context& context_out, ModContext& mod_context_out) { +N64Recomp::ModSymbolsError N64Recomp::parse_mod_symbols(std::span data, std::span binary, const std::unordered_map& sections_by_vrom, const Context& reference_context, ModContext& mod_context_out) { size_t offset = 0; - context_out = {}; mod_context_out = {}; const FileHeader* header = reinterpret_data(data, offset); + mod_context_out.base_context.import_reference_context(reference_context); + if (header == nullptr) { return ModSymbolsError::NotASymbolFile; } @@ -201,22 +328,20 @@ N64Recomp::ModSymbolsError N64Recomp::parse_mod_symbols(std::span da switch (header->version) { case 1: - valid = parse_v1(data, sections_by_vrom, context_out, mod_context_out); + valid = parse_v1(data, sections_by_vrom, mod_context_out); break; default: return ModSymbolsError::UnknownSymbolFileVersion; } if (!valid) { - context_out = {}; mod_context_out = {}; return ModSymbolsError::CorruptSymbolFile; } // Fill in the words for each function. - for (auto& cur_func : context_out.functions) { + for (auto& cur_func : mod_context_out.base_context.functions) { if (cur_func.rom + cur_func.words.size() * sizeof(cur_func.words[0]) > binary.size()) { - context_out = {}; mod_context_out = {}; return ModSymbolsError::FunctionOutOfBounds; } @@ -255,12 +380,14 @@ std::vector N64Recomp::symbols_to_bin_v1(const N64Recomp::ModContext& m vec_put(ret, &header); size_t num_exported_funcs = mod_context.exported_funcs.size(); - size_t num_imported_funcs = mod_context.import_symbol_mod_ids.size(); + size_t num_dependencies = mod_context.dependencies.size(); + size_t num_imported_funcs = mod_context.import_symbol_dependency_indices.size(); FileSubHeaderV1 sub_header { .num_sections = static_cast(context.sections.size()), .num_replacements = static_cast(mod_context.replacements.size()), .num_exports = static_cast(num_exported_funcs), + .num_dependencies = static_cast(num_dependencies), .num_imports = static_cast(num_imported_funcs), .string_data_size = 0, }; @@ -283,7 +410,17 @@ std::vector N64Recomp::symbols_to_bin_v1(const N64Recomp::ModContext& m vec_put(ret, exported_func.name); } - // Track the start of every imported function's name in the string data, as well as any mod ids that have been written to the string data. + // Track the start of every dependency's name in the string data. + std::vector dependency_name_positions{}; + dependency_name_positions.resize(num_dependencies); + for (size_t dependency_index = 0; dependency_index < num_dependencies; dependency_index++) { + const Dependency& dependency = mod_context.dependencies[dependency_index]; + + dependency_name_positions[dependency_index] = static_cast(ret.size() - strings_start); + vec_put(ret, dependency.mod_id); + } + + // Track the start of every imported function's name in the string data. std::vector imported_func_name_positions{}; imported_func_name_positions.resize(num_imported_funcs); std::unordered_map mod_id_name_positions{}; @@ -294,14 +431,6 @@ std::vector N64Recomp::symbols_to_bin_v1(const N64Recomp::ModContext& m size_t reference_symbol_index = import_symbol_base_index + import_index; const ReferenceSymbol& imported_func = mod_context.base_context.reference_symbols[reference_symbol_index]; const std::string& imported_func_name = mod_context.base_context.reference_symbol_names[reference_symbol_index]; - const std::string& cur_mod_id = mod_context.import_symbol_mod_ids[import_index]; - - // If this import's mod id hasn't been written into the strings data, write it now. - auto mod_id_find_it = mod_id_name_positions.find(cur_mod_id); - if (mod_id_find_it == mod_id_name_positions.end()) { - mod_id_name_positions.emplace(cur_mod_id, static_cast(ret.size() - strings_start)); - vec_put(ret, cur_mod_id); - } // Write this import's name into the strings data. imported_func_name_positions[import_index] = static_cast(ret.size() - strings_start); @@ -340,11 +469,13 @@ std::vector N64Recomp::symbols_to_bin_v1(const N64Recomp::ModContext& m for (const Reloc& cur_reloc : cur_section.relocs) { uint32_t target_section_vrom; + uint32_t target_section_offset = cur_reloc.target_section_offset; if (cur_reloc.target_section == SectionSelf) { target_section_vrom = SectionSelfVromV1; } else if (cur_reloc.target_section == SectionImport) { target_section_vrom = SectionImportVromV1; + target_section_offset = cur_reloc.symbol_index; } else if (cur_reloc.reference_symbol) { target_section_vrom = context.reference_sections[cur_reloc.target_section].rom_addr; @@ -355,7 +486,7 @@ std::vector N64Recomp::symbols_to_bin_v1(const N64Recomp::ModContext& m RelocV1 reloc_out { .section_offset = cur_reloc.address - cur_section.ram_addr, .type = static_cast(cur_reloc.type), - .target_section_offset = cur_reloc.target_section_offset, + .target_section_offset = target_section_offset, .target_section_vrom = target_section_vrom }; @@ -394,25 +525,33 @@ std::vector N64Recomp::symbols_to_bin_v1(const N64Recomp::ModContext& m vec_put(ret, &export_out); } + // Write the dependencies. + for (size_t dependency_index = 0; dependency_index < num_dependencies; dependency_index++) { + const Dependency& dependency = mod_context.dependencies[dependency_index]; + + DependencyV1 dependency_out { + .major_version = dependency.major_version, + .minor_version = dependency.minor_version, + .patch_version = dependency.patch_version, + .mod_id_start = dependency_name_positions[dependency_index], + .mod_id_size = static_cast(dependency.mod_id.size()) + }; + + vec_put(ret, &dependency_out); + } + // Write the imported functions. for (size_t import_index = 0; import_index < num_imported_funcs; import_index++) { // Get the index of the reference symbol for this import. size_t reference_symbol_index = import_symbol_base_index + import_index; const ReferenceSymbol& imported_func = mod_context.base_context.reference_symbols[reference_symbol_index]; const std::string& imported_func_name = mod_context.base_context.reference_symbol_names[reference_symbol_index]; - const std::string& cur_mod_id = mod_context.import_symbol_mod_ids[import_index]; - - auto mod_id_find_it = mod_id_name_positions.find(cur_mod_id); - if (mod_id_find_it == mod_id_name_positions.end()) { - fprintf(stderr, "Internal error: failed to find position of mod id %s in string data\n", cur_mod_id.c_str()); - return {}; - } + size_t dependency_index = mod_context.import_symbol_dependency_indices[import_index]; ImportV1 import_out { .name_start = imported_func_name_positions[import_index], .name_size = static_cast(imported_func_name.size()), - .mod_id_start = mod_id_find_it->second, - .mod_id_size = static_cast(cur_mod_id.size()) + .dependency = static_cast(dependency_index) }; vec_put(ret, &import_out); diff --git a/src/recompilation.cpp b/src/recompilation.cpp index 6a61207..2724179 100644 --- a/src/recompilation.cpp +++ b/src/recompilation.cpp @@ -160,32 +160,30 @@ bool process_instruction(const N64Recomp::Context& context, const N64Recomp::Fun reloc_section = reloc.target_section; // Only process this relocation if this section is relocatable or if this relocation targets a reference symbol. if (section.relocatable || reloc.reference_symbol) { - // Some symbols are in a nonexistent section (e.g. absolute symbols), so check that the section is valid before doing anything else. - // Absolute symbols will never need to be relocated so it's safe to skip this. - // Always process reference symbols relocations. - if (reloc_section < context.sections.size() || reloc.reference_symbol) { - // Ignore this reloc if it points to a different section. - // Also check if the reloc points to the bss section since that will also be relocated with the section. - // Additionally, always process reference symbol relocations. - if (reloc_section == func.section_index || reloc_section == section.bss_section_index || reloc.reference_symbol) { - // Record the reloc's data. - reloc_type = reloc.type; - reloc_target_section_offset = reloc.target_section_offset; - // Ignore all relocs that aren't HI16 or LO16. - if (reloc_type == N64Recomp::RelocType::R_MIPS_HI16 || reloc_type == N64Recomp::RelocType::R_MIPS_LO16 || reloc_type == N64Recomp::RelocType::R_MIPS_26) { - if (reloc.reference_symbol) { - reloc_reference_symbol = reloc.symbol_index; - static N64Recomp::ReferenceSection dummy_section{ - .rom_addr = 0, - .ram_addr = 0, - .size = 0, - .relocatable = false - }; + // Ignore this reloc if it points to a different section. + // Also check if the reloc points to the bss section since that will also be relocated with the section. + // Additionally, always process reference symbol relocations. + if (reloc_section == func.section_index || reloc_section == section.bss_section_index || reloc_section == N64Recomp::SectionSelf || reloc.reference_symbol) { + // Record the reloc's data. + reloc_type = reloc.type; + reloc_target_section_offset = reloc.target_section_offset; + // Ignore all relocs that aren't HI16 or LO16. + if (reloc_type == N64Recomp::RelocType::R_MIPS_HI16 || reloc_type == N64Recomp::RelocType::R_MIPS_LO16 || reloc_type == N64Recomp::RelocType::R_MIPS_26) { + if (reloc.reference_symbol) { + reloc_reference_symbol = reloc.symbol_index; + static N64Recomp::ReferenceSection dummy_section{ + .rom_addr = 0, + .ram_addr = 0, + .size = 0, + .relocatable = false + }; + // Don't try to relocate import symbols. + if (reloc.target_section != N64Recomp::SectionImport) { const auto& reloc_reference_section = reloc.target_section == N64Recomp::SectionAbsolute ? dummy_section : context.reference_sections[reloc.target_section]; // Resolve HI16 and LO16 reference symbol relocs to non-relocatable sections by patching the instruction immediate. if (!reloc_reference_section.relocatable && (reloc_type == N64Recomp::RelocType::R_MIPS_HI16 || reloc_type == N64Recomp::RelocType::R_MIPS_LO16)) { uint32_t full_immediate = reloc.target_section_offset + reloc_reference_section.ram_addr; - + if (reloc_type == N64Recomp::RelocType::R_MIPS_HI16) { imm = (full_immediate >> 16) + ((full_immediate >> 15) & 1); reloc_type = N64Recomp::RelocType::R_MIPS_NONE; @@ -194,18 +192,18 @@ bool process_instruction(const N64Recomp::Context& context, const N64Recomp::Fun imm = full_immediate & 0xFFFF; reloc_type = N64Recomp::RelocType::R_MIPS_NONE; } - + // The reloc has been processed, so delete it to none to prevent it getting processed a second time during instruction code generation. reloc_type = N64Recomp::RelocType::R_MIPS_NONE; reloc_reference_symbol = (size_t)-1; } } } + } - // Repoint bss relocations at their non-bss counterpart section. - if (reloc_section == section.bss_section_index) { - reloc_section = func.section_index; - } + // Repoint bss relocations at their non-bss counterpart section. + if (reloc_section != N64Recomp::SectionSelf && reloc_section == section.bss_section_index) { + reloc_section = func.section_index; } } }