#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[]) { bool skipSyscallCheck = false; bool toIntel = false; std::string inputPath; std::string outputElfPath; std::optional registryPath; std::string runPath = "$ORIGIN/libs"; for (int i = 1; i < argc; ++i) { const std::string arg = argv[i]; if (arg == "--skip-syscall-check") { skipSyscallCheck = true; } else if (arg == "--to-intel") { toIntel = true; } else if (arg == "--rpath") { if (i + 1 >= argc) { std::cerr << "FAIL: --rpath requires a value\n"; return 1; } runPath = argv[++i]; } else if (inputPath.empty()) { inputPath = arg; } else if (outputElfPath.empty()) { outputElfPath = arg; } else if (!registryPath.has_value()) { registryPath = arg; } } if (inputPath.empty() || outputElfPath.empty()) { std::cerr << "Usage: relinker [--skip-syscall-check] [--to-intel] [--rpath ] [output_registry.json]\n"; return 1; } const std::filesystem::path outputElfFsPath(outputElfPath); const std::filesystem::path outputDir = outputElfFsPath.parent_path() / (outputElfFsPath.stem().string() + "_out"); std::filesystem::create_directories(outputDir); outputElfPath = (outputDir / outputElfFsPath.filename()).string(); if (registryPath.has_value()) registryPath = (outputDir / std::filesystem::path(*registryPath).filename()).string(); try { Io::FileReader fileReader; Io::FileWriter fileWriter; auto sourceBytes = fileReader.Read(inputPath); if (toIntel) { const Relinker::ElfReader elfReader(sourceBytes); const auto converter = Codegen::MakeAmd64OnlyConverter(); auto result = converter->Convert(std::move(sourceBytes), elfReader.ReadCodeSegments()); fileWriter.Write(outputElfPath, std::move(result.Bytes)); std::cout << "OK: " << result.ReplacedCount << " instructions replaced\n"; return 0; } auto elfReader = std::make_shared(sourceBytes); auto syscallScanner = skipSyscallCheck ? Relinker::MakeNullSyscallScanner() : Relinker::MakeSyscallScanner(); const auto pipeline = std::make_shared( elfReader, std::move(syscallScanner), Relinker::MakeCallSiteResolver(), std::make_shared(), std::make_shared() ); auto result = pipeline->Relink(sourceBytes); if (registryPath.has_value()) { auto callRegistryWriter = std::make_shared(); fileWriter.Write(*registryPath, callRegistryWriter->WriteCallRegistry(result.RegistryEntries)); } auto byteWriter = std::make_shared(); Elfpatcher::Linux::LinuxElfPatcher elfPatcher( std::make_shared(), std::make_shared( std::make_shared(), byteWriter ), std::make_shared(byteWriter), byteWriter ); auto patchedElf = elfPatcher.Patch(sourceBytes, result.OriginalHeaders, result.DynamicSection, result.OriginalPltGotVaddr, runPath); fileWriter.Write(outputElfPath, patchedElf); } 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; }