Added single-file mode and absolute symbol options (for patch recompilation)
This commit is contained in:
parent
d249363fe5
commit
be275c198a
|
@ -46,7 +46,10 @@ namespace RecompPort {
|
||||||
|
|
||||||
struct Config {
|
struct Config {
|
||||||
int32_t entrypoint;
|
int32_t entrypoint;
|
||||||
|
bool has_entrypoint;
|
||||||
bool uses_mips3_float_mode;
|
bool uses_mips3_float_mode;
|
||||||
|
bool single_file_output;
|
||||||
|
bool use_absolute_symbols;
|
||||||
std::filesystem::path elf_path;
|
std::filesystem::path elf_path;
|
||||||
std::filesystem::path output_func_path;
|
std::filesystem::path output_func_path;
|
||||||
std::filesystem::path relocatable_sections_path;
|
std::filesystem::path relocatable_sections_path;
|
||||||
|
@ -154,7 +157,7 @@ namespace RecompPort {
|
||||||
};
|
};
|
||||||
|
|
||||||
bool analyze_function(const Context& context, const Function& function, const std::vector<rabbitizer::InstructionCpu>& instructions, FunctionStats& stats);
|
bool analyze_function(const Context& context, const Function& function, const std::vector<rabbitizer::InstructionCpu>& instructions, FunctionStats& stats);
|
||||||
bool recompile_function(const Context& context, const Config& config, const Function& func, const std::filesystem::path& output_path, std::span<std::vector<uint32_t>> static_funcs);
|
bool recompile_function(const Context& context, const Config& config, const Function& func, std::ofstream& output_file, std::span<std::vector<uint32_t>> static_funcs, bool write_header);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -22,8 +22,10 @@
|
||||||
<ClCompile Include="rabbitizer\cplusplus\src\analysis\LoPairingInfo.cpp" />
|
<ClCompile Include="rabbitizer\cplusplus\src\analysis\LoPairingInfo.cpp" />
|
||||||
<ClCompile Include="rabbitizer\cplusplus\src\analysis\RegistersTracker.cpp" />
|
<ClCompile Include="rabbitizer\cplusplus\src\analysis\RegistersTracker.cpp" />
|
||||||
<ClCompile Include="rabbitizer\cplusplus\src\instructions\InstrId.cpp" />
|
<ClCompile Include="rabbitizer\cplusplus\src\instructions\InstrId.cpp" />
|
||||||
|
<ClCompile Include="rabbitizer\cplusplus\src\instructions\InstrIdType.cpp" />
|
||||||
<ClCompile Include="rabbitizer\cplusplus\src\instructions\InstructionBase.cpp" />
|
<ClCompile Include="rabbitizer\cplusplus\src\instructions\InstructionBase.cpp" />
|
||||||
<ClCompile Include="rabbitizer\cplusplus\src\instructions\InstructionCpu.cpp" />
|
<ClCompile Include="rabbitizer\cplusplus\src\instructions\InstructionCpu.cpp" />
|
||||||
|
<ClCompile Include="rabbitizer\cplusplus\src\instructions\InstructionR3000GTE.cpp" />
|
||||||
<ClCompile Include="rabbitizer\cplusplus\src\instructions\InstructionR5900.cpp" />
|
<ClCompile Include="rabbitizer\cplusplus\src\instructions\InstructionR5900.cpp" />
|
||||||
<ClCompile Include="rabbitizer\cplusplus\src\instructions\InstructionRsp.cpp" />
|
<ClCompile Include="rabbitizer\cplusplus\src\instructions\InstructionRsp.cpp" />
|
||||||
<ClCompile Include="rabbitizer\src\analysis\RabbitizerLoPairingInfo.c" />
|
<ClCompile Include="rabbitizer\src\analysis\RabbitizerLoPairingInfo.c" />
|
||||||
|
@ -35,8 +37,12 @@
|
||||||
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstrCategory.c" />
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstrCategory.c" />
|
||||||
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstrDescriptor.c" />
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstrDescriptor.c" />
|
||||||
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstrId.c" />
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstrId.c" />
|
||||||
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstrIdType.c" />
|
||||||
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstrSuffix.c" />
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstrSuffix.c" />
|
||||||
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionCpu\RabbitizerInstructionCpu_OperandType.c" />
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionCpu\RabbitizerInstructionCpu_OperandType.c" />
|
||||||
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionR3000GTE\RabbitizerInstructionR3000GTE.c" />
|
||||||
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionR3000GTE\RabbitizerInstructionR3000GTE_OperandType.c" />
|
||||||
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionR3000GTE\RabbitizerInstructionR3000GTE_ProcessUniqueId.c" />
|
||||||
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionR5900\RabbitizerInstructionR5900.c" />
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionR5900\RabbitizerInstructionR5900.c" />
|
||||||
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionR5900\RabbitizerInstructionR5900_OperandType.c" />
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionR5900\RabbitizerInstructionR5900_OperandType.c" />
|
||||||
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionR5900\RabbitizerInstructionR5900_ProcessUniqueId.c" />
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionR5900\RabbitizerInstructionR5900_ProcessUniqueId.c" />
|
||||||
|
@ -46,8 +52,10 @@
|
||||||
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstruction\RabbitizerInstruction.c" />
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstruction\RabbitizerInstruction.c" />
|
||||||
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstruction\RabbitizerInstruction_Disassemble.c" />
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstruction\RabbitizerInstruction_Disassemble.c" />
|
||||||
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstruction\RabbitizerInstruction_Examination.c" />
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstruction\RabbitizerInstruction_Examination.c" />
|
||||||
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstruction\RabbitizerInstruction_Operand.c" />
|
||||||
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstruction\RabbitizerInstruction_ProcessUniqueId.c" />
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstruction\RabbitizerInstruction_ProcessUniqueId.c" />
|
||||||
<ClCompile Include="rabbitizer\src\instructions\RabbitizerRegister.c" />
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerRegister.c" />
|
||||||
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerRegisterDescriptor.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="rabbitizer\cplusplus\include\analysis\LoPairingInfo.hpp" />
|
<ClInclude Include="rabbitizer\cplusplus\include\analysis\LoPairingInfo.hpp" />
|
||||||
|
@ -158,7 +166,7 @@
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
</Link>
|
</Link>
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)rabbitizer\include;$(ProjectDir)rabbitizer\cplusplus\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ProjectDir)rabbitizer\include;$(ProjectDir)rabbitizer\cplusplus\include;$(ProjectDir)rabbitizer\tables</AdditionalIncludeDirectories>
|
||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
|
@ -171,7 +179,7 @@
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
</Link>
|
</Link>
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)rabbitizer\include;$(ProjectDir)rabbitizer\cplusplus\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ProjectDir)rabbitizer\include;$(ProjectDir)rabbitizer\cplusplus\include;$(ProjectDir)rabbitizer\tables</AdditionalIncludeDirectories>
|
||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
|
@ -182,7 +190,7 @@
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
</Link>
|
</Link>
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)rabbitizer\include;$(ProjectDir)rabbitizer\cplusplus\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ProjectDir)rabbitizer\include;$(ProjectDir)rabbitizer\cplusplus\include;$(ProjectDir)rabbitizer\tables</AdditionalIncludeDirectories>
|
||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
|
@ -195,7 +203,7 @@
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
</Link>
|
</Link>
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)rabbitizer\include;$(ProjectDir)rabbitizer\cplusplus\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ProjectDir)rabbitizer\include;$(ProjectDir)rabbitizer\cplusplus\include;$(ProjectDir)rabbitizer\tables</AdditionalIncludeDirectories>
|
||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
|
|
|
@ -102,6 +102,30 @@
|
||||||
<ClCompile Include="rabbitizer\cplusplus\src\analysis\RegistersTracker.cpp">
|
<ClCompile Include="rabbitizer\cplusplus\src\analysis\RegistersTracker.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstrIdType.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerRegisterDescriptor.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionR3000GTE\RabbitizerInstructionR3000GTE.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionR3000GTE\RabbitizerInstructionR3000GTE_OperandType.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionR3000GTE\RabbitizerInstructionR3000GTE_ProcessUniqueId.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="rabbitizer\src\instructions\RabbitizerInstruction\RabbitizerInstruction_Operand.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="rabbitizer\cplusplus\src\instructions\InstrIdType.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="rabbitizer\cplusplus\src\instructions\InstructionR3000GTE.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="rabbitizer\include\instructions\RabbitizerAccessType.h">
|
<ClInclude Include="rabbitizer\include\instructions\RabbitizerAccessType.h">
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit b9a39f6ec0a3ff6690ef2925e6275cf6578602cc
|
Subproject commit e0d8003047938e2ec3697eaf8d61a84d11d17b43
|
|
@ -211,12 +211,20 @@ RecompPort::Config::Config(const char* path) {
|
||||||
// Input section (required)
|
// Input section (required)
|
||||||
const toml::value& input_data = toml::find<toml::value>(config_data, "input");
|
const toml::value& input_data = toml::find<toml::value>(config_data, "input");
|
||||||
|
|
||||||
entrypoint = toml::find<int32_t>(input_data, "entrypoint");
|
if (input_data.contains("entrypoint")) {
|
||||||
|
entrypoint = toml::find<int32_t>(input_data, "entrypoint");
|
||||||
|
has_entrypoint = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
has_entrypoint = false;
|
||||||
|
}
|
||||||
elf_path = concat_if_not_empty(basedir, toml::find<std::string>(input_data, "elf_path"));
|
elf_path = concat_if_not_empty(basedir, toml::find<std::string>(input_data, "elf_path"));
|
||||||
output_func_path = concat_if_not_empty(basedir, toml::find<std::string>(input_data, "output_func_path"));
|
output_func_path = concat_if_not_empty(basedir, toml::find<std::string>(input_data, "output_func_path"));
|
||||||
relocatable_sections_path = concat_if_not_empty(basedir, toml::find_or<std::string>(input_data, "relocatable_sections_path", ""));
|
relocatable_sections_path = concat_if_not_empty(basedir, toml::find_or<std::string>(input_data, "relocatable_sections_path", ""));
|
||||||
uses_mips3_float_mode = toml::find_or<bool>(input_data, "uses_mips3_float_mode", false);
|
uses_mips3_float_mode = toml::find_or<bool>(input_data, "uses_mips3_float_mode", false);
|
||||||
bss_section_suffix = toml::find_or<std::string>(input_data, "bss_section_suffix", ".bss");
|
bss_section_suffix = toml::find_or<std::string>(input_data, "bss_section_suffix", ".bss");
|
||||||
|
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);
|
||||||
|
|
||||||
// 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{});
|
||||||
|
|
151
src/main.cpp
151
src/main.cpp
|
@ -573,7 +573,7 @@ std::unordered_set<std::string> renamed_funcs{
|
||||||
"__assert",
|
"__assert",
|
||||||
};
|
};
|
||||||
|
|
||||||
bool read_symbols(RecompPort::Context& context, const ELFIO::elfio& elf_file, ELFIO::section* symtab_section, uint32_t entrypoint) {
|
bool read_symbols(RecompPort::Context& context, const ELFIO::elfio& elf_file, ELFIO::section* symtab_section, uint32_t entrypoint, bool has_entrypoint, bool use_absolute_symbols) {
|
||||||
bool found_entrypoint_func = false;
|
bool found_entrypoint_func = false;
|
||||||
ELFIO::symbol_section_accessor symbols{ elf_file, symtab_section };
|
ELFIO::symbol_section_accessor symbols{ elf_file, symtab_section };
|
||||||
fmt::print("Num symbols: {}\n", symbols.get_symbols_num());
|
fmt::print("Num symbols: {}\n", symbols.get_symbols_num());
|
||||||
|
@ -593,12 +593,28 @@ bool read_symbols(RecompPort::Context& context, const ELFIO::elfio& elf_file, EL
|
||||||
symbols.get_symbol(sym_index, name, value, size, bind, type,
|
symbols.get_symbol(sym_index, name, value, size, bind, type,
|
||||||
section_index, other);
|
section_index, other);
|
||||||
|
|
||||||
|
if (section_index == ELFIO::SHN_ABS && use_absolute_symbols) {
|
||||||
|
uint32_t vram = static_cast<uint32_t>(value);
|
||||||
|
context.functions_by_vram[vram].push_back(context.functions.size());
|
||||||
|
|
||||||
|
context.functions.emplace_back(
|
||||||
|
vram,
|
||||||
|
0,
|
||||||
|
std::vector<uint32_t>{},
|
||||||
|
std::move(name),
|
||||||
|
0,
|
||||||
|
true,
|
||||||
|
reimplemented
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (section_index >= context.sections.size()) {
|
if (section_index >= context.sections.size()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this symbol is the entrypoint
|
// Check if this symbol is the entrypoint
|
||||||
if (value == entrypoint && type == ELFIO::STT_FUNC) {
|
if (has_entrypoint && value == entrypoint && type == ELFIO::STT_FUNC) {
|
||||||
if (found_entrypoint_func) {
|
if (found_entrypoint_func) {
|
||||||
fmt::print(stderr, "Ambiguous entrypoint: {}\n", name);
|
fmt::print(stderr, "Ambiguous entrypoint: {}\n", name);
|
||||||
return false;
|
return false;
|
||||||
|
@ -996,6 +1012,59 @@ bool read_list_file(const std::filesystem::path& filename, std::vector<std::stri
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool compare_files(const std::filesystem::path& file1_path, const std::filesystem::path& file2_path) {
|
||||||
|
static std::vector<char> file1_buf(65536);
|
||||||
|
static std::vector<char> file2_buf(65536);
|
||||||
|
|
||||||
|
std::ifstream file1(file1_path, std::ifstream::ate | std::ifstream::binary); //open file at the end
|
||||||
|
std::ifstream file2(file2_path, std::ifstream::ate | std::ifstream::binary); //open file at the end
|
||||||
|
const std::ifstream::pos_type fileSize = file1.tellg();
|
||||||
|
|
||||||
|
file1.rdbuf()->pubsetbuf(file1_buf.data(), file1_buf.size());
|
||||||
|
file2.rdbuf()->pubsetbuf(file2_buf.data(), file2_buf.size());
|
||||||
|
|
||||||
|
if (fileSize != file2.tellg()) {
|
||||||
|
return false; //different file size
|
||||||
|
}
|
||||||
|
|
||||||
|
file1.seekg(0); //rewind
|
||||||
|
file2.seekg(0); //rewind
|
||||||
|
|
||||||
|
std::istreambuf_iterator<char> begin1(file1);
|
||||||
|
std::istreambuf_iterator<char> begin2(file2);
|
||||||
|
|
||||||
|
return std::equal(begin1, std::istreambuf_iterator<char>(), begin2); //Second argument is end-of-range iterator
|
||||||
|
}
|
||||||
|
|
||||||
|
bool recompile_single_function(const RecompPort::Context& context, const RecompPort::Config& config, const RecompPort::Function& func, const std::filesystem::path& output_path, std::span<std::vector<uint32_t>> static_funcs_out) {
|
||||||
|
// Open the temporary output file
|
||||||
|
std::filesystem::path temp_path = output_path;
|
||||||
|
temp_path.replace_extension(".tmp");
|
||||||
|
std::ofstream output_file{ temp_path };
|
||||||
|
if (!output_file.good()) {
|
||||||
|
fmt::print(stderr, "Failed to open file for writing: {}\n", temp_path.string() );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!RecompPort::recompile_function(context, config, func, output_file, static_funcs_out, true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
output_file.close();
|
||||||
|
|
||||||
|
// If a file of the target name exists and it's identical to the output file, delete the output file.
|
||||||
|
// This prevents updating the existing file so that it doesn't need to be rebuilt.
|
||||||
|
if (std::filesystem::exists(output_path) && compare_files(output_path, temp_path)) {
|
||||||
|
std::filesystem::remove(temp_path);
|
||||||
|
}
|
||||||
|
// Otherwise, rename the new file to the target path.
|
||||||
|
else {
|
||||||
|
std::filesystem::rename(temp_path, output_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
auto exit_failure = [] (const std::string& error_str) {
|
auto exit_failure = [] (const std::string& error_str) {
|
||||||
fmt::vprint(stderr, error_str, fmt::make_format_args());
|
fmt::vprint(stderr, error_str, fmt::make_format_args());
|
||||||
|
@ -1069,9 +1138,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);
|
bool found_entrypoint_func = read_symbols(context, elf_file, symtab_section, config.entrypoint, config.has_entrypoint, config.use_absolute_symbols);
|
||||||
|
|
||||||
if (!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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1079,17 +1148,8 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
std::filesystem::create_directories(config.output_func_path);
|
std::filesystem::create_directories(config.output_func_path);
|
||||||
|
|
||||||
std::ofstream lookup_file{ config.output_func_path / "lookup.cpp" };
|
|
||||||
std::ofstream func_header_file{ config.output_func_path / "funcs.h" };
|
std::ofstream func_header_file{ config.output_func_path / "funcs.h" };
|
||||||
|
|
||||||
fmt::print(lookup_file,
|
|
||||||
//"#include <utility>\n"
|
|
||||||
"#include \"recomp.h\"\n"
|
|
||||||
//"#include \"funcs.h\"\n"
|
|
||||||
"\n"
|
|
||||||
//"std::pair<uint32_t, recomp_func_t*> funcs[] {{\n"
|
|
||||||
);
|
|
||||||
|
|
||||||
fmt::print(func_header_file,
|
fmt::print(func_header_file,
|
||||||
"#include \"recomp.h\"\n"
|
"#include \"recomp.h\"\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
@ -1152,6 +1212,13 @@ int main(int argc, char** argv) {
|
||||||
func.words[instruction_index] = byteswap(patch.value);
|
func.words[instruction_index] = byteswap(patch.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ofstream single_output_file;
|
||||||
|
bool header_written = false;
|
||||||
|
|
||||||
|
if (config.single_file_output) {
|
||||||
|
single_output_file.open(config.output_func_path / config.elf_path.stem().replace_extension(".c"));
|
||||||
|
}
|
||||||
|
|
||||||
//#pragma omp parallel for
|
//#pragma omp parallel for
|
||||||
for (size_t i = 0; i < context.functions.size(); i++) {
|
for (size_t i = 0; i < context.functions.size(); i++) {
|
||||||
const auto& func = context.functions[i];
|
const auto& func = context.functions[i];
|
||||||
|
@ -1159,18 +1226,21 @@ int main(int argc, char** argv) {
|
||||||
if (!func.ignored && func.words.size() != 0) {
|
if (!func.ignored && func.words.size() != 0) {
|
||||||
fmt::print(func_header_file,
|
fmt::print(func_header_file,
|
||||||
"void {}(uint8_t* rdram, recomp_context* ctx);\n", func.name);
|
"void {}(uint8_t* rdram, recomp_context* ctx);\n", func.name);
|
||||||
//fmt::print(lookup_file,
|
bool result;
|
||||||
// " {{ 0x{:08X}u, {} }},\n", func.vram, func.name);
|
if (config.single_file_output) {
|
||||||
if (RecompPort::recompile_function(context, config, func, config.output_func_path / (func.name + ".c"), static_funcs_by_section) == false) {
|
result = RecompPort::recompile_function(context, config, func, single_output_file, static_funcs_by_section, !header_written);
|
||||||
//lookup_file.clear();
|
header_written = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = recompile_single_function(context, config, func, config.output_func_path / (func.name + ".c"), static_funcs_by_section);
|
||||||
|
}
|
||||||
|
if (result == false) {
|
||||||
fmt::print(stderr, "Error recompiling {}\n", func.name);
|
fmt::print(stderr, "Error recompiling {}\n", func.name);
|
||||||
std::exit(EXIT_FAILURE);
|
std::exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
} else if (func.reimplemented) {
|
} else if (func.reimplemented) {
|
||||||
fmt::print(func_header_file,
|
fmt::print(func_header_file,
|
||||||
"void {}(uint8_t* rdram, recomp_context* ctx);\n", func.name);
|
"void {}(uint8_t* rdram, recomp_context* ctx);\n", func.name);
|
||||||
//fmt::print(lookup_file,
|
|
||||||
// " {{ 0x{:08X}u, {} }},\n", func.vram, func.name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1228,27 +1298,40 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
fmt::print(func_header_file,
|
fmt::print(func_header_file,
|
||||||
"void {}(uint8_t* rdram, recomp_context* ctx);\n", func.name);
|
"void {}(uint8_t* rdram, recomp_context* ctx);\n", func.name);
|
||||||
//fmt::print(lookup_file,
|
|
||||||
// " {{ 0x{:08X}u, {} }},\n", func.vram, func.name);
|
bool result;
|
||||||
if (RecompPort::recompile_function(context, config, func, config.output_func_path / (func.name + ".c"), static_funcs_by_section) == false) {
|
if (config.single_file_output) {
|
||||||
//lookup_file.clear();
|
result = RecompPort::recompile_function(context, config, func, single_output_file, static_funcs_by_section, !header_written);
|
||||||
|
header_written = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = recompile_single_function(context, config, func, config.output_func_path / (func.name + ".c"), static_funcs_by_section);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == false) {
|
||||||
fmt::print(stderr, "Error recompiling {}\n", func.name);
|
fmt::print(stderr, "Error recompiling {}\n", func.name);
|
||||||
std::exit(EXIT_FAILURE);
|
std::exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt::print(lookup_file,
|
if (config.has_entrypoint) {
|
||||||
//"}};\n"
|
std::ofstream lookup_file{ config.output_func_path / "lookup.cpp" };
|
||||||
//"extern const size_t num_funcs = sizeof(funcs) / sizeof(funcs[0]);\n"
|
|
||||||
//"\n"
|
fmt::print(lookup_file,
|
||||||
"gpr get_entrypoint_address() {{ return (gpr)(int32_t)0x{:08X}u; }}\n"
|
"#include \"recomp.h\"\n"
|
||||||
"\n"
|
"\n"
|
||||||
"const char* get_rom_name() {{ return \"{}\"; }}\n"
|
);
|
||||||
"\n",
|
|
||||||
static_cast<uint32_t>(config.entrypoint),
|
fmt::print(lookup_file,
|
||||||
config.elf_path.filename().replace_extension(".z64").string()
|
"gpr get_entrypoint_address() {{ return (gpr)(int32_t)0x{:08X}u; }}\n"
|
||||||
);
|
"\n"
|
||||||
|
"const char* get_rom_name() {{ return \"{}\"; }}\n"
|
||||||
|
"\n",
|
||||||
|
static_cast<uint32_t>(config.entrypoint),
|
||||||
|
config.elf_path.filename().replace_extension(".z64").string()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fmt::print(func_header_file,
|
fmt::print(func_header_file,
|
||||||
"\n"
|
"\n"
|
||||||
|
|
|
@ -191,6 +191,7 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::C
|
||||||
}
|
}
|
||||||
needs_link_branch = true;
|
needs_link_branch = true;
|
||||||
print_unconditional_branch("{}(rdram, ctx)", jal_target_name);
|
print_unconditional_branch("{}(rdram, ctx)", jal_target_name);
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (indent) {
|
if (indent) {
|
||||||
|
@ -674,6 +675,7 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::C
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Cop1 compares
|
// Cop1 compares
|
||||||
|
// TODO allow NaN in ordered and unordered float comparisons, default to a compare result of 1 for ordered and 0 for unordered if a NaN is present
|
||||||
case InstrId::cpu_c_lt_s:
|
case InstrId::cpu_c_lt_s:
|
||||||
print_line("CHECK_FR(ctx, {})", fs);
|
print_line("CHECK_FR(ctx, {})", fs);
|
||||||
print_line("CHECK_FR(ctx, {})", ft);
|
print_line("CHECK_FR(ctx, {})", ft);
|
||||||
|
@ -701,6 +703,12 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::C
|
||||||
//print_line("*(volatile int*)0 = 0;");
|
//print_line("*(volatile int*)0 = 0;");
|
||||||
print_line("c1cs = ctx->f{}.fl <= ctx->f{}.fl", fs, ft);
|
print_line("c1cs = ctx->f{}.fl <= ctx->f{}.fl", fs, ft);
|
||||||
break;
|
break;
|
||||||
|
case InstrId::cpu_c_ule_s:
|
||||||
|
print_line("CHECK_FR(ctx, {})", fs);
|
||||||
|
print_line("CHECK_FR(ctx, {})", ft);
|
||||||
|
//print_line("*(volatile int*)0 = 0;");
|
||||||
|
print_line("c1cs = ctx->f{}.fl <= ctx->f{}.fl", fs, ft);
|
||||||
|
break;
|
||||||
case InstrId::cpu_c_le_d:
|
case InstrId::cpu_c_le_d:
|
||||||
print_line("CHECK_FR(ctx, {})", fs);
|
print_line("CHECK_FR(ctx, {})", fs);
|
||||||
print_line("CHECK_FR(ctx, {})", ft);
|
print_line("CHECK_FR(ctx, {})", ft);
|
||||||
|
@ -947,47 +955,19 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::C
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool compare_files(const std::filesystem::path& file1_path, const std::filesystem::path& file2_path) {
|
bool RecompPort::recompile_function(const RecompPort::Context& context, const RecompPort::Config& config, const RecompPort::Function& func, std::ofstream& output_file, std::span<std::vector<uint32_t>> static_funcs_out, bool write_header) {
|
||||||
static std::vector<char> file1_buf(65536);
|
|
||||||
static std::vector<char> file2_buf(65536);
|
|
||||||
|
|
||||||
std::ifstream file1(file1_path, std::ifstream::ate | std::ifstream::binary); //open file at the end
|
|
||||||
std::ifstream file2(file2_path, std::ifstream::ate | std::ifstream::binary); //open file at the end
|
|
||||||
const std::ifstream::pos_type fileSize = file1.tellg();
|
|
||||||
|
|
||||||
file1.rdbuf()->pubsetbuf(file1_buf.data(), file1_buf.size());
|
|
||||||
file2.rdbuf()->pubsetbuf(file2_buf.data(), file2_buf.size());
|
|
||||||
|
|
||||||
if (fileSize != file2.tellg()) {
|
|
||||||
return false; //different file size
|
|
||||||
}
|
|
||||||
|
|
||||||
file1.seekg(0); //rewind
|
|
||||||
file2.seekg(0); //rewind
|
|
||||||
|
|
||||||
std::istreambuf_iterator<char> begin1(file1);
|
|
||||||
std::istreambuf_iterator<char> begin2(file2);
|
|
||||||
|
|
||||||
return std::equal(begin1, std::istreambuf_iterator<char>(), begin2); //Second argument is end-of-range iterator
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RecompPort::recompile_function(const RecompPort::Context& context, const RecompPort::Config& config, const RecompPort::Function& func, const std::filesystem::path& output_path, std::span<std::vector<uint32_t>> static_funcs_out) {
|
|
||||||
//fmt::print("Recompiling {}\n", func.name);
|
//fmt::print("Recompiling {}\n", func.name);
|
||||||
std::vector<rabbitizer::InstructionCpu> instructions;
|
std::vector<rabbitizer::InstructionCpu> instructions;
|
||||||
|
|
||||||
// Open the output file and write the file header
|
if (write_header) {
|
||||||
std::filesystem::path temp_path = output_path;
|
// Write the file header
|
||||||
temp_path.replace_extension(".tmp");
|
fmt::print(output_file,
|
||||||
std::ofstream output_file{ temp_path };
|
"#include \"recomp.h\"\n"
|
||||||
if (!output_file.good()) {
|
"#include \"disable_warnings.h\"\n"
|
||||||
fmt::print(stderr, "Failed to open file for writing: {}\n", temp_path.string() );
|
"\n");
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt::print(output_file,
|
fmt::print(output_file,
|
||||||
"#include \"recomp.h\"\n"
|
|
||||||
"#include \"disable_warnings.h\"\n"
|
|
||||||
"\n"
|
|
||||||
"void {}(uint8_t* rdram, recomp_context* ctx) {{\n"
|
"void {}(uint8_t* rdram, recomp_context* ctx) {{\n"
|
||||||
// these variables shouldn't need to be preserved across function boundaries, so make them local for more efficient output
|
// these variables shouldn't need to be preserved across function boundaries, so make them local for more efficient output
|
||||||
" uint64_t hi = 0, lo = 0, result = 0;\n"
|
" uint64_t hi = 0, lo = 0, result = 0;\n"
|
||||||
|
@ -1070,7 +1050,7 @@ bool RecompPort::recompile_function(const RecompPort::Context& context, const Re
|
||||||
|
|
||||||
// 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 recompilation, clearing {}\n", output_path.string());
|
fmt::print(stderr, "Error in recompiling {}, clearing output file\n", func.name);
|
||||||
output_file.clear();
|
output_file.clear();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1093,17 +1073,5 @@ bool RecompPort::recompile_function(const RecompPort::Context& context, const Re
|
||||||
// Terminate the function
|
// Terminate the function
|
||||||
fmt::print(output_file, ";}}\n");
|
fmt::print(output_file, ";}}\n");
|
||||||
|
|
||||||
output_file.close();
|
|
||||||
|
|
||||||
// If a file of the target name exists and it's identical to the output file, delete the output file.
|
|
||||||
// This prevents updating the existing file so that it doesn't need to be rebuilt.
|
|
||||||
if (std::filesystem::exists(output_path) && compare_files(output_path, temp_path)) {
|
|
||||||
std::filesystem::remove(temp_path);
|
|
||||||
}
|
|
||||||
// Otherwise, rename the new file to the target path.
|
|
||||||
else {
|
|
||||||
std::filesystem::rename(temp_path, output_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue