mirror of
https://github.com/N64Recomp/N64Recomp.git
synced 2026-04-28 04:51:43 +00:00
Implemented writing import and exports in the mod tool
This commit is contained in:
parent
ab80ff962e
commit
4b4dcff7ca
3 changed files with 159 additions and 14 deletions
|
|
@ -199,7 +199,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, bool& good) {
|
||||
N64Recomp::ModContext build_mod_context(const N64Recomp::Context& input_context, std::vector<std::string>&& import_symbol_mod_ids, bool& good) {
|
||||
N64Recomp::ModContext ret{};
|
||||
good = false;
|
||||
|
||||
|
|
@ -330,14 +330,23 @@ N64Recomp::ModContext build_mod_context(const N64Recomp::Context& input_context,
|
|||
);
|
||||
}
|
||||
|
||||
std::string name_out;
|
||||
|
||||
if (export_section) {
|
||||
ret.exported_funcs.push_back(output_func_index);
|
||||
// Names are required for exported funcs, so copy the input function's name if we're in the export section.
|
||||
name_out = cur_func.name;
|
||||
}
|
||||
|
||||
ret.base_context.section_functions[output_section_index].push_back(output_func_index);
|
||||
|
||||
|
||||
// Add this function to the output context.
|
||||
ret.base_context.functions.emplace_back(
|
||||
cur_func.vram,
|
||||
cur_func.rom,
|
||||
std::vector<uint32_t>{}, // words
|
||||
"", // name
|
||||
std::move(name_out), // name
|
||||
(uint16_t)output_section_index,
|
||||
false, // ignored
|
||||
false, // reimplemented
|
||||
|
|
@ -427,10 +436,29 @@ N64Recomp::ModContext build_mod_context(const N64Recomp::Context& input_context,
|
|||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO exports
|
||||
ret.import_symbol_mod_ids = std::move(import_symbol_mod_ids);
|
||||
|
||||
// TODO imports
|
||||
// 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++) {
|
||||
size_t reference_symbol_index = import_symbol_index + import_symbol_start_index;
|
||||
const auto& reference_symbol = input_context.reference_symbols[reference_symbol_index];
|
||||
const std::string& reference_symbol_name = input_context.reference_symbol_names[reference_symbol_index];
|
||||
|
||||
if (reference_symbol.section_index != N64Recomp::SectionImport) {
|
||||
fmt::print("Import symbol index {} (reference symbol index {}, name {}) is not in the import section!\n",
|
||||
import_symbol_index, reference_symbol_index, reference_symbol_name);
|
||||
return {};
|
||||
}
|
||||
|
||||
ret.base_context.reference_symbols[import_symbol_index] = reference_symbol;
|
||||
ret.base_context.reference_symbol_names[import_symbol_index] = reference_symbol_name;
|
||||
ret.base_context.reference_symbols_by_name[reference_symbol_name] = import_symbol_index;
|
||||
}
|
||||
|
||||
good = true;
|
||||
|
|
@ -467,7 +495,14 @@ int main(int argc, const char** argv) {
|
|||
context.import_reference_context(reference_context);
|
||||
}
|
||||
|
||||
size_t import_section_symbol_start = context.reference_symbols.size();
|
||||
for (const std::filesystem::path& cur_data_sym_path : config.data_reference_syms_file_paths) {
|
||||
if (!context.read_data_reference_syms(cur_data_sym_path)) {
|
||||
fmt::print(stderr, "Failed to load provided data reference symbol file: {}\n", cur_data_sym_path.string());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Read the imported symbols, placing them at the end of the reference symbol list.
|
||||
std::vector<std::string> import_symbol_mod_ids{};
|
||||
|
||||
for (const std::filesystem::path& dependency_path : config.dependency_paths) {
|
||||
|
|
@ -477,13 +512,6 @@ int main(int argc, const char** argv) {
|
|||
}
|
||||
}
|
||||
|
||||
for (const std::filesystem::path& cur_data_sym_path : config.data_reference_syms_file_paths) {
|
||||
if (!context.read_data_reference_syms(cur_data_sym_path)) {
|
||||
fmt::print(stderr, "Failed to load provided data reference symbol file: {}\n", cur_data_sym_path.string());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
N64Recomp::ElfParsingConfig elf_config {
|
||||
.bss_section_suffix = {},
|
||||
.manually_sized_funcs = {},
|
||||
|
|
@ -509,7 +537,7 @@ int main(int argc, const char** argv) {
|
|||
}
|
||||
|
||||
bool mod_context_good;
|
||||
N64Recomp::ModContext mod_context = build_mod_context(context, mod_context_good);
|
||||
N64Recomp::ModContext mod_context = build_mod_context(context, std::move(import_symbol_mod_ids), mod_context_good);
|
||||
std::vector<uint8_t> symbols_bin = N64Recomp::symbols_to_bin_v1(mod_context);
|
||||
|
||||
std::ofstream output_syms_file{ config.output_syms_path, std::ios::binary };
|
||||
|
|
|
|||
|
|
@ -167,6 +167,10 @@ namespace N64Recomp {
|
|||
struct ModContext {
|
||||
Context base_context;
|
||||
std::vector<FunctionReplacement> replacements;
|
||||
// Mod id of every imported function (which exist at the end of `base_context.reference_symbols`).
|
||||
std::vector<std::string> import_symbol_mod_ids;
|
||||
// Indices of every exported function.
|
||||
std::vector<size_t> exported_funcs;
|
||||
};
|
||||
enum class ModSymbolsError {
|
||||
Good,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ struct FileSubHeaderV1 {
|
|||
uint32_t num_replacements;
|
||||
uint32_t num_exports;
|
||||
uint32_t num_imports;
|
||||
uint32_t string_data_size;
|
||||
};
|
||||
|
||||
struct SectionHeaderV1 {
|
||||
|
|
@ -40,6 +41,19 @@ struct ReplacementV1 {
|
|||
uint32_t flags; // force
|
||||
};
|
||||
|
||||
struct ExportV1 {
|
||||
uint32_t func_index;
|
||||
uint32_t name_start; // offset into the string data
|
||||
uint32_t name_size;
|
||||
};
|
||||
|
||||
struct ImportV1 {
|
||||
uint32_t name_start;
|
||||
uint32_t name_size;
|
||||
uint32_t mod_id_start;
|
||||
uint32_t mod_id_size;
|
||||
};
|
||||
|
||||
constexpr uint32_t SectionSelfVromV1 = 0xFFFFFFFF;
|
||||
constexpr uint32_t SectionImportVromV1 = 0xFFFFFFFE;
|
||||
|
||||
|
|
@ -219,7 +233,13 @@ template <typename T>
|
|||
void vec_put(std::vector<uint8_t>& vec, const T* data) {
|
||||
size_t start_size = vec.size();
|
||||
vec.resize(vec.size() + sizeof(T));
|
||||
memcpy(vec.data() + start_size, reinterpret_cast<const uint8_t*>(data), sizeof(T));
|
||||
memcpy(vec.data() + start_size, data, sizeof(T));
|
||||
}
|
||||
|
||||
void vec_put(std::vector<uint8_t>& vec, const std::string& data) {
|
||||
size_t start_size = vec.size();
|
||||
vec.resize(vec.size() + data.size());
|
||||
memcpy(vec.data() + start_size, data.data(), data.size());
|
||||
}
|
||||
|
||||
std::vector<uint8_t> N64Recomp::symbols_to_bin_v1(const N64Recomp::ModContext& mod_context) {
|
||||
|
|
@ -234,13 +254,67 @@ std::vector<uint8_t> 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();
|
||||
|
||||
FileSubHeaderV1 sub_header {
|
||||
.num_sections = static_cast<uint32_t>(context.sections.size()),
|
||||
.num_replacements = static_cast<uint32_t>(mod_context.replacements.size()),
|
||||
.num_exports = static_cast<uint32_t>(num_exported_funcs),
|
||||
.num_imports = static_cast<uint32_t>(num_imported_funcs),
|
||||
.string_data_size = 0,
|
||||
};
|
||||
|
||||
// Record the sub-header offset so the string data size can be filled in later.
|
||||
size_t sub_header_offset = ret.size();
|
||||
vec_put(ret, &sub_header);
|
||||
|
||||
// Build the string data from the exports and imports.
|
||||
size_t strings_start = ret.size();
|
||||
|
||||
// Track the start of every exported function's name in the string data. Size comes from the function, so no need to store it.
|
||||
std::vector<uint32_t> exported_func_name_positions{};
|
||||
exported_func_name_positions.resize(num_exported_funcs);
|
||||
for (size_t export_index = 0; export_index < num_exported_funcs; export_index++) {
|
||||
size_t function_index = mod_context.exported_funcs[export_index];
|
||||
const Function& exported_func = mod_context.base_context.functions[function_index];
|
||||
|
||||
exported_func_name_positions[export_index] = static_cast<uint32_t>(ret.size() - strings_start);
|
||||
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.
|
||||
std::vector<uint32_t> imported_func_name_positions{};
|
||||
imported_func_name_positions.resize(num_imported_funcs);
|
||||
std::unordered_map<std::string, uint32_t> mod_id_name_positions{};
|
||||
// Calculate the index of the first import symbol. Import symbols are all grouped at the end of the reference symbol list.
|
||||
size_t import_symbol_base_index = mod_context.base_context.reference_symbols.size() - num_imported_funcs;
|
||||
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];
|
||||
|
||||
// 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<uint32_t>(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<uint32_t>(ret.size() - strings_start);
|
||||
vec_put(ret, imported_func_name);
|
||||
}
|
||||
|
||||
// Align the data after the strings to 4 bytes.
|
||||
size_t strings_size = round_up_4(ret.size() - strings_start);
|
||||
ret.resize(strings_size + strings_start);
|
||||
|
||||
// Fill in the string data size in the sub-header.
|
||||
reinterpret_cast<FileSubHeaderV1*>(ret.data() + sub_header_offset)->string_data_size = strings_size;
|
||||
|
||||
for (size_t section_index = 0; section_index < context.sections.size(); section_index++) {
|
||||
const Section& cur_section = context.sections[section_index];
|
||||
SectionHeaderV1 section_out {
|
||||
|
|
@ -289,6 +363,7 @@ std::vector<uint8_t> N64Recomp::symbols_to_bin_v1(const N64Recomp::ModContext& m
|
|||
}
|
||||
}
|
||||
|
||||
// Write the function replacements.
|
||||
for (const FunctionReplacement& cur_replacement : mod_context.replacements) {
|
||||
uint32_t flags = 0;
|
||||
if ((cur_replacement.flags & ReplacementFlags::Force) == ReplacementFlags::Force) {
|
||||
|
|
@ -305,5 +380,43 @@ std::vector<uint8_t> N64Recomp::symbols_to_bin_v1(const N64Recomp::ModContext& m
|
|||
vec_put(ret, &replacement_out);
|
||||
};
|
||||
|
||||
// Write the exported functions.
|
||||
for (size_t export_index = 0; export_index < num_exported_funcs; export_index++) {
|
||||
size_t function_index = mod_context.exported_funcs[export_index];
|
||||
const Function& exported_func = mod_context.base_context.functions[function_index];
|
||||
|
||||
ExportV1 export_out {
|
||||
.func_index = static_cast<uint32_t>(function_index),
|
||||
.name_start = exported_func_name_positions[export_index],
|
||||
.name_size = static_cast<uint32_t>(exported_func.name.size())
|
||||
};
|
||||
|
||||
vec_put(ret, &export_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 {};
|
||||
}
|
||||
|
||||
ImportV1 import_out {
|
||||
.name_start = imported_func_name_positions[import_index],
|
||||
.name_size = static_cast<uint32_t>(imported_func_name.size()),
|
||||
.mod_id_start = mod_id_find_it->second,
|
||||
.mod_id_size = static_cast<uint32_t>(cur_mod_id.size())
|
||||
};
|
||||
|
||||
vec_put(ret, &import_out);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue