Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions core/libs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,16 @@ if(BUILD_TESTING)
configure_windows_unwind(savedata_replace_file_failure_tests)
add_test(NAME savedata_replace_file_failure COMMAND savedata_replace_file_failure_tests)

add_test_executable(guest_crt_tests tests/GuestCrt.cpp)
target_include_directories(guest_crt_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_crt_tests PRIVATE libSceAmpr libc)
configure_windows_unwind(guest_crt_tests)
add_test(NAME guest_crt COMMAND guest_crt_tests)
if(WIN32)
set_tests_properties(guest_crt PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceAmpr>")
endif()

if(MINGW)
target_compile_options(savedata_core_write_replacement_tests PRIVATE -fasynchronous-unwind-tables)
target_compile_options(savedata_native_write_replacement_tests PRIVATE -fasynchronous-unwind-tables)
Expand Down
17 changes: 17 additions & 0 deletions core/libs/SceTypes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,23 @@ struct alignas(16) __m128 { float v[4]; };

using Bool = std::uint8_t;

struct SonyLconv {
char* monetary[7];
char chars[14];
char pad[2];
char* decimal_point;
char* grouping;
char* thousands_sep;
char* frac_grouping;
char* frac_sep;
char* false_text;
char* true_text;
char* no_text;
char* yes_text;
};
static_assert(offsetof(SonyLconv, decimal_point) == 0x48);
static_assert(sizeof(SonyLconv) == 0x90);

using KernelModule = std::int32_t;
using KernelCpumask = std::uint64_t;
using KernelUseconds = unsigned int;
Expand Down
62 changes: 62 additions & 0 deletions core/libs/prx/libSceAmpr/Export.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#include <cstdint>
#include <cstddef>
#include <ctime>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
#include "prx/libc/include/SonyCrt.hpp"
#include "prx/libkernel/Apr/include/AprCommandBuffer.hpp"
#include "prx/libkernel/Time/include/Time.hpp"
#include <algorithm>
Expand Down Expand Up @@ -967,4 +969,64 @@ int APS5_VABI __cxa_call_unexpected_nid_postfix(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}

APS5_EXPORT("0hlfW1O4Aa4", sceAmprLocaleconv);
SonyLconv* APS5_VABI sceAmprLocaleconv(void) {
return SonyLocaleconv();
}

APS5_EXPORT("802pFCwC9w0", sceAmprUdivti3);
unsigned __int128 APS5_VABI sceAmprUdivti3(unsigned __int128 dividend, unsigned __int128 divisor) {
return SonyUdivti3(dividend, divisor);
}

APS5_EXPORT("MU25eqxSDTw", sceAmprSinh);
double APS5_VABI sceAmprSinh(double x, double y) {
return SonySinh(x, y);
}

APS5_EXPORT("-vXEQdRADLI", sceAmprStrtokS);
char* APS5_VABI sceAmprStrtokS(char* str, const char* delim, char** context) {
return SonyStrtokS(str, delim, context);
}

APS5_EXPORT("2UFh+YKfuzk", sceAmprCtimeS);
int APS5_VABI sceAmprCtimeS(char* buffer, std::size_t size, const std::int64_t* time) {
return SonyCtimeS(buffer, size, time);
}

APS5_EXPORT("6f5f-qx4ucA", sceAmprWcscpyS);
int APS5_VABI sceAmprWcscpyS(std::uint16_t* dest, std::size_t size, const std::uint16_t* src) {
return SonyWcscpyS(dest, size, src);
}

APS5_EXPORT("ENLfKJEZTjE", sceAmprSetConstraintHandlerS);
void* APS5_VABI sceAmprSetConstraintHandlerS(void* handler) {
return SonySetConstraintHandlerS(handler);
}

APS5_EXPORT("Jo9ON-AX9eU", sceAmprFltrounds);
int APS5_VABI sceAmprFltrounds(void) {
return SonyFltrounds();
}

APS5_EXPORT("ODGONXcSmz4", sceAmprIgnoreHandlerS);
void APS5_VABI sceAmprIgnoreHandlerS(const char* message, void* pointer, int error) {
SonyIgnoreHandlerS(message, pointer, error);
}

APS5_EXPORT("VUzjXknPPBs", sceAmprMbstowcs);
std::size_t APS5_VABI sceAmprMbstowcs(std::uint16_t* dest, const char* src, std::size_t size) {
return SonyMbstowcs(dest, src, size);
}

APS5_EXPORT("qPe7-h5Jnuc", sceAmprAsctimeS);
int APS5_VABI sceAmprAsctimeS(char* buffer, std::size_t size, const GuestTm* time) {
return SonyAsctimeS(buffer, size, time);
}

APS5_EXPORT("qlWiRfOJx1A", sceAmprFpclassifyd);
int APS5_VABI sceAmprFpclassifyd(double value) {
return SonyFpclassifyd(value);
}
}
199 changes: 199 additions & 0 deletions core/libs/prx/libc/include/SonyCrt.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
#ifndef CORE_LIBS_PRX_LIBC_INCLUDE_SONYCRT_HPP
#define CORE_LIBS_PRX_LIBC_INCLUDE_SONYCRT_HPP

#include <cfenv>
#include <cerrno>
#include <climits>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <mutex>
#include <stdexcept>

#include "SceTypes.hpp"
#include "prx/libc/include/GuestTime.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"

extern "C" GuestTm* APS5_VABI localtime_s_nid_postfix(const std::int64_t* timer, GuestTm* result);

namespace {

using SonyConstraintHandler = void (*)(const char* message, void* pointer, int error);

inline void SonyDefaultConstraintHandler(const char* message, void* pointer, int error) {
(void)message;
(void)pointer;
(void)error;
std::abort();
}

inline std::mutex& SonyConstraintMutex() {
static std::mutex mutex;
return mutex;
}

inline SonyConstraintHandler& SonyConstraintHandlerSlot() {
static SonyConstraintHandler handler = SonyDefaultConstraintHandler;
return handler;
}

inline void SonyInvokeConstraintHandler(const char* message, void* pointer, int error) {
SonyConstraintHandler handler = nullptr;
{
std::lock_guard<std::mutex> lock(SonyConstraintMutex());
handler = SonyConstraintHandlerSlot();
}
if (handler) handler(message, pointer, error);
}

inline char* SonyStrtokS(char* str, const char* delim, char** context) {
if (!delim || !context) return nullptr;
char* cursor = str ? str : *context;
if (!cursor) return nullptr;
cursor += std::strspn(cursor, delim);
if (*cursor == '\0') {
*context = cursor;
return nullptr;
}
char* token = cursor;
cursor += std::strcspn(cursor, delim);
if (*cursor != '\0') {
*cursor = '\0';
*context = cursor + 1;
} else {
*context = cursor;
}
return token;
}

inline int SonyFormatAsctime(char* buffer, std::size_t size, const GuestTm& time) {
static const char* const days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
static const char* const months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
if (!buffer || size < 26) return EINVAL;
if (time.tm_wday < 0 || time.tm_wday > 6 || time.tm_mon < 0 || time.tm_mon > 11) return EINVAL;
std::snprintf(buffer, size, "%.3s %.3s %2d %.2d:%.2d:%.2d %4d\n", days[time.tm_wday], months[time.tm_mon],
time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec, 1900 + time.tm_year);
return 0;
}

inline int SonyCtimeS(char* buffer, std::size_t size, const std::int64_t* time) {
if (!buffer || size < 26 || !time) return EINVAL;
GuestTm parts{};
if (!localtime_s_nid_postfix(time, &parts)) return EINVAL;
return SonyFormatAsctime(buffer, size, parts);
}

inline int SonyAsctimeS(char* buffer, std::size_t size, const GuestTm* time) {
if (!buffer || size < 26 || !time) return EINVAL;
return SonyFormatAsctime(buffer, size, *time);
}

inline void SonyIgnoreHandlerS(const char* message, void* pointer, int error) {
(void)message;
(void)pointer;
(void)error;
}

inline void* SonySetConstraintHandlerS(void* handler) {
std::lock_guard<std::mutex> lock(SonyConstraintMutex());
void* previous = reinterpret_cast<void*>(SonyConstraintHandlerSlot());
SonyConstraintHandlerSlot() = handler ? reinterpret_cast<SonyConstraintHandler>(handler) : SonyDefaultConstraintHandler;
return previous;
}

inline int SonyWcscpyS(std::uint16_t* dest, std::size_t size, const std::uint16_t* src) {
if (!dest || !src || size == 0) {
SonyInvokeConstraintHandler("wcscpy_s", dest, EINVAL);
return EINVAL;
}
std::size_t i = 0;
while (i + 1 < size && src[i] != 0) {
dest[i] = src[i];
++i;
}
dest[i] = 0;
if (src[i] != 0) {
SonyInvokeConstraintHandler("wcscpy_s", dest, ERANGE);
return ERANGE;
}
return 0;
}

inline std::size_t SonyMbstowcs(std::uint16_t* dest, const char* src, std::size_t size) {
if (!src) return 0;
std::size_t converted = 0;
while (converted < size) {
const auto value = static_cast<unsigned char>(src[converted]);
if (dest) dest[converted] = value;
if (value == 0) return converted;
++converted;
}
return converted;
}

inline SonyLconv* SonyLocaleconv(void) {
static char empty[] = "";
static char point[] = ".";
static char falseText[] = "false";
static char trueText[] = "true";
static SonyLconv value = [] {
SonyLconv init{};
for (auto& pointer : init.monetary) pointer = empty;
for (auto& byte : init.chars) byte = CHAR_MAX;
init.decimal_point = point;
init.grouping = empty;
init.thousands_sep = empty;
init.frac_grouping = empty;
init.frac_sep = empty;
init.false_text = falseText;
init.true_text = trueText;
init.no_text = empty;
init.yes_text = empty;
return init;
}();
return &value;
}

inline int SonyFpclassifyd(double value) {
if (std::isnan(value)) return 2;
if (std::isinf(value)) return 1;
if (value == 0.0) return 0;
if (std::fpclassify(value) == FP_SUBNORMAL) return -2;
return -1;
}

inline double SonySinh(double x, double y) {
return y * std::sinh(x);
}

inline int SonyFltrounds(void) {
switch (std::fegetround()) {
case FE_TONEAREST: return 1;
case FE_DOWNWARD: return 3;
case FE_UPWARD: return 2;
case FE_TOWARDZERO: return 0;
default: return 1;
}
}

inline unsigned __int128 SonyUdivti3(unsigned __int128 dividend, unsigned __int128 divisor) {
if (divisor == 0) throw std::runtime_error("__udivti3: integer divide by zero");
unsigned __int128 quotient = 0;
unsigned __int128 remainder = 0;
for (int i = 127; i >= 0; --i) {
remainder = (remainder << 1) | ((dividend >> i) & 1);
if (remainder >= divisor) {
remainder -= divisor;
quotient |= (unsigned __int128)1 << i;
}
}
return quotient;
}

}

#endif
6 changes: 6 additions & 0 deletions core/libs/prx/libc/src/LocaleSupport.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <climits>
#include <clocale>
#include <cstddef>
#include <cstdio>
#include <cstdint>
Expand All @@ -17,6 +18,7 @@
#include <string>

#include "prx/libc/include/General.hpp"
#include "prx/libc/include/SonyCrt.hpp"
#include "prx/libc/include/ApplicationHeap.hpp"
#include "prx/libc/include/GuestLocale.hpp"
#include "SceTypes.hpp"
Expand Down Expand Up @@ -380,4 +382,8 @@ void APS5_VABI init_env_nid_postfix(const InitEnvParams* params) {
_init_env_nid_postfix();
}

SonyLconv* APS5_VABI localeconv_nid_postfix(void) {
return SonyLocaleconv();
}

}
13 changes: 13 additions & 0 deletions core/libs/prx/libc/src/Math.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <stdexcept>

#include "prx/libc/include/General.hpp"
#include "prx/libc/include/SonyCrt.hpp"

namespace {

Expand Down Expand Up @@ -199,4 +200,16 @@ void APS5_VABI srand_nid_postfix(unsigned int seed) {
g_randState = seed;
}

int APS5_VABI __fpclassifyd_nid_postfix(double value) {
return SonyFpclassifyd(value);
}

double APS5_VABI _Sinh_nid_postfix(double x, double y) {
return SonySinh(x, y);
}

int APS5_VABI _Fltrounds_nid_postfix(void) {
return SonyFltrounds();
}

}
5 changes: 5 additions & 0 deletions core/libs/prx/libc/src/Multibyte.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "prx/libc/include/general/VabiMacros.hpp"
#include "prx/libc/include/SonyCrt.hpp"
#include <cerrno>
#include <cstddef>
#include <cstdint>
Expand Down Expand Up @@ -158,4 +159,8 @@ std::size_t APS5_VABI mbsrtowcs_nid_postfix(std::uint16_t* destination, const ch
return converted;
}

std::size_t APS5_VABI mbstowcs_nid_postfix(std::uint16_t* dest, const char* src, std::size_t size) {
return SonyMbstowcs(dest, src, size);
}

}
5 changes: 5 additions & 0 deletions core/libs/prx/libc/src/RuntimeSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <cinttypes>

#include "prx/libc/include/General.hpp"
#include "prx/libc/include/SonyCrt.hpp"
#include "prx/libc/include/specifics/gcc/AtomicOps.hpp"
#include "prx/libc/include/FileStream.hpp"

Expand Down Expand Up @@ -154,4 +155,8 @@ void APS5_VABI _Unlocksyslock_nid_postfix() {
g_sysLock.unlock();
}

unsigned __int128 APS5_VABI __udivti3_nid_postfix(unsigned __int128 dividend, unsigned __int128 divisor) {
return SonyUdivti3(dividend, divisor);
}

}
Loading
Loading