From 36c11dc9266b59f194f97fcba58612708ff48be1 Mon Sep 17 00:00:00 2001 From: Zenodeon Date: Tue, 13 Oct 2026 18:20:23 +0400 Subject: [PATCH 1/2] fix(relinker): identify failed inputs and invalid dynamic values --- core/relinker/CMakeLists.txt | 3 + .../src/macos/MacOsGuestModuleWriter.cpp | 3 +- .../src/windows/WindowsGuestModuleWriter.cpp | 3 +- .../relinker/src/guest/GuestImageReader.cpp | 8 +- .../relinker/src/pipeline/Conversion.cpp | 12 ++- .../src/pipeline/RelinkerPipeline.cpp | 45 +++++----- .../relinker/tests/ConversionTests.cpp | 29 +++++++ .../tests/test_conversion_diagnostics.py | 83 +++++++++++++++++++ 8 files changed, 156 insertions(+), 30 deletions(-) create mode 100644 core/relinker/relinker/tests/test_conversion_diagnostics.py diff --git a/core/relinker/CMakeLists.txt b/core/relinker/CMakeLists.txt index 2d92caeab..f15f71fd8 100644 --- a/core/relinker/CMakeLists.txt +++ b/core/relinker/CMakeLists.txt @@ -387,6 +387,9 @@ if(BUILD_TESTING) set_tests_properties(windows_fixed_base PROPERTIES TIMEOUT 20) add_test(NAME elf_offsets COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_elf_offsets.py $) + add_test(NAME conversion_diagnostics COMMAND ${Python3_EXECUTABLE} + ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_conversion_diagnostics.py $) + set_tests_properties(conversion_diagnostics PROPERTIES TIMEOUT 20) add_test(NAME dynamic_segment COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_dynamic_segment.py $) add_test(NAME rela_size COMMAND ${Python3_EXECUTABLE} diff --git a/core/relinker/elfpatcher/src/macos/MacOsGuestModuleWriter.cpp b/core/relinker/elfpatcher/src/macos/MacOsGuestModuleWriter.cpp index ff7e31f79..b8c3f7b06 100644 --- a/core/relinker/elfpatcher/src/macos/MacOsGuestModuleWriter.cpp +++ b/core/relinker/elfpatcher/src/macos/MacOsGuestModuleWriter.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -114,7 +115,7 @@ std::vector GuestModuleWriter::WriteMacOs(const Relinker::GuestIma try { return WriteMacOsImage(input); } catch (Domain::RelinkerException& error) { - error.InputPath = guest.SourcePath.string(); + if (error.InputPath.empty()) error.InputPath = Io::Utf8Path(guest.SourcePath); throw; } } diff --git a/core/relinker/elfpatcher/src/windows/WindowsGuestModuleWriter.cpp b/core/relinker/elfpatcher/src/windows/WindowsGuestModuleWriter.cpp index bcc3469dd..60a42e276 100644 --- a/core/relinker/elfpatcher/src/windows/WindowsGuestModuleWriter.cpp +++ b/core/relinker/elfpatcher/src/windows/WindowsGuestModuleWriter.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -84,7 +85,7 @@ std::vector GuestModuleWriter::WriteWindows(const Relinker::GuestI try { directories[9] = WindowsTlsBuilder().Build(guest.Bytes, guest.Headers, image, sections, relocations, nextRva, &tlsIndex); } catch (Domain::RelinkerException& error) { - error.InputPath = guest.SourcePath.string(); + if (error.InputPath.empty()) error.InputPath = Io::Utf8Path(guest.SourcePath); throw; } WindowsTrampolineBuilder().Build(guest.Trampolines, image, sections, nextRva); diff --git a/core/relinker/relinker/src/guest/GuestImageReader.cpp b/core/relinker/relinker/src/guest/GuestImageReader.cpp index c07cb7535..f1734eeba 100644 --- a/core/relinker/relinker/src/guest/GuestImageReader.cpp +++ b/core/relinker/relinker/src/guest/GuestImageReader.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -87,8 +88,8 @@ std::vector GuestImageReader::ReadModuleNames(const std::vector bytes, const bool windows) const { - const auto fail = [&](const std::string& message) { throw Domain::RelinkerException(path.string() + ": " + message); }; +GuestImage GuestImageReader::Read(const std::filesystem::path& path, std::vector bytes, const bool windows) const try { + const auto fail = [&](const std::string& message) { throw Domain::RelinkerException(Io::Utf8Path(path) + ": " + message); }; const auto range = [&](std::uint64_t offset, std::uint64_t size) { if (offset > bytes.size() || size > bytes.size() - offset) { std::ostringstream message; @@ -361,6 +362,9 @@ GuestImage GuestImageReader::Read(const std::filesystem::path& path, std::vector if (tags.contains(33) && tags.at(33) != 0 && image.Init == 0) fail("Guest PREINIT_ARRAY has no module initializer"); image.Bytes = std::move(bytes); return image; +} catch (Domain::RelinkerException& error) { + if (error.InputPath.empty()) error.InputPath = Io::Utf8Path(path); + throw; } } diff --git a/core/relinker/relinker/src/pipeline/Conversion.cpp b/core/relinker/relinker/src/pipeline/Conversion.cpp index 5d6b03824..024ec4d0f 100644 --- a/core/relinker/relinker/src/pipeline/Conversion.cpp +++ b/core/relinker/relinker/src/pipeline/Conversion.cpp @@ -34,7 +34,7 @@ namespace Relinker { Conversion::Conversion(Domain::IProgress& progress) : progress(progress) {} -ConversionOutput Conversion::Convert(ConversionInput input, const ConversionOptions& options) const { +ConversionOutput Conversion::Convert(ConversionInput input, const ConversionOptions& options) const try { Domain::InputProgress inputProgress(progress, Io::Utf8Path(input.InputPath)); static_assert(std::endian::native == std::endian::little); if (options.Target != TargetSystem::Linux && options.Target != TargetSystem::Windows && options.Target != TargetSystem::MacOs) throw Domain::RelinkerException("Unknown target system"); @@ -117,18 +117,16 @@ ConversionOutput Conversion::Convert(ConversionInput input, const ConversionOpti if (!windows) inputProgress.Report({Domain::ProgressStage::Image, Io::Utf8Path(input.InputPath), 0, 1}); std::vector executableBytes; - try { - executableBytes = patcher->Patch(sourceBytes, result.OriginalHeaders, result.DynamicSection, result.OriginalPltGotVaddr, options.RunPath, options.LazyBinding, options.WindowsDiagnostics, trampolines); - } catch (Domain::RelinkerException& error) { - error.InputPath = Io::Utf8Path(input.InputPath); - throw; - } + executableBytes = patcher->Patch(sourceBytes, result.OriginalHeaders, result.DynamicSection, result.OriginalPltGotVaddr, options.RunPath, options.LazyBinding, options.WindowsDiagnostics, trampolines); if (!windows) inputProgress.Report({Domain::ProgressStage::Image, Io::Utf8Path(input.InputPath), 1, 1}); std::string diagnostics; if (windows) diagnostics = std::static_pointer_cast(patcher)->GetDiagnostics(); inputProgress.Report({Domain::ProgressStage::Executable, Io::Utf8Path(input.InputPath), 1, 1}); return {std::move(executableBytes), std::move(guestArtifacts), std::move(result), std::move(diagnostics)}; +} catch (Domain::RelinkerException& error) { + if (error.InputPath.empty()) error.InputPath = Io::Utf8Path(input.InputPath); + throw; } } diff --git a/core/relinker/relinker/src/pipeline/RelinkerPipeline.cpp b/core/relinker/relinker/src/pipeline/RelinkerPipeline.cpp index 2baf1b713..238216056 100644 --- a/core/relinker/relinker/src/pipeline/RelinkerPipeline.cpp +++ b/core/relinker/relinker/src/pipeline/RelinkerPipeline.cpp @@ -99,11 +99,13 @@ RelinkResult RelinkerPipeline::Relink(const std::vector& sourceElf return false; }; - auto getTagValue = [&](const std::int64_t tag) -> std::uint64_t { + auto getTagValue = [&](const std::int64_t tag, const char* name) -> std::uint64_t { for (const auto& t : dynTags) if (t.Tag == tag) return t.Value; - throw RelinkerException("DT tag not found"); + std::ostringstream message; + message << "Required dynamic tag " << name << " (0x" << std::hex << tag << ") not found"; + throw RelinkerException(message.str()); }; auto requireExactlyOneOf = [&](const std::int64_t osTag, const std::int64_t sysvTag, const char* name) { @@ -111,24 +113,27 @@ RelinkResult RelinkerPipeline::Relink(const std::vector& sourceElf const bool hasSysv = hasTag(sysvTag); if (hasOs && hasSysv) throw RelinkerException(std::string("Both DT_OS_ and DT_ variants present for ") + name); - if (!hasOs && !hasSysv) - throw RelinkerException(std::string("Neither DT_OS_ nor DT_ variant present for ") + name); + if (!hasOs && !hasSysv) { + std::ostringstream message; + message << "Neither DT_OS_ nor DT_ variant present for " << name << " (tags 0x" << std::hex << osTag << " and 0x" << sysvTag << ")"; + throw RelinkerException(message.str()); + } return hasOs; }; auto readAsOffset = [&](const std::int64_t osTag, const std::int64_t sysvTag, const char* name) -> FileByteOffset { if (requireExactlyOneOf(osTag, sysvTag, name)) { - const std::uint64_t value = getTagValue(osTag); + const std::uint64_t value = getTagValue(osTag, name); if (value > std::numeric_limits::max() - sceTableBase) throw RelinkerException(std::string("Adding PT_SCE_DYNLIBDATA base to ") + name + " overflows", value); return sceTableBase + value; } - return elfReader->TranslateVirtualAddress(getTagValue(sysvTag)); + return elfReader->TranslateVirtualAddress(getTagValue(sysvTag, name)); }; auto readAsSize = [&](const std::int64_t osTag, const std::int64_t sysvTag, const char* name) -> ByteCount { requireExactlyOneOf(osTag, sysvTag, name); - return hasTag(osTag) ? getTagValue(osTag) : getTagValue(sysvTag); + return hasTag(osTag) ? getTagValue(osTag, name) : getTagValue(sysvTag, name); }; const bool hasPltRelocations = hasTag(DT_OS_PLTRELSZ) || hasTag(DT_PLTRELSZ) @@ -136,8 +141,8 @@ RelinkResult RelinkerPipeline::Relink(const std::vector& sourceElf || hasTag(DT_OS_JMPREL) || hasTag(DT_JMPREL); if (hasPltRelocations || hasTag(DT_OS_PLTGOT) || hasTag(DT_PLTGOT)) { gotVAddr = requireExactlyOneOf(DT_OS_PLTGOT, DT_PLTGOT, "DT_PLTGOT") - ? getTagValue(DT_OS_PLTGOT) - : getTagValue(DT_PLTGOT); + ? getTagValue(DT_OS_PLTGOT, "DT_OS_PLTGOT") + : getTagValue(DT_PLTGOT, "DT_PLTGOT"); } const FileByteOffset dynStrTabOffset = readAsOffset(DT_OS_STRTAB, DT_STRTAB, "DT_STRTAB"); @@ -145,30 +150,32 @@ RelinkResult RelinkerPipeline::Relink(const std::vector& sourceElf const FileByteOffset dynSymTabOffset = readAsOffset(DT_OS_SYMTAB, DT_SYMTAB, "DT_SYMTAB"); constexpr std::size_t symEntSize = 24; - if (readAsSize(DT_OS_SYMENT, DT_SYMENT, "DT_SYMENT") != symEntSize) - throw RelinkerException("Unsupported DT_SYMENT value"); + const auto symbolEntrySize = readAsSize(DT_OS_SYMENT, DT_SYMENT, "DT_SYMENT"); + if (symbolEntrySize != symEntSize) + throw RelinkerException("Unsupported DT_SYMENT value: " + std::to_string(symbolEntrySize) + "; expected 24 bytes"); FileByteOffset dynJmpRelOffset = 0; if (hasPltRelocations) { gotSize = readAsSize(DT_OS_PLTRELSZ, DT_PLTRELSZ, "DT_PLTRELSZ"); const std::int64_t jmprelType = requireExactlyOneOf(DT_OS_PLTREL, DT_PLTREL, "DT_PLTREL") - ? getTagValue(DT_OS_PLTREL) - : getTagValue(DT_PLTREL); + ? getTagValue(DT_OS_PLTREL, "DT_OS_PLTREL") + : getTagValue(DT_PLTREL, "DT_PLTREL"); if (jmprelType != DT_RELA) - throw RelinkerException("Unsupported DT_PLTREL type"); + throw RelinkerException("Unsupported DT_PLTREL type: " + std::to_string(jmprelType) + "; expected DT_RELA (7)"); dynJmpRelOffset = readAsOffset(DT_OS_JMPREL, DT_JMPREL, "DT_JMPREL"); if (gotSize % 24 != 0) - throw RelinkerException("Invalid DT_PLTRELSZ value"); + throw RelinkerException("Invalid DT_PLTRELSZ value: " + std::to_string(gotSize) + " bytes; expected a multiple of 24 bytes"); } const ByteCount dynJmpRelSize = gotSize; const FileByteOffset dynRelaOffset = readAsOffset(DT_OS_RELA, DT_RELA, "DT_RELA"); const ByteCount dynRelaSize = readAsSize(DT_OS_RELASZ, DT_RELASZ, "DT_RELASZ"); constexpr std::size_t relaEntSize = 24; - if (readAsSize(DT_OS_RELAENT, DT_RELAENT, "DT_RELAENT") != relaEntSize) - throw RelinkerException("Unsupported DT_RELAENT value"); + const auto relocationEntrySize = readAsSize(DT_OS_RELAENT, DT_RELAENT, "DT_RELAENT"); + if (relocationEntrySize != relaEntSize) + throw RelinkerException("Unsupported DT_RELAENT value: " + std::to_string(relocationEntrySize) + "; expected 24 bytes"); if (dynRelaSize % relaEntSize != 0) - throw RelinkerException("Invalid DT_RELASZ value"); + throw RelinkerException("Invalid DT_RELASZ value: " + std::to_string(dynRelaSize) + " bytes; expected a multiple of 24 bytes"); std::vector> neededLibraryNamesByStrOffset; for (const auto& tag : dynTags) @@ -384,7 +391,7 @@ RelinkResult RelinkerPipeline::Relink(const std::vector& sourceElf } if (hasTag(DT_OS_SYMTABSZ)) { - const auto symbolBytes = getTagValue(DT_OS_SYMTABSZ); + const auto symbolBytes = getTagValue(DT_OS_SYMTABSZ, "DT_OS_SYMTABSZ"); if (symbolBytes % symEntSize != 0 || dynSymTabOffset > raw.size() || symbolBytes > raw.size() - dynSymTabOffset) throw RelinkerException("Invalid executable dynamic symbol table size"); for (ByteCount off = symEntSize; off < symbolBytes; off += symEntSize) { diff --git a/core/relinker/relinker/tests/ConversionTests.cpp b/core/relinker/relinker/tests/ConversionTests.cpp index a2ff847e1..9e58d06fc 100644 --- a/core/relinker/relinker/tests/ConversionTests.cpp +++ b/core/relinker/relinker/tests/ConversionTests.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -162,6 +163,33 @@ void scanning() { require(progress.Events.back().Completed < progress.Events.back().Total, "Failed scan reported completion"); } +class FailingProgress final : public Domain::IProgress { +public: + std::string InputPath; + void Report(const Domain::ProgressEvent&) override { + Domain::RelinkerException error("diagnostic context", 0x1234); + error.InputPath = InputPath; + throw error; + } + void Message(std::string_view) override {} +}; + +void diagnosticContext() { + for (const bool specific : {false, true}) { + FailingProgress progress; + if (specific) progress.InputPath = "virtual/title/sce_module/plugin.prx"; + const auto source = input(); + try { Relinker::Conversion(progress).Convert(source, {}); } + catch (const Domain::RelinkerException& error) { + require(error.InputPath == (specific ? progress.InputPath : Io::Utf8Path(source.InputPath)), "Wrong diagnostic input path"); + require(error.FailureOffset == 0x1234, "Diagnostic offset changed"); + require(std::string(error.what()) == "diagnostic context", "Diagnostic message changed"); + continue; + } + throw std::runtime_error("Diagnostic failure was swallowed"); + } +} + class CancellingProgress final : public Domain::IProgress { public: Domain::ProgressStage Stage = Domain::ProgressStage::Decode; @@ -192,6 +220,7 @@ int main() { try { convert(); scanning(); + diagnosticContext(); cancellation(); } catch (const std::exception& error) { std::cerr << error.what() << '\n'; diff --git a/core/relinker/relinker/tests/test_conversion_diagnostics.py b/core/relinker/relinker/tests/test_conversion_diagnostics.py new file mode 100644 index 000000000..776206cc5 --- /dev/null +++ b/core/relinker/relinker/tests/test_conversion_diagnostics.py @@ -0,0 +1,83 @@ +from pathlib import Path +import struct +import subprocess +import sys +import tempfile + +from test_optional_plt import fixture +from test_guest_intel_trampolines import guest_fixture, main_fixture, PLAIN_SITE + + +def main(): + relinker = Path(sys.argv[1]).resolve() + failures = [] + with tempfile.TemporaryDirectory(prefix="anyps5-diagnostics-") as directory: + work = Path(directory) / "title space \u00e9" + work.mkdir() + + def convert(name, image, expected, flags, module=None, extra=False): + case = work / name + case.mkdir() + source = case / "eboot.bin" + source.write_bytes(main_fixture() if module is not None or extra else image) + options = [] + offending = source + if module is not None: + modules = case / "sce_module" + modules.mkdir() + offending = modules / "broken \u00e9.prx" + offending.write_bytes(module) + options = ["--sce-module-path", str(case)] + elif extra: + offending = case / "picker.bin" + offending.write_bytes(image) + (case / "sce_module").mkdir() + options = ["--sce-module-path", str(case), "--executable", "picker.bin"] + else: + options = ["--skip-sce-module"] + output = case / "converted.out" + result = subprocess.run([str(relinker), *flags, *options, str(source), str(output)], + capture_output=True, text=True, encoding="utf-8", timeout=20) + valid = (result.returncode == 2 and expected in result.stderr + and result.stderr.splitlines().count(f"Input: {offending}") == 1 + and not output.exists() and not list(case.rglob("*.guest.prx"))) + if extra: + valid = valid and not (case / "picker.bin.out").exists() + if not valid: + failures.append((name, result.returncode, result.stdout, result.stderr)) + + cases = [] + for tag, value, message in ( + (11, 16, "Unsupported DT_SYMENT value: 16; expected 24 bytes"), + (9, 8, "Unsupported DT_RELAENT value: 8; expected 24 bytes"), + (8, 25, "Invalid DT_RELASZ value: 25 bytes; expected a multiple of 24 bytes"), + ): + image = fixture() + for offset in range(0x400, 0x470, 16): + if struct.unpack_from(" Date: Tue, 13 Oct 2026 18:37:50 +0400 Subject: [PATCH 2/2] fix(relinker): keep diagnostics compatible with pending refactors --- .../relinker/src/pipeline/Conversion.cpp | 7 ++- .../src/pipeline/RelinkerPipeline.cpp | 44 +++++++++++++++---- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/core/relinker/relinker/src/pipeline/Conversion.cpp b/core/relinker/relinker/src/pipeline/Conversion.cpp index 024ec4d0f..2b69cfcd1 100644 --- a/core/relinker/relinker/src/pipeline/Conversion.cpp +++ b/core/relinker/relinker/src/pipeline/Conversion.cpp @@ -117,7 +117,12 @@ ConversionOutput Conversion::Convert(ConversionInput input, const ConversionOpti if (!windows) inputProgress.Report({Domain::ProgressStage::Image, Io::Utf8Path(input.InputPath), 0, 1}); std::vector executableBytes; - executableBytes = patcher->Patch(sourceBytes, result.OriginalHeaders, result.DynamicSection, result.OriginalPltGotVaddr, options.RunPath, options.LazyBinding, options.WindowsDiagnostics, trampolines); + try { + executableBytes = patcher->Patch(sourceBytes, result.OriginalHeaders, result.DynamicSection, result.OriginalPltGotVaddr, options.RunPath, options.LazyBinding, options.WindowsDiagnostics, trampolines); + } catch (Domain::RelinkerException& error) { + if (error.InputPath.empty()) error.InputPath = Io::Utf8Path(input.InputPath); + throw; + } if (!windows) inputProgress.Report({Domain::ProgressStage::Image, Io::Utf8Path(input.InputPath), 1, 1}); std::string diagnostics; diff --git a/core/relinker/relinker/src/pipeline/RelinkerPipeline.cpp b/core/relinker/relinker/src/pipeline/RelinkerPipeline.cpp index 238216056..4ccaba99f 100644 --- a/core/relinker/relinker/src/pipeline/RelinkerPipeline.cpp +++ b/core/relinker/relinker/src/pipeline/RelinkerPipeline.cpp @@ -99,10 +99,36 @@ RelinkResult RelinkerPipeline::Relink(const std::vector& sourceElf return false; }; - auto getTagValue = [&](const std::int64_t tag, const char* name) -> std::uint64_t { + auto getTagValue = [&](const std::int64_t tag) -> std::uint64_t { for (const auto& t : dynTags) if (t.Tag == tag) return t.Value; + const char* name = "unknown"; + switch (tag) { + case DT_OS_STRTAB: name = "DT_OS_STRTAB"; break; + case DT_STRTAB: name = "DT_STRTAB"; break; + case DT_OS_STRSZ: name = "DT_OS_STRSZ"; break; + case DT_STRSZ: name = "DT_STRSZ"; break; + case DT_OS_SYMTAB: name = "DT_OS_SYMTAB"; break; + case DT_SYMTAB: name = "DT_SYMTAB"; break; + case DT_OS_SYMENT: name = "DT_OS_SYMENT"; break; + case DT_SYMENT: name = "DT_SYMENT"; break; + case DT_OS_PLTGOT: name = "DT_OS_PLTGOT"; break; + case DT_PLTGOT: name = "DT_PLTGOT"; break; + case DT_OS_PLTREL: name = "DT_OS_PLTREL"; break; + case DT_PLTREL: name = "DT_PLTREL"; break; + case DT_OS_PLTRELSZ: name = "DT_OS_PLTRELSZ"; break; + case DT_PLTRELSZ: name = "DT_PLTRELSZ"; break; + case DT_OS_JMPREL: name = "DT_OS_JMPREL"; break; + case DT_JMPREL: name = "DT_JMPREL"; break; + case DT_OS_RELA: name = "DT_OS_RELA"; break; + case DT_RELA: name = "DT_RELA"; break; + case DT_OS_RELASZ: name = "DT_OS_RELASZ"; break; + case DT_RELASZ: name = "DT_RELASZ"; break; + case DT_OS_RELAENT: name = "DT_OS_RELAENT"; break; + case DT_RELAENT: name = "DT_RELAENT"; break; + case DT_OS_SYMTABSZ: name = "DT_OS_SYMTABSZ"; break; + } std::ostringstream message; message << "Required dynamic tag " << name << " (0x" << std::hex << tag << ") not found"; throw RelinkerException(message.str()); @@ -123,17 +149,17 @@ RelinkResult RelinkerPipeline::Relink(const std::vector& sourceElf auto readAsOffset = [&](const std::int64_t osTag, const std::int64_t sysvTag, const char* name) -> FileByteOffset { if (requireExactlyOneOf(osTag, sysvTag, name)) { - const std::uint64_t value = getTagValue(osTag, name); + const std::uint64_t value = getTagValue(osTag); if (value > std::numeric_limits::max() - sceTableBase) throw RelinkerException(std::string("Adding PT_SCE_DYNLIBDATA base to ") + name + " overflows", value); return sceTableBase + value; } - return elfReader->TranslateVirtualAddress(getTagValue(sysvTag, name)); + return elfReader->TranslateVirtualAddress(getTagValue(sysvTag)); }; auto readAsSize = [&](const std::int64_t osTag, const std::int64_t sysvTag, const char* name) -> ByteCount { requireExactlyOneOf(osTag, sysvTag, name); - return hasTag(osTag) ? getTagValue(osTag, name) : getTagValue(sysvTag, name); + return hasTag(osTag) ? getTagValue(osTag) : getTagValue(sysvTag); }; const bool hasPltRelocations = hasTag(DT_OS_PLTRELSZ) || hasTag(DT_PLTRELSZ) @@ -141,8 +167,8 @@ RelinkResult RelinkerPipeline::Relink(const std::vector& sourceElf || hasTag(DT_OS_JMPREL) || hasTag(DT_JMPREL); if (hasPltRelocations || hasTag(DT_OS_PLTGOT) || hasTag(DT_PLTGOT)) { gotVAddr = requireExactlyOneOf(DT_OS_PLTGOT, DT_PLTGOT, "DT_PLTGOT") - ? getTagValue(DT_OS_PLTGOT, "DT_OS_PLTGOT") - : getTagValue(DT_PLTGOT, "DT_PLTGOT"); + ? getTagValue(DT_OS_PLTGOT) + : getTagValue(DT_PLTGOT); } const FileByteOffset dynStrTabOffset = readAsOffset(DT_OS_STRTAB, DT_STRTAB, "DT_STRTAB"); @@ -158,8 +184,8 @@ RelinkResult RelinkerPipeline::Relink(const std::vector& sourceElf if (hasPltRelocations) { gotSize = readAsSize(DT_OS_PLTRELSZ, DT_PLTRELSZ, "DT_PLTRELSZ"); const std::int64_t jmprelType = requireExactlyOneOf(DT_OS_PLTREL, DT_PLTREL, "DT_PLTREL") - ? getTagValue(DT_OS_PLTREL, "DT_OS_PLTREL") - : getTagValue(DT_PLTREL, "DT_PLTREL"); + ? getTagValue(DT_OS_PLTREL) + : getTagValue(DT_PLTREL); if (jmprelType != DT_RELA) throw RelinkerException("Unsupported DT_PLTREL type: " + std::to_string(jmprelType) + "; expected DT_RELA (7)"); dynJmpRelOffset = readAsOffset(DT_OS_JMPREL, DT_JMPREL, "DT_JMPREL"); @@ -391,7 +417,7 @@ RelinkResult RelinkerPipeline::Relink(const std::vector& sourceElf } if (hasTag(DT_OS_SYMTABSZ)) { - const auto symbolBytes = getTagValue(DT_OS_SYMTABSZ, "DT_OS_SYMTABSZ"); + const auto symbolBytes = getTagValue(DT_OS_SYMTABSZ); if (symbolBytes % symEntSize != 0 || dynSymTabOffset > raw.size() || symbolBytes > raw.size() - dynSymTabOffset) throw RelinkerException("Invalid executable dynamic symbol table size"); for (ByteCount off = symEntSize; off < symbolBytes; off += symEntSize) {