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) <[email protected]>
This commit is contained in:
priyanshrv-netizenandClaude Opus 5 committed 2026-10-20 23:09:52 +05:30
1 parent 0b1d678fe5
commit abc07a1192
2 files changed
+40

No files matched your search

@@ -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);
+31
View File
@@ -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(&copy, &args);
Require(std::memcmp(&copy, &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<unsigned char>(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());