feat(elfpatcher): add dt_runpath libs/ support with configurable --rpath flag
This commit is contained in:
parent
f786ea6576
commit
dd2481951d
|
|
@ -4,8 +4,7 @@ Converter for native execution of PlayStation 5 ELF binaries on Linux through bi
|
|||
|
||||
## Status
|
||||
|
||||
Output ELF is accepted by the Linux kernel and handed to ld.so. Crashes during ld.so startup:
|
||||
e_entry contains a file offset instead of a virtual address, causing an invalid jump at loader handoff.
|
||||
Loader startup works: execution reaches `_start` and runs normally up to the first call into an external library function (from test `.prx` stubs).
|
||||
|
||||
## Disclaimer
|
||||
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ inline constexpr std::int64_t DT_STRSZ = 10;
|
|||
inline constexpr std::int64_t DT_SYMENT = 11;
|
||||
inline constexpr std::int64_t DT_PLTREL = 20;
|
||||
inline constexpr std::int64_t DT_JMPREL = 23;
|
||||
inline constexpr std::int64_t DT_RUNPATH = 29;
|
||||
|
||||
inline constexpr std::uint32_t SHT_NULL = 0;
|
||||
inline constexpr std::uint32_t SHT_PROGBITS = 1;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <domain/Types.hpp>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Elfpatcher {
|
||||
|
|
@ -15,7 +16,8 @@ public:
|
|||
const std::vector<std::uint8_t>& sourceElf,
|
||||
const std::vector<Domain::ProgramHeader>& originalHeaders,
|
||||
const Domain::SysVDynamicSection& dynamicSection,
|
||||
std::uint64_t originalPltGotVaddr
|
||||
std::uint64_t originalPltGotVaddr,
|
||||
const std::string& runPath
|
||||
) = 0;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <elfpatcher/general/ISectionHeaderTableBuilder.hpp>
|
||||
#include <io/IByteWriter.hpp>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace Elfpatcher::Linux {
|
||||
|
||||
|
|
@ -23,7 +24,8 @@ public:
|
|||
const std::vector<std::uint8_t>& sourceElf,
|
||||
const std::vector<Domain::ProgramHeader>& originalHeaders,
|
||||
const Domain::SysVDynamicSection& dynamicSection,
|
||||
std::uint64_t originalPltGotVaddr
|
||||
std::uint64_t originalPltGotVaddr,
|
||||
const std::string& runPath
|
||||
) override;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <elfpatcher/general/ISectionHeaderTableBuilder.hpp>
|
||||
#include <io/IByteWriter.hpp>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace Elfpatcher::Windows {
|
||||
|
||||
|
|
@ -23,7 +24,8 @@ public:
|
|||
const std::vector<std::uint8_t>& sourceElf,
|
||||
const std::vector<Domain::ProgramHeader>& originalHeaders,
|
||||
const Domain::SysVDynamicSection& dynamicSection,
|
||||
std::uint64_t originalPltGotVaddr
|
||||
std::uint64_t originalPltGotVaddr,
|
||||
const std::string& runPath
|
||||
) override;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include <elfpatcher/general/ElfConstants.hpp>
|
||||
#include <elfpatcher/general/ProgramHeaderLayoutRequest.hpp>
|
||||
#include <elfpatcher/general/SectionHeaderTableRequest.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace Elfpatcher::Linux {
|
||||
|
||||
|
|
@ -27,7 +28,8 @@ std::vector<std::uint8_t> LinuxElfPatcher::Patch(
|
|||
const std::vector<std::uint8_t>& sourceElf,
|
||||
const std::vector<Domain::ProgramHeader>& originalHeaders,
|
||||
const Domain::SysVDynamicSection& dynSection,
|
||||
const std::uint64_t originalPltGotVaddr)
|
||||
const std::uint64_t originalPltGotVaddr,
|
||||
const std::string& runPath)
|
||||
{
|
||||
std::vector<std::uint8_t> buf = sourceElf;
|
||||
|
||||
|
|
@ -51,6 +53,10 @@ std::vector<std::uint8_t> LinuxElfPatcher::Patch(
|
|||
const auto dynStrOff = static_cast<std::uint64_t>(buf.size());
|
||||
for (std::uint8_t b : dynSection.DynStrData)
|
||||
buf.push_back(b);
|
||||
const std::uint64_t runPathStrOff = static_cast<std::uint64_t>(buf.size()) - dynStrOff;
|
||||
for (char c : runPath)
|
||||
buf.push_back(static_cast<std::uint8_t>(c));
|
||||
buf.push_back(0);
|
||||
alignBuf(buf, kDynStrAlignment);
|
||||
|
||||
const auto dynSymOff = static_cast<std::uint64_t>(buf.size());
|
||||
|
|
@ -95,6 +101,7 @@ std::vector<std::uint8_t> LinuxElfPatcher::Patch(
|
|||
_appendDynEntry(dynSegBuf, DT_PLTREL, static_cast<std::uint64_t>(DT_RELA));
|
||||
_appendDynEntry(dynSegBuf, DT_PLTGOT, originalPltGotVaddr);
|
||||
}
|
||||
_appendDynEntry(dynSegBuf, DT_RUNPATH, runPathStrOff);
|
||||
_appendDynEntry(dynSegBuf, DT_NULL, 0);
|
||||
|
||||
const auto dynSegOff = static_cast<std::uint64_t>(buf.size());
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ std::vector<std::uint8_t> WindowsElfPatcher::Patch(
|
|||
const std::vector<std::uint8_t>& sourceElf,
|
||||
const std::vector<Domain::ProgramHeader>& originalHeaders,
|
||||
const Domain::SysVDynamicSection& dynamicSection,
|
||||
std::uint64_t originalPltGotVaddr)
|
||||
std::uint64_t originalPltGotVaddr,
|
||||
const std::string& runPath)
|
||||
{
|
||||
throw Domain::RelinkerException("Not implemented");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include <relinker/output/CallRegistryWriter.hpp>
|
||||
#include <relinker/pipeline/RelinkerPipeline.hpp>
|
||||
#include <codegen/IAmd64OnlyConverter.hpp>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
|
@ -26,6 +27,7 @@ int main(const int argc, char* argv[]) {
|
|||
std::string inputPath;
|
||||
std::string outputElfPath;
|
||||
std::optional<std::string> registryPath;
|
||||
std::string runPath = "$ORIGIN/libs";
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
const std::string arg = argv[i];
|
||||
|
|
@ -33,6 +35,12 @@ int main(const int argc, char* argv[]) {
|
|||
skipSyscallCheck = true;
|
||||
} else if (arg == "--to-intel") {
|
||||
toIntel = true;
|
||||
} else if (arg == "--rpath") {
|
||||
if (i + 1 >= argc) {
|
||||
std::cerr << "FAIL: --rpath requires a value\n";
|
||||
return 1;
|
||||
}
|
||||
runPath = argv[++i];
|
||||
} else if (inputPath.empty()) {
|
||||
inputPath = arg;
|
||||
} else if (outputElfPath.empty()) {
|
||||
|
|
@ -43,10 +51,17 @@ int main(const int argc, char* argv[]) {
|
|||
}
|
||||
|
||||
if (inputPath.empty() || outputElfPath.empty()) {
|
||||
std::cerr << "Usage: relinker [--skip-syscall-check] [--to-intel] <input.elf> <output.elf> [output_registry.json]\n";
|
||||
std::cerr << "Usage: relinker [--skip-syscall-check] [--to-intel] [--rpath <path>] <input.elf> <output.elf> [output_registry.json]\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
const std::filesystem::path outputElfFsPath(outputElfPath);
|
||||
const std::filesystem::path outputDir = outputElfFsPath.parent_path() / (outputElfFsPath.stem().string() + "_out");
|
||||
std::filesystem::create_directories(outputDir);
|
||||
outputElfPath = (outputDir / outputElfFsPath.filename()).string();
|
||||
if (registryPath.has_value())
|
||||
registryPath = (outputDir / std::filesystem::path(*registryPath).filename()).string();
|
||||
|
||||
try {
|
||||
Io::FileReader fileReader;
|
||||
Io::FileWriter fileWriter;
|
||||
|
|
@ -93,7 +108,7 @@ int main(const int argc, char* argv[]) {
|
|||
std::make_shared<Elfpatcher::SectionHeaderTableBuilder>(byteWriter),
|
||||
byteWriter
|
||||
);
|
||||
auto patchedElf = elfPatcher.Patch(sourceBytes, result.OriginalHeaders, result.DynamicSection, result.OriginalPltGotVaddr);
|
||||
auto patchedElf = elfPatcher.Patch(sourceBytes, result.OriginalHeaders, result.DynamicSection, result.OriginalPltGotVaddr, runPath);
|
||||
fileWriter.Write(outputElfPath, patchedElf);
|
||||
|
||||
} catch (const Domain::RelinkerException& e) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue