diff --git a/CMakeLists.txt b/CMakeLists.txt index df3672be0..30de845bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,4 +4,6 @@ project(Relinker CXX) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -static-libgcc -static-libstdc++") + add_subdirectory(core) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index f6151965a..8c009c2cb 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -9,8 +9,6 @@ add_executable(relinker ${CMAKE_CURRENT_SOURCE_DIR}/io/src/FileReader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/io/src/FileWriter.cpp ${CMAKE_CURRENT_SOURCE_DIR}/relinker/src/parsing/ElfReader.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/relinker/src/parsing/SceDynlibParser.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/relinker/src/parsing/SdkRevisionProfile.cpp ${CMAKE_CURRENT_SOURCE_DIR}/relinker/src/analysis/SyscallScanner.cpp ${CMAKE_CURRENT_SOURCE_DIR}/relinker/src/analysis/CallSiteResolver.cpp ${CMAKE_CURRENT_SOURCE_DIR}/relinker/src/analysis/ValidationPolicy.cpp diff --git a/core/main.cpp b/core/main.cpp index f49c7e96b..0d4254da4 100644 --- a/core/main.cpp +++ b/core/main.cpp @@ -8,8 +8,6 @@ #include #include #include -#include -#include #include #include #include @@ -52,14 +50,6 @@ int main(const int argc, char* argv[]) { auto sourceBytes = fileReader.Read(inputPath); auto elfReader = std::make_shared(sourceBytes); - auto programHeaders = elfReader->ReadProgramHeaders(); - - std::vector sceDynlibData; - for (const auto& ph : programHeaders) - if (ph.Type == 0x61000000) - sceDynlibData = elfReader->ReadSegment(ph); - - auto sdkProfile = std::make_shared(sceDynlibData); auto syscallScanner = skipSyscallCheck ? Relinker::MakeNullSyscallScanner() @@ -67,7 +57,6 @@ int main(const int argc, char* argv[]) { const auto pipeline = std::make_shared( elfReader, - std::make_shared(sdkProfile), std::move(syscallScanner), Relinker::MakeCallSiteResolver(), std::make_shared(), diff --git a/core/relinker/include/relinker/domain/ISceDynlibParser.hpp b/core/relinker/include/relinker/domain/ISceDynlibParser.hpp deleted file mode 100644 index f8d1f840c..000000000 --- a/core/relinker/include/relinker/domain/ISceDynlibParser.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef RELINKER_DOMAIN_ISCEDYNLIBPARSER_HPP -#define RELINKER_DOMAIN_ISCEDYNLIBPARSER_HPP - -#include -#include - -namespace Relinker { - -struct LibraryImport { - std::string LibraryName; - std::uint32_t LibraryId; - std::uint32_t Version; -}; - -struct RelocationEntry { - FileByteOffset EntryOffset; - std::uint64_t Info; - std::int64_t Addend; -}; - -class ISceDynlibParser { -public: - virtual ~ISceDynlibParser() = default; - - virtual std::vector ParseLibraryImports(const std::vector& sceDynlibData) = 0; - virtual std::vector ParseRelocationTable(const std::vector& sceDynlibData) = 0; - virtual std::vector ExtractNidReferences( - const std::vector& relocations, - const std::vector& imports - ) = 0; -}; - -} - -#endif diff --git a/core/relinker/include/relinker/domain/ISdkRevisionProfile.hpp b/core/relinker/include/relinker/domain/ISdkRevisionProfile.hpp deleted file mode 100644 index 19ca813b8..000000000 --- a/core/relinker/include/relinker/domain/ISdkRevisionProfile.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef RELINKER_DOMAIN_ISDKREVISIONPROFILE_HPP -#define RELINKER_DOMAIN_ISDKREVISIONPROFILE_HPP - -#include -#include - -namespace Relinker { - -class ISdkRevisionProfile { -public: - virtual ~ISdkRevisionProfile() = default; - - [[nodiscard]] virtual std::uint32_t GetSceModuleParamHeaderSize() const = 0; - [[nodiscard]] virtual std::uint32_t GetSceModuleParamEntrySize() const = 0; - [[nodiscard]] virtual std::uint32_t GetSceDynlibDataHeaderSize() const = 0; - [[nodiscard]] virtual std::uint32_t GetSceDynlibDataEntrySize() const = 0; - [[nodiscard]] virtual std::uint32_t GetRelocationEntrySize() const = 0; - [[nodiscard]] virtual std::uint32_t GetImportsOffset() const = 0; - [[nodiscard]] virtual std::uint32_t GetImportsCount(const std::vector& data) const = 0; - [[nodiscard]] virtual std::uint32_t GetRelocationTableOffset() const = 0; -}; - -} - -#endif diff --git a/core/relinker/include/relinker/parsing/SceDynlibParser.hpp b/core/relinker/include/relinker/parsing/SceDynlibParser.hpp deleted file mode 100644 index af7d898a7..000000000 --- a/core/relinker/include/relinker/parsing/SceDynlibParser.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef RELINKER_PARSING_SCEDYNLIBPARSER_HPP -#define RELINKER_PARSING_SCEDYNLIBPARSER_HPP - -#include -#include -#include - -namespace Relinker { - -class SceDynlibParser : public ISceDynlibParser { -public: - explicit SceDynlibParser(std::shared_ptr sdkProfile); - - std::vector ParseLibraryImports(const std::vector& sceDynlibData) override; - std::vector ParseRelocationTable(const std::vector& sceDynlibData) override; - std::vector ExtractNidReferences( - const std::vector& relocations, - const std::vector& imports - ) override; - -private: - std::shared_ptr _sdkProfile; - - [[nodiscard]] std::uint32_t _readU32At(const std::vector& data, FileByteOffset offset) const; - [[nodiscard]] std::uint16_t _readU16At(const std::vector& data, FileByteOffset offset) const; - [[nodiscard]] std::uint8_t _readU8At(const std::vector& data, FileByteOffset offset) const; - [[nodiscard]] std::uint64_t _readU64At(const std::vector& data, FileByteOffset offset) const; - [[nodiscard]] std::string _extractNidFromRelocationInfo(std::uint64_t info) const; - [[nodiscard]] std::string _getLibraryNameForRelocation(const std::vector& imports, std::uint64_t info) const; -}; - -} - -#endif diff --git a/core/relinker/include/relinker/parsing/SdkRevisionProfile.hpp b/core/relinker/include/relinker/parsing/SdkRevisionProfile.hpp deleted file mode 100644 index 005e92e60..000000000 --- a/core/relinker/include/relinker/parsing/SdkRevisionProfile.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef RELINKER_PARSING_SDKREVISIONPROFILE_HPP -#define RELINKER_PARSING_SDKREVISIONPROFILE_HPP - -#include -#include - -namespace Relinker { - -class SdkRevisionProfile : public ISdkRevisionProfile { -public: - explicit SdkRevisionProfile(const std::vector& sceDynlibData); - - [[nodiscard]] std::uint32_t GetSceModuleParamHeaderSize() const override; - [[nodiscard]] std::uint32_t GetSceModuleParamEntrySize() const override; - [[nodiscard]] std::uint32_t GetSceDynlibDataHeaderSize() const override; - [[nodiscard]] std::uint32_t GetSceDynlibDataEntrySize() const override; - [[nodiscard]] std::uint32_t GetRelocationEntrySize() const override; - [[nodiscard]] std::uint32_t GetImportsOffset() const override; - [[nodiscard]] std::uint32_t GetImportsCount(const std::vector& data) const override; - [[nodiscard]] std::uint32_t GetRelocationTableOffset() const override; - -private: - std::uint32_t _sdkRevision; - - void _detectSdkRevision(const std::vector& data); - [[nodiscard]] std::uint32_t _readU32LittleEndian(const std::vector& data, FileByteOffset fileByteOffset) const; - [[nodiscard]] std::uint16_t _readU16LittleEndian(const std::vector& data, FileByteOffset fileByteOffset) const; -}; - -} - -#endif // RELINKER_SDKREVISIONPROFILE_HPP diff --git a/core/relinker/include/relinker/pipeline/RelinkerPipeline.hpp b/core/relinker/include/relinker/pipeline/RelinkerPipeline.hpp index 20f5591a4..e6e9c6861 100644 --- a/core/relinker/include/relinker/pipeline/RelinkerPipeline.hpp +++ b/core/relinker/include/relinker/pipeline/RelinkerPipeline.hpp @@ -3,8 +3,6 @@ #include #include -#include -#include #include #include #include @@ -17,7 +15,6 @@ class RelinkerPipeline : public IRelinkerPipeline { public: RelinkerPipeline( std::shared_ptr elfReader, - std::shared_ptr dynlibParser, std::shared_ptr syscallScanner, std::shared_ptr callSiteResolver, std::shared_ptr validationPolicy, @@ -28,7 +25,6 @@ public: private: std::shared_ptr _elfReader; - std::shared_ptr _dynlibParser; std::shared_ptr _syscallScanner; std::shared_ptr _callSiteResolver; std::shared_ptr _validationPolicy; @@ -36,7 +32,6 @@ private: static constexpr std::uint32_t PT_LOAD = 1; static constexpr std::uint32_t PT_DYNAMIC = 2; - static constexpr std::uint32_t PT_SCE_DYNLIBDATA = 0x61000000; static constexpr std::uint32_t PF_X = 0x1; static constexpr std::int64_t DT_PLTGOT = 0x00000003; @@ -45,10 +40,8 @@ private: static constexpr std::int64_t DT_OS_PLTRELSZ = 0x6100002d; static constexpr std::int64_t DT_NEEDED = 0x00000001; static constexpr std::int64_t DT_STRTAB = 0x00000005; - static constexpr std::int64_t DT_STRSZ = 0x0000000a; static constexpr std::int64_t DT_RELA = 0x00000007; static constexpr std::int64_t DT_RELASZ = 0x00000008; - static constexpr std::int64_t DT_JMPREL = 0x61000029; static constexpr std::int64_t DT_SYSV_JMPREL = 0x00000017; static constexpr std::int64_t DT_PLTRELSZ_SYSV = 0x00000002; static constexpr std::int64_t DT_SYMTAB = 0x00000006; diff --git a/core/relinker/src/parsing/SceDynlibParser.cpp b/core/relinker/src/parsing/SceDynlibParser.cpp deleted file mode 100644 index 9afc12a63..000000000 --- a/core/relinker/src/parsing/SceDynlibParser.cpp +++ /dev/null @@ -1,158 +0,0 @@ -#include -#include -#include -#include - -namespace Relinker { - -static constexpr std::uint64_t NID_INDEX_MASK = 0x000000000000FFFFULL; -static constexpr std::uint64_t LIB_INDEX_MASK = 0x00000000FFFF0000ULL; -static constexpr int LIB_INDEX_SHIFT = 16; -static constexpr std::uint32_t RELOC_TYPE_MASK = 0xFFFFFFFFU; - -SceDynlibParser::SceDynlibParser(std::shared_ptr SdkProfile) - : _sdkProfile(std::move(SdkProfile)) { -} - -std::uint8_t SceDynlibParser::_readU8At( - const std::vector& data, const FileByteOffset fileByteOffset) const { - if (fileByteOffset >= data.size()) { - throw RelinkerException("SCE dynlib data offset out of bounds", fileByteOffset); - } - return data[fileByteOffset]; -} - -std::uint16_t SceDynlibParser::_readU16At( - const std::vector& data, const FileByteOffset fileByteOffset) const { - if (fileByteOffset + 2 > data.size()) { - throw RelinkerException("SCE dynlib data offset out of bounds", fileByteOffset); - } - std::uint16_t value; - std::memcpy(&value, data.data() + fileByteOffset, 2); - return value; -} - -std::uint32_t SceDynlibParser::_readU32At( - const std::vector& data, const FileByteOffset fileByteOffset) const { - if (fileByteOffset + 4 > data.size()) { - throw RelinkerException("SCE dynlib data offset out of bounds", fileByteOffset); - } - std::uint32_t value; - std::memcpy(&value, data.data() + fileByteOffset, 4); - return value; -} - -std::uint64_t SceDynlibParser::_readU64At( - const std::vector& data, const FileByteOffset fileByteOffset) const { - if (fileByteOffset + 8 > data.size()) { - throw RelinkerException("SCE dynlib data offset out of bounds", fileByteOffset); - } - std::uint64_t value; - std::memcpy(&value, data.data() + fileByteOffset, 8); - return value; -} - -std::vector SceDynlibParser::ParseLibraryImports( - const std::vector& sceDynlibData) { - std::uint32_t count = _sdkProfile->GetImportsCount(sceDynlibData); - std::uint32_t baseOff = _sdkProfile->GetImportsOffset(); - std::uint32_t entrySize = _sdkProfile->GetSceDynlibDataEntrySize(); - - std::vector imports; - imports.reserve(count); - - FileByteOffset cursor = baseOff; - for (std::uint32_t i = 0; i < count; ++i) { - if (cursor + entrySize > sceDynlibData.size()) { - throw RelinkerException("Library import entry out of bounds", cursor); - } - - std::uint32_t nameOffset = _readU32At(sceDynlibData, cursor); - std::uint32_t libraryId = _readU16At(sceDynlibData, cursor + 0x04); - std::uint32_t version = _readU16At(sceDynlibData, cursor + 0x06); - - std::string name; - FileByteOffset namePos = nameOffset; - while (namePos < sceDynlibData.size() && sceDynlibData[namePos] != '\0') { - name += static_cast(sceDynlibData[namePos]); - ++namePos; - } - - LibraryImport imp; - imp.LibraryName = std::move(name); - imp.LibraryId = libraryId; - imp.Version = version; - imports.push_back(std::move(imp)); - - cursor += entrySize; - } - - return imports; -} - -std::vector SceDynlibParser::ParseRelocationTable( - const std::vector& sceDynlibData) { - const std::uint32_t tableOffset = _sdkProfile->GetRelocationTableOffset(); - const std::uint32_t entrySize = _sdkProfile->GetRelocationEntrySize(); - - if (tableOffset >= sceDynlibData.size()) { - return {}; - } - - std::vector entries; - FileByteOffset cursor = tableOffset; - - while (cursor + entrySize <= sceDynlibData.size()) { - RelocationEntry entry; - entry.EntryOffset = _readU64At(sceDynlibData, cursor); - entry.Info = _readU64At(sceDynlibData, cursor + 0x08); - entry.Addend = static_cast(_readU64At(sceDynlibData, cursor + 0x10)); - entries.push_back(entry); - cursor += entrySize; - } - - return entries; -} - -std::string SceDynlibParser::_extractNidFromRelocationInfo(std::uint64_t info) const { - std::uint64_t symIndex = info >> 32; - std::ostringstream oss; - oss << std::hex << symIndex; - return oss.str(); -} - -std::string SceDynlibParser::_getLibraryNameForRelocation( - const std::vector& imports, const std::uint64_t info) const { - std::uint32_t libIndex = static_cast((info & LIB_INDEX_MASK) >> LIB_INDEX_SHIFT); - if (libIndex == 0 || libIndex > imports.size()) { - return ""; - } - return imports[libIndex - 1].LibraryName; -} - -std::vector SceDynlibParser::ExtractNidReferences( - const std::vector& relocations, - const std::vector& imports) { - std::vector refs; - refs.reserve(relocations.size()); - - for (std::size_t i = 0; i < relocations.size(); ++i) { - const auto& reloc = relocations[i]; - std::uint32_t relocType = static_cast(reloc.Info & RELOC_TYPE_MASK); - - std::string nid = _extractNidFromRelocationInfo(reloc.Info); - std::string library = _getLibraryNameForRelocation(imports, reloc.Info); - - NidReference ref; - ref.Nid = std::move(nid); - ref.Library = std::move(library); - ref.RelocationTypeValue = relocType; - ref.RelocationTableOffset = static_cast(i * _sdkProfile->GetRelocationEntrySize()); - ref.RelocationAddress = reloc.EntryOffset; - refs.push_back(std::move(ref)); - } - - return refs; -} - -} diff --git a/core/relinker/src/parsing/SdkRevisionProfile.cpp b/core/relinker/src/parsing/SdkRevisionProfile.cpp deleted file mode 100644 index 5e8ca25d6..000000000 --- a/core/relinker/src/parsing/SdkRevisionProfile.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include -#include - -namespace Relinker { - -constexpr std::uint32_t DEFAULT_SDK_REVISION = 0x05000000; - -constexpr std::uint32_t SCE_MODULE_PARAM_HEADER_SIZE = 0x38; -constexpr std::uint32_t SCE_MODULE_PARAM_ENTRY_SIZE = 0x08; -constexpr std::uint32_t SCE_DYNLIBDATA_HEADER_SIZE = 0x10; -constexpr std::uint32_t SCE_DYNLIBDATA_ENTRY_SIZE = 0x10; -constexpr std::uint32_t RELOCATION_ENTRY_SIZE = 0x18; - -SdkRevisionProfile::SdkRevisionProfile(const std::vector& sceDynlibData) - : _sdkRevision(DEFAULT_SDK_REVISION) { - _detectSdkRevision(sceDynlibData); -} - -void SdkRevisionProfile::_detectSdkRevision(const std::vector& data) { - if (data.size() < 8) { - return; - } - - _sdkRevision = _readU32LittleEndian(data, 0x04); -} - -std::uint32_t SdkRevisionProfile::_readU32LittleEndian( - const std::vector& data, const FileByteOffset fileByteOffset) const { - if (fileByteOffset + 4 > data.size()) { - throw RelinkerException("FileByteOffset out of bounds", fileByteOffset); - } - std::uint32_t value; - std::memcpy(&value, data.data() + fileByteOffset, 4); - return value; -} - -std::uint16_t SdkRevisionProfile::_readU16LittleEndian( - const std::vector& data, const FileByteOffset fileByteOffset) const { - if (fileByteOffset + 2 > data.size()) { - throw RelinkerException("FileByteOffset out of bounds", fileByteOffset); - } - std::uint16_t value; - std::memcpy(&value, data.data() + fileByteOffset, 2); - return value; -} - -std::uint32_t SdkRevisionProfile::GetSceModuleParamHeaderSize() const { - return SCE_MODULE_PARAM_HEADER_SIZE; -} - -std::uint32_t SdkRevisionProfile::GetSceModuleParamEntrySize() const { - return SCE_MODULE_PARAM_ENTRY_SIZE; -} - -std::uint32_t SdkRevisionProfile::GetSceDynlibDataHeaderSize() const { - return SCE_DYNLIBDATA_HEADER_SIZE; -} - -std::uint32_t SdkRevisionProfile::GetSceDynlibDataEntrySize() const { - return SCE_DYNLIBDATA_ENTRY_SIZE; -} - -std::uint32_t SdkRevisionProfile::GetRelocationEntrySize() const { - return RELOCATION_ENTRY_SIZE; -} - -std::uint32_t SdkRevisionProfile::GetImportsOffset() const { - return SCE_DYNLIBDATA_HEADER_SIZE; -} - -std::uint32_t SdkRevisionProfile::GetImportsCount(const std::vector& data) const { - if (data.size() < 8) { - return 0; - } - return _readU32LittleEndian(data, 0x00); -} - -std::uint32_t SdkRevisionProfile::GetRelocationTableOffset() const { - return 0; -} - -} diff --git a/core/relinker/src/pipeline/RelinkerPipeline.cpp b/core/relinker/src/pipeline/RelinkerPipeline.cpp index 88ad23f34..b212a3c10 100644 --- a/core/relinker/src/pipeline/RelinkerPipeline.cpp +++ b/core/relinker/src/pipeline/RelinkerPipeline.cpp @@ -8,13 +8,11 @@ namespace Relinker { RelinkerPipeline::RelinkerPipeline( std::shared_ptr elfReader, - std::shared_ptr dynlibParser, std::shared_ptr syscallScanner, std::shared_ptr callSiteResolver, std::shared_ptr validationPolicy, std::shared_ptr dynamicSectionBuilder) : _elfReader(std::move(elfReader)) - , _dynlibParser(std::move(dynlibParser)) , _syscallScanner(std::move(syscallScanner)) , _callSiteResolver(std::move(callSiteResolver)) , _validationPolicy(std::move(validationPolicy)) @@ -38,16 +36,11 @@ std::string RelinkerPipeline::_relocationTypeName(std::uint32_t type) { RelinkResult RelinkerPipeline::Relink(const std::vector& sourceElf) { auto programHeaders = _elfReader->ReadProgramHeaders(); - std::vector sceDynlibData; std::vector textSection; VirtualAddress textVAddr = 0; VirtualAddress gotVAddr = 0; ByteCount gotSize = 0; - for (const auto& ph : programHeaders) - if (ph.Type == PT_SCE_DYNLIBDATA) - sceDynlibData = _elfReader->ReadSegment(ph); - for (const auto& ph : programHeaders) { if (ph.Type == PT_LOAD && (ph.Flags & PF_X) != 0) { textSection = _elfReader->ReadSegment(ph); @@ -57,18 +50,20 @@ RelinkResult RelinkerPipeline::Relink(const std::vector& sourceElf } FileByteOffset dynStrTabOffset = 0; - ByteCount dynStrTabSize = 0; FileByteOffset dynSymTabOffset = 0; FileByteOffset dynRelaOffset = 0; ByteCount dynRelaSize = 0; FileByteOffset dynJmpRelOffset = 0; ByteCount dynJmpRelSize = 0; + bool hasDynamicSegment = false; std::vector> neededLibraryNamesByStrOffset; for (const auto& ph : programHeaders) { if (ph.Type != PT_DYNAMIC) continue; + hasDynamicSegment = true; + for (const auto& tag : _elfReader->ReadDynamicTags(ph)) { if (tag.Tag == DT_PLTGOT || tag.Tag == DT_OS_PLTGOT) gotVAddr = tag.Value; @@ -76,8 +71,6 @@ RelinkResult RelinkerPipeline::Relink(const std::vector& sourceElf gotSize = tag.Value; else if (tag.Tag == DT_STRTAB) dynStrTabOffset = _elfReader->TranslateVirtualAddress(tag.Value); - else if (tag.Tag == DT_STRSZ) - dynStrTabSize = tag.Value; else if (tag.Tag == DT_SYMTAB) dynSymTabOffset = _elfReader->TranslateVirtualAddress(tag.Value); else if (tag.Tag == DT_RELA) @@ -94,83 +87,70 @@ RelinkResult RelinkerPipeline::Relink(const std::vector& sourceElf break; } + if (!hasDynamicSegment) + throw RelinkerException("No PT_DYNAMIC segment found"); + if (dynStrTabOffset == 0) + throw RelinkerException("DT_STRTAB not found in PT_DYNAMIC segment"); + if (dynSymTabOffset == 0) + throw RelinkerException("DT_SYMTAB not found in PT_DYNAMIC segment"); + std::vector nidRefs; std::vector neededLibraries; auto policy = std::dynamic_pointer_cast(_validationPolicy); - if (!sceDynlibData.empty()) { - auto imports = _dynlibParser->ParseLibraryImports(sceDynlibData); - auto relocations = _dynlibParser->ParseRelocationTable(sceDynlibData); - nidRefs = _dynlibParser->ExtractNidReferences(relocations, imports); + const std::vector& raw = _elfReader->GetRawBytes(); - for (const auto& imp : imports) { - if (policy) policy->RegisterLibraryImport(imp.LibraryName); - neededLibraries.push_back(imp.LibraryName); - } - for (const auto& ref : nidRefs) { - _validationPolicy->ValidateRelocationTypeSupported(ref.RelocationTypeValue, ref.RelocationTableOffset); - _validationPolicy->ValidateNidBelongsToLibrary(ref.Nid, ref.Library); - } - } else if (dynStrTabOffset != 0) { - const std::vector& raw = _elfReader->GetRawBytes(); + auto readCStr = [&](FileByteOffset strOff) -> std::string { + std::string result; + FileByteOffset pos = dynStrTabOffset + strOff; + while (pos < raw.size() && raw[pos] != 0) + result.push_back(static_cast(raw[pos++])); + return result; + }; - auto readCStr = [&](FileByteOffset strOff) -> std::string { - std::string result; - FileByteOffset pos = dynStrTabOffset + strOff; - while (pos < raw.size() && raw[pos] != 0) - result.push_back(static_cast(raw[pos++])); - return result; - }; - - for (auto& [fst, snd] : neededLibraryNamesByStrOffset) { - snd = readCStr(fst); - neededLibraries.push_back(snd); - if (policy) policy->RegisterLibraryImport(snd); - } - - auto extractRela = [&](const FileByteOffset relaOff, const ByteCount relaSize) { - constexpr std::size_t entrySize = 24; - for (ByteCount off = 0; off + entrySize <= relaSize; off += entrySize) { - const FileByteOffset pos = relaOff + off; - if (pos + entrySize > raw.size()) - break; - - std::uint64_t rOffset = 0, rInfo = 0; - std::memcpy(&rOffset, raw.data() + pos, 8); - std::memcpy(&rInfo, raw.data() + pos + 8, 8); - - const std::uint32_t symIdx = static_cast(rInfo >> 32); - const std::uint32_t relType = static_cast(rInfo & 0xffffffff); - - if (dynSymTabOffset == 0) - continue; - - const FileByteOffset symOff = dynSymTabOffset + static_cast(symIdx) * 24; - if (symOff + 4 > raw.size()) - continue; - - std::uint32_t nameOff = 0; - std::memcpy(&nameOff, raw.data() + symOff, 4); - - NidReference ref; - ref.Nid = readCStr(nameOff); - ref.Library = {}; - ref.RelocationTypeValue = relType; - ref.RelocationTableOffset = pos; - ref.RelocationAddress = rOffset; - nidRefs.push_back(ref); - } - }; - - if (dynRelaOffset != 0) extractRela(dynRelaOffset, dynRelaSize); - if (dynJmpRelOffset != 0) extractRela(dynJmpRelOffset, dynJmpRelSize); - - for (const auto& ref : nidRefs) - _validationPolicy->ValidateRelocationTypeSupported(ref.RelocationTypeValue, ref.RelocationTableOffset); - } else { - throw RelinkerException("Neither SCE_DYNLIBDATA segment nor hybrid PT_DYNAMIC NID data found"); + for (auto& [fst, snd] : neededLibraryNamesByStrOffset) { + snd = readCStr(fst); + neededLibraries.push_back(snd); + if (policy) policy->RegisterLibraryImport(snd); } + auto extractRela = [&](const FileByteOffset relaOff, const ByteCount relaSize) { + constexpr std::size_t entrySize = 24; + for (ByteCount off = 0; off + entrySize <= relaSize; off += entrySize) { + const FileByteOffset pos = relaOff + off; + if (pos + entrySize > raw.size()) + throw RelinkerException("Relocation entry out of bounds", pos); + + std::uint64_t rOffset = 0, rInfo = 0; + std::memcpy(&rOffset, raw.data() + pos, 8); + std::memcpy(&rInfo, raw.data() + pos + 8, 8); + + const std::uint32_t symIdx = static_cast(rInfo >> 32); + const std::uint32_t relType = static_cast(rInfo & 0xffffffff); + + const FileByteOffset symOff = dynSymTabOffset + static_cast(symIdx) * 24; + if (symOff + 4 > raw.size()) + throw RelinkerException("Symbol table entry out of bounds", symOff); + + std::uint32_t nameOff = 0; + std::memcpy(&nameOff, raw.data() + symOff, 4); + + NidReference ref; + ref.Nid = readCStr(nameOff); + ref.Library = {}; + ref.RelocationTypeValue = relType; + ref.RelocationTableOffset = pos; + ref.RelocationAddress = rOffset; + nidRefs.push_back(ref); + } + }; + + if (dynRelaOffset != 0) extractRela(dynRelaOffset, dynRelaSize); + if (dynJmpRelOffset != 0) extractRela(dynJmpRelOffset, dynJmpRelSize); + + for (const auto& ref : nidRefs) + _validationPolicy->ValidateRelocationTypeSupported(ref.RelocationTypeValue, ref.RelocationTableOffset); + if (!textSection.empty()) _syscallScanner->ScanCodeSectionForSyscalls(textSection, textVAddr, textSection.size());