Added manual sections input option, fixed bug with multiplications and added mthi/lo instructions
This commit is contained in:
parent
72fe4ed79c
commit
50d55bd171
|
@ -44,6 +44,13 @@ namespace RecompPort {
|
||||||
uint32_t size_bytes;
|
uint32_t size_bytes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ManualFunction {
|
||||||
|
std::string func_name;
|
||||||
|
std::string section_name;
|
||||||
|
uint32_t vram;
|
||||||
|
uint32_t size;
|
||||||
|
};
|
||||||
|
|
||||||
struct Config {
|
struct Config {
|
||||||
int32_t entrypoint;
|
int32_t entrypoint;
|
||||||
bool has_entrypoint;
|
bool has_entrypoint;
|
||||||
|
@ -58,6 +65,7 @@ namespace RecompPort {
|
||||||
DeclaredFunctionMap declared_funcs;
|
DeclaredFunctionMap declared_funcs;
|
||||||
std::vector<InstructionPatch> instruction_patches;
|
std::vector<InstructionPatch> instruction_patches;
|
||||||
std::vector<FunctionSize> manual_func_sizes;
|
std::vector<FunctionSize> manual_func_sizes;
|
||||||
|
std::vector<ManualFunction> manual_functions;
|
||||||
std::string bss_section_suffix;
|
std::string bss_section_suffix;
|
||||||
|
|
||||||
Config(const char* path);
|
Config(const char* path);
|
||||||
|
|
|
@ -17,6 +17,30 @@ struct value_error : public toml::exception {
|
||||||
std::string what_;
|
std::string what_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::vector<RecompPort::ManualFunction> get_manual_funcs(const toml::value& manual_funcs_data) {
|
||||||
|
std::vector<RecompPort::ManualFunction> ret;
|
||||||
|
|
||||||
|
if (manual_funcs_data.type() != toml::value_t::array) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the funcs array as an array type.
|
||||||
|
const toml::array& manual_funcs_array = manual_funcs_data.as_array();
|
||||||
|
|
||||||
|
// Reserve room for all the funcs in the map.
|
||||||
|
ret.reserve(manual_funcs_array.size());
|
||||||
|
for (const toml::value& cur_func_val : manual_funcs_array) {
|
||||||
|
const std::string& func_name = toml::find<std::string>(cur_func_val, "name");
|
||||||
|
const std::string& section_name = toml::find<std::string>(cur_func_val, "section");
|
||||||
|
uint32_t vram_in = toml::find<uint32_t>(cur_func_val, "vram");
|
||||||
|
uint32_t size = toml::find<uint32_t>(cur_func_val, "size");
|
||||||
|
|
||||||
|
ret.emplace_back(func_name, section_name, vram_in, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> get_stubbed_funcs(const toml::value& patches_data) {
|
std::vector<std::string> get_stubbed_funcs(const toml::value& patches_data) {
|
||||||
std::vector<std::string> stubbed_funcs{};
|
std::vector<std::string> stubbed_funcs{};
|
||||||
|
|
||||||
|
@ -226,6 +250,12 @@ RecompPort::Config::Config(const char* path) {
|
||||||
single_file_output = toml::find_or<bool>(input_data, "single_file_output", false);
|
single_file_output = toml::find_or<bool>(input_data, "single_file_output", false);
|
||||||
use_absolute_symbols = toml::find_or<bool>(input_data, "use_absolute_symbols", false);
|
use_absolute_symbols = toml::find_or<bool>(input_data, "use_absolute_symbols", false);
|
||||||
|
|
||||||
|
// Manual functions (optional)
|
||||||
|
const toml::value& manual_functions_data = toml::find_or<toml::value>(input_data, "manual_funcs", toml::value{});
|
||||||
|
if (manual_functions_data.type() != toml::value_t::empty) {
|
||||||
|
manual_functions = get_manual_funcs(manual_functions_data);
|
||||||
|
}
|
||||||
|
|
||||||
// Patches section (optional)
|
// Patches section (optional)
|
||||||
const toml::value& patches_data = toml::find_or<toml::value>(config_data, "patches", toml::value{});
|
const toml::value& patches_data = toml::find_or<toml::value>(config_data, "patches", toml::value{});
|
||||||
if (patches_data.type() != toml::value_t::empty) {
|
if (patches_data.type() != toml::value_t::empty) {
|
||||||
|
|
62
src/main.cpp
62
src/main.cpp
|
@ -707,6 +707,65 @@ bool read_symbols(RecompPort::Context& context, const ELFIO::elfio& elf_file, EL
|
||||||
return found_entrypoint_func;
|
return found_entrypoint_func;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add_manual_functions(RecompPort::Context& context, const ELFIO::elfio& elf_file, const std::vector<RecompPort::ManualFunction>& manual_funcs) {
|
||||||
|
auto exit_failure = [](const std::string& error_str) {
|
||||||
|
fmt::vprint(stderr, error_str, fmt::make_format_args());
|
||||||
|
std::exit(EXIT_FAILURE);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Build a lookup from section name to section index.
|
||||||
|
std::unordered_map<std::string, size_t> section_indices_by_name{};
|
||||||
|
section_indices_by_name.reserve(context.sections.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < context.sections.size(); i++) {
|
||||||
|
section_indices_by_name.emplace(context.sections[i].name, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const RecompPort::ManualFunction& cur_func_def : manual_funcs) {
|
||||||
|
const auto section_find_it = section_indices_by_name.find(cur_func_def.section_name);
|
||||||
|
if (section_find_it == section_indices_by_name.end()) {
|
||||||
|
exit_failure(fmt::format("Manual function {} specified with section {}, which doesn't exist!\n", cur_func_def.func_name, cur_func_def.section_name));
|
||||||
|
}
|
||||||
|
size_t section_index = section_find_it->second;
|
||||||
|
|
||||||
|
const auto func_find_it = context.functions_by_name.find(cur_func_def.func_name);
|
||||||
|
if (func_find_it != context.functions_by_name.end()) {
|
||||||
|
exit_failure(fmt::format("Manual function {} already exists!\n", cur_func_def.func_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cur_func_def.size & 0b11) != 0) {
|
||||||
|
exit_failure(fmt::format("Manual function {} has a size that isn't divisible by 4!\n", cur_func_def.func_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& section = context.sections[section_index];
|
||||||
|
uint32_t section_offset = cur_func_def.vram - section.ram_addr;
|
||||||
|
uint32_t rom_address = section_offset + section.rom_addr;
|
||||||
|
|
||||||
|
std::vector<uint32_t> words;
|
||||||
|
words.resize(cur_func_def.size / 4);
|
||||||
|
const uint32_t* elf_words = reinterpret_cast<const uint32_t*>(elf_file.sections[section_index]->get_data() + section_offset);
|
||||||
|
|
||||||
|
words.assign(elf_words, elf_words + words.size());
|
||||||
|
|
||||||
|
size_t function_index = context.functions.size();
|
||||||
|
context.functions.emplace_back(
|
||||||
|
cur_func_def.vram,
|
||||||
|
rom_address,
|
||||||
|
std::move(words),
|
||||||
|
cur_func_def.func_name,
|
||||||
|
ELFIO::Elf_Half(section_index),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
context.section_functions[section_index].push_back(function_index);
|
||||||
|
section.function_addrs.push_back(function_index);
|
||||||
|
context.functions_by_vram[cur_func_def.vram].push_back(function_index);
|
||||||
|
context.functions_by_name[cur_func_def.func_name] = function_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct SegmentEntry {
|
struct SegmentEntry {
|
||||||
ELFIO::Elf64_Off data_offset;
|
ELFIO::Elf64_Off data_offset;
|
||||||
ELFIO::Elf64_Addr physical_address;
|
ELFIO::Elf64_Addr physical_address;
|
||||||
|
@ -1140,6 +1199,9 @@ int main(int argc, char** argv) {
|
||||||
// Read all of the symbols in the elf and look for the entrypoint function
|
// Read all of the symbols in the elf and look for the entrypoint function
|
||||||
bool found_entrypoint_func = read_symbols(context, elf_file, symtab_section, config.entrypoint, config.has_entrypoint, config.use_absolute_symbols);
|
bool found_entrypoint_func = read_symbols(context, elf_file, symtab_section, config.entrypoint, config.has_entrypoint, config.use_absolute_symbols);
|
||||||
|
|
||||||
|
// Add any manual functions
|
||||||
|
add_manual_functions(context, elf_file, config.manual_functions);
|
||||||
|
|
||||||
if (config.has_entrypoint && !found_entrypoint_func) {
|
if (config.has_entrypoint && !found_entrypoint_func) {
|
||||||
exit_failure("Could not find entrypoint function\n");
|
exit_failure("Could not find entrypoint function\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -381,10 +381,10 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::C
|
||||||
print_line("{}{} = {}{} < {} ? 1 : 0", ctx_gpr_prefix(rt), rt, ctx_gpr_prefix(rs), rs, signed_imm_string);
|
print_line("{}{} = {}{} < {} ? 1 : 0", ctx_gpr_prefix(rt), rt, ctx_gpr_prefix(rs), rs, signed_imm_string);
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_mult:
|
case InstrId::cpu_mult:
|
||||||
print_line("result = S64({}{}) * S64({}{}); lo = S32(result >> 0); hi = S32(result >> 32)", ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
|
print_line("result = S64(S32({}{})) * S64(S32({}{})); lo = S32(result >> 0); hi = S32(result >> 32)", ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_multu:
|
case InstrId::cpu_multu:
|
||||||
print_line("result = U64({}{}) * U64({}{}); lo = S32(result >> 0); hi = S32(result >> 32)", ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
|
print_line("result = U64(U32({}{})) * U64(U32({}{})); lo = S32(result >> 0); hi = S32(result >> 32)", ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_div:
|
case InstrId::cpu_div:
|
||||||
// Cast to 64-bits before division to prevent artihmetic exception for s32(0x80000000) / -1
|
// Cast to 64-bits before division to prevent artihmetic exception for s32(0x80000000) / -1
|
||||||
|
@ -399,6 +399,12 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::C
|
||||||
case InstrId::cpu_mfhi:
|
case InstrId::cpu_mfhi:
|
||||||
print_line("{}{} = hi", ctx_gpr_prefix(rd), rd);
|
print_line("{}{} = hi", ctx_gpr_prefix(rd), rd);
|
||||||
break;
|
break;
|
||||||
|
case InstrId::cpu_mtlo:
|
||||||
|
print_line("lo = {}{}", ctx_gpr_prefix(rd), rd);
|
||||||
|
break;
|
||||||
|
case InstrId::cpu_mthi:
|
||||||
|
print_line("hi = {}{}", ctx_gpr_prefix(rd), rd);
|
||||||
|
break;
|
||||||
// Loads
|
// Loads
|
||||||
case InstrId::cpu_ld:
|
case InstrId::cpu_ld:
|
||||||
print_line("{}{} = LD({}, {}{})", ctx_gpr_prefix(rt), rt, signed_imm_string, ctx_gpr_prefix(base), base);
|
print_line("{}{} = LD({}, {}{})", ctx_gpr_prefix(rt), rt, signed_imm_string, ctx_gpr_prefix(base), base);
|
||||||
|
@ -1095,11 +1101,6 @@ bool RecompPort::recompile_function(const RecompPort::Context& context, const Re
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (section.name == ".anseq") {
|
|
||||||
std::this_thread::yield();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process the current instruction and check for errors
|
// Process the current instruction and check for errors
|
||||||
if (process_instruction(context, config, func, stats, skipped_insns, instr_index, instructions, output_file, false, needs_link_branch, num_link_branches, reloc_index, needs_link_branch, is_branch_likely, static_funcs_out) == false) {
|
if (process_instruction(context, config, func, stats, skipped_insns, instr_index, instructions, output_file, false, needs_link_branch, num_link_branches, reloc_index, needs_link_branch, is_branch_likely, static_funcs_out) == false) {
|
||||||
fmt::print(stderr, "Error in recompiling {}, clearing output file\n", func.name);
|
fmt::print(stderr, "Error in recompiling {}, clearing output file\n", func.name);
|
||||||
|
|
Loading…
Reference in a new issue