From abc07a1192c0bed708fc71a4e1f68f309dbffb2b Mon Sep 17 00:00:00 2001 From: priyanshrv-netizen <275132450+priyanshrv-netizen@users.noreply.github.com> Date: Tue, 20 Oct 2026 23:09:52 +0530 Subject: [PATCH] feat(libc): implement _Vacopy Copy the 24-byte System V argument list, writing the overflow pointer before the register offsets as the console's libc.prx does. Co-Authored-By: Claude Opus 5 (1M context) --- core/libs/prx/libc/src/RuntimeSupport.cpp | 9 +++++++ core/libs/tests/GuestStdioVariadic.cpp | 31 +++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/core/libs/prx/libc/src/RuntimeSupport.cpp b/core/libs/prx/libc/src/RuntimeSupport.cpp index 02058dc4af..54d3ed0104 100644 --- a/core/libs/prx/libc/src/RuntimeSupport.cpp +++ b/core/libs/prx/libc/src/RuntimeSupport.cpp @@ -95,6 +95,15 @@ void APS5_VABI cxa_finalize_nid_postfix(void* dsoHandle) { CxaFinalize_nid_no_patch(dsoHandle); } +void APS5_VABI _Vacopy_nid_postfix(unsigned char* destination, const unsigned char* source) { + std::uint64_t overflowArea; + std::memcpy(&overflowArea, source + 16, sizeof(overflowArea)); + std::memcpy(destination + 16, &overflowArea, sizeof(overflowArea)); + unsigned char offsets[16]; + std::memcpy(offsets, source, sizeof(offsets)); + std::memcpy(destination, offsets, sizeof(offsets)); +} + unsigned int APS5_VABI _Atomic_fetch_add_4_nid_postfix(volatile unsigned int* target, unsigned int value, int memoryOrder) { (void)memoryOrder; return GccAtomicFetchAdd(target, value); diff --git a/core/libs/tests/GuestStdioVariadic.cpp b/core/libs/tests/GuestStdioVariadic.cpp index 62ead8be7f..7bc4ba7cdb 100644 --- a/core/libs/tests/GuestStdioVariadic.cpp +++ b/core/libs/tests/GuestStdioVariadic.cpp @@ -16,6 +16,7 @@ int APS5_VABI vfwprintf_nid_postfix(FileStream*, const char16_t*, void*); int APS5_VABI fwprintf_nid_postfix(FileStream*, const char16_t*, ...); int APS5_VABI vswscanf_nid_postfix(const char16_t*, const char16_t*, void*); int APS5_VABI vswscanf_s_nid_postfix(const char16_t*, const char16_t*, void*); +void APS5_VABI _Vacopy_nid_postfix(void*, const void*); } #ifdef _WIN32 @@ -67,6 +68,36 @@ static int APS5_VABI ScanWideSized(const char16_t* input, const char16_t* format return result; } +static long APS5_VABI SumThroughCopy(int count, ...) { + APS5_VA_BEGIN(count); + unsigned char before[24]; + std::memcpy(before, &args, sizeof(before)); +#ifdef _WIN32 + __builtin_sysv_va_list copy; +#else + std::va_list copy; +#endif + _Vacopy_nid_postfix(©, &args); + Require(std::memcmp(©, &args, sizeof(before)) == 0, "_Vacopy copies all 24 bytes"); + long sum = 0; + for (int index = 0; index < count; ++index) sum += __builtin_va_arg(copy, long) * (index + 1); + Require(std::memcmp(&args, before, sizeof(before)) == 0, "_Vacopy leaves the source untouched"); + for (int index = 0; index < count; ++index) sum -= __builtin_va_arg(args, long); + APS5_VA_END(); + return sum; +} + +static void CheckVacopy() { + long expected = 0; + for (long index = 1; index <= 9; ++index) expected += index * 100 * index - index * 100; + Require(SumThroughCopy(9, 100L, 200L, 300L, 400L, 500L, 600L, 700L, 800L, 900L) == expected, "_Vacopy copy reads every argument"); + unsigned char overlap[32]; + for (int index = 0; index < 32; ++index) overlap[index] = static_cast(index); + _Vacopy_nid_postfix(overlap + 8, overlap); + const unsigned char shifted[32] = {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; + Require(std::memcmp(overlap, shifted, sizeof(overlap)) == 0, "_Vacopy copies the overflow area before the offsets"); +} + static std::string Contents(FileStream& stream) { std::fflush(stream.GetHandle()); std::rewind(stream.GetHandle());