fix(libc): update locale signatures + add sysv abi to math funcs

This commit is contained in:
boykopovar 2026-09-24 22:57:49 +03:00
parent 2778c1e86e
commit 9a4c8eab8b
4 changed files with 94 additions and 63 deletions

View File

@ -12,9 +12,9 @@ Execution reaches `_start`, [stack unwinding](core/libs/prx/libc/src/exception/U
The [shader recompiler](core/shader/recompiler/Recompiler.cpp) successfully produces validated via [Spirv-Tools](3rdparty/SPIRV-Tools) SPIR-V.
The real game successfully presents the logo and loads the main menu, then crashes before the menu buttons appear.
The real game reaches the main menu, which renders correctly with buttons and audio.
Current error: Access Violation at ~frame 168.
Current stop: [libScePad](core/libs/prx/libScePad) does not record the input, so the button cannot be pressed.
## Build

View File

@ -8,6 +8,7 @@
#include <cstring>
#include <vector>
#include <array>
#include <limits>
#include "prx/libc/include/General.hpp"
#include "prx/libc/include/ApplicationHeap.hpp"
@ -50,14 +51,14 @@ constexpr std::array<short, 257> MakeClassificationTable() {
std::array<short, 257> table{};
for (unsigned int value = 0; value < 256; ++value) {
short mask = 0;
if (value < 32 || value == 127) mask |= 0x20;
if (value == ' ' || (value >= '\t' && value <= '\r')) mask |= 0x08;
if (value == ' ' || value == '\t') mask |= 0x40;
if (value >= 'A' && value <= 'Z') mask |= 0x101;
if (value >= 'a' && value <= 'z') mask |= 0x102;
if (value >= '0' && value <= '9') mask |= 0x04;
if ((value >= '0' && value <= '9') || (value >= 'A' && value <= 'F') || (value >= 'a' && value <= 'f')) mask |= 0x80;
if (value >= 33 && value <= 126 && (mask & 0x107) == 0) mask |= 0x10;
if (value < 32 || value == 127) mask |= 0x80;
if (value == ' ') mask |= 0x04;
if (value >= '\t' && value <= '\r') mask |= 0x40;
if (value >= 'A' && value <= 'Z') mask |= 0x02;
if (value >= 'a' && value <= 'z') mask |= 0x10;
if (value >= '0' && value <= '9') mask |= 0x20;
if ((value >= '0' && value <= '9') || (value >= 'A' && value <= 'F') || (value >= 'a' && value <= 'f')) mask |= 0x01;
if (value >= 33 && value <= 126 && (mask & 0x232) == 0) mask |= 0x08;
table[value + 1] = mask;
}
return table;
@ -102,11 +103,12 @@ void APS5_VABI _ZNSt8ios_baseD2Ev_nid_postfix(GuestLocale::IosBase* self) {
self->locale = nullptr;
}
void APS5_VABI _ZNSt6locale5_InitEv_nid_postfix() {
GuestLocale::Implementation* APS5_VABI _ZNSt6locale5_InitEv_nid_postfix() {
std::lock_guard<std::mutex> lock(g_localeInitMutex);
if (!g_localeInitialized) {
g_localeInitialized = true;
}
return &g_classicLocale;
}
void APS5_VABI _ZNSt6locale5facet9_RegisterEv_nid_postfix(GuestLocale::Facet* self) {
@ -135,25 +137,23 @@ void APS5_VABI _ZNSt8_LocinfoD1Ev_nid_postfix(GuestLocale::LocinfoStorage* self)
if (self == nullptr) throw std::invalid_argument("_Locinfo destructor: null object");
}
wchar_t* APS5_VABI _Mbtowcx_nid_postfix(wchar_t* dst, const char* src, std::size_t count, mbstate_t* st) {
while (count > 0) {
std::size_t result = std::mbrtowc(dst, src, count, st);
if (result == static_cast<std::size_t>(-1) || result == static_cast<std::size_t>(-2))
return nullptr;
if (result == 0)
return dst;
src += result;
count -= result;
++dst;
}
return dst;
int APS5_VABI _Mbtowcx_nid_postfix(std::uint16_t* dst, const char* src, std::size_t count, mbstate_t* st) {
if (dst == nullptr || src == nullptr || st == nullptr || count == 0) throw std::invalid_argument("_Mbtowcx: invalid conversion arguments");
wchar_t converted{};
const auto result = std::mbrtowc(&converted, src, count, st);
if (result == static_cast<std::size_t>(-1)) throw std::runtime_error("_Mbtowcx: invalid multibyte character");
if (result == static_cast<std::size_t>(-2)) throw std::runtime_error("_Mbtowcx: incomplete multibyte character");
if (result > static_cast<std::size_t>(std::numeric_limits<int>::max()) || static_cast<std::uint32_t>(converted) > 0xffff) throw std::runtime_error("_Mbtowcx: conversion exceeds guest character limits");
*dst = static_cast<std::uint16_t>(converted);
return static_cast<int>(result);
}
char* APS5_VABI _Wctombx_nid_postfix(char* dst, wchar_t src, mbstate_t* st) {
std::size_t result = std::wcrtomb(dst, src, st);
if (result == static_cast<std::size_t>(-1))
return nullptr;
return dst + result;
int APS5_VABI _Wctombx_nid_postfix(char* dst, std::uint16_t src, mbstate_t* st) {
if (dst == nullptr || st == nullptr) throw std::invalid_argument("_Wctombx: invalid conversion arguments");
const auto result = std::wcrtomb(dst, static_cast<wchar_t>(src), st);
if (result == static_cast<std::size_t>(-1)) throw std::runtime_error("_Wctombx: invalid wide character");
if (result > static_cast<std::size_t>(std::numeric_limits<int>::max())) throw std::runtime_error("_Wctombx: conversion size exceeds guest limits");
return static_cast<int>(result);
}
const short* APS5_VABI _Getpctype_nid_postfix() {

View File

@ -4,47 +4,47 @@
extern "C" {
double cbrt_nid_postfix(double x) { return std::cbrt(x); }
double asin_nid_postfix(double x) { return std::asin(x); }
double acos_nid_postfix(double x) { return std::acos(x); }
double exp_nid_postfix(double x) { return std::exp(x); }
double atan_nid_postfix(double x) { return std::atan(x); }
double tan_nid_postfix(double x) { return std::tan(x); }
double log2_nid_postfix(double x) { return std::log2(x); }
double log_nid_postfix(double x) { return std::log(x); }
double APS5_VABI cbrt_nid_postfix(double x) { return std::cbrt(x); }
double APS5_VABI asin_nid_postfix(double x) { return std::asin(x); }
double APS5_VABI acos_nid_postfix(double x) { return std::acos(x); }
double APS5_VABI exp_nid_postfix(double x) { return std::exp(x); }
double APS5_VABI atan_nid_postfix(double x) { return std::atan(x); }
double APS5_VABI tan_nid_postfix(double x) { return std::tan(x); }
double APS5_VABI log2_nid_postfix(double x) { return std::log2(x); }
double APS5_VABI log_nid_postfix(double x) { return std::log(x); }
float sinf_nid_postfix(float x) { return std::sin(x); }
float cosf_nid_postfix(float x) { return std::cos(x); }
float APS5_VABI sinf_nid_postfix(float x) { return std::sin(x); }
float APS5_VABI cosf_nid_postfix(float x) { return std::cos(x); }
void APS5_VABI sincosf_nid_postfix(float x, float* sinp, float* cosp) {
*sinp = std::sin(x);
*cosp = std::cos(x);
}
double sin_nid_postfix(double x) { return std::sin(x); }
double cos_nid_postfix(double x) { return std::cos(x); }
double APS5_VABI sin_nid_postfix(double x) { return std::sin(x); }
double APS5_VABI cos_nid_postfix(double x) { return std::cos(x); }
void APS5_VABI sincos_nid_postfix(double x, double* sinp, double* cosp) {
*sinp = std::sin(x);
*cosp = std::cos(x);
}
float atanf_nid_postfix(float x) { return std::atan(x); }
double atan2_nid_postfix(double y, double x) { return std::atan2(y, x); }
float powf_nid_postfix(float base, float exp) { return std::pow(base, exp); }
double pow_nid_postfix(double base, double exp) { return std::pow(base, exp); }
float expf_nid_postfix(float x) { return std::exp(x); }
float exp2f_nid_postfix(float x) { return std::exp2(x); }
float logf_nid_postfix(float x) { return std::log(x); }
float log2f_nid_postfix(float x) { return std::log2(x); }
double log10_nid_postfix(double x) { return std::log10(x); }
float ldexpf_nid_postfix(float x, int exp) { return std::ldexp(x, exp); }
double fmod_nid_postfix(double x, double y) { return std::fmod(x, y); }
float roundf_nid_postfix(float x) { return std::round(x); }
double round_nid_postfix(double x) { return std::round(x); }
float APS5_VABI atanf_nid_postfix(float x) { return std::atan(x); }
double APS5_VABI atan2_nid_postfix(double y, double x) { return std::atan2(y, x); }
float APS5_VABI powf_nid_postfix(float base, float exp) { return std::pow(base, exp); }
double APS5_VABI pow_nid_postfix(double base, double exp) { return std::pow(base, exp); }
float APS5_VABI expf_nid_postfix(float x) { return std::exp(x); }
float APS5_VABI exp2f_nid_postfix(float x) { return std::exp2(x); }
float APS5_VABI logf_nid_postfix(float x) { return std::log(x); }
float APS5_VABI log2f_nid_postfix(float x) { return std::log2(x); }
double APS5_VABI log10_nid_postfix(double x) { return std::log10(x); }
float APS5_VABI ldexpf_nid_postfix(float x, int exp) { return std::ldexp(x, exp); }
double APS5_VABI fmod_nid_postfix(double x, double y) { return std::fmod(x, y); }
float APS5_VABI roundf_nid_postfix(float x) { return std::round(x); }
double APS5_VABI round_nid_postfix(double x) { return std::round(x); }
int __isfinite_nid_postfix(double x) { return std::isfinite(x) ? 1 : 0; }
int __isnan_nid_postfix(double x) { return std::isnan(x) ? 1 : 0; }
int __signbit_nid_postfix(double x) { return std::signbit(x) ? 1 : 0; }
int APS5_VABI __isfinite_nid_postfix(double x) { return std::isfinite(x) ? 1 : 0; }
int APS5_VABI __isnan_nid_postfix(double x) { return std::isnan(x) ? 1 : 0; }
int APS5_VABI __signbit_nid_postfix(double x) { return std::signbit(x) ? 1 : 0; }
}

View File

@ -1,6 +1,8 @@
#include "prx/libc/include/GuestLocale.hpp"
#include <array>
#include <cstring>
#include <cwchar>
#include <climits>
#include <iostream>
#include <stdexcept>
#include <thread>
@ -9,7 +11,7 @@
extern "C" {
extern GuestLocale::Implementation* _ZSt21_sceLibcClassicLocale_nid_postfix;
GuestLocale::Implementation* APS5_VABI _ZNSt6locale16_GetgloballocaleEv_nid_postfix();
void APS5_VABI _ZNSt6locale5_InitEv_nid_postfix();
GuestLocale::Implementation* APS5_VABI _ZNSt6locale5_InitEv_nid_postfix();
void APS5_VABI _ZNSt6locale5facet9_RegisterEv_nid_postfix(GuestLocale::Facet* self);
void APS5_VABI _ZNSt8_LocinfoC1EPKc_nid_postfix(GuestLocale::LocinfoStorage* self, const char* localeName);
void APS5_VABI _ZNSt8_LocinfoD1Ev_nid_postfix(GuestLocale::LocinfoStorage* self);
@ -17,6 +19,8 @@ void APS5_VABI _ZNSt8ios_baseD2Ev_nid_postfix(GuestLocale::IosBase* self);
const short* APS5_VABI _Getpctype_nid_postfix();
const short* APS5_VABI _Getptolower_nid_postfix();
const short* APS5_VABI _Getptoupper_nid_postfix();
int APS5_VABI _Mbtowcx_nid_postfix(std::uint16_t* dst, const char* src, std::size_t count, std::mbstate_t* st);
int APS5_VABI _Wctombx_nid_postfix(char* dst, std::uint16_t src, std::mbstate_t* st);
void APS5_VABI _Locksyslock_nid_postfix();
void APS5_VABI _Unlocksyslock_nid_postfix();
@ -40,8 +44,8 @@ static void RequireException(TAction action) {
static void CheckGuestCalls() {
auto* locale = _ZSt21_sceLibcClassicLocale_nid_postfix;
Require(locale != nullptr && locale == _ZNSt6locale16_GetgloballocaleEv_nid_postfix());
_ZNSt6locale5_InitEv_nid_postfix();
_ZNSt6locale5_InitEv_nid_postfix();
Require(_ZNSt6locale5_InitEv_nid_postfix() == locale);
Require(_ZNSt6locale5_InitEv_nid_postfix() == locale);
const std::byte* table = nullptr;
std::memcpy(&table, locale, sizeof(table));
void (APS5_VABI *retain)(GuestLocale::Facet*) = nullptr;
@ -88,10 +92,10 @@ static void CheckCharacterTables() {
const auto* lower = _Getptolower_nid_postfix();
const auto* upper = _Getptoupper_nid_postfix();
Require(classification[-1] == 0 && lower[-1] == -1 && upper[-1] == -1);
Require(classification['A'] == 0x181 && classification['a'] == 0x182);
Require(classification['G'] == 0x101 && classification['0'] == 0x84);
Require(classification[' '] == 0x48 && classification['\t'] == 0x68);
Require(classification['\n'] == 0x28 && classification['!'] == 0x10);
Require(classification['A'] == 0x03 && classification['a'] == 0x11);
Require(classification['G'] == 0x02 && classification['0'] == 0x21);
Require(classification[' '] == 0x04 && classification['\t'] == 0xc0);
Require(classification['\n'] == 0xc0 && classification['!'] == 0x08);
for (int value = 0; value < 256; ++value) {
Require(lower[value] == (value >= 'A' && value <= 'Z' ? value + 32 : value));
Require(upper[value] == (value >= 'a' && value <= 'z' ? value - 32 : value));
@ -99,6 +103,32 @@ static void CheckCharacterTables() {
}
}
static void CheckCharacterConversions() {
const auto* classification = _Getpctype_nid_postfix();
for (std::uint16_t value = 0; value < 128; ++value) {
std::array<char, MB_LEN_MAX + 1> bytes{};
bytes.fill('!');
std::mbstate_t encodeState{};
Require(_Wctombx_nid_postfix(bytes.data(), value, &encodeState) == 1);
Require(bytes[0] == static_cast<char>(value) && bytes[1] == '!');
std::array<std::uint16_t, 2> wide{0xffff, 0x1234};
std::mbstate_t decodeState{};
Require(_Mbtowcx_nid_postfix(wide.data(), bytes.data(), 2, &decodeState) == (value == 0 ? 0 : 1));
Require(wide[0] == value && wide[1] == 0x1234);
const bool alnum = (value >= '0' && value <= '9') || (value >= 'A' && value <= 'Z') || (value >= 'a' && value <= 'z');
Require(((classification[static_cast<unsigned char>(bytes[0])] & 0x232) != 0) == alnum);
}
std::mbstate_t state{};
char byte{};
std::uint16_t wide{};
RequireException([&] { _Mbtowcx_nid_postfix(&wide, "]", 0, &state); });
RequireException([&] { _Mbtowcx_nid_postfix(nullptr, "]", 1, &state); });
RequireException([&] { _Mbtowcx_nid_postfix(&wide, nullptr, 1, &state); });
RequireException([&] { _Mbtowcx_nid_postfix(&wide, "]", 1, nullptr); });
RequireException([&] { _Wctombx_nid_postfix(nullptr, ']', &state); });
RequireException([&] { _Wctombx_nid_postfix(&byte, ']', nullptr); });
}
static void CheckStreamDestruction() {
struct GuardedStream {
std::uint64_t before = 0x12345678;
@ -118,6 +148,7 @@ int main() {
CheckGuestCalls();
CheckLocinfoAlignment();
CheckCharacterTables();
CheckCharacterConversions();
CheckStreamDestruction();
_Locksyslock_nid_postfix();
_Locksyslock_nid_postfix();