mirror of
				https://github.com/N64Recomp/N64Recomp.git
				synced 2025-10-30 08:02:11 +00:00 
			
		
		
		
	Added single-file mode and absolute symbol options (for patch recompilation)
This commit is contained in:
		
							parent
							
								
									d249363fe5
								
							
						
					
					
						commit
						be275c198a
					
				
					 7 changed files with 184 additions and 90 deletions
				
			
		|  | @ -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; | ||||||
|             } |             } | ||||||
|  | @ -1092,18 +1072,6 @@ 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…
	
	Add table
		
		Reference in a new issue
	
	 Mr-Wiseguy
						Mr-Wiseguy