#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int main(const int argc, char* argv[]) { Cli::Args args; try { args = Cli::ParseArgs(argc, argv); } catch (const std::exception& e) { std::cerr << "FAIL: " << e.what() << "\n"; return 1; } try { Io::FileReader fileReader; Io::FileWriter fileWriter; auto sourceBytes = fileReader.Read(args.inputPath); const std::string absPath = std::filesystem::absolute(args.outputPath).string(); if (args.toIntel) { std::cout << "Mode: Intel instruction conversion; system unchanged; unused-filter=" << args.unusedFilterLevel << " (not applied)\n"; const Relinker::ElfReader elfReader(sourceBytes); const auto converter = Codegen::MakeAmd64OnlyConverter(); auto result = converter->Convert(std::move(sourceBytes), elfReader.ReadCodeSegments()); fileWriter.Write(absPath, std::move(result.Bytes)); std::cout << "OK: " << result.ReplacedCount << " instructions replaced\n"; if (args.autorun) Cli::Autorun(absPath, args.toWindows); return 0; } auto elfReader = std::make_shared(sourceBytes); const auto pipeline = std::make_shared( elfReader, args.skipSyscallCheck ? Relinker::MakeNullSyscallScanner() : Relinker::MakeSyscallScanner(), Relinker::MakeCallSiteResolver(), std::make_shared(), std::make_shared(), args.unusedFilterLevel == 2 ? Relinker::MakeStrictUnusedNidFilter() : Relinker::MakeUnusedNidFilter(), args.unusedFilterLevel ); std::cout << "System: " << (args.toWindows ? "Windows" : "Linux") << "; unused-filter=" << args.unusedFilterLevel << "\n"; auto result = pipeline->Relink(sourceBytes); for (const auto& patch : result.Patches) { if (patch.Offset > sourceBytes.size() || patch.Bytes.size() > sourceBytes.size() - patch.Offset) throw Domain::RelinkerException("Relinker patch exceeds source image", patch.Offset); for (std::size_t index = 0; index < patch.Bytes.size(); ++index) sourceBytes[patch.Offset + index] = patch.Bytes[index]; } if (args.writeRegistry) { const std::filesystem::path outFsPath(absPath); const std::string registryPath = (outFsPath.parent_path() / (outFsPath.stem().string() + ".registry.json")).string(); fileWriter.Write(registryPath, std::make_shared()->WriteCallRegistry(result.RegistryEntries)); } auto byteWriter = std::make_shared(); std::shared_ptr patcher; if (args.toWindows) { patcher = std::make_shared(); } else { patcher = std::make_shared( std::make_shared(), std::make_shared( std::make_shared(), byteWriter ), std::make_shared(byteWriter), byteWriter ); } fileWriter.Write(absPath, patcher->Patch(sourceBytes, result.OriginalHeaders, result.DynamicSection, result.OriginalPltGotVaddr, args.runPath, args.lazyBinding, args.windowsDiagnostics)); std::cout << "External prx references: " << result.RegistryEntries.size() << "\nOutput file: " << absPath << '\n'; if (args.autorun) Cli::Autorun(absPath, args.toWindows); } catch (const Domain::RelinkerException& e) { std::cerr << "FAIL: " << e.what(); if (e.FailureOffset != 0) std::cerr << " (offset 0x" << std::hex << e.FailureOffset << ")"; std::cerr << "\n"; return 2; } catch (const std::exception& e) { std::cerr << "FAIL: " << e.what() << "\n"; return 2; } return 0; }