feat(core): relocation tables from pt dynamic instead of hardcoded offset

This commit is contained in:
boykopovar 2026-08-04 13:32:22 +03:00
parent 7689e85d8f
commit 39ae562b51
11 changed files with 61 additions and 465 deletions

View File

@ -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)

View File

@ -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

View File

@ -8,8 +8,6 @@
#include <elfpatcher/sections/SectionHeaderTableBuilder.hpp>
#include <io/ByteWriter.hpp>
#include <relinker/parsing/ElfReader.hpp>
#include <relinker/parsing/SceDynlibParser.hpp>
#include <relinker/parsing/SdkRevisionProfile.hpp>
#include <relinker/analysis/ValidationPolicy.hpp>
#include <relinker/analysis/SyscallScanner.hpp>
#include <relinker/analysis/CallSiteResolver.hpp>
@ -52,14 +50,6 @@ int main(const int argc, char* argv[]) {
auto sourceBytes = fileReader.Read(inputPath);
auto elfReader = std::make_shared<Relinker::ElfReader>(sourceBytes);
auto programHeaders = elfReader->ReadProgramHeaders();
std::vector<std::uint8_t> sceDynlibData;
for (const auto& ph : programHeaders)
if (ph.Type == 0x61000000)
sceDynlibData = elfReader->ReadSegment(ph);
auto sdkProfile = std::make_shared<Relinker::SdkRevisionProfile>(sceDynlibData);
auto syscallScanner = skipSyscallCheck
? Relinker::MakeNullSyscallScanner()
@ -67,7 +57,6 @@ int main(const int argc, char* argv[]) {
const auto pipeline = std::make_shared<Relinker::RelinkerPipeline>(
elfReader,
std::make_shared<Relinker::SceDynlibParser>(sdkProfile),
std::move(syscallScanner),
Relinker::MakeCallSiteResolver(),
std::make_shared<Relinker::ValidationPolicy>(),

View File

@ -1,35 +0,0 @@
#ifndef RELINKER_DOMAIN_ISCEDYNLIBPARSER_HPP
#define RELINKER_DOMAIN_ISCEDYNLIBPARSER_HPP
#include <relinker/domain/Types.hpp>
#include <vector>
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<LibraryImport> ParseLibraryImports(const std::vector<std::uint8_t>& sceDynlibData) = 0;
virtual std::vector<RelocationEntry> ParseRelocationTable(const std::vector<std::uint8_t>& sceDynlibData) = 0;
virtual std::vector<NidReference> ExtractNidReferences(
const std::vector<RelocationEntry>& relocations,
const std::vector<LibraryImport>& imports
) = 0;
};
}
#endif

View File

@ -1,25 +0,0 @@
#ifndef RELINKER_DOMAIN_ISDKREVISIONPROFILE_HPP
#define RELINKER_DOMAIN_ISDKREVISIONPROFILE_HPP
#include <relinker/domain/Types.hpp>
#include <vector>
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<std::uint8_t>& data) const = 0;
[[nodiscard]] virtual std::uint32_t GetRelocationTableOffset() const = 0;
};
}
#endif

View File

@ -1,34 +0,0 @@
#ifndef RELINKER_PARSING_SCEDYNLIBPARSER_HPP
#define RELINKER_PARSING_SCEDYNLIBPARSER_HPP
#include <relinker/domain/ISceDynlibParser.hpp>
#include <relinker/domain/ISdkRevisionProfile.hpp>
#include <memory>
namespace Relinker {
class SceDynlibParser : public ISceDynlibParser {
public:
explicit SceDynlibParser(std::shared_ptr<ISdkRevisionProfile> sdkProfile);
std::vector<LibraryImport> ParseLibraryImports(const std::vector<std::uint8_t>& sceDynlibData) override;
std::vector<RelocationEntry> ParseRelocationTable(const std::vector<std::uint8_t>& sceDynlibData) override;
std::vector<NidReference> ExtractNidReferences(
const std::vector<RelocationEntry>& relocations,
const std::vector<LibraryImport>& imports
) override;
private:
std::shared_ptr<ISdkRevisionProfile> _sdkProfile;
[[nodiscard]] std::uint32_t _readU32At(const std::vector<std::uint8_t>& data, FileByteOffset offset) const;
[[nodiscard]] std::uint16_t _readU16At(const std::vector<std::uint8_t>& data, FileByteOffset offset) const;
[[nodiscard]] std::uint8_t _readU8At(const std::vector<std::uint8_t>& data, FileByteOffset offset) const;
[[nodiscard]] std::uint64_t _readU64At(const std::vector<std::uint8_t>& data, FileByteOffset offset) const;
[[nodiscard]] std::string _extractNidFromRelocationInfo(std::uint64_t info) const;
[[nodiscard]] std::string _getLibraryNameForRelocation(const std::vector<LibraryImport>& imports, std::uint64_t info) const;
};
}
#endif

View File

@ -1,32 +0,0 @@
#ifndef RELINKER_PARSING_SDKREVISIONPROFILE_HPP
#define RELINKER_PARSING_SDKREVISIONPROFILE_HPP
#include <relinker/domain/ISdkRevisionProfile.hpp>
#include <map>
namespace Relinker {
class SdkRevisionProfile : public ISdkRevisionProfile {
public:
explicit SdkRevisionProfile(const std::vector<std::uint8_t>& 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<std::uint8_t>& data) const override;
[[nodiscard]] std::uint32_t GetRelocationTableOffset() const override;
private:
std::uint32_t _sdkRevision;
void _detectSdkRevision(const std::vector<std::uint8_t>& data);
[[nodiscard]] std::uint32_t _readU32LittleEndian(const std::vector<std::uint8_t>& data, FileByteOffset fileByteOffset) const;
[[nodiscard]] std::uint16_t _readU16LittleEndian(const std::vector<std::uint8_t>& data, FileByteOffset fileByteOffset) const;
};
}
#endif // RELINKER_SDKREVISIONPROFILE_HPP

View File

@ -3,8 +3,6 @@
#include <relinker/domain/IRelinkerPipeline.hpp>
#include <relinker/domain/IElfReader.hpp>
#include <relinker/domain/ISceDynlibParser.hpp>
#include <relinker/domain/ISdkRevisionProfile.hpp>
#include <relinker/domain/ISyscallScanner.hpp>
#include <relinker/domain/ICallSiteResolver.hpp>
#include <relinker/domain/IValidationPolicy.hpp>
@ -17,7 +15,6 @@ class RelinkerPipeline : public IRelinkerPipeline {
public:
RelinkerPipeline(
std::shared_ptr<IElfReader> elfReader,
std::shared_ptr<ISceDynlibParser> dynlibParser,
std::shared_ptr<ISyscallScanner> syscallScanner,
std::shared_ptr<ICallSiteResolver> callSiteResolver,
std::shared_ptr<IValidationPolicy> validationPolicy,
@ -28,7 +25,6 @@ public:
private:
std::shared_ptr<IElfReader> _elfReader;
std::shared_ptr<ISceDynlibParser> _dynlibParser;
std::shared_ptr<ISyscallScanner> _syscallScanner;
std::shared_ptr<ICallSiteResolver> _callSiteResolver;
std::shared_ptr<IValidationPolicy> _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;

View File

@ -1,158 +0,0 @@
#include <relinker/parsing/SceDynlibParser.hpp>
#include <relinker/domain/ISdkRevisionProfile.hpp>
#include <cstring>
#include <sstream>
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<ISdkRevisionProfile> SdkProfile)
: _sdkProfile(std::move(SdkProfile)) {
}
std::uint8_t SceDynlibParser::_readU8At(
const std::vector<std::uint8_t>& 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<std::uint8_t>& 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<std::uint8_t>& 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<std::uint8_t>& 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<LibraryImport> SceDynlibParser::ParseLibraryImports(
const std::vector<std::uint8_t>& sceDynlibData) {
std::uint32_t count = _sdkProfile->GetImportsCount(sceDynlibData);
std::uint32_t baseOff = _sdkProfile->GetImportsOffset();
std::uint32_t entrySize = _sdkProfile->GetSceDynlibDataEntrySize();
std::vector<LibraryImport> 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<char>(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<RelocationEntry> SceDynlibParser::ParseRelocationTable(
const std::vector<std::uint8_t>& sceDynlibData) {
const std::uint32_t tableOffset = _sdkProfile->GetRelocationTableOffset();
const std::uint32_t entrySize = _sdkProfile->GetRelocationEntrySize();
if (tableOffset >= sceDynlibData.size()) {
return {};
}
std::vector<RelocationEntry> 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<std::int64_t>(_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<LibraryImport>& imports, const std::uint64_t info) const {
std::uint32_t libIndex = static_cast<std::uint32_t>((info & LIB_INDEX_MASK) >> LIB_INDEX_SHIFT);
if (libIndex == 0 || libIndex > imports.size()) {
return "";
}
return imports[libIndex - 1].LibraryName;
}
std::vector<NidReference> SceDynlibParser::ExtractNidReferences(
const std::vector<RelocationEntry>& relocations,
const std::vector<LibraryImport>& imports) {
std::vector<NidReference> 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<std::uint32_t>(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<FileByteOffset>(i * _sdkProfile->GetRelocationEntrySize());
ref.RelocationAddress = reloc.EntryOffset;
refs.push_back(std::move(ref));
}
return refs;
}
}

View File

@ -1,82 +0,0 @@
#include <relinker/parsing/SdkRevisionProfile.hpp>
#include <cstring>
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<std::uint8_t>& sceDynlibData)
: _sdkRevision(DEFAULT_SDK_REVISION) {
_detectSdkRevision(sceDynlibData);
}
void SdkRevisionProfile::_detectSdkRevision(const std::vector<std::uint8_t>& data) {
if (data.size() < 8) {
return;
}
_sdkRevision = _readU32LittleEndian(data, 0x04);
}
std::uint32_t SdkRevisionProfile::_readU32LittleEndian(
const std::vector<std::uint8_t>& 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<std::uint8_t>& 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<std::uint8_t>& data) const {
if (data.size() < 8) {
return 0;
}
return _readU32LittleEndian(data, 0x00);
}
std::uint32_t SdkRevisionProfile::GetRelocationTableOffset() const {
return 0;
}
}

View File

@ -8,13 +8,11 @@ namespace Relinker {
RelinkerPipeline::RelinkerPipeline(
std::shared_ptr<IElfReader> elfReader,
std::shared_ptr<ISceDynlibParser> dynlibParser,
std::shared_ptr<ISyscallScanner> syscallScanner,
std::shared_ptr<ICallSiteResolver> callSiteResolver,
std::shared_ptr<IValidationPolicy> validationPolicy,
std::shared_ptr<ISysVDynamicSectionBuilder> 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<std::uint8_t>& sourceElf) {
auto programHeaders = _elfReader->ReadProgramHeaders();
std::vector<std::uint8_t> sceDynlibData;
std::vector<std::uint8_t> 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<std::uint8_t>& 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<std::pair<std::uint64_t, std::string>> 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<std::uint8_t>& 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<std::uint8_t>& 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<NidReference> nidRefs;
std::vector<std::string> neededLibraries;
auto policy = std::dynamic_pointer_cast<ValidationPolicy>(_validationPolicy);
if (!sceDynlibData.empty()) {
auto imports = _dynlibParser->ParseLibraryImports(sceDynlibData);
auto relocations = _dynlibParser->ParseRelocationTable(sceDynlibData);
nidRefs = _dynlibParser->ExtractNidReferences(relocations, imports);
const std::vector<std::uint8_t>& 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<std::uint8_t>& 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<char>(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<char>(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<std::uint32_t>(rInfo >> 32);
const std::uint32_t relType = static_cast<std::uint32_t>(rInfo & 0xffffffff);
if (dynSymTabOffset == 0)
continue;
const FileByteOffset symOff = dynSymTabOffset + static_cast<FileByteOffset>(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<std::uint32_t>(rInfo >> 32);
const std::uint32_t relType = static_cast<std::uint32_t>(rInfo & 0xffffffff);
const FileByteOffset symOff = dynSymTabOffset + static_cast<FileByteOffset>(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());