feat(cli): add --windows-diagnostics arg - off by default
This commit is contained in:
parent
04e1bc0a2d
commit
7e5f41aba3
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 <path>] [--lazy-binding] [--autorun] <input.elf> <output.elf>\n"
|
||||
"Usage: relinker [--windows] [--windows-diagnostics] [--skip-syscall-check] [--to-intel] [unused-filter=0|1|2] [--registry] [--rpath <path>] [--lazy-binding] [--autorun] <input.elf> <output.elf>\n"
|
||||
"Example: relinker input.elf output.elf"
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ public:
|
|||
const Domain::SysVDynamicSection& dynamicSection,
|
||||
std::uint64_t originalPltGotVaddr,
|
||||
const std::string& runPath,
|
||||
bool lazyBinding
|
||||
bool lazyBinding,
|
||||
bool dependencyDiagnostics
|
||||
) = 0;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ namespace Elfpatcher::Windows {
|
|||
|
||||
class WindowsPePatcher : public IElfPatcher {
|
||||
public:
|
||||
std::vector<std::uint8_t> Patch(const std::vector<std::uint8_t>& sourceElf, const std::vector<Domain::ProgramHeader>& originalHeaders, const Domain::SysVDynamicSection& dynamicSection, std::uint64_t originalPltGotVaddr, const std::string& runPath, bool lazyBinding) override;
|
||||
std::vector<std::uint8_t> Patch(const std::vector<std::uint8_t>& sourceElf, const std::vector<Domain::ProgramHeader>& originalHeaders, const Domain::SysVDynamicSection& dynamicSection, std::uint64_t originalPltGotVaddr, const std::string& runPath, bool lazyBinding, bool dependencyDiagnostics) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<std::string>& libraries, const std::vector<PeImport>& imports, const std::string& runPath, bool lazyBinding) const;
|
||||
WindowsEntryStub Build(std::uint32_t dataRva, std::uint32_t entryRva, const WindowsImports& nativeImports, const std::vector<std::string>& libraries, const std::vector<PeImport>& imports, const std::string& runPath, bool lazyBinding, bool dependencyDiagnostics) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,8 +30,12 @@ std::vector<std::uint8_t> 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<std::uint8_t> buf = sourceElf;
|
||||
|
||||
buf[kEhdrOsAbiOffset] = 0;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <elfpatcher/windows/WindowsDependencyStubBuilder.hpp>
|
||||
#include <io/BufferUtils.hpp>
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
|
||||
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<std::string>& libraries, const std::vector<PeImport>& 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<std::string>& libraries, const std::vector<PeImport>& 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<WindowsDependencyStubBuilder> dependencyBuilder;
|
||||
if (dependencyDiagnostics)
|
||||
dependencyBuilder.emplace(result.Data);
|
||||
std::vector<std::size_t> 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ void writeGotStub(std::vector<PeSection>& sections, const std::uint32_t targetRv
|
|||
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> WindowsPePatcher::Patch(const std::vector<std::uint8_t>& sourceElf, const std::vector<Domain::ProgramHeader>& originalHeaders, const Domain::SysVDynamicSection& dynamicSection, const std::uint64_t originalPltGotVaddr, const std::string& runPath, const bool lazyBinding) {
|
||||
std::vector<std::uint8_t> WindowsPePatcher::Patch(const std::vector<std::uint8_t>& sourceElf, const std::vector<Domain::ProgramHeader>& 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<std::uint8_t> WindowsPePatcher::Patch(const std::vector<std::uint8_t
|
|||
directories[12] = nativeImports.AddressTable;
|
||||
nextRva = AlignRva(nextRva + nativeImports.Section.Data.size());
|
||||
const auto libraries = importBuilder.ReadLibraries(dynamicSection);
|
||||
auto entry = WindowsEntryStubBuilder().Build(nextRva, image.GetEntryRva(), nativeImports, libraries, relocations.Imports, runPath, lazyBinding);
|
||||
auto entry = WindowsEntryStubBuilder().Build(nextRva, image.GetEntryRva(), nativeImports, libraries, relocations.Imports, runPath, lazyBinding, dependencyDiagnostics);
|
||||
directories[3] = entry.ExceptionDirectory;
|
||||
const auto entryRva = entry.Code.Rva;
|
||||
sections.push_back(std::move(nativeImports.Section));
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ int main(const int argc, char* argv[]) {
|
|||
);
|
||||
}
|
||||
|
||||
fileWriter.Write(absPath, patcher->Patch(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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue