fix(libs): fix args sysv abi for types (windows)

This commit is contained in:
boykopovar 2026-09-10 19:54:03 +03:00
parent d23e1ca84e
commit b765cefa42
5 changed files with 29 additions and 13 deletions

View File

@ -37,9 +37,11 @@ void patchAccess(std::vector<PeSection>& sections, const TlsAccess& access, cons
PeDirectory WindowsTlsBuilder::Build(const std::vector<std::uint8_t>& source, const std::vector<Domain::ProgramHeader>& headers, const WindowsLoadImage& image, std::vector<PeSection>& sections, std::vector<std::uint32_t>& relocations, std::uint32_t& nextRva) const {
const Domain::ProgramHeader* tls = nullptr;
const Codegen::X64InstructionDecoder decoder;
std::vector<TlsAccess> accesses;
std::set<std::uint32_t> 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<std::uint8_t>& 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<std::int64_t>(rva) + static_cast<std::int64_t>(info.Length) + info.BranchDisp;
if (target >= 0 && target <= std::numeric_limits<std::uint32_t>::max())
branchTargets.insert(static_cast<std::uint32_t>(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<std::uint8_t>& 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<std::uint64_t>(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<std::uint8_t>(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<std::uint8_t>& 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::uint32_t>(std::bit_width(alignment)) << 20);
const PeDirectory directory{data.Rva, 40};
sections.push_back(std::move(data));

View File

@ -4,6 +4,7 @@
#include <cstddef>
#include <cstdint>
#include <cstdio>
#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;

View File

@ -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<UltQueueState>* out) {
return ULT_OK;
}
void* ulthreadRunner(void* arg) {
void* APS5_VABI ulthreadRunner(void* arg) {
auto* state = static_cast<UltUlthreadState*>(arg);
return reinterpret_cast<void*>(static_cast<std::intptr_t>(state->_entry(state->_arg)));
}

View File

@ -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<PthreadPrivate>();
bool detached = false;

View File

@ -3,18 +3,18 @@
#include <iostream>
#include <stdexcept>
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<void> checked;
};
static void* CheckThread(void* arg) {
static void* APS5_VABI CheckThread(void* arg) {
auto& context = *static_cast<ThreadContext*>(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");