mirror of
https://github.com/N64Recomp/N64Recomp.git
synced 2026-04-28 04:51:43 +00:00
Add strict mode and ability to generate exports for normal recompilation (for patches)
This commit is contained in:
parent
8fcf73de4d
commit
623013a371
8 changed files with 103 additions and 5 deletions
|
|
@ -139,9 +139,11 @@ int main(int argc, const char** argv) {
|
|||
RabbitizerConfig_Cfg.pseudos.pseudoNot = false;
|
||||
RabbitizerConfig_Cfg.pseudos.pseudoBal = false;
|
||||
|
||||
std::string recomp_include = "#include \"librecomp/recomp.h\"";
|
||||
|
||||
bool should_write_header = true;
|
||||
for (const auto& func : mod_context.base_context.functions) {
|
||||
N64Recomp::recompile_function(mod_context.base_context, func, output_file, static_funcs_by_section, should_write_header);
|
||||
N64Recomp::recompile_function(mod_context.base_context, func, recomp_include, output_file, static_funcs_by_section, should_write_header);
|
||||
should_write_header = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -307,9 +307,9 @@ N64Recomp::ModContext build_mod_context(const N64Recomp::Context& input_context,
|
|||
}
|
||||
|
||||
// Check for special section names.
|
||||
bool patch_section = cur_section.name == ".recomp_patch";
|
||||
bool force_patch_section = cur_section.name == ".recomp_force_patch";
|
||||
bool export_section = cur_section.name == ".recomp_export";
|
||||
bool patch_section = cur_section.name == N64Recomp::PatchSectionName;
|
||||
bool force_patch_section = cur_section.name == N64Recomp::ForcedPatchSectionName;
|
||||
bool export_section = cur_section.name == N64Recomp::ExportSectionName;
|
||||
|
||||
// Add the functions from the current input section to the current output section.
|
||||
auto& section_out = ret.base_context.sections[output_section_index];
|
||||
|
|
|
|||
|
|
@ -60,6 +60,9 @@ namespace N64Recomp {
|
|||
constexpr uint16_t SectionSelf = (uint16_t)-1;
|
||||
constexpr uint16_t SectionAbsolute = (uint16_t)-2;
|
||||
constexpr uint16_t SectionImport = (uint16_t)-3; // Imported symbols for mods
|
||||
constexpr std::string_view PatchSectionName = ".recomp_patch";
|
||||
constexpr std::string_view ForcedPatchSectionName = ".recomp_force_patch";
|
||||
constexpr std::string_view ExportSectionName = ".recomp_export";
|
||||
struct Section {
|
||||
uint32_t rom_addr = 0;
|
||||
uint32_t ram_addr = 0;
|
||||
|
|
|
|||
|
|
@ -408,6 +408,25 @@ N64Recomp::Config::Config(const char* path) {
|
|||
const toml::array* array = data_reference_syms_file_data.as_array();
|
||||
data_reference_syms_file_paths = get_data_syms_paths(array, basedir);
|
||||
}
|
||||
|
||||
// Control whether the recompiler emits exported symbol data.
|
||||
std::optional<bool> allow_exports_opt = input_data["allow_exports"].value<bool>();
|
||||
if (allow_exports_opt.has_value()) {
|
||||
allow_exports = allow_exports_opt.value();
|
||||
}
|
||||
else {
|
||||
allow_exports = false;
|
||||
}
|
||||
|
||||
// Enable patch recompilation strict mode, which ensures that patch functions are marked and that other functions are not marked as patches.
|
||||
std::optional<bool> strict_patch_mode_opt = input_data["strict_patch_mode"].value<bool>();
|
||||
if (strict_patch_mode_opt.has_value()) {
|
||||
strict_patch_mode = strict_patch_mode_opt.value();
|
||||
}
|
||||
else {
|
||||
// Default to strict patch mode if a function reference symbol file was provided.
|
||||
strict_patch_mode = !func_reference_syms_file_path.empty();
|
||||
}
|
||||
}
|
||||
catch (const toml::parse_error& err) {
|
||||
std::cerr << "Syntax error parsing toml: " << *err.source().path << " (" << err.source().begin << "):\n" << err.description() << std::endl;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ namespace N64Recomp {
|
|||
bool single_file_output;
|
||||
bool use_absolute_symbols;
|
||||
bool unpaired_lo16_warnings;
|
||||
bool allow_exports;
|
||||
bool strict_patch_mode;
|
||||
std::filesystem::path elf_path;
|
||||
std::filesystem::path symbols_file_path;
|
||||
std::filesystem::path func_reference_syms_file_path;
|
||||
|
|
|
|||
16
src/elf.cpp
16
src/elf.cpp
|
|
@ -431,7 +431,21 @@ ELFIO::section* read_sections(N64Recomp::Context& context, const N64Recomp::ElfP
|
|||
else {
|
||||
reloc_out.reference_symbol = false;
|
||||
reloc_out.target_section = rel_symbol_section_index;
|
||||
rel_section_vram = context.sections[rel_symbol_section_index].ram_addr;
|
||||
// Handle special sections.
|
||||
if (rel_symbol_section_index >= context.sections.size()) {
|
||||
switch (rel_symbol_section_index) {
|
||||
case ELFIO::SHN_ABS:
|
||||
rel_section_vram = 0;
|
||||
break;
|
||||
default:
|
||||
fmt::print(stderr, "Reloc {} references symbol {} which is in an unknown section 0x{:04X}!\n",
|
||||
i, rel_symbol_name, rel_symbol_section_index);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
rel_section_vram = context.sections[rel_symbol_section_index].ram_addr;
|
||||
}
|
||||
}
|
||||
|
||||
// Reloc pairing, see MIPS System V ABI documentation page 4-18 (https://refspecs.linuxfoundation.org/elf/mipsabi.pdf)
|
||||
|
|
|
|||
57
src/main.cpp
57
src/main.cpp
|
|
@ -568,6 +568,10 @@ int main(int argc, char** argv) {
|
|||
open_new_output_file();
|
||||
}
|
||||
|
||||
std::vector<size_t> export_function_indices{};
|
||||
|
||||
bool failed_strict_mode = false;
|
||||
|
||||
//#pragma omp parallel for
|
||||
for (size_t i = 0; i < context.functions.size(); i++) {
|
||||
const auto& func = context.functions[i];
|
||||
|
|
@ -576,6 +580,33 @@ int main(int argc, char** argv) {
|
|||
fmt::print(func_header_file,
|
||||
"void {}(uint8_t* rdram, recomp_context* ctx);\n", func.name);
|
||||
bool result;
|
||||
const auto& func_section = context.sections[func.section_index];
|
||||
// Apply strict patch mode validation if enabled.
|
||||
if (config.strict_patch_mode) {
|
||||
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);
|
||||
|
||||
// This is a patch function, but no corresponding symbol was found in the original symbol list.
|
||||
if (in_patch_section && !reference_symbol_found) {
|
||||
fmt::print(stderr, "Function {} is marked as a replacement, but no function with the same name was found in the reference symbols!\n", func.name);
|
||||
failed_strict_mode = true;
|
||||
continue;
|
||||
}
|
||||
// This is not a patch function, but it has the same name as a function in the original symbol list.
|
||||
else if (!in_patch_section && reference_symbol_found) {
|
||||
fmt::print(stderr, "Function {} is not marked as a replacement, but a function with the same name was found in the reference symbols!\n", func.name);
|
||||
failed_strict_mode = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Check if this is an export and add it to the list if exports are enabled.
|
||||
if (config.allow_exports && func_section.name == N64Recomp::ExportSectionName) {
|
||||
export_function_indices.push_back(i);
|
||||
}
|
||||
|
||||
// Recompile the function.
|
||||
if (config.single_file_output || config.functions_per_output_file > 1) {
|
||||
result = N64Recomp::recompile_function(context, func, config.recomp_include, current_output_file, static_funcs_by_section, false);
|
||||
if (!config.single_file_output) {
|
||||
|
|
@ -598,6 +629,15 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
}
|
||||
|
||||
if (failed_strict_mode) {
|
||||
if (config.single_file_output || config.functions_per_output_file > 1) {
|
||||
current_output_file.close();
|
||||
std::error_code ec;
|
||||
std::filesystem::remove(config.output_func_path / config.elf_path.stem().replace_extension(".c"), ec);
|
||||
}
|
||||
exit_failure("Strict mode validation failed!\n");
|
||||
}
|
||||
|
||||
for (size_t section_index = 0; section_index < context.sections.size(); section_index++) {
|
||||
auto& section = context.sections[section_index];
|
||||
auto& section_funcs = section.function_addrs;
|
||||
|
|
@ -789,6 +829,23 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
}
|
||||
fmt::print(overlay_file, "}};\n");
|
||||
|
||||
if (config.allow_exports) {
|
||||
fmt::print(overlay_file,
|
||||
"\n"
|
||||
"static FunctionExport export_table[] = {{\n"
|
||||
);
|
||||
|
||||
for (size_t func_index : export_function_indices) {
|
||||
const auto& func = context.functions[func_index];
|
||||
fmt::print(overlay_file, " {{ \"{}\", 0x{:08X} }},\n", func.name, func.vram);
|
||||
}
|
||||
|
||||
// Add a dummy element at the end to ensure the array has a valid length because C doesn't allow zero-size arrays.
|
||||
fmt::print(overlay_file, " {{ NULL, 0 }}\n");
|
||||
|
||||
fmt::print(overlay_file, "}};\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.output_binary_path.empty()) {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ struct FileSubHeaderV1 {
|
|||
};
|
||||
|
||||
struct SectionHeaderV1 {
|
||||
uint32_t flags;
|
||||
uint32_t file_offset;
|
||||
uint32_t vram;
|
||||
uint32_t rom_size;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue