diff --git a/core/relinker/cli/include/Cli.hpp b/core/relinker/cli/include/Cli.hpp index 2d66c3390..faad9076b 100644 --- a/core/relinker/cli/include/Cli.hpp +++ b/core/relinker/cli/include/Cli.hpp @@ -11,6 +11,7 @@ struct Args { bool toWindows = false; bool lazyBinding = false; bool autorun = false; + bool windowsDiagnostics = false; std::uint32_t unusedFilterLevel = 2; std::string inputPath; std::string outputPath; diff --git a/core/relinker/cli/src/CliArgs.cpp b/core/relinker/cli/src/CliArgs.cpp index 9817d2257..12b1631f0 100644 --- a/core/relinker/cli/src/CliArgs.cpp +++ b/core/relinker/cli/src/CliArgs.cpp @@ -33,6 +33,8 @@ Args ParseArgs(int argc, char* argv[]) { args.lazyBinding = true; } else if (arg == "--autorun") { args.autorun = true; + } else if (arg == "--windows-diagnostics") { + args.windowsDiagnostics = true; } else if (arg.rfind("--", 0) == 0 || arg == "unused-filter") { throw std::runtime_error("unknown option: " + arg); } else if (args.inputPath.empty()) { @@ -44,9 +46,12 @@ Args ParseArgs(int argc, char* argv[]) { } } + if (args.windowsDiagnostics && !args.toWindows) + throw std::runtime_error("--windows-diagnostics requires --windows"); + if (args.inputPath.empty() || args.outputPath.empty()) throw std::runtime_error( - "Usage: relinker [--windows] [--skip-syscall-check] [--to-intel] [unused-filter=0|1|2] [--registry] [--rpath ] [--lazy-binding] [--autorun] \n" + "Usage: relinker [--windows] [--windows-diagnostics] [--skip-syscall-check] [--to-intel] [unused-filter=0|1|2] [--registry] [--rpath ] [--lazy-binding] [--autorun] \n" "Example: relinker input.elf output.elf" ); diff --git a/core/relinker/elfpatcher/include/elfpatcher/general/IElfPatcher.hpp b/core/relinker/elfpatcher/include/elfpatcher/general/IElfPatcher.hpp index 9de920f4e..41b667ba6 100644 --- a/core/relinker/elfpatcher/include/elfpatcher/general/IElfPatcher.hpp +++ b/core/relinker/elfpatcher/include/elfpatcher/general/IElfPatcher.hpp @@ -18,7 +18,8 @@ public: const Domain::SysVDynamicSection& dynamicSection, std::uint64_t originalPltGotVaddr, const std::string& runPath, - bool lazyBinding + bool lazyBinding, + bool dependencyDiagnostics ) = 0; }; diff --git a/core/relinker/elfpatcher/include/elfpatcher/linux/LinuxElfPatcher.hpp b/core/relinker/elfpatcher/include/elfpatcher/linux/LinuxElfPatcher.hpp index b2a1197be..30a9cceef 100644 --- a/core/relinker/elfpatcher/include/elfpatcher/linux/LinuxElfPatcher.hpp +++ b/core/relinker/elfpatcher/include/elfpatcher/linux/LinuxElfPatcher.hpp @@ -26,7 +26,8 @@ public: const Domain::SysVDynamicSection& dynamicSection, std::uint64_t originalPltGotVaddr, const std::string& runPath, - bool lazyBinding + bool lazyBinding, + bool dependencyDiagnostics ) override; private: diff --git a/core/relinker/elfpatcher/include/elfpatcher/windows/WindowsElfPatcher.hpp b/core/relinker/elfpatcher/include/elfpatcher/windows/WindowsElfPatcher.hpp index bc438b2bc..2ee1017a0 100644 --- a/core/relinker/elfpatcher/include/elfpatcher/windows/WindowsElfPatcher.hpp +++ b/core/relinker/elfpatcher/include/elfpatcher/windows/WindowsElfPatcher.hpp @@ -7,7 +7,7 @@ namespace Elfpatcher::Windows { class WindowsPePatcher : public IElfPatcher { public: - std::vector Patch(const std::vector& sourceElf, const std::vector& originalHeaders, const Domain::SysVDynamicSection& dynamicSection, std::uint64_t originalPltGotVaddr, const std::string& runPath, bool lazyBinding) override; + std::vector Patch(const std::vector& sourceElf, const std::vector& originalHeaders, const Domain::SysVDynamicSection& dynamicSection, std::uint64_t originalPltGotVaddr, const std::string& runPath, bool lazyBinding, bool dependencyDiagnostics) override; }; } diff --git a/core/relinker/elfpatcher/include/elfpatcher/windows/WindowsEntryStubBuilder.hpp b/core/relinker/elfpatcher/include/elfpatcher/windows/WindowsEntryStubBuilder.hpp index a79c67364..1ab27beca 100644 --- a/core/relinker/elfpatcher/include/elfpatcher/windows/WindowsEntryStubBuilder.hpp +++ b/core/relinker/elfpatcher/include/elfpatcher/windows/WindowsEntryStubBuilder.hpp @@ -19,7 +19,7 @@ struct WindowsEntryStub { class WindowsEntryStubBuilder { public: - WindowsEntryStub Build(std::uint32_t dataRva, std::uint32_t entryRva, const WindowsImports& nativeImports, const std::vector& libraries, const std::vector& imports, const std::string& runPath, bool lazyBinding) const; + WindowsEntryStub Build(std::uint32_t dataRva, std::uint32_t entryRva, const WindowsImports& nativeImports, const std::vector& libraries, const std::vector& imports, const std::string& runPath, bool lazyBinding, bool dependencyDiagnostics) const; }; } diff --git a/core/relinker/elfpatcher/src/linux/LinuxElfPatcher.cpp b/core/relinker/elfpatcher/src/linux/LinuxElfPatcher.cpp index af085f415..0172eef32 100644 --- a/core/relinker/elfpatcher/src/linux/LinuxElfPatcher.cpp +++ b/core/relinker/elfpatcher/src/linux/LinuxElfPatcher.cpp @@ -30,8 +30,12 @@ std::vector LinuxElfPatcher::Patch( const Domain::SysVDynamicSection& dynSection, const std::uint64_t originalPltGotVaddr, const std::string& runPath, - const bool lazyBinding) + const bool lazyBinding, + const bool dependencyDiagnostics) { + if (dependencyDiagnostics) + throw Domain::RelinkerException("Linux target does not support --windows-diagnostics"); + std::vector buf = sourceElf; buf[kEhdrOsAbiOffset] = 0; diff --git a/core/relinker/elfpatcher/src/windows/WindowsEntryStubBuilder.cpp b/core/relinker/elfpatcher/src/windows/WindowsEntryStubBuilder.cpp index 198a622ec..747cd1f6f 100644 --- a/core/relinker/elfpatcher/src/windows/WindowsEntryStubBuilder.cpp +++ b/core/relinker/elfpatcher/src/windows/WindowsEntryStubBuilder.cpp @@ -3,6 +3,7 @@ #include #include #include +#include namespace Elfpatcher::Windows { @@ -28,7 +29,7 @@ std::string normalizeRunPath(std::string path) { } -WindowsEntryStub WindowsEntryStubBuilder::Build(const std::uint32_t dataRva, const std::uint32_t entryRva, const WindowsImports& nativeImports, const std::vector& libraries, const std::vector& imports, const std::string& runPath, const bool lazyBinding) const { +WindowsEntryStub WindowsEntryStubBuilder::Build(const std::uint32_t dataRva, const std::uint32_t entryRva, const WindowsImports& nativeImports, const std::vector& libraries, const std::vector& imports, const std::string& runPath, const bool lazyBinding, const bool dependencyDiagnostics) const { if (!imports.empty() && libraries.empty()) throw Domain::RelinkerException("ELF imports have no DT_NEEDED libraries"); const auto path = normalizeRunPath(runPath); @@ -97,7 +98,9 @@ WindowsEntryStub WindowsEntryStubBuilder::Build(const std::uint32_t dataRva, con if (data.size() <= diagnosticsOffset) throw Domain::RelinkerException("Empty startup diagnostics"); - const WindowsDependencyStubBuilder dependencyBuilder(result.Data); + std::optional dependencyBuilder; + if (dependencyDiagnostics) + dependencyBuilder.emplace(result.Data); std::vector dependencyCalls; result.Code.Rva = AlignRva(dataRva + data.size()); WindowsStubEmitter code(result.Code.Rva); @@ -247,9 +250,11 @@ WindowsEntryStub WindowsEntryStubBuilder::Build(const std::uint32_t dataRva, con captureLastError(); writeString(loadFailed, true); writeLastError(); - code.Rip({0x48, 0x8d, 0x0d}, resolvedPaths[index]); - code.Rip({0x48, 0x8d, 0x15}, programPath); - dependencyCalls.push_back(code.Branch({0xe8})); + if (dependencyDiagnostics) { + code.Rip({0x48, 0x8d, 0x0d}, resolvedPaths[index]); + code.Rip({0x48, 0x8d, 0x15}, programPath); + dependencyCalls.push_back(code.Branch({0xe8})); + } raise(0xc0000135u); code.PatchBranch(loadSucceeded, code.GetRva()); code.Rip({0x48, 0x89, 0x05}, CheckedRva(handles + index * 8)); @@ -332,16 +337,20 @@ WindowsEntryStub WindowsEntryStubBuilder::Build(const std::uint32_t dataRva, con Io::WriteU32(data, functionTable - dataRva, result.Code.Rva); Io::WriteU32(data, functionTable - dataRva + 4, functionEnd); Io::WriteU32(data, functionTable - dataRva + 8, unwindRva); - const auto dependency = dependencyBuilder.Build(code, nativeImports); - for (const auto offset : dependencyCalls) - code.PatchBranch(offset, dependency.EntryRva); - if (dependency.Functions.size() >= 32) - throw Domain::RelinkerException("Too many dependency diagnostic routines"); - for (std::size_t index = 0; index < dependency.Functions.size(); ++index) { - for (std::size_t field = 0; field < 3; ++field) - Io::WriteU32(data, functionTable - dataRva + (index + 1) * 12 + field * 4, dependency.Functions[index][field]); + auto exceptionEntries = CheckedRva(1); + if (dependencyBuilder.has_value()) { + const auto dependency = dependencyBuilder->Build(code, nativeImports); + for (const auto offset : dependencyCalls) + code.PatchBranch(offset, dependency.EntryRva); + if (dependency.Functions.size() >= 32) + throw Domain::RelinkerException("Too many dependency diagnostic routines"); + for (std::size_t index = 0; index < dependency.Functions.size(); ++index) { + for (std::size_t field = 0; field < 3; ++field) + Io::WriteU32(data, functionTable - dataRva + (index + 1) * 12 + field * 4, dependency.Functions[index][field]); + } + exceptionEntries = CheckedRva(dependency.Functions.size() + 1); } - result.ExceptionDirectory = {functionTable, CheckedRva((dependency.Functions.size() + 1) * 12)}; + result.ExceptionDirectory = {functionTable, CheckedRva(exceptionEntries * 12)}; result.Code.Data = code.TakeBytes(); return result; } diff --git a/core/relinker/elfpatcher/src/windows/WindowsPePatcher.cpp b/core/relinker/elfpatcher/src/windows/WindowsPePatcher.cpp index 9b23cb6db..0ab50ad6a 100644 --- a/core/relinker/elfpatcher/src/windows/WindowsPePatcher.cpp +++ b/core/relinker/elfpatcher/src/windows/WindowsPePatcher.cpp @@ -23,7 +23,7 @@ void writeGotStub(std::vector& sections, const std::uint32_t targetRv } -std::vector WindowsPePatcher::Patch(const std::vector& sourceElf, const std::vector& originalHeaders, const Domain::SysVDynamicSection& dynamicSection, const std::uint64_t originalPltGotVaddr, const std::string& runPath, const bool lazyBinding) { +std::vector WindowsPePatcher::Patch(const std::vector& sourceElf, const std::vector& originalHeaders, const Domain::SysVDynamicSection& dynamicSection, const std::uint64_t originalPltGotVaddr, const std::string& runPath, const bool lazyBinding, const bool dependencyDiagnostics) { WindowsLoadImage image(sourceElf, originalHeaders); if (originalPltGotVaddr != 0) image.GetRva(originalPltGotVaddr, 8); @@ -52,7 +52,7 @@ std::vector WindowsPePatcher::Patch(const std::vectorPatch(sourceBytes, result.OriginalHeaders, result.DynamicSection, result.OriginalPltGotVaddr, args.runPath, args.lazyBinding)); + 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);