Some cleanup by making some Context members private

This commit is contained in:
Mr-Wiseguy 2024-08-18 14:11:03 -04:00
parent 5f1b9a845b
commit f300b6dccc
8 changed files with 191 additions and 126 deletions

View file

@ -81,14 +81,12 @@ int main(int argc, const char** argv) {
// Populate R_MIPS_26 reloc symbol indices. Start by building a map of vram address to matching reference symbols.
std::unordered_map<uint32_t, std::vector<size_t>> reference_symbols_by_vram{};
for (size_t reference_symbol_index = 0; reference_symbol_index < mod_context.reference_symbols.size(); reference_symbol_index++) {
const auto& sym = mod_context.reference_symbols[reference_symbol_index];
for (size_t reference_symbol_index = 0; reference_symbol_index < mod_context.num_regular_reference_symbols(); reference_symbol_index++) {
const auto& sym = mod_context.get_regular_reference_symbol(reference_symbol_index);
uint16_t section_index = sym.section_index;
if (section_index != N64Recomp::SectionAbsolute && section_index != N64Recomp::SectionSelf) {
const auto& section = mod_context.reference_sections[section_index];
uint32_t vram = section.ram_addr + sym.section_offset;
reference_symbols_by_vram[vram].push_back(reference_symbol_index);
uint32_t section_vram = mod_context.get_reference_section_vram(section_index);
reference_symbols_by_vram[section_vram + sym.section_offset].push_back(reference_symbol_index);
}
}
@ -97,8 +95,8 @@ int main(int argc, const char** argv) {
for (auto& reloc : section.relocs) {
if (reloc.type == N64Recomp::RelocType::R_MIPS_26 && reloc.reference_symbol) {
if (mod_context.is_regular_reference_section(reloc.target_section)) {
const auto& target_section = mod_context.reference_sections[reloc.target_section];
uint32_t target_vram = target_section.ram_addr + reloc.target_section_offset;
uint32_t section_vram = mod_context.get_reference_section_vram(reloc.target_section);
uint32_t target_vram = section_vram + reloc.target_section_offset;
auto find_funcs_it = reference_symbols_by_vram.find(target_vram);
bool found = false;

View file

@ -113,21 +113,9 @@ static bool read_dependency_file(const std::filesystem::path& dependency_path, N
throw toml::parse_error("Invalid dependency function", function_node.source());
}
const std::string& function_name = function_node.ref<std::string>();
context.reference_symbols_by_name[function_name] = N64Recomp::SymbolReference {
.section_index = N64Recomp::SectionImport,
.symbol_index = import_symbol_dependency_indices.size()
};
context.import_symbols.emplace_back(
N64Recomp::ImportSymbol {
.base = N64Recomp::ReferenceSymbol {
.name = function_name,
.section_index = N64Recomp::SectionImport,
.section_offset = 0,
.is_function = true
},
.dependency_index = dependency_index,
}
);
size_t symbol_index = import_symbol_dependency_indices.size();
context.add_import_symbol(function_name, dependency_index, symbol_index);
import_symbol_dependency_indices.emplace_back(dependency_index);
}
}
@ -328,22 +316,8 @@ N64Recomp::Context build_mod_context(const N64Recomp::Context& input_context, st
// If this is the patch section, create a replacement for this function.
if (patch_section || force_patch_section) {
// Find the corresponding symbol in the reference symbols.
bool original_func_exists = false;
auto find_sym_it = input_context.reference_symbols_by_name.find(cur_func.name);
// Check if the function was found.
if (find_sym_it == input_context.reference_symbols_by_name.end()) {
original_func_exists = false;
}
// Ignore reference symbols in the import section, as those are imports and not original symbols.
else if (
find_sym_it->second.section_index == N64Recomp::SectionImport ||
find_sym_it->second.section_index == N64Recomp::SectionHook) {
original_func_exists = false;
}
else {
original_func_exists = true;
}
N64Recomp::SymbolReference cur_reference;
bool original_func_exists = input_context.find_regular_reference_symbol(cur_func.name, cur_reference);
// Check that the function being patched exists in the original reference symbols.
if (!original_func_exists) {
@ -352,20 +326,21 @@ N64Recomp::Context build_mod_context(const N64Recomp::Context& input_context, st
}
// Check that the reference symbol is actually a function.
const auto& reference_symbol = input_context.get_reference_symbol(find_sym_it->second.section_index, find_sym_it->second.symbol_index);
const auto& reference_symbol = input_context.get_reference_symbol(cur_reference);
if (!reference_symbol.is_function) {
fmt::print("Function {0} is marked as a patch, but {0} was a variable in the original ROM!\n", cur_func.name);
return {};
}
const auto& reference_section = input_context.reference_sections[reference_symbol.section_index];
uint32_t reference_section_vram = input_context.get_reference_section_vram(reference_symbol.section_index);
uint32_t reference_section_rom = input_context.get_reference_section_rom(reference_symbol.section_index);
// Add a replacement for this function to the output context.
ret.replacements.emplace_back(
N64Recomp::FunctionReplacement {
.func_index = (uint32_t)output_func_index,
.original_section_vrom = reference_section.rom_addr,
.original_vram = reference_section.ram_addr + reference_symbol.section_offset,
.original_section_vrom = reference_section_rom,
.original_vram = reference_section_vram + reference_symbol.section_offset,
.flags = force_patch_section ? N64Recomp::ReplacementFlags::Force : N64Recomp::ReplacementFlags{}
}
);
@ -405,16 +380,17 @@ N64Recomp::Context build_mod_context(const N64Recomp::Context& input_context, st
if (cur_reloc.type == N64Recomp::RelocType::R_MIPS_NONE) {
continue;
}
// Reloc to an imported symbol.
if (cur_reloc.target_section == N64Recomp::SectionImport) {
// Reloc to a special section symbol.
if (!input_context.is_regular_reference_section(cur_reloc.target_section)) {
section_out.relocs.emplace_back(cur_reloc);
}
// Reloc to a reference symbol.
else if (cur_reloc.reference_symbol) {
const auto& reloc_section = input_context.reference_sections[cur_reloc.target_section];
bool is_relocatable = input_context.is_reference_section_relocatable(cur_reloc.target_section);
uint32_t section_vram = input_context.get_reference_section_vram(cur_reloc.target_section);
// Patch relocations to non-relocatable reference sections.
if (!reloc_section.relocatable) {
uint32_t reloc_target_address = reloc_section.ram_addr + cur_reloc.target_section_offset;
if (!is_relocatable) {
uint32_t reloc_target_address = section_vram + cur_reloc.target_section_offset;
uint32_t reloc_rom_address = cur_reloc.address - cur_section.ram_addr + cur_section.rom_addr;
uint32_t* reloc_word_ptr = reinterpret_cast<uint32_t*>(ret.rom.data() + reloc_rom_address);
@ -477,7 +453,7 @@ N64Recomp::Context build_mod_context(const N64Recomp::Context& input_context, st
ret.import_symbols = input_context.import_symbols;
// Copy the reference sections from the input context as-is for resolving reference symbol relocations.
ret.reference_sections = input_context.reference_sections;
ret.copy_reference_sections_from(input_context);
good = true;
return ret;
@ -510,7 +486,10 @@ int main(int argc, const char** argv) {
}
// Use the reference context to build a reference symbol list for the actual context.
context.import_reference_context(reference_context);
if (!context.import_reference_context(reference_context)) {
fmt::print(stderr, "Internal error: failed to import reference context\n");
return EXIT_FAILURE;
}
}
for (const std::filesystem::path& cur_data_sym_path : config.data_reference_syms_file_paths) {

View file

@ -154,7 +154,16 @@ namespace N64Recomp {
ReplacementFlags flags;
};
struct Context {
class Context {
private:
//// Reference symbols (used for populating relocations for patches)
// A list of the sections that contain the reference symbols.
std::vector<ReferenceSection> reference_sections;
// A list of the reference symbols.
std::vector<ReferenceSymbol> reference_symbols;
// Mapping of symbol name to reference symbol index.
std::unordered_map<std::string, SymbolReference> reference_symbols_by_name;
public:
std::vector<Section> sections;
std::vector<Function> functions;
// A list of the list of each function (by index in `functions`) in a given section
@ -169,14 +178,6 @@ namespace N64Recomp {
// A mapping of function name to index in the functions vector
std::unordered_map<std::string, size_t> functions_by_name;
//// Reference symbols (used for populating relocations for patches)
// A list of the sections that contain the reference symbols.
std::vector<ReferenceSection> reference_sections;
// A list of the reference symbols.
std::vector<ReferenceSymbol> reference_symbols;
// Mapping of symbol name to reference symbol index.
std::unordered_map<std::string, SymbolReference> reference_symbols_by_name;
//// Mod dependencies and their symbols
std::vector<Dependency> dependencies;
std::vector<ImportSymbol> import_symbols;
@ -187,7 +188,7 @@ namespace N64Recomp {
std::vector<FunctionReplacement> replacements;
// Imports sections and function symbols from a provided context into this context's reference sections and reference functions.
void import_reference_context(const Context& reference_context);
bool import_reference_context(const Context& reference_context);
// Reads a data symbol file and adds its contents into this context's reference data symbols.
bool read_data_reference_syms(const std::filesystem::path& data_syms_file_path);
@ -204,6 +205,38 @@ namespace N64Recomp {
return section_index != SectionImport && section_index != SectionHook;
}
bool find_reference_symbol(const std::string& symbol_name, SymbolReference& ref_out) const {
auto find_sym_it = reference_symbols_by_name.find(symbol_name);
// Check if the symbol was found.
if (find_sym_it == reference_symbols_by_name.end()) {
return false;
}
ref_out = find_sym_it->second;
return true;
}
bool reference_symbol_exists(const std::string& symbol_name) const {
SymbolReference dummy_ref;
return find_reference_symbol(symbol_name, dummy_ref);
}
bool find_regular_reference_symbol(const std::string& symbol_name, SymbolReference& ref_out) const {
SymbolReference ref_found;
if (!find_reference_symbol(symbol_name, ref_found)) {
return false;
}
// Ignore reference symbols in special sections.
if (!is_regular_reference_section(ref_found.section_index)) {
return false;
}
ref_out = ref_found;
return true;
}
const ReferenceSymbol& get_reference_symbol(uint16_t section_index, size_t symbol_index) const {
if (section_index == SectionImport) {
return import_symbols[symbol_index].base;
@ -214,16 +247,102 @@ namespace N64Recomp {
return reference_symbols[symbol_index];
}
size_t num_regular_reference_symbols() {
return reference_symbols.size();
}
const ReferenceSymbol& get_regular_reference_symbol(size_t index) const {
return reference_symbols[index];
}
const ReferenceSymbol& get_reference_symbol(const SymbolReference& ref) const {
return get_reference_symbol(ref.section_index, ref.symbol_index);
}
bool is_reference_section_relocatable(uint16_t section_index) const {
if (section_index == SectionImport || section_index == SectionHook) {
if (section_index == SectionAbsolute) {
return false;
}
else if (section_index == SectionImport || section_index == SectionHook) {
return true;
}
return reference_sections[section_index].relocatable;
}
bool add_reference_symbol(const std::string& symbol_name, uint16_t section_index, uint32_t vram, bool is_function) {
uint32_t section_vram;
if (section_index == SectionAbsolute) {
section_vram = 0;
}
else if (section_index < reference_sections.size()) {
section_vram = reference_sections[section_index].ram_addr;
}
// Invalid section index.
else {
return false;
}
// TODO Check if reference_symbols_by_name already contains the name and show a conflict error if so.
reference_symbols_by_name.emplace(symbol_name, N64Recomp::SymbolReference{
.section_index = section_index,
.symbol_index = reference_symbols.size()
});
reference_symbols.emplace_back(N64Recomp::ReferenceSymbol{
.name = symbol_name,
.section_index = section_index,
.section_offset = vram - section_vram,
.is_function = is_function
});
return true;
}
void add_import_symbol(const std::string& symbol_name, size_t dependency_index, size_t symbol_index) {
reference_symbols_by_name[symbol_name] = N64Recomp::SymbolReference {
.section_index = N64Recomp::SectionImport,
.symbol_index = symbol_index
};
import_symbols.emplace_back(
N64Recomp::ImportSymbol {
.base = N64Recomp::ReferenceSymbol {
.name = symbol_name,
.section_index = N64Recomp::SectionImport,
.section_offset = 0,
.is_function = true
},
.dependency_index = dependency_index,
}
);
}
uint32_t get_reference_section_vram(uint16_t section_index) const {
if (section_index == N64Recomp::SectionAbsolute) {
return 0;
}
else if (!is_regular_reference_section(section_index)) {
return 0;
}
else {
return reference_sections[section_index].ram_addr;
}
}
uint32_t get_reference_section_rom(uint16_t section_index) const {
if (section_index == N64Recomp::SectionAbsolute) {
return (uint32_t)-1;
}
else if (!is_regular_reference_section(section_index)) {
return (uint32_t)-1;
}
else {
return reference_sections[section_index].rom_addr;
}
}
void copy_reference_sections_from(const Context& rhs) {
reference_sections = rhs.reference_sections;
}
};
bool recompile_function(const Context& context, const Function& func, const std::string& recomp_include, std::ofstream& output_file, std::span<std::vector<uint32_t>> static_funcs, bool write_header);

View file

@ -611,7 +611,7 @@ bool N64Recomp::Context::from_symbol_file(const std::filesystem::path& symbol_fi
return true;
}
void N64Recomp::Context::import_reference_context(const N64Recomp::Context& reference_context) {
bool N64Recomp::Context::import_reference_context(const N64Recomp::Context& reference_context) {
reference_sections.resize(reference_context.sections.size());
reference_symbols.reserve(reference_context.functions.size());
@ -628,21 +628,12 @@ void N64Recomp::Context::import_reference_context(const N64Recomp::Context& refe
// Copy the functions from the reference context into the reference context's function map.
for (const N64Recomp::Function& func_in: reference_context.functions) {
const N64Recomp::Section& func_section = reference_context.sections[func_in.section_index];
// TODO Check if reference_symbols_by_name already contains the name and show a conflict error if so.
reference_symbols_by_name.emplace(func_in.name, N64Recomp::SymbolReference{
.section_index = func_in.section_index,
.symbol_index = reference_symbols.size()
});
reference_symbols.emplace_back(N64Recomp::ReferenceSymbol{
.name = func_in.name,
.section_index = func_in.section_index,
.section_offset = func_in.vram - static_cast<uint32_t>(func_section.ram_addr),
.is_function = true
});
if (!add_reference_symbol(func_in.name, func_in.section_index, func_in.vram, true)) {
return false;
}
}
return true;
}
// Reads a data symbol file and adds its contents into this context's reference data symbols.
@ -730,20 +721,9 @@ bool N64Recomp::Context::read_data_reference_syms(const std::filesystem::path& d
throw toml::parse_error("Reference data symbol entry is missing required field(s)", data_sym_el.source());
}
// TODO Check if reference_symbols_by_name already contains the name and show a conflict error if so.
this->reference_symbols_by_name.emplace(name.value(), SymbolReference {
.section_index = ref_section_index,
.symbol_index = reference_symbols.size()
});
this->reference_symbols.emplace_back(
ReferenceSymbol {
.name = name.value(),
.section_index = ref_section_index,
.section_offset = vram_addr.value() - ref_section_vram,
.is_function = false
}
);
if (!this->add_reference_symbol(name.value(), ref_section_index, vram_addr.value(), false)) {
throw toml::parse_error("Internal error: Failed to add reference symbol to context", data_sym_el.source());
}
}
else {
throw toml::parse_error("Invalid data symbol entry", data_sym_el.source());

View file

@ -213,6 +213,7 @@ ELFIO::section* read_sections(N64Recomp::Context& context, const N64Recomp::ElfP
ELFIO::section* symtab_section = nullptr;
std::vector<SegmentEntry> segments{};
segments.resize(elf_file.segments.size());
bool has_reference_symbols = context.has_reference_symbols();
// Copy the data for each segment into the segment entry list
for (size_t segment_index = 0; segment_index < elf_file.segments.size(); segment_index++) {
@ -263,7 +264,8 @@ ELFIO::section* read_sections(N64Recomp::Context& context, const N64Recomp::ElfP
// If this reloc section is for a section that has been marked as relocatable, record it in the reloc section lookup.
// Alternatively, if this recompilation uses reference symbols then record all reloc sections.
if (elf_config.all_sections_relocatable || !context.reference_sections.empty() || elf_config.relocatable_sections.contains(reloc_target_section)) {
bool section_is_relocatable = elf_config.all_sections_relocatable || elf_config.relocatable_sections.contains(reloc_target_section);
if (has_reference_symbols || section_is_relocatable) {
reloc_sections_by_name[reloc_target_section] = section.get();
}
}
@ -396,8 +398,8 @@ ELFIO::section* read_sections(N64Recomp::Context& context, const N64Recomp::ElfP
// Check if the symbol is undefined and to know whether to look for it in the reference symbols.
if (rel_symbol_section_index == ELFIO::SHN_UNDEF) {
// Undefined sym, check the reference symbols.
auto sym_find_it = context.reference_symbols_by_name.find(rel_symbol_name);
if (sym_find_it == context.reference_symbols_by_name.end()) {
N64Recomp::SymbolReference sym_ref;
if (!context.find_reference_symbol(rel_symbol_name, sym_ref)) {
fmt::print(stderr, "Undefined symbol: {}, not found in input or reference symbols!\n",
rel_symbol_name);
return nullptr;
@ -406,8 +408,8 @@ ELFIO::section* read_sections(N64Recomp::Context& context, const N64Recomp::ElfP
reloc_out.reference_symbol = true;
// Replace the reloc's symbol index with the index into the reference symbol array.
rel_section_vram = 0;
reloc_out.target_section = sym_find_it->second.section_index;
reloc_out.symbol_index = sym_find_it->second.symbol_index;
reloc_out.target_section = sym_ref.section_index;
reloc_out.symbol_index = sym_ref.symbol_index;
const auto& reference_symbol = context.get_reference_symbol(reloc_out.target_section, reloc_out.symbol_index);
rel_symbol_offset = reference_symbol.section_offset;
@ -504,10 +506,7 @@ ELFIO::section* read_sections(N64Recomp::Context& context, const N64Recomp::ElfP
// TODO set section_out.has_mips32_relocs to true if this section should emit its mips32 relocs (mainly for TLB mapping).
if (reloc_out.reference_symbol) {
uint32_t reloc_target_section_addr = 0;
if (reloc_out.target_section != N64Recomp::SectionAbsolute) {
reloc_target_section_addr = context.reference_sections[reloc_out.target_section].ram_addr;
}
uint32_t reloc_target_section_addr = context.get_reference_section_vram(reloc_out.target_section);
// Patch the word in the ROM to incorporate the symbol's value.
uint32_t updated_reloc_word = reloc_rom_word + reloc_target_section_addr + reloc_out.target_section_offset;
*reinterpret_cast<uint32_t*>(context.rom.data() + reloc_rom_addr) = byteswap(updated_reloc_word);

View file

@ -320,7 +320,9 @@ int main(int argc, char** argv) {
}
// Use the reference context to build a reference symbol list for the actual context.
context.import_reference_context(reference_context);
if (!context.import_reference_context(reference_context)) {
exit_failure("Internal error: Failed to import reference context\n");
}
}
for (const std::filesystem::path& cur_data_sym_path : config.data_reference_syms_file_paths) {
@ -586,7 +588,8 @@ int main(int argc, char** argv) {
bool in_normal_patch_section = func_section.name == N64Recomp::PatchSectionName;
bool in_force_patch_section = func_section.name == N64Recomp::ForcedPatchSectionName;
bool in_patch_section = in_normal_patch_section || in_force_patch_section;
bool reference_symbol_found = context.reference_symbols_by_name.contains(func.name);
N64Recomp::SymbolReference dummy_ref;
bool reference_symbol_found = context.reference_symbol_exists(func.name);
// This is a patch function, but no corresponding symbol was found in the original symbol list.
if (in_patch_section && !reference_symbol_found) {

View file

@ -116,11 +116,14 @@ bool parse_v1(std::span<const char> data, const std::unordered_map<uint32_t, uin
return false;
}
// TODO add proper add methods for these vectors and change these to reserves instead.
mod_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_symbols.resize(num_imports);
mod_context.import_symbols.reserve(num_imports);
for (size_t section_index = 0; section_index < num_sections; section_index++) {
const SectionHeaderV1* section_header = reinterpret_data<SectionHeaderV1>(data, offset);
if (section_header == nullptr) {
@ -304,18 +307,7 @@ bool parse_v1(std::span<const char> data, const std::unordered_map<uint32_t, uin
std::string_view import_name{ string_data + name_start, string_data + name_start + name_size };
mod_context.import_symbols[import_index] = N64Recomp::ImportSymbol{
.base = {
.name = std::string{import_name},
.section_index = N64Recomp::SectionImport,
.section_offset = 0,
.is_function = true,
},
.dependency_index = dependency_index,
};
auto& symbol_reference = mod_context.reference_symbols_by_name[std::string{import_name}];
symbol_reference.section_index = N64Recomp::SectionImport;
symbol_reference.symbol_index = import_index;
mod_context.add_import_symbol(std::string{import_name}, dependency_index, import_index);
}
return offset == data.size();
@ -484,7 +476,7 @@ std::vector<uint8_t> N64Recomp::symbols_to_bin_v1(const N64Recomp::Context& cont
target_section_offset_or_index = cur_reloc.symbol_index;
}
else if (cur_reloc.reference_symbol) {
target_section_vrom = context.reference_sections[cur_reloc.target_section].rom_addr;
target_section_vrom = context.get_reference_section_rom(cur_reloc.target_section);
}
else {
target_section_vrom = context.sections[cur_reloc.target_section].rom_addr;

View file

@ -171,18 +171,13 @@ bool process_instruction(const N64Recomp::Context& context, const N64Recomp::Fun
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];
// Don't try to relocate special section symbols.
if (context.is_regular_reference_section(reloc.target_section)) {
bool ref_section_relocatable = context.is_reference_section_relocatable(reloc.target_section);
uint32_t ref_section_vram = context.get_reference_section_vram(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 (!ref_section_relocatable && (reloc_type == N64Recomp::RelocType::R_MIPS_HI16 || reloc_type == N64Recomp::RelocType::R_MIPS_LO16)) {
uint32_t full_immediate = reloc.target_section_offset + ref_section_vram;
if (reloc_type == N64Recomp::RelocType::R_MIPS_HI16) {
imm = (full_immediate >> 16) + ((full_immediate >> 15) & 1);