From b765cefa4276fe8b5a98d01bb07dabd22b49fdf6 Mon Sep 17 00:00:00 2001 From: boykopovar Date: Thu, 10 Sep 2026 19:54:03 +0300 Subject: [PATCH] fix(libs): fix args sysv abi for types (windows) --- .../elfpatcher/src/windows/WindowsTlsBuilder.cpp | 16 +++++++++++++++- core/libs/SceTypes.hpp | 4 +++- core/libs/prx/libSceUlt/Export.cpp | 6 +++--- core/libs/prx/libkernel/Pthread/Pthread.cpp | 4 ++-- core/libs/tests/PthreadStart.cpp | 12 ++++++------ 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/core/elfpatcher/src/windows/WindowsTlsBuilder.cpp b/core/elfpatcher/src/windows/WindowsTlsBuilder.cpp index d674fcf0e..5b7f81ad8 100644 --- a/core/elfpatcher/src/windows/WindowsTlsBuilder.cpp +++ b/core/elfpatcher/src/windows/WindowsTlsBuilder.cpp @@ -37,9 +37,11 @@ void patchAccess(std::vector& sections, const TlsAccess& access, cons PeDirectory WindowsTlsBuilder::Build(const std::vector& source, const std::vector& headers, const WindowsLoadImage& image, std::vector& sections, std::vector& relocations, std::uint32_t& nextRva) const { const Domain::ProgramHeader* tls = nullptr; + const Codegen::X64InstructionDecoder decoder; + std::vector accesses; std::set branchTargets; - const Codegen::X64InstructionDecoder decoder; + for (const auto& header : headers) { if (header.Type == 7) { if (tls != nullptr) @@ -52,11 +54,13 @@ PeDirectory WindowsTlsBuilder::Build(const std::vector& source, co const auto* bytes = source.data() + header.Offset + offset; const auto info = decoder.DecodeInstruction(bytes, header.FileSize - offset); const auto rva = image.GetRva(header.MappedAddress + offset, info.Length); + if (info.HasBranchTarget && !info.HasRipRelativeDisp) { const auto target = static_cast(rva) + static_cast(info.Length) + info.BranchDisp; if (target >= 0 && target <= std::numeric_limits::max()) branchTargets.insert(static_cast(target)); } + if (info.SegmentPrefix != 0) { const auto position = info.OpcodeOffset; if (info.SegmentPrefix != 0x64 || info.RexPrefix != 0x48 || info.Length - position != 7 || bytes[position] != 0x8b || bytes[position + 1] != 0x04 || bytes[position + 2] != 0x25 || Io::ReadU32(source, header.Offset + offset + position + 3) != 0) @@ -66,36 +70,43 @@ PeDirectory WindowsTlsBuilder::Build(const std::vector& source, co offset += info.Length; } } + if (tls == nullptr) { if (!accesses.empty()) throw Domain::RelinkerException("Guest TLS access without PT_TLS"); return {}; } + if (tls->MemorySize == 0 || tls->FileSize > tls->MemorySize || tls->Offset > source.size() || tls->FileSize > source.size() - tls->Offset || !std::has_single_bit(tls->Alignment) || tls->Alignment > 8192 || tls->MemorySize > 0x7fff0000u) throw Domain::RelinkerException("Invalid or unsupported ELF TLS layout", tls->Offset); const auto alignment = std::max(tls->Alignment, 16); const auto blockSize = CheckedRva((tls->MemorySize + alignment - 1) & ~(alignment - 1)); const auto templateOffset = CheckedRva((64 + alignment - 1) & ~(alignment - 1)); PeSection data{".gtls", nextRva, SectionRead | SectionWrite | 0x40u, std::vector(templateOffset + blockSize + 16)}; + const auto indexRva = nextRva + 40; const auto callbackTableRva = nextRva + 48; const auto templateRva = nextRva + templateOffset; const auto codeRva = AlignRva(nextRva + data.Data.size()); + WindowsStubEmitter code(codeRva); const auto loadPointer = [&] { code.Rip({0x8b, 0x0d}, indexRva); code.Emit({0x65, 0x48, 0x8b, 0x04, 0x25, 0x58, 0, 0, 0, 0x48, 0x8b, 0x04, 0xc8, 0x48, 0x8d, 0x80}); code.U32(blockSize); }; + code.Emit({0x83, 0xfa, 1}); const auto processAttach = code.Branch({0x0f, 0x84}); code.Emit({0x83, 0xfa, 2}); const auto skipCallback = code.Branch({0x0f, 0x85}); code.PatchBranch(processAttach, code.GetRva()); loadPointer(); + code.Emit({0x48, 0x89, 0x00}); code.PatchBranch(skipCallback, code.GetRva()); code.Emit({0xc3}); + for (const auto& access : accesses) { const auto target = branchTargets.upper_bound(access.Rva); if (target != branchTargets.end() && *target < access.Rva + access.Length) @@ -106,16 +117,19 @@ PeDirectory WindowsTlsBuilder::Build(const std::vector& source, co code.Emit({0x59, 0x48, 0x8d, 0xa4, 0x24, 0x80, 0, 0, 0}); code.Rip({0xe9}, CheckedRva(access.Rva + access.Length)); } + std::copy_n(source.begin() + tls->Offset, tls->FileSize, data.Data.begin() + templateOffset); const auto writeAddress = [&](const std::size_t offset, const std::uint32_t rva) { Io::WriteU64(data.Data, offset, ImageBase + rva); relocations.push_back(CheckedRva(data.Rva + offset)); }; + writeAddress(0, templateRva); writeAddress(8, CheckedRva(templateRva + blockSize + 16)); writeAddress(16, indexRva); writeAddress(24, callbackTableRva); writeAddress(48, codeRva); + Io::WriteU32(data.Data, 36, static_cast(std::bit_width(alignment)) << 20); const PeDirectory directory{data.Rva, 40}; sections.push_back(std::move(data)); diff --git a/core/libs/SceTypes.hpp b/core/libs/SceTypes.hpp index 338c653ce..9fa85e725 100644 --- a/core/libs/SceTypes.hpp +++ b/core/libs/SceTypes.hpp @@ -4,6 +4,7 @@ #include #include #include +#include "prx/libc/include/general/VabiMacros.hpp" #if defined(__GNUC__) || defined(__clang__) typedef float __m128 __attribute__((__vector_size__(16), __aligned__(16))); @@ -161,6 +162,7 @@ struct PthreadCondPrivate; using KernelSema = KernelSemaPrivate*; using KernelEventFlag = KernelEventFlagPrivate*; using Pthread = PthreadPrivate*; +using PthreadEntry = void* (APS5_VABI *)(void*); using PthreadAttr = PthreadAttrPrivate*; using PthreadMutex = PthreadMutexPrivate*; using PthreadMutexattr = PthreadMutexattrPrivate*; @@ -1882,7 +1884,7 @@ struct UltMutexOptParam { struct UltUlthreadRuntimeOptParam { std::uint8_t bytes[128]; }; -using UltUlthreadEntry = std::int32_t (*)(std::uint64_t); +using UltUlthreadEntry = std::int32_t (APS5_VABI *)(std::uint64_t); struct VideoOutBufferAttribute2 { std::uint32_t reserved0; diff --git a/core/libs/prx/libSceUlt/Export.cpp b/core/libs/prx/libSceUlt/Export.cpp index 013d84886..ce49fcc2c 100644 --- a/core/libs/prx/libSceUlt/Export.cpp +++ b/core/libs/prx/libSceUlt/Export.cpp @@ -13,8 +13,8 @@ #include "prx/libc/include/General.hpp" #include "SceUltTypes.hpp" -extern "C" int scePthreadCreate(Pthread* thread, const PthreadAttr* attr, void* (*entry)(void*), void* arg, const char* name); -extern "C" int scePthreadJoin(Pthread thread, void** retval); +extern "C" int APS5_VABI scePthreadCreate(Pthread* thread, const PthreadAttr* attr, PthreadEntry entry, void* arg, const char* name); +extern "C" int APS5_VABI scePthreadJoin(Pthread thread, void** retval); namespace { @@ -52,7 +52,7 @@ int queueGetState(void* queue, std::shared_ptr* out) { return ULT_OK; } -void* ulthreadRunner(void* arg) { +void* APS5_VABI ulthreadRunner(void* arg) { auto* state = static_cast(arg); return reinterpret_cast(static_cast(state->_entry(state->_arg))); } diff --git a/core/libs/prx/libkernel/Pthread/Pthread.cpp b/core/libs/prx/libkernel/Pthread/Pthread.cpp index d4bf4ba74..98b39971f 100644 --- a/core/libs/prx/libkernel/Pthread/Pthread.cpp +++ b/core/libs/prx/libkernel/Pthread/Pthread.cpp @@ -33,7 +33,7 @@ static constexpr int DETACH_DETACHED = 1; static constexpr int SCHED_FIFO_PS5 = 1; struct ThreadArgs { - void* (*entry)(void*); + PthreadEntry entry; void* arg; PthreadPrivate* self; }; @@ -253,7 +253,7 @@ int APS5_VABI scePthreadAttrGet(Pthread thread, PthreadAttr* attr) { return SCE_OK; } -int APS5_VABI scePthreadCreate(Pthread* thread, const PthreadAttr* attr, void* (*entry)(void*), void* arg, const char*) { +int APS5_VABI scePthreadCreate(Pthread* thread, const PthreadAttr* attr, PthreadEntry entry, void* arg, const char*) { if (!thread || !entry) throw std::runtime_error("scePthreadCreate: null arg"); auto p = std::make_unique(); bool detached = false; diff --git a/core/libs/tests/PthreadStart.cpp b/core/libs/tests/PthreadStart.cpp index 6eb686c22..520b2b29b 100644 --- a/core/libs/tests/PthreadStart.cpp +++ b/core/libs/tests/PthreadStart.cpp @@ -3,18 +3,18 @@ #include #include -extern "C" int scePthreadCreate(Pthread* thread, const PthreadAttr* attr, void* (*entry)(void*), void* arg, const char* name); -extern "C" int scePthreadJoin(Pthread thread, void** retval); -extern "C" int scePthreadAttrInit(PthreadAttr* attr); -extern "C" int scePthreadAttrDestroy(PthreadAttr* attr); -extern "C" int scePthreadAttrGet(Pthread thread, PthreadAttr* attr); +extern "C" int APS5_VABI scePthreadCreate(Pthread* thread, const PthreadAttr* attr, PthreadEntry entry, void* arg, const char* name); +extern "C" int APS5_VABI scePthreadJoin(Pthread thread, void** retval); +extern "C" int APS5_VABI scePthreadAttrInit(PthreadAttr* attr); +extern "C" int APS5_VABI scePthreadAttrDestroy(PthreadAttr* attr); +extern "C" int APS5_VABI scePthreadAttrGet(Pthread thread, PthreadAttr* attr); struct ThreadContext { Pthread thread = nullptr; std::promise checked; }; -static void* CheckThread(void* arg) { +static void* APS5_VABI CheckThread(void* arg) { auto& context = *static_cast(arg); if (!context.thread) throw std::runtime_error("Thread handle was not published"); if (context.thread->_thr.get_id() != std::this_thread::get_id()) throw std::runtime_error("Thread object was not initialized");