mirror of
https://github.com/N64Recomp/N64Recomp.git
synced 2026-04-30 22:11: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);
|
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{};
|
N64Recomp::ModContext ret{};
|
||||||
good = false;
|
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);
|
ret.base_context.section_functions[output_section_index].push_back(output_func_index);
|
||||||
|
|
||||||
|
|
||||||
// Add this function to the output context.
|
// Add this function to the output context.
|
||||||
ret.base_context.functions.emplace_back(
|
ret.base_context.functions.emplace_back(
|
||||||
cur_func.vram,
|
cur_func.vram,
|
||||||
cur_func.rom,
|
cur_func.rom,
|
||||||
std::vector<uint32_t>{}, // words
|
std::vector<uint32_t>{}, // words
|
||||||
"", // name
|
std::move(name_out), // name
|
||||||
(uint16_t)output_section_index,
|
(uint16_t)output_section_index,
|
||||||
false, // ignored
|
false, // ignored
|
||||||
false, // reimplemented
|
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;
|
good = true;
|
||||||
|
|
@ -467,7 +495,14 @@ int main(int argc, const char** argv) {
|
||||||
context.import_reference_context(reference_context);
|
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{};
|
std::vector<std::string> import_symbol_mod_ids{};
|
||||||
|
|
||||||
for (const std::filesystem::path& dependency_path : config.dependency_paths) {
|
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 {
|
N64Recomp::ElfParsingConfig elf_config {
|
||||||
.bss_section_suffix = {},
|
.bss_section_suffix = {},
|
||||||
.manually_sized_funcs = {},
|
.manually_sized_funcs = {},
|
||||||
|
|
@ -509,7 +537,7 @@ int main(int argc, const char** argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mod_context_good;
|
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::vector<uint8_t> symbols_bin = N64Recomp::symbols_to_bin_v1(mod_context);
|
||||||
|
|
||||||
std::ofstream output_syms_file{ config.output_syms_path, std::ios::binary };
|
std::ofstream output_syms_file{ config.output_syms_path, std::ios::binary };
|
||||||
|
|
|
||||||
|
|
@ -167,6 +167,10 @@ namespace N64Recomp {
|
||||||
struct ModContext {
|
struct ModContext {
|
||||||
Context base_context;
|
Context base_context;
|
||||||
std::vector<FunctionReplacement> replacements;
|
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 {
|
enum class ModSymbolsError {
|
||||||
Good,
|
Good,
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ struct FileSubHeaderV1 {
|
||||||
uint32_t num_replacements;
|
uint32_t num_replacements;
|
||||||
uint32_t num_exports;
|
uint32_t num_exports;
|
||||||
uint32_t num_imports;
|
uint32_t num_imports;
|
||||||
|
uint32_t string_data_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SectionHeaderV1 {
|
struct SectionHeaderV1 {
|
||||||
|
|
@ -40,6 +41,19 @@ struct ReplacementV1 {
|
||||||
uint32_t flags; // force
|
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 SectionSelfVromV1 = 0xFFFFFFFF;
|
||||||
constexpr uint32_t SectionImportVromV1 = 0xFFFFFFFE;
|
constexpr uint32_t SectionImportVromV1 = 0xFFFFFFFE;
|
||||||
|
|
||||||
|
|
@ -219,7 +233,13 @@ template <typename T>
|
||||||
void vec_put(std::vector<uint8_t>& vec, const T* data) {
|
void vec_put(std::vector<uint8_t>& vec, const T* data) {
|
||||||
size_t start_size = vec.size();
|
size_t start_size = vec.size();
|
||||||
vec.resize(vec.size() + sizeof(T));
|
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) {
|
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);
|
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 {
|
FileSubHeaderV1 sub_header {
|
||||||
.num_sections = static_cast<uint32_t>(context.sections.size()),
|
.num_sections = static_cast<uint32_t>(context.sections.size()),
|
||||||
.num_replacements = static_cast<uint32_t>(mod_context.replacements.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);
|
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++) {
|
for (size_t section_index = 0; section_index < context.sections.size(); section_index++) {
|
||||||
const Section& cur_section = context.sections[section_index];
|
const Section& cur_section = context.sections[section_index];
|
||||||
SectionHeaderV1 section_out {
|
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) {
|
for (const FunctionReplacement& cur_replacement : mod_context.replacements) {
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
if ((cur_replacement.flags & ReplacementFlags::Force) == ReplacementFlags::Force) {
|
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);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue