refactor(core): separate io from domain logic + di
This commit is contained in:
parent
e451fde738
commit
850eae37eb
|
|
@ -4,4 +4,7 @@ project(Relinker CXX)
|
|||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
add_subdirectory(core/domain)
|
||||
add_subdirectory(core/elfpatcher)
|
||||
add_subdirectory(core/io)
|
||||
add_subdirectory(core/relinker)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
add_library(domain INTERFACE)
|
||||
target_include_directories(domain INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
#ifndef DOMAIN_TYPES_HPP
|
||||
#define DOMAIN_TYPES_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace Domain {
|
||||
|
||||
using FileByteOffset = std::uint64_t;
|
||||
using VirtualAddress = std::uint64_t;
|
||||
using ByteCount = std::uint64_t;
|
||||
|
||||
struct ElfHeader {
|
||||
std::uint16_t Machine;
|
||||
std::uint16_t Type;
|
||||
std::uint8_t OsAbi;
|
||||
std::uint8_t AbiVersion;
|
||||
std::uint64_t EntryPoint;
|
||||
std::uint64_t ProgramHeaderOffset;
|
||||
std::uint64_t SectionHeaderOffset;
|
||||
std::uint32_t ProgramHeaderEntrySize;
|
||||
std::uint16_t ProgramHeaderCount;
|
||||
std::uint32_t SectionHeaderEntrySize;
|
||||
std::uint16_t SectionHeaderCount;
|
||||
std::uint16_t SectionHeaderStringIndex;
|
||||
};
|
||||
|
||||
struct ProgramHeader {
|
||||
std::uint32_t Type;
|
||||
std::uint32_t Flags;
|
||||
FileByteOffset Offset;
|
||||
VirtualAddress MappedAddress;
|
||||
VirtualAddress PhysicalAddress;
|
||||
ByteCount FileSize;
|
||||
ByteCount MemorySize;
|
||||
std::uint64_t Alignment;
|
||||
};
|
||||
|
||||
struct SectionHeader {
|
||||
std::string Name;
|
||||
std::uint32_t Type;
|
||||
std::uint64_t Flags;
|
||||
VirtualAddress MappedAddress;
|
||||
FileByteOffset Offset;
|
||||
ByteCount SectionSize;
|
||||
std::uint32_t Link;
|
||||
std::uint32_t Info;
|
||||
std::uint64_t EntrySize;
|
||||
};
|
||||
|
||||
struct NidReference {
|
||||
std::string Nid;
|
||||
std::string Library;
|
||||
std::uint32_t RelocationTypeValue;
|
||||
FileByteOffset RelocationTableOffset;
|
||||
VirtualAddress RelocationAddress;
|
||||
};
|
||||
|
||||
struct CallSiteInfo {
|
||||
std::vector<FileByteOffset> Sites;
|
||||
bool Resolved;
|
||||
};
|
||||
|
||||
struct SymbolExport {
|
||||
std::string Nid;
|
||||
std::string Library;
|
||||
FileByteOffset GotOffset;
|
||||
FileByteOffset PltOffset;
|
||||
CallSiteInfo CallSites;
|
||||
};
|
||||
|
||||
struct DynamicTag {
|
||||
std::int64_t Tag;
|
||||
std::uint64_t Value;
|
||||
};
|
||||
|
||||
struct RelinkerException : std::runtime_error {
|
||||
FileByteOffset FailureOffset;
|
||||
|
||||
explicit RelinkerException(const std::string& message, const FileByteOffset failureOffset = 0)
|
||||
: std::runtime_error(message), FailureOffset(failureOffset) {}
|
||||
};
|
||||
|
||||
struct SysVDynamicSection {
|
||||
std::vector<std::uint8_t> DynamicSegmentData;
|
||||
std::vector<std::uint8_t> DynSymData;
|
||||
std::vector<std::uint8_t> DynStrData;
|
||||
std::vector<std::uint8_t> RelaData;
|
||||
std::vector<std::uint8_t> RelaPltData;
|
||||
};
|
||||
|
||||
struct CallRegistryEntry {
|
||||
std::string Nid;
|
||||
std::string Library;
|
||||
std::string RelocationTypeString;
|
||||
FileByteOffset RelocationOffset;
|
||||
std::string TargetSection;
|
||||
FileByteOffset TargetOffset;
|
||||
std::vector<FileByteOffset> CallSites;
|
||||
bool CallSitesResolved;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
add_library(elfpatcher STATIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/ElfPatcher.cpp
|
||||
)
|
||||
target_include_directories(elfpatcher PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
target_link_libraries(elfpatcher PRIVATE domain)
|
||||
|
|
@ -1,17 +1,16 @@
|
|||
#ifndef RELINKER_OUTPUT_ELFPATCHER_HPP
|
||||
#define RELINKER_OUTPUT_ELFPATCHER_HPP
|
||||
#ifndef ELFPATCHER_ELFPATCHER_HPP
|
||||
#define ELFPATCHER_ELFPATCHER_HPP
|
||||
|
||||
#include <relinker/domain/IElfPatcher.hpp>
|
||||
#include <elfpatcher/IElfPatcher.hpp>
|
||||
|
||||
namespace Relinker {
|
||||
namespace Elfpatcher {
|
||||
|
||||
class ElfPatcher : public IElfPatcher {
|
||||
public:
|
||||
void PatchAndWrite(
|
||||
const std::string& inputPath,
|
||||
const std::string& outputPath,
|
||||
const std::vector<ProgramHeader>& originalHeaders,
|
||||
const SysVDynamicSection& dynamicSection
|
||||
std::vector<std::uint8_t> Patch(
|
||||
const std::vector<std::uint8_t>& sourceElf,
|
||||
const std::vector<Domain::ProgramHeader>& originalHeaders,
|
||||
const Domain::SysVDynamicSection& dynamicSection
|
||||
) override;
|
||||
|
||||
private:
|
||||
|
|
@ -42,9 +41,9 @@ private:
|
|||
static constexpr std::int64_t DT_PLTREL = 20;
|
||||
|
||||
[[nodiscard]] bool _isSceSpecificSegment(std::uint32_t type) const;
|
||||
[[nodiscard]] bool _isNullPageLoad(const ProgramHeader& ph) const;
|
||||
[[nodiscard]] bool _shouldSkip(const ProgramHeader& ph) const;
|
||||
[[nodiscard]] ProgramHeader _makeLoadHeader(std::uint64_t offset, std::uint64_t size) const;
|
||||
[[nodiscard]] bool _isNullPageLoad(const Domain::ProgramHeader& ph) const;
|
||||
[[nodiscard]] bool _shouldSkip(const Domain::ProgramHeader& ph) const;
|
||||
[[nodiscard]] Domain::ProgramHeader _makeLoadHeader(std::uint64_t offset, std::uint64_t size) const;
|
||||
[[nodiscard]] std::vector<std::uint8_t> _buildEntryStub(std::uint64_t stubVaddr, std::uint64_t realEntryVaddr) const;
|
||||
void _writeInterp(std::vector<std::uint8_t>& buf, std::size_t phEntOff, std::uint64_t interpOff, std::uint64_t interpSize) const;
|
||||
void _writeU16(std::vector<std::uint8_t>& buf, std::size_t offset, std::uint16_t v) const;
|
||||
|
|
@ -53,7 +52,7 @@ private:
|
|||
void _appendU64(std::vector<std::uint8_t>& buf, std::uint64_t v) const;
|
||||
void _appendI64(std::vector<std::uint8_t>& buf, std::int64_t v) const;
|
||||
void _appendDynEntry(std::vector<std::uint8_t>& buf, std::int64_t tag, std::uint64_t val) const;
|
||||
void _writeProgramHeader(std::vector<std::uint8_t>& buf, std::size_t offset, const ProgramHeader& ph) const;
|
||||
void _writeProgramHeader(std::vector<std::uint8_t>& buf, std::size_t offset, const Domain::ProgramHeader& ph) const;
|
||||
[[nodiscard]] std::uint32_t _fixLoadFlags(std::uint32_t originalFlags) const;
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef ELFPATCHER_IELFPATCHER_HPP
|
||||
#define ELFPATCHER_IELFPATCHER_HPP
|
||||
|
||||
#include <domain/Types.hpp>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace Elfpatcher {
|
||||
|
||||
class IElfPatcher {
|
||||
public:
|
||||
virtual ~IElfPatcher() = default;
|
||||
|
||||
virtual std::vector<std::uint8_t> Patch(
|
||||
const std::vector<std::uint8_t>& sourceElf,
|
||||
const std::vector<Domain::ProgramHeader>& originalHeaders,
|
||||
const Domain::SysVDynamicSection& dynamicSection
|
||||
) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,8 +1,7 @@
|
|||
#include <relinker/output/ElfPatcher.hpp>
|
||||
#include <fstream>
|
||||
#include <elfpatcher/ElfPatcher.hpp>
|
||||
#include <cstring>
|
||||
|
||||
namespace Relinker {
|
||||
namespace Elfpatcher {
|
||||
|
||||
bool ElfPatcher::_isSceSpecificSegment(std::uint32_t type) const {
|
||||
return type == PT_SCE_DYNLIBDATA
|
||||
|
|
@ -11,7 +10,7 @@ bool ElfPatcher::_isSceSpecificSegment(std::uint32_t type) const {
|
|||
|| (type >= 0x61000000 && type <= 0x6fffffff);
|
||||
}
|
||||
|
||||
bool ElfPatcher::_isNullPageLoad(const ProgramHeader& ph) const {
|
||||
bool ElfPatcher::_isNullPageLoad(const Domain::ProgramHeader& ph) const {
|
||||
return ph.Type == PT_LOAD && ph.MappedAddress == 0;
|
||||
}
|
||||
|
||||
|
|
@ -42,7 +41,7 @@ void ElfPatcher::_appendDynEntry(std::vector<std::uint8_t>& buf, std::int64_t ta
|
|||
_appendU64(buf, val);
|
||||
}
|
||||
|
||||
void ElfPatcher::_writeProgramHeader(std::vector<std::uint8_t>& buf, std::size_t offset, const ProgramHeader& ph) const {
|
||||
void ElfPatcher::_writeProgramHeader(std::vector<std::uint8_t>& buf, std::size_t offset, const Domain::ProgramHeader& ph) const {
|
||||
_writeU32(buf, offset + 0, ph.Type);
|
||||
_writeU32(buf, offset + 4, ph.Flags);
|
||||
_writeU64(buf, offset + 8, ph.Offset);
|
||||
|
|
@ -53,8 +52,8 @@ void ElfPatcher::_writeProgramHeader(std::vector<std::uint8_t>& buf, std::size_t
|
|||
_writeU64(buf, offset + 48, ph.Alignment);
|
||||
}
|
||||
|
||||
ProgramHeader ElfPatcher::_makeLoadHeader(std::uint64_t offset, std::uint64_t size) const {
|
||||
ProgramHeader ph{};
|
||||
Domain::ProgramHeader ElfPatcher::_makeLoadHeader(std::uint64_t offset, std::uint64_t size) const {
|
||||
Domain::ProgramHeader ph{};
|
||||
ph.Type = PT_LOAD;
|
||||
ph.Flags = PF_R;
|
||||
ph.Offset = offset;
|
||||
|
|
@ -67,7 +66,7 @@ ProgramHeader ElfPatcher::_makeLoadHeader(std::uint64_t offset, std::uint64_t si
|
|||
}
|
||||
|
||||
void ElfPatcher::_writeInterp(std::vector<std::uint8_t>& buf, std::size_t phEntOff, std::uint64_t interpOff, std::uint64_t interpSize) const {
|
||||
ProgramHeader ph{};
|
||||
Domain::ProgramHeader ph{};
|
||||
ph.Type = PT_INTERP;
|
||||
ph.Flags = PF_R;
|
||||
ph.Offset = interpOff;
|
||||
|
|
@ -79,7 +78,7 @@ void ElfPatcher::_writeInterp(std::vector<std::uint8_t>& buf, std::size_t phEntO
|
|||
_writeProgramHeader(buf, phEntOff, ph);
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> ElfPatcher::_buildEntryStub(std::uint64_t stubVaddr, std::uint64_t realEntryVaddr) const {
|
||||
std::vector<std::uint8_t> ElfPatcher::_buildEntryStub(const std::uint64_t stubVaddr, const std::uint64_t realEntryVaddr) const {
|
||||
std::vector<std::uint8_t> s;
|
||||
s.push_back(0x58);
|
||||
s.push_back(0x48); s.push_back(0x89); s.push_back(0xe3);
|
||||
|
|
@ -104,7 +103,7 @@ std::uint32_t ElfPatcher::_fixLoadFlags(std::uint32_t originalFlags) const {
|
|||
return originalFlags | PF_R;
|
||||
}
|
||||
|
||||
bool ElfPatcher::_shouldSkip(const ProgramHeader& ph) const {
|
||||
bool ElfPatcher::_shouldSkip(const Domain::ProgramHeader& ph) const {
|
||||
if (_isSceSpecificSegment(ph.Type)) return true;
|
||||
if (ph.Type == PT_DYNAMIC) return true;
|
||||
if (_isNullPageLoad(ph)) return true;
|
||||
|
|
@ -112,20 +111,12 @@ bool ElfPatcher::_shouldSkip(const ProgramHeader& ph) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
void ElfPatcher::PatchAndWrite(
|
||||
const std::string& inputPath,
|
||||
const std::string& outputPath,
|
||||
const std::vector<ProgramHeader>& originalHeaders,
|
||||
const SysVDynamicSection& dynSection)
|
||||
std::vector<std::uint8_t> ElfPatcher::Patch(
|
||||
const std::vector<std::uint8_t>& sourceElf,
|
||||
const std::vector<Domain::ProgramHeader>& originalHeaders,
|
||||
const Domain::SysVDynamicSection& dynSection)
|
||||
{
|
||||
std::ifstream in(inputPath, std::ios::binary | std::ios::ate);
|
||||
if (!in)
|
||||
throw RelinkerException("Cannot open input ELF: " + inputPath);
|
||||
const std::streamsize fileSize = in.tellg();
|
||||
in.seekg(0);
|
||||
std::vector<std::uint8_t> buf(static_cast<std::size_t>(fileSize));
|
||||
if (!in.read(reinterpret_cast<char*>(buf.data()), fileSize))
|
||||
throw RelinkerException("Cannot read input ELF: " + inputPath);
|
||||
std::vector<std::uint8_t> buf = sourceElf;
|
||||
|
||||
buf[7] = 0;
|
||||
buf[8] = 0;
|
||||
|
|
@ -211,7 +202,7 @@ void ElfPatcher::PatchAndWrite(
|
|||
}
|
||||
const std::uint16_t neededPh = keptCount + 3;
|
||||
if (neededPh > phNum)
|
||||
throw RelinkerException(
|
||||
throw Domain::RelinkerException(
|
||||
"Not enough program header slots: need " + std::to_string(neededPh) +
|
||||
", available " + std::to_string(phNum));
|
||||
|
||||
|
|
@ -221,7 +212,7 @@ void ElfPatcher::PatchAndWrite(
|
|||
continue;
|
||||
const std::size_t phEntOff = static_cast<std::size_t>(phOff) + writtenPh * phEntSize;
|
||||
if (ph.Type == PT_LOAD) {
|
||||
ProgramHeader fixed = ph;
|
||||
Domain::ProgramHeader fixed = ph;
|
||||
fixed.Flags = _fixLoadFlags(ph.Flags);
|
||||
_writeProgramHeader(buf, phEntOff, fixed);
|
||||
} else {
|
||||
|
|
@ -238,7 +229,7 @@ void ElfPatcher::PatchAndWrite(
|
|||
|
||||
{
|
||||
const std::size_t phEntOff = static_cast<std::size_t>(phOff) + writtenPh * phEntSize;
|
||||
ProgramHeader dynPh{};
|
||||
Domain::ProgramHeader dynPh{};
|
||||
dynPh.Type = PT_DYNAMIC;
|
||||
dynPh.Flags = PF_R | PF_W;
|
||||
dynPh.Offset = dynSegOff;
|
||||
|
|
@ -259,12 +250,7 @@ void ElfPatcher::PatchAndWrite(
|
|||
|
||||
_writeU16(buf, 56, writtenPh);
|
||||
|
||||
std::ofstream out(outputPath, std::ios::binary);
|
||||
if (!out)
|
||||
throw RelinkerException("Cannot open output ELF: " + outputPath);
|
||||
out.write(reinterpret_cast<const char*>(buf.data()), static_cast<std::streamsize>(buf.size()));
|
||||
if (!out)
|
||||
throw RelinkerException("Failed to write output ELF: " + outputPath);
|
||||
return buf;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
add_library(io STATIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/FileReader.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/FileWriter.cpp
|
||||
)
|
||||
target_include_directories(io PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
target_link_libraries(io PRIVATE domain)
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef IO_FILEREADER_HPP
|
||||
#define IO_FILEREADER_HPP
|
||||
|
||||
#include <io/IFileReader.hpp>
|
||||
|
||||
namespace Io {
|
||||
|
||||
class FileReader : public IFileReader {
|
||||
public:
|
||||
std::vector<std::uint8_t> Read(const std::string& path) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef IO_FILEWRITER_HPP
|
||||
#define IO_FILEWRITER_HPP
|
||||
|
||||
#include <io/IFileWriter.hpp>
|
||||
|
||||
namespace Io {
|
||||
|
||||
class FileWriter : public IFileWriter {
|
||||
public:
|
||||
void Write(const std::string& path, const std::vector<std::uint8_t>& data) override;
|
||||
void Write(const std::string& path, const std::string& content) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef IO_IFILEREADER_HPP
|
||||
#define IO_IFILEREADER_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Io {
|
||||
|
||||
class IFileReader {
|
||||
public:
|
||||
virtual ~IFileReader() = default;
|
||||
|
||||
virtual std::vector<std::uint8_t> Read(const std::string& path) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef IO_IFILEWRITER_HPP
|
||||
#define IO_IFILEWRITER_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Io {
|
||||
|
||||
class IFileWriter {
|
||||
public:
|
||||
virtual ~IFileWriter() = default;
|
||||
|
||||
virtual void Write(const std::string& path, const std::vector<std::uint8_t>& data) = 0;
|
||||
virtual void Write(const std::string& path, const std::string& content) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#include <io/FileReader.hpp>
|
||||
#include <domain/Types.hpp>
|
||||
#include <fstream>
|
||||
|
||||
namespace Io {
|
||||
|
||||
std::vector<std::uint8_t> FileReader::Read(const std::string& path) {
|
||||
std::ifstream f(path, std::ios::binary | std::ios::ate);
|
||||
if (!f)
|
||||
throw Domain::RelinkerException("Cannot open file: " + path);
|
||||
const std::streamsize size = f.tellg();
|
||||
f.seekg(0);
|
||||
std::vector<std::uint8_t> buf(static_cast<std::size_t>(size));
|
||||
if (!f.read(reinterpret_cast<char*>(buf.data()), size))
|
||||
throw Domain::RelinkerException("Cannot read file: " + path);
|
||||
return buf;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#include <io/FileWriter.hpp>
|
||||
#include <domain/Types.hpp>
|
||||
#include <fstream>
|
||||
|
||||
namespace Io {
|
||||
|
||||
void FileWriter::Write(const std::string& path, const std::vector<std::uint8_t>& data) {
|
||||
std::ofstream f(path, std::ios::binary);
|
||||
if (!f)
|
||||
throw Domain::RelinkerException("Cannot open output file: " + path);
|
||||
f.write(reinterpret_cast<const char*>(data.data()), static_cast<std::streamsize>(data.size()));
|
||||
if (!f)
|
||||
throw Domain::RelinkerException("Failed to write file: " + path);
|
||||
}
|
||||
|
||||
void FileWriter::Write(const std::string& path, const std::string& content) {
|
||||
std::ofstream f(path);
|
||||
if (!f)
|
||||
throw Domain::RelinkerException("Cannot open output file: " + path);
|
||||
f << content;
|
||||
if (!f)
|
||||
throw Domain::RelinkerException("Failed to write file: " + path);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -10,9 +10,9 @@ set(RELINKER_SOURCES
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/src/analysis/ValidationPolicy.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/output/SysVDynamicSectionBuilder.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/output/CallRegistryWriter.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/output/ElfPatcher.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pipeline/RelinkerPipeline.cpp
|
||||
)
|
||||
|
||||
add_executable(relinker ${RELINKER_SOURCES})
|
||||
target_include_directories(relinker PRIVATE ${RELINKER_INCLUDE_DIR})
|
||||
target_link_libraries(relinker PRIVATE domain elfpatcher io)
|
||||
|
|
|
|||
|
|
@ -7,17 +7,6 @@
|
|||
|
||||
namespace Relinker {
|
||||
|
||||
struct CallRegistryEntry {
|
||||
std::string Nid;
|
||||
std::string Library;
|
||||
std::string RelocationTypeString;
|
||||
FileByteOffset RelocationOffset;
|
||||
std::string TargetSection;
|
||||
FileByteOffset TargetOffset;
|
||||
std::vector<FileByteOffset> CallSites;
|
||||
bool CallSitesResolved;
|
||||
};
|
||||
|
||||
class ICallRegistryWriter {
|
||||
public:
|
||||
virtual ~ICallRegistryWriter() = default;
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
#ifndef RELINKER_DOMAIN_IELFPATCHER_HPP
|
||||
#define RELINKER_DOMAIN_IELFPATCHER_HPP
|
||||
|
||||
#include <relinker/domain/Types.hpp>
|
||||
#include <relinker/domain/ISysVDynamicSectionBuilder.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Relinker {
|
||||
|
||||
class IElfPatcher {
|
||||
public:
|
||||
virtual ~IElfPatcher() = default;
|
||||
|
||||
virtual void PatchAndWrite(
|
||||
const std::string& inputPath,
|
||||
const std::string& outputPath,
|
||||
const std::vector<ProgramHeader>& originalHeaders,
|
||||
const SysVDynamicSection& dynamicSection
|
||||
) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -19,6 +19,7 @@ public:
|
|||
[[nodiscard]] virtual std::vector<std::uint8_t> ReadSection(const SectionHeader& header) const = 0;
|
||||
[[nodiscard]] virtual std::vector<std::uint8_t> ReadSegment(const ProgramHeader& header) const = 0;
|
||||
[[nodiscard]] virtual std::uint64_t GetFileSize() const = 0;
|
||||
[[nodiscard]] virtual const std::vector<std::uint8_t>& GetRawBytes() const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
#ifndef RELINKER_DOMAIN_IRELINKERPIPELINE_HPP
|
||||
#define RELINKER_DOMAIN_IRELINKERPIPELINE_HPP
|
||||
|
||||
#include <string>
|
||||
#include <relinker/domain/RelinkResult.hpp>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace Relinker {
|
||||
|
||||
|
|
@ -9,11 +11,7 @@ class IRelinkerPipeline {
|
|||
public:
|
||||
virtual ~IRelinkerPipeline() = default;
|
||||
|
||||
virtual void Run(
|
||||
const std::string& inputElfPath,
|
||||
const std::string& outputRegistryPath,
|
||||
const std::string& outputElfPath
|
||||
) = 0;
|
||||
virtual RelinkResult Relink(const std::vector<std::uint8_t>& sourceElf) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,14 +6,6 @@
|
|||
|
||||
namespace Relinker {
|
||||
|
||||
struct SysVDynamicSection {
|
||||
std::vector<std::uint8_t> DynamicSegmentData;
|
||||
std::vector<std::uint8_t> DynSymData;
|
||||
std::vector<std::uint8_t> DynStrData;
|
||||
std::vector<std::uint8_t> RelaData;
|
||||
std::vector<std::uint8_t> RelaPltData;
|
||||
};
|
||||
|
||||
class ISysVDynamicSectionBuilder {
|
||||
public:
|
||||
virtual ~ISysVDynamicSectionBuilder() = default;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef RELINKER_DOMAIN_RELINKRESULT_HPP
|
||||
#define RELINKER_DOMAIN_RELINKRESULT_HPP
|
||||
|
||||
#include <relinker/domain/Types.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace Relinker {
|
||||
|
||||
struct RelinkResult {
|
||||
std::vector<CallRegistryEntry> RegistryEntries;
|
||||
std::vector<ProgramHeader> OriginalHeaders;
|
||||
SysVDynamicSection DynamicSection;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,89 +1,23 @@
|
|||
#ifndef RELINKER_DOMAIN_TYPES_HPP
|
||||
#define RELINKER_DOMAIN_TYPES_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <domain/Types.hpp>
|
||||
|
||||
namespace Relinker {
|
||||
|
||||
using FileByteOffset = std::uint64_t;
|
||||
using VirtualAddress = std::uint64_t;
|
||||
using ByteCount = std::uint64_t;
|
||||
|
||||
struct ElfHeader {
|
||||
std::uint16_t Machine;
|
||||
std::uint16_t Type;
|
||||
std::uint8_t OsAbi;
|
||||
std::uint8_t AbiVersion;
|
||||
std::uint64_t EntryPoint;
|
||||
std::uint64_t ProgramHeaderOffset;
|
||||
std::uint64_t SectionHeaderOffset;
|
||||
std::uint32_t ProgramHeaderEntrySize;
|
||||
std::uint16_t ProgramHeaderCount;
|
||||
std::uint32_t SectionHeaderEntrySize;
|
||||
std::uint16_t SectionHeaderCount;
|
||||
std::uint16_t SectionHeaderStringIndex;
|
||||
};
|
||||
|
||||
struct ProgramHeader {
|
||||
std::uint32_t Type;
|
||||
std::uint32_t Flags;
|
||||
FileByteOffset Offset;
|
||||
VirtualAddress MappedAddress;
|
||||
VirtualAddress PhysicalAddress;
|
||||
ByteCount FileSize;
|
||||
ByteCount MemorySize;
|
||||
std::uint64_t Alignment;
|
||||
};
|
||||
|
||||
struct SectionHeader {
|
||||
std::string Name;
|
||||
std::uint32_t Type;
|
||||
std::uint64_t Flags;
|
||||
VirtualAddress MappedAddress;
|
||||
FileByteOffset Offset;
|
||||
ByteCount SectionSize;
|
||||
std::uint32_t Link;
|
||||
std::uint32_t Info;
|
||||
std::uint64_t EntrySize;
|
||||
};
|
||||
|
||||
struct NidReference {
|
||||
std::string Nid;
|
||||
std::string Library;
|
||||
std::uint32_t RelocationTypeValue;
|
||||
FileByteOffset RelocationTableOffset;
|
||||
VirtualAddress RelocationAddress;
|
||||
};
|
||||
|
||||
struct CallSiteInfo {
|
||||
std::vector<FileByteOffset> Sites;
|
||||
bool Resolved;
|
||||
};
|
||||
|
||||
struct SymbolExport {
|
||||
std::string Nid;
|
||||
std::string Library;
|
||||
FileByteOffset GotOffset;
|
||||
FileByteOffset PltOffset;
|
||||
CallSiteInfo CallSites;
|
||||
};
|
||||
|
||||
struct DynamicTag {
|
||||
std::int64_t Tag;
|
||||
std::uint64_t Value;
|
||||
};
|
||||
|
||||
struct RelinkerException : std::runtime_error {
|
||||
FileByteOffset FailureOffset;
|
||||
|
||||
explicit RelinkerException(const std::string& message, const FileByteOffset failureOffset = 0)
|
||||
: std::runtime_error(message), FailureOffset(failureOffset) {}
|
||||
};
|
||||
using FileByteOffset = Domain::FileByteOffset;
|
||||
using VirtualAddress = Domain::VirtualAddress;
|
||||
using ByteCount = Domain::ByteCount;
|
||||
using ElfHeader = Domain::ElfHeader;
|
||||
using ProgramHeader = Domain::ProgramHeader;
|
||||
using SectionHeader = Domain::SectionHeader;
|
||||
using NidReference = Domain::NidReference;
|
||||
using CallSiteInfo = Domain::CallSiteInfo;
|
||||
using SymbolExport = Domain::SymbolExport;
|
||||
using DynamicTag = Domain::DynamicTag;
|
||||
using RelinkerException = Domain::RelinkerException;
|
||||
using SysVDynamicSection = Domain::SysVDynamicSection;
|
||||
using CallRegistryEntry = Domain::CallRegistryEntry;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace Relinker {
|
|||
|
||||
class ElfReader : public IElfReader {
|
||||
public:
|
||||
explicit ElfReader(const std::string& filePath);
|
||||
explicit ElfReader(std::vector<std::uint8_t> fileBuffer);
|
||||
|
||||
ElfHeader ReadHeader() const override;
|
||||
std::vector<ProgramHeader> ReadProgramHeaders() const override;
|
||||
|
|
@ -18,12 +18,11 @@ public:
|
|||
std::vector<std::uint8_t> ReadSection(const SectionHeader& header) const override;
|
||||
std::vector<std::uint8_t> ReadSegment(const ProgramHeader& header) const override;
|
||||
std::uint64_t GetFileSize() const override;
|
||||
const std::vector<std::uint8_t>& GetRawBytes() const override;
|
||||
|
||||
private:
|
||||
std::string _filePath;
|
||||
mutable std::vector<std::uint8_t> _fileBuffer;
|
||||
std::vector<std::uint8_t> _fileBuffer;
|
||||
|
||||
void _loadFileIntoBuffer() const;
|
||||
std::uint64_t _readU64At(FileByteOffset offset) const;
|
||||
std::uint32_t _readU32At(FileByteOffset offset) const;
|
||||
std::uint16_t _readU16At(FileByteOffset offset) const;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
#include <relinker/domain/IValidationPolicy.hpp>
|
||||
#include <relinker/domain/ISysVDynamicSectionBuilder.hpp>
|
||||
#include <relinker/domain/ICallRegistryWriter.hpp>
|
||||
#include <relinker/domain/IElfPatcher.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace Relinker {
|
||||
|
|
@ -24,15 +23,10 @@ public:
|
|||
std::shared_ptr<ICallSiteResolver> callSiteResolver,
|
||||
std::shared_ptr<IValidationPolicy> validationPolicy,
|
||||
std::shared_ptr<ISysVDynamicSectionBuilder> dynamicSectionBuilder,
|
||||
std::shared_ptr<ICallRegistryWriter> callRegistryWriter,
|
||||
std::shared_ptr<IElfPatcher> elfPatcher
|
||||
std::shared_ptr<ICallRegistryWriter> callRegistryWriter
|
||||
);
|
||||
|
||||
void Run(
|
||||
const std::string& inputElfPath,
|
||||
const std::string& outputRegistryPath,
|
||||
const std::string& outputElfPath
|
||||
) override;
|
||||
RelinkResult Relink(const std::vector<std::uint8_t>& sourceElf) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<IElfReader> _elfReader;
|
||||
|
|
@ -42,7 +36,6 @@ private:
|
|||
std::shared_ptr<IValidationPolicy> _validationPolicy;
|
||||
std::shared_ptr<ISysVDynamicSectionBuilder> _dynamicSectionBuilder;
|
||||
std::shared_ptr<ICallRegistryWriter> _callRegistryWriter;
|
||||
std::shared_ptr<IElfPatcher> _elfPatcher;
|
||||
|
||||
static constexpr std::uint32_t PT_LOAD = 1;
|
||||
static constexpr std::uint32_t PT_DYNAMIC = 2;
|
||||
|
|
@ -64,7 +57,6 @@ private:
|
|||
static constexpr std::int64_t DT_SYMTAB = 0x00000006;
|
||||
|
||||
static std::string _relocationTypeName(std::uint32_t type);
|
||||
void _writeFile(const std::string& path, const std::string& content) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
#include <relinker/domain/Types.hpp>
|
||||
#include <domain/Types.hpp>
|
||||
#include <io/FileReader.hpp>
|
||||
#include <io/FileWriter.hpp>
|
||||
#include <elfpatcher/ElfPatcher.hpp>
|
||||
#include <relinker/parsing/ElfReader.hpp>
|
||||
#include <relinker/parsing/SceDynlibParser.hpp>
|
||||
#include <relinker/parsing/SdkRevisionProfile.hpp>
|
||||
|
|
@ -7,7 +10,6 @@
|
|||
#include <relinker/analysis/CallSiteResolver.hpp>
|
||||
#include <relinker/output/SysVDynamicSectionBuilder.hpp>
|
||||
#include <relinker/output/CallRegistryWriter.hpp>
|
||||
#include <relinker/output/ElfPatcher.hpp>
|
||||
#include <relinker/pipeline/RelinkerPipeline.hpp>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
|
@ -23,7 +25,12 @@ int main(const int argc, char* argv[]) {
|
|||
const std::string outputElfPath = argv[3];
|
||||
|
||||
try {
|
||||
auto elfReader = std::make_shared<Relinker::ElfReader>(inputPath);
|
||||
Io::FileReader fileReader;
|
||||
Io::FileWriter fileWriter;
|
||||
|
||||
auto sourceBytes = fileReader.Read(inputPath);
|
||||
|
||||
auto elfReader = std::make_shared<Relinker::ElfReader>(sourceBytes);
|
||||
auto programHeaders = elfReader->ReadProgramHeaders();
|
||||
|
||||
std::vector<std::uint8_t> sceDynlibData;
|
||||
|
|
@ -40,13 +47,19 @@ int main(const int argc, char* argv[]) {
|
|||
Relinker::MakeCallSiteResolver(),
|
||||
std::make_shared<Relinker::ValidationPolicy>(),
|
||||
std::make_shared<Relinker::SysVDynamicSectionBuilder>(),
|
||||
std::make_shared<Relinker::CallRegistryWriter>(),
|
||||
std::make_shared<Relinker::ElfPatcher>()
|
||||
std::make_shared<Relinker::CallRegistryWriter>()
|
||||
);
|
||||
|
||||
pipeline->Run(inputPath, registryPath, outputElfPath);
|
||||
auto result = pipeline->Relink(sourceBytes);
|
||||
|
||||
} catch (const Relinker::RelinkerException& e) {
|
||||
auto callRegistryWriter = std::make_shared<Relinker::CallRegistryWriter>();
|
||||
fileWriter.Write(registryPath, callRegistryWriter->WriteCallRegistry(result.RegistryEntries));
|
||||
|
||||
Elfpatcher::ElfPatcher elfPatcher;
|
||||
auto patchedElf = elfPatcher.Patch(sourceBytes, result.OriginalHeaders, result.DynamicSection);
|
||||
fileWriter.Write(outputElfPath, patchedElf);
|
||||
|
||||
} catch (const Domain::RelinkerException& e) {
|
||||
std::cerr << "FAIL: " << e.what();
|
||||
if (e.FailureOffset != 0)
|
||||
std::cerr << " (offset 0x" << std::hex << e.FailureOffset << ")";
|
||||
|
|
|
|||
|
|
@ -1,34 +1,19 @@
|
|||
#include <relinker/parsing/ElfReader.hpp>
|
||||
#include <relinker/domain/Types.hpp>
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
|
||||
namespace Relinker {
|
||||
|
||||
ElfReader::ElfReader(const std::string& filePath) : _filePath(filePath) {
|
||||
ElfReader::ElfReader(std::vector<std::uint8_t> fileBuffer)
|
||||
: _fileBuffer(std::move(fileBuffer))
|
||||
{
|
||||
}
|
||||
|
||||
void ElfReader::_loadFileIntoBuffer() const {
|
||||
if (!_fileBuffer.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::ifstream file(_filePath, std::ios::binary | std::ios::ate);
|
||||
if (!file.is_open()) {
|
||||
throw RelinkerException("Cannot open file: " + _filePath);
|
||||
}
|
||||
|
||||
std::streamsize size = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
_fileBuffer.resize(size);
|
||||
if (!file.read(reinterpret_cast<char*>(_fileBuffer.data()), size)) {
|
||||
throw RelinkerException("Cannot read file: " + _filePath);
|
||||
}
|
||||
const std::vector<std::uint8_t>& ElfReader::GetRawBytes() const {
|
||||
return _fileBuffer;
|
||||
}
|
||||
|
||||
std::uint8_t ElfReader::_readU8At(FileByteOffset fileByteOffset) const {
|
||||
_loadFileIntoBuffer();
|
||||
if (fileByteOffset >= _fileBuffer.size()) {
|
||||
throw RelinkerException("FileByteOffset out of bounds", fileByteOffset);
|
||||
}
|
||||
|
|
@ -36,7 +21,6 @@ std::uint8_t ElfReader::_readU8At(FileByteOffset fileByteOffset) const {
|
|||
}
|
||||
|
||||
std::uint16_t ElfReader::_readU16At(FileByteOffset fileByteOffset) const {
|
||||
_loadFileIntoBuffer();
|
||||
if (fileByteOffset + 2 > _fileBuffer.size()) {
|
||||
throw RelinkerException("FileByteOffset out of bounds", fileByteOffset);
|
||||
}
|
||||
|
|
@ -46,7 +30,6 @@ std::uint16_t ElfReader::_readU16At(FileByteOffset fileByteOffset) const {
|
|||
}
|
||||
|
||||
std::uint32_t ElfReader::_readU32At(FileByteOffset fileByteOffset) const {
|
||||
_loadFileIntoBuffer();
|
||||
if (fileByteOffset + 4 > _fileBuffer.size()) {
|
||||
throw RelinkerException("FileByteOffset out of bounds", fileByteOffset);
|
||||
}
|
||||
|
|
@ -56,7 +39,6 @@ std::uint32_t ElfReader::_readU32At(FileByteOffset fileByteOffset) const {
|
|||
}
|
||||
|
||||
std::uint64_t ElfReader::_readU64At(FileByteOffset fileByteOffset) const {
|
||||
_loadFileIntoBuffer();
|
||||
if (fileByteOffset + 8 > _fileBuffer.size()) {
|
||||
throw RelinkerException("FileByteOffset out of bounds", fileByteOffset);
|
||||
}
|
||||
|
|
@ -66,17 +48,15 @@ std::uint64_t ElfReader::_readU64At(FileByteOffset fileByteOffset) const {
|
|||
}
|
||||
|
||||
ElfHeader ElfReader::ReadHeader() const {
|
||||
_loadFileIntoBuffer();
|
||||
|
||||
if (_fileBuffer.size() < 20) {
|
||||
throw RelinkerException("File too small for ELF header");
|
||||
}
|
||||
|
||||
if (_fileBuffer[0] != 0x7f || _fileBuffer[1] != 'E' ||
|
||||
|
||||
if (_fileBuffer[0] != 0x7f || _fileBuffer[1] != 'E' ||
|
||||
_fileBuffer[2] != 'L' || _fileBuffer[3] != 'F') {
|
||||
throw RelinkerException("Invalid ELF magic number");
|
||||
}
|
||||
|
||||
|
||||
ElfHeader header{};
|
||||
header.Machine = _readU16At(0x12);
|
||||
header.Type = _readU16At(0x10);
|
||||
|
|
@ -95,7 +75,6 @@ ElfHeader ElfReader::ReadHeader() const {
|
|||
}
|
||||
|
||||
std::vector<ProgramHeader> ElfReader::ReadProgramHeaders() const {
|
||||
_loadFileIntoBuffer();
|
||||
const ElfHeader header = ReadHeader();
|
||||
|
||||
std::vector<ProgramHeader> headers;
|
||||
|
|
@ -120,7 +99,6 @@ std::vector<ProgramHeader> ElfReader::ReadProgramHeaders() const {
|
|||
}
|
||||
|
||||
std::vector<SectionHeader> ElfReader::ReadSectionHeaders() const {
|
||||
_loadFileIntoBuffer();
|
||||
const ElfHeader header = ReadHeader();
|
||||
|
||||
std::vector<SectionHeader> headers;
|
||||
|
|
@ -169,8 +147,6 @@ std::string ElfReader::_resolveShdrName(std::uint32_t nameOffset, const ElfHeade
|
|||
}
|
||||
|
||||
std::vector<DynamicTag> ElfReader::ReadDynamicTags(const ProgramHeader& dynamicHeader) const {
|
||||
_loadFileIntoBuffer();
|
||||
|
||||
std::vector<DynamicTag> tags;
|
||||
FileByteOffset offset = dynamicHeader.Offset;
|
||||
const FileByteOffset end = dynamicHeader.Offset + dynamicHeader.FileSize;
|
||||
|
|
@ -192,7 +168,6 @@ std::vector<DynamicTag> ElfReader::ReadDynamicTags(const ProgramHeader& dynamicH
|
|||
}
|
||||
|
||||
FileByteOffset ElfReader::TranslateVirtualAddress(VirtualAddress address) const {
|
||||
_loadFileIntoBuffer();
|
||||
const ElfHeader header = ReadHeader();
|
||||
|
||||
FileByteOffset offset = header.ProgramHeaderOffset;
|
||||
|
|
@ -216,29 +191,26 @@ FileByteOffset ElfReader::TranslateVirtualAddress(VirtualAddress address) const
|
|||
}
|
||||
|
||||
std::vector<std::uint8_t> ElfReader::ReadSection(const SectionHeader& header) const {
|
||||
_loadFileIntoBuffer();
|
||||
|
||||
if (header.Offset + header.SectionSize > _fileBuffer.size()) {
|
||||
throw RelinkerException("Section offset out of bounds", header.Offset);
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> data(_fileBuffer.begin() + header.Offset, _fileBuffer.begin() + header.Offset + header.SectionSize);
|
||||
return data;
|
||||
return std::vector<std::uint8_t>(
|
||||
_fileBuffer.begin() + header.Offset,
|
||||
_fileBuffer.begin() + header.Offset + header.SectionSize);
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> ElfReader::ReadSegment(const ProgramHeader& header) const {
|
||||
_loadFileIntoBuffer();
|
||||
|
||||
if (header.Offset + header.FileSize > _fileBuffer.size()) {
|
||||
throw RelinkerException("Segment offset out of bounds", header.Offset);
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> data(_fileBuffer.begin() + header.Offset, _fileBuffer.begin() + header.Offset + header.FileSize);
|
||||
return data;
|
||||
return std::vector<std::uint8_t>(
|
||||
_fileBuffer.begin() + header.Offset,
|
||||
_fileBuffer.begin() + header.Offset + header.FileSize);
|
||||
}
|
||||
|
||||
std::uint64_t ElfReader::GetFileSize() const {
|
||||
_loadFileIntoBuffer();
|
||||
return _fileBuffer.size();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#include <relinker/pipeline/RelinkerPipeline.hpp>
|
||||
#include <relinker/analysis/ValidationPolicy.hpp>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
|
@ -14,8 +13,7 @@ RelinkerPipeline::RelinkerPipeline(
|
|||
std::shared_ptr<ICallSiteResolver> callSiteResolver,
|
||||
std::shared_ptr<IValidationPolicy> validationPolicy,
|
||||
std::shared_ptr<ISysVDynamicSectionBuilder> dynamicSectionBuilder,
|
||||
std::shared_ptr<ICallRegistryWriter> callRegistryWriter,
|
||||
std::shared_ptr<IElfPatcher> elfPatcher)
|
||||
std::shared_ptr<ICallRegistryWriter> callRegistryWriter)
|
||||
: _elfReader(std::move(elfReader))
|
||||
, _dynlibParser(std::move(dynlibParser))
|
||||
, _syscallScanner(std::move(syscallScanner))
|
||||
|
|
@ -23,7 +21,6 @@ RelinkerPipeline::RelinkerPipeline(
|
|||
, _validationPolicy(std::move(validationPolicy))
|
||||
, _dynamicSectionBuilder(std::move(dynamicSectionBuilder))
|
||||
, _callRegistryWriter(std::move(callRegistryWriter))
|
||||
, _elfPatcher(std::move(elfPatcher))
|
||||
{}
|
||||
|
||||
std::string RelinkerPipeline::_relocationTypeName(std::uint32_t type) {
|
||||
|
|
@ -40,18 +37,7 @@ std::string RelinkerPipeline::_relocationTypeName(std::uint32_t type) {
|
|||
}
|
||||
}
|
||||
|
||||
void RelinkerPipeline::_writeFile(const std::string& path, const std::string& content) const {
|
||||
std::ofstream f(path);
|
||||
if (!f)
|
||||
throw RelinkerException("Cannot open output file: " + path);
|
||||
f << content;
|
||||
}
|
||||
|
||||
void RelinkerPipeline::Run(
|
||||
const std::string& inputElfPath,
|
||||
const std::string& outputRegistryPath,
|
||||
const std::string& outputElfPath)
|
||||
{
|
||||
RelinkResult RelinkerPipeline::Relink(const std::vector<std::uint8_t>& sourceElf) {
|
||||
auto programHeaders = _elfReader->ReadProgramHeaders();
|
||||
|
||||
std::vector<std::uint8_t> sceDynlibData;
|
||||
|
|
@ -128,11 +114,7 @@ void RelinkerPipeline::Run(
|
|||
_validationPolicy->ValidateNidBelongsToLibrary(ref.Nid, ref.Library);
|
||||
}
|
||||
} else if (dynStrTabOffset != 0) {
|
||||
std::ifstream wholeFile(inputElfPath, std::ios::binary | std::ios::ate);
|
||||
const std::streamsize wholeSize = wholeFile.tellg();
|
||||
wholeFile.seekg(0);
|
||||
std::vector<std::uint8_t> raw(static_cast<std::size_t>(wholeSize));
|
||||
wholeFile.read(reinterpret_cast<char*>(raw.data()), wholeSize);
|
||||
const std::vector<std::uint8_t>& raw = _elfReader->GetRawBytes();
|
||||
|
||||
auto readCStr = [&](FileByteOffset strOff) -> std::string {
|
||||
std::string result;
|
||||
|
|
@ -142,7 +124,7 @@ void RelinkerPipeline::Run(
|
|||
return result;
|
||||
};
|
||||
|
||||
for (auto&[fst, snd] : neededLibraryNamesByStrOffset) {
|
||||
for (auto& [fst, snd] : neededLibraryNamesByStrOffset) {
|
||||
snd = readCStr(fst);
|
||||
neededLibraries.push_back(snd);
|
||||
if (policy) policy->RegisterLibraryImport(snd);
|
||||
|
|
@ -220,12 +202,9 @@ void RelinkerPipeline::Run(
|
|||
entries.push_back(std::move(entry));
|
||||
}
|
||||
|
||||
_writeFile(outputRegistryPath, _callRegistryWriter->WriteCallRegistry(entries));
|
||||
_elfPatcher->PatchAndWrite(inputElfPath, outputElfPath, programHeaders, dynSection);
|
||||
|
||||
std::cout << "OK: " << entries.size() << " NID references processed\n";
|
||||
std::cout << "Registry: " << outputRegistryPath << "\n";
|
||||
std::cout << "Output ELF: " << outputElfPath << "\n";
|
||||
|
||||
return RelinkResult{std::move(entries), std::move(programHeaders), std::move(dynSection)};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue