diff --git a/README.md b/README.md index 38a4c2952..b715749ec 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/core/elfpatcher/include/elfpatcher/general/ElfConstants.hpp b/core/elfpatcher/include/elfpatcher/general/ElfConstants.hpp index f5b63794e..22f3a7e81 100644 --- a/core/elfpatcher/include/elfpatcher/general/ElfConstants.hpp +++ b/core/elfpatcher/include/elfpatcher/general/ElfConstants.hpp @@ -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; diff --git a/core/elfpatcher/include/elfpatcher/general/IElfPatcher.hpp b/core/elfpatcher/include/elfpatcher/general/IElfPatcher.hpp index e7c2996e7..81e9cd155 100644 --- a/core/elfpatcher/include/elfpatcher/general/IElfPatcher.hpp +++ b/core/elfpatcher/include/elfpatcher/general/IElfPatcher.hpp @@ -3,6 +3,7 @@ #include #include +#include #include namespace Elfpatcher { @@ -15,7 +16,8 @@ public: const std::vector& sourceElf, const std::vector& originalHeaders, const Domain::SysVDynamicSection& dynamicSection, - std::uint64_t originalPltGotVaddr + std::uint64_t originalPltGotVaddr, + const std::string& runPath ) = 0; }; diff --git a/core/elfpatcher/include/elfpatcher/linux/LinuxElfPatcher.hpp b/core/elfpatcher/include/elfpatcher/linux/LinuxElfPatcher.hpp index c81e380f9..1fbb10853 100644 --- a/core/elfpatcher/include/elfpatcher/linux/LinuxElfPatcher.hpp +++ b/core/elfpatcher/include/elfpatcher/linux/LinuxElfPatcher.hpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace Elfpatcher::Linux { @@ -23,7 +24,8 @@ public: const std::vector& sourceElf, const std::vector& originalHeaders, const Domain::SysVDynamicSection& dynamicSection, - std::uint64_t originalPltGotVaddr + std::uint64_t originalPltGotVaddr, + const std::string& runPath ) override; private: diff --git a/core/elfpatcher/include/elfpatcher/windows/WindowsElfPatcher.hpp b/core/elfpatcher/include/elfpatcher/windows/WindowsElfPatcher.hpp index 5cc46fa6b..96cb58235 100644 --- a/core/elfpatcher/include/elfpatcher/windows/WindowsElfPatcher.hpp +++ b/core/elfpatcher/include/elfpatcher/windows/WindowsElfPatcher.hpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace Elfpatcher::Windows { @@ -23,7 +24,8 @@ public: const std::vector& sourceElf, const std::vector& originalHeaders, const Domain::SysVDynamicSection& dynamicSection, - std::uint64_t originalPltGotVaddr + std::uint64_t originalPltGotVaddr, + const std::string& runPath ) override; private: diff --git a/core/elfpatcher/src/linux/LinuxElfPatcher.cpp b/core/elfpatcher/src/linux/LinuxElfPatcher.cpp index 50a287def..e8fb1cb50 100644 --- a/core/elfpatcher/src/linux/LinuxElfPatcher.cpp +++ b/core/elfpatcher/src/linux/LinuxElfPatcher.cpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace Elfpatcher::Linux { @@ -27,7 +28,8 @@ std::vector LinuxElfPatcher::Patch( const std::vector& sourceElf, const std::vector& originalHeaders, const Domain::SysVDynamicSection& dynSection, - const std::uint64_t originalPltGotVaddr) + const std::uint64_t originalPltGotVaddr, + const std::string& runPath) { std::vector buf = sourceElf; @@ -51,6 +53,10 @@ std::vector LinuxElfPatcher::Patch( const auto dynStrOff = static_cast(buf.size()); for (std::uint8_t b : dynSection.DynStrData) buf.push_back(b); + const std::uint64_t runPathStrOff = static_cast(buf.size()) - dynStrOff; + for (char c : runPath) + buf.push_back(static_cast(c)); + buf.push_back(0); alignBuf(buf, kDynStrAlignment); const auto dynSymOff = static_cast(buf.size()); @@ -95,6 +101,7 @@ std::vector LinuxElfPatcher::Patch( _appendDynEntry(dynSegBuf, DT_PLTREL, static_cast(DT_RELA)); _appendDynEntry(dynSegBuf, DT_PLTGOT, originalPltGotVaddr); } + _appendDynEntry(dynSegBuf, DT_RUNPATH, runPathStrOff); _appendDynEntry(dynSegBuf, DT_NULL, 0); const auto dynSegOff = static_cast(buf.size()); diff --git a/core/elfpatcher/src/windows/WindowsElfPatcher.cpp b/core/elfpatcher/src/windows/WindowsElfPatcher.cpp index 8f46d5dd4..bb85c5868 100644 --- a/core/elfpatcher/src/windows/WindowsElfPatcher.cpp +++ b/core/elfpatcher/src/windows/WindowsElfPatcher.cpp @@ -20,7 +20,8 @@ std::vector WindowsElfPatcher::Patch( const std::vector& sourceElf, const std::vector& originalHeaders, const Domain::SysVDynamicSection& dynamicSection, - std::uint64_t originalPltGotVaddr) + std::uint64_t originalPltGotVaddr, + const std::string& runPath) { throw Domain::RelinkerException("Not implemented"); } diff --git a/core/main.cpp b/core/main.cpp index 841672ff1..ef5c1bfc6 100644 --- a/core/main.cpp +++ b/core/main.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -26,6 +27,7 @@ int main(const int argc, char* argv[]) { std::string inputPath; std::string outputElfPath; std::optional 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] [output_registry.json]\n"; + std::cerr << "Usage: relinker [--skip-syscall-check] [--to-intel] [--rpath ] [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(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) {