From 809413a880808e750d2832d224c1719e0d36eb5f Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Sun, 1 Oct 2023 16:29:48 +0300 Subject: [PATCH 1/7] dummy libc printf call --- src/Core/PS4/HLE/LibC.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Core/PS4/HLE/LibC.cpp b/src/Core/PS4/HLE/LibC.cpp index 72624578..124c2777 100644 --- a/src/Core/PS4/HLE/LibC.cpp +++ b/src/Core/PS4/HLE/LibC.cpp @@ -92,6 +92,12 @@ namespace HLE::Libs::LibC { } static PS4_SYSV_ABI void _Assert() { BREAKPOINT(); } + static PS4_SYSV_ABI int printf() { /* + BREAKPOINT();*/ + //PRINT_DUMMY_FUNCTION_NAME(); + return 0;//not correct + } + void LibC_Register(SymbolsResolver* sym) { LIB_FUNCTION("bzQExy189ZI", "libc", 1, "libc", 1, 1, init_env); @@ -103,6 +109,7 @@ namespace HLE::Libs::LibC { LIB_FUNCTION("uMei1W9uyNo", "libc", 1, "libc", 1, 1, exit); LIB_FUNCTION("8G2LB+A3rzg", "libc", 1, "libc", 1, 1, atexit); LIB_FUNCTION("-QgqOT5u2Vk", "libc", 1, "libc", 1, 1, _Assert); + LIB_FUNCTION("hcuQgD53UxM", "libc", 1, "libc", 1, 1, printf); LIB_OBJ("P330P3dFF68", "libc", 1, "libc", 1, 1, &HLE::Libs::LibC::g_need_sceLibc); } From 825d38ef31c29d911344e8749a2ae84796ef630f Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Thu, 5 Oct 2023 18:38:36 +0300 Subject: [PATCH 2/7] partial printf , hello world demo (not from OpenOrbis) works --- src/Core/PS4/HLE/LibC.cpp | 176 ++++++++++++++++++-------------------- 1 file changed, 84 insertions(+), 92 deletions(-) diff --git a/src/Core/PS4/HLE/LibC.cpp b/src/Core/PS4/HLE/LibC.cpp index 124c2777..f6ccc148 100644 --- a/src/Core/PS4/HLE/LibC.cpp +++ b/src/Core/PS4/HLE/LibC.cpp @@ -1,117 +1,109 @@ #include "LibC.h" -#include "Libs.h" -#include "../Loader/Elf.h" + #include #include +#include "../Loader/Elf.h" +#include "Libs.h" + namespace HLE::Libs::LibC { - static u32 g_need_sceLibc = 1; +static u32 g_need_sceLibc = 1; - static PS4_SYSV_ABI void init_env() // every game/demo should probably - { - //dummy no need atm - } +static PS4_SYSV_ABI void init_env() // every game/demo should probably +{ + // dummy no need atm +} - static pthread_mutex_t __guard_mutex; - static pthread_once_t __once_control = PTHREAD_ONCE_INIT; +static pthread_mutex_t __guard_mutex; +static pthread_once_t __once_control = PTHREAD_ONCE_INIT; - static void recursiveMutex() +static void recursiveMutex() { + pthread_mutexattr_t recursiveMutexAttr; + pthread_mutexattr_init(&recursiveMutexAttr); + pthread_mutexattr_settype(&recursiveMutexAttr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&__guard_mutex, &recursiveMutexAttr); +} + +static pthread_mutex_t* mutex_quard() { + pthread_once(&__once_control, &recursiveMutex); + return &__guard_mutex; +} + +int PS4_SYSV_ABI __cxa_guard_acquire(u64* guard_object) { + if ((*((uint8_t*)guard_object) != 0)) // low 8 bits checks if its already init { - pthread_mutexattr_t recursiveMutexAttr; - pthread_mutexattr_init(&recursiveMutexAttr); - pthread_mutexattr_settype(&recursiveMutexAttr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&__guard_mutex, &recursiveMutexAttr); + return 0; + } + int result = ::pthread_mutex_lock(mutex_quard()); + if (result != 0) { + BREAKPOINT(); } - static pthread_mutex_t* mutex_quard() { - pthread_once(&__once_control, &recursiveMutex); - return &__guard_mutex; - } - - int PS4_SYSV_ABI __cxa_guard_acquire(u64* guard_object) { - if ((*((uint8_t*)guard_object) != 0)) // low 8 bits checks if its already init - { - return 0; - } - int result = ::pthread_mutex_lock(mutex_quard()); - if (result != 0) { - BREAKPOINT(); - } - - // Check if another thread has completed initializer run - if ((*((uint8_t*)guard_object) != 0)) { // check again if other thread init it - int result = ::pthread_mutex_unlock(mutex_quard()); - if (result != 0) { - BREAKPOINT(); - } - return 0; - } - - if (((uint8_t*)guard_object)[1] != 0) { // the second lowest byte marks if it's being used by a thread - BREAKPOINT(); - } - - // mark this guard object as being in use - ((uint8_t*)guard_object)[1] = 1; - - return 1; - } - - void PS4_SYSV_ABI __cxa_guard_release(u64* guard_object) - { - *((uint8_t*)guard_object) = 1;//mark it as done - - // release global mutex + // Check if another thread has completed initializer run + if ((*((uint8_t*)guard_object) != 0)) { // check again if other thread init it int result = ::pthread_mutex_unlock(mutex_quard()); if (result != 0) { BREAKPOINT(); } - } - - int PS4_SYSV_ABI memcmp(const void* s1, const void* s2, size_t n) { - return ::memcmp(s1, s2, n); + return 0; } - void* PS4_SYSV_ABI memcpy(void* dest, const void* src, size_t n) { - return ::memcpy(dest, src, n); + if (((uint8_t*)guard_object)[1] != 0) { // the second lowest byte marks if it's being used by a thread + BREAKPOINT(); } - static PS4_SYSV_ABI void catchReturnFromMain(int status) { BREAKPOINT(); - } - static PS4_SYSV_ABI void exit(int code) { BREAKPOINT(); - } - static PS4_SYSV_ABI int atexit(void (*func)()) - { - int rt = ::atexit(func); - if (rt != 0) - { - BREAKPOINT(); - } - return rt; - } - static PS4_SYSV_ABI void _Assert() { BREAKPOINT(); } + // mark this guard object as being in use + ((uint8_t*)guard_object)[1] = 1; - static PS4_SYSV_ABI int printf() { /* - BREAKPOINT();*/ - //PRINT_DUMMY_FUNCTION_NAME(); - return 0;//not correct + return 1; +} + +void PS4_SYSV_ABI __cxa_guard_release(u64* guard_object) { + *((uint8_t*)guard_object) = 1; // mark it as done + + // release global mutex + int result = ::pthread_mutex_unlock(mutex_quard()); + if (result != 0) { + BREAKPOINT(); } +} - void LibC_Register(SymbolsResolver* sym) - { - LIB_FUNCTION("bzQExy189ZI", "libc", 1, "libc", 1, 1, init_env); - LIB_FUNCTION("3GPpjQdAMTw", "libc", 1, "libc", 1, 1, __cxa_guard_acquire); - LIB_FUNCTION("9rAeANT2tyE", "libc", 1, "libc", 1, 1, __cxa_guard_release); - LIB_FUNCTION("DfivPArhucg", "libc", 1, "libc", 1, 1, memcmp); - LIB_FUNCTION("Q3VBxCXhUHs", "libc", 1, "libc", 1, 1, memcpy); - LIB_FUNCTION("XKRegsFpEpk", "libc", 1, "libc", 1, 1, catchReturnFromMain); - LIB_FUNCTION("uMei1W9uyNo", "libc", 1, "libc", 1, 1, exit); - LIB_FUNCTION("8G2LB+A3rzg", "libc", 1, "libc", 1, 1, atexit); - LIB_FUNCTION("-QgqOT5u2Vk", "libc", 1, "libc", 1, 1, _Assert); - LIB_FUNCTION("hcuQgD53UxM", "libc", 1, "libc", 1, 1, printf); +int PS4_SYSV_ABI memcmp(const void* s1, const void* s2, size_t n) { return ::memcmp(s1, s2, n); } - LIB_OBJ("P330P3dFF68", "libc", 1, "libc", 1, 1, &HLE::Libs::LibC::g_need_sceLibc); +void* PS4_SYSV_ABI memcpy(void* dest, const void* src, size_t n) { return ::memcpy(dest, src, n); } + +static PS4_SYSV_ABI void catchReturnFromMain(int status) { + // dummy +} +static PS4_SYSV_ABI void exit(int code) { ::exit(code); } +static PS4_SYSV_ABI int atexit(void (*func)()) { + int rt = ::atexit(func); + if (rt != 0) { + BREAKPOINT(); } - -}; \ No newline at end of file + return rt; +} +static PS4_SYSV_ABI void _Assert() { BREAKPOINT(); } + +static PS4_SYSV_ABI int printf(const char* s) { + puts(s); + return 0; // not correct +} + +void LibC_Register(SymbolsResolver* sym) { + LIB_FUNCTION("bzQExy189ZI", "libc", 1, "libc", 1, 1, init_env); + LIB_FUNCTION("3GPpjQdAMTw", "libc", 1, "libc", 1, 1, __cxa_guard_acquire); + LIB_FUNCTION("9rAeANT2tyE", "libc", 1, "libc", 1, 1, __cxa_guard_release); + LIB_FUNCTION("DfivPArhucg", "libc", 1, "libc", 1, 1, memcmp); + LIB_FUNCTION("Q3VBxCXhUHs", "libc", 1, "libc", 1, 1, memcpy); + LIB_FUNCTION("XKRegsFpEpk", "libc", 1, "libc", 1, 1, catchReturnFromMain); + LIB_FUNCTION("uMei1W9uyNo", "libc", 1, "libc", 1, 1, exit); + LIB_FUNCTION("8G2LB+A3rzg", "libc", 1, "libc", 1, 1, atexit); + LIB_FUNCTION("-QgqOT5u2Vk", "libc", 1, "libc", 1, 1, _Assert); + LIB_FUNCTION("hcuQgD53UxM", "libc", 1, "libc", 1, 1, printf); + + LIB_OBJ("P330P3dFF68", "libc", 1, "libc", 1, 1, &HLE::Libs::LibC::g_need_sceLibc); +} + +}; // namespace HLE::Libs::LibC \ No newline at end of file From b9c6d9d3952f1b7fa4d43a1cde49506ff0983ea8 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 6 Oct 2023 12:46:28 +0300 Subject: [PATCH 3/7] printf implementation from vita3k (not yet adapted) --- src/Emulator/HLE/Libraries/LibC/printf.h | 711 +++++++++++++++++++++++ 1 file changed, 711 insertions(+) create mode 100644 src/Emulator/HLE/Libraries/LibC/printf.h diff --git a/src/Emulator/HLE/Libraries/LibC/printf.h b/src/Emulator/HLE/Libraries/LibC/printf.h new file mode 100644 index 00000000..c9506dc9 --- /dev/null +++ b/src/Emulator/HLE/Libraries/LibC/printf.h @@ -0,0 +1,711 @@ +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info@paland.com) +// 2014-2018, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on +// embedded systems with a very limited resources. +// Use this instead of bloated standard/newlib printf. +// These routines are thread safe and reentrant! +// +/////////////////////////////////////////////////////////////////////////////// +// Vita3K emulator project +// Copyright (C) 2023 Vita3K team +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +//copied from Vita3k project at 6/10/2023 (latest update 30/06/2023) +//modifications for adapting va_args parameters + +#pragma once + +#include +#include +#include +#include + +namespace utils { +// ntoa conversion buffer size, this must be big enough to hold +// one converted numeric number including padded zeros (dynamically created on stack) +// 32 byte is a good default +#define PRINTF_NTOA_BUFFER_SIZE 32U + +// ftoa conversion buffer size, this must be big enough to hold +// one converted float number including padded zeros (dynamically created on stack) +// 32 byte is a good default +#define PRINTF_FTOA_BUFFER_SIZE 32U + +// define this to support floating point (%f) +#define PRINTF_SUPPORT_FLOAT + +// define this to support long long types (%llu or %p) +#define PRINTF_SUPPORT_LONG_LONG + +// define this to support the ptrdiff_t type (%t) +// ptrdiff_t is normally defined in as long or long long type +#define PRINTF_SUPPORT_PTRDIFF_T + + +/////////////////////////////////////////////////////////////////////////////// + +// internal flag definitions +#define FLAGS_ZEROPAD (1U << 0U) +#define FLAGS_LEFT (1U << 1U) +#define FLAGS_PLUS (1U << 2U) +#define FLAGS_SPACE (1U << 3U) +#define FLAGS_HASH (1U << 4U) +#define FLAGS_UPPERCASE (1U << 5U) +#define FLAGS_CHAR (1U << 6U) +#define FLAGS_SHORT (1U << 7U) +#define FLAGS_LONG (1U << 8U) +#define FLAGS_LONG_LONG (1U << 9U) +#define FLAGS_PRECISION (1U << 10U) +#define FLAGS_WIDTH (1U << 11U) + + +// output function type +typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen); + + +// wrapper (used as buffer) for output function type +typedef struct { + void (*fct)(char character, void* arg); + void* arg; +} out_fct_wrap_type; + + +// internal buffer output +static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen) +{ + if (idx < maxlen) { + ((char*)buffer)[idx] = character; + } +} + + +// internal null output +static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)character; (void)buffer; (void)idx; (void)maxlen; +} + + +// internal output function wrapper +static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)idx; (void)maxlen; + // buffer is the output fct pointer + ((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg); +} + + +// internal strlen +// \return The length of the string (excluding the terminating 0) +static inline unsigned int _strlen(const char* str) +{ + const char* s; + for (s = str; *s; ++s); + return (unsigned int)(s - str); +} + + +// internal test if char is a digit (0-9) +// \return true if char is a digit +static inline bool _is_digit(char ch) +{ + return (ch >= '0') && (ch <= '9'); +} + + +// internal ASCII string to unsigned int conversion +static inline unsigned int _atoi(const char** str) +{ + unsigned int i = 0U; + while (_is_digit(**str)) { + i = i * 10U + (unsigned int)(*((*str)++) - '0'); + } + return i; +} + + +// internal itoa format +static inline size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags) +{ + const size_t start_idx = idx; + + // pad leading zeros + while (!(flags & FLAGS_LEFT) && (len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + while (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + + // handle hash + if (flags & FLAGS_HASH) { + if (((len == prec) || (len == width)) && (len > 0U)) { + len--; + if ((base == 16U) && (len > 0U)) { + len--; + } + } + if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'x'; + } + if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'X'; + } + if (len < PRINTF_NTOA_BUFFER_SIZE) { + buf[len++] = '0'; + } + } + + // handle sign + if ((len == width) && (negative || (flags & FLAGS_PLUS) || (flags & FLAGS_SPACE))) { + len--; + } + if (len < PRINTF_NTOA_BUFFER_SIZE) { + if (negative) { + buf[len++] = '-'; + } + else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } + else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + // pad spaces up to given width + if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { + for (size_t i = len; i < width; i++) { + out(' ', buffer, idx++, maxlen); + } + } + + // reverse string + for (size_t i = 0U; i < len; i++) { + out(buf[len - i - 1U], buffer, idx++, maxlen); + } + + // append pad spaces up to given width + if (flags & FLAGS_LEFT) { + while (idx - start_idx < width) { + out(' ', buffer, idx++, maxlen); + } + } + + return idx; +} + + +// internal itoa for 'long' type +static inline size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } + + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); +} + + +// internal itoa for 'long long' type +#if defined(PRINTF_SUPPORT_LONG_LONG) +static inline size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } + + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); +} +#endif // PRINTF_SUPPORT_LONG_LONG + + +#if defined(PRINTF_SUPPORT_FLOAT) +static inline size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_FTOA_BUFFER_SIZE]; + size_t len = 0U; + double diff = 0.0; + + // if input is larger than thres_max, revert to exponential + const double thres_max = (double)0x7FFFFFFF; + + // powers of 10 + static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + + // test for negative + bool negative = false; + if (value < 0) { + negative = true; + value = 0 - value; + } + + // set default precision to 6, if not set explicitly + if (!(flags & FLAGS_PRECISION)) { + prec = 6U; + } + // limit precision to 9, cause a prec >= 10 can lead to overflow errors + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) { + buf[len++] = '0'; + prec--; + } + + int whole = (int)value; + double tmp = (value - whole) * pow10[prec]; + unsigned long frac = (unsigned long)tmp; + diff = tmp - frac; + + if (diff > 0.5) { + ++frac; + // handle rollover, e.g. case 0.99 with prec 1 is 1.0 + if (frac >= pow10[prec]) { + frac = 0; + ++whole; + } + } + else if ((diff == 0.5) && ((frac == 0U) || (frac & 1U))) { + // if halfway, round up if odd, OR if last digit is 0 + ++frac; + } + + // TBD: for very large numbers switch back to native sprintf for exponentials. Anyone want to write code to replace this? + // Normal printf behavior is to print EVERY whole number digit which can be 100s of characters overflowing your buffers == bad + if (value > thres_max) { + return 0U; + } + + if (prec == 0U) { + diff = value - (double)whole; + if (diff > 0.5) { + // greater than 0.5, round up, e.g. 1.6 -> 2 + ++whole; + } + else if ((diff == 0.5) && (whole & 1)) { + // exactly 0.5 and ODD, then round up + // 1.5 -> 2, but 2.5 -> 2 + ++whole; + } + } + else { + unsigned int count = prec; + // now do fractional part, as an unsigned number + while (len < PRINTF_FTOA_BUFFER_SIZE) { + --count; + buf[len++] = (char)(48U + (frac % 10U)); + if (!(frac /= 10U)) { + break; + } + } + // add extra 0s + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) { + buf[len++] = '0'; + } + if (len < PRINTF_FTOA_BUFFER_SIZE) { + // add decimal + buf[len++] = '.'; + } + } + + // do whole part, number is reversed + while (len < PRINTF_FTOA_BUFFER_SIZE) { + buf[len++] = (char)(48 + (whole % 10)); + if (!(whole /= 10)) { + break; + } + } + + // pad leading zeros + while (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + + // handle sign + if ((len == width) && (negative || (flags & FLAGS_PLUS) || (flags & FLAGS_SPACE))) { + len--; + } + if (len < PRINTF_FTOA_BUFFER_SIZE) { + if (negative) { + buf[len++] = '-'; + } + else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } + else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + // pad spaces up to given width + if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { + for (size_t i = len; i < width; i++) { + out(' ', buffer, idx++, maxlen); + } + } + + // reverse string + for (size_t i = 0U; i < len; i++) { + out(buf[len - i - 1U], buffer, idx++, maxlen); + } + + // append pad spaces up to given width + if (flags & FLAGS_LEFT) { + while (idx < width) { + out(' ', buffer, idx++, maxlen); + } + } + + return idx; +} +#endif // PRINTF_SUPPORT_FLOAT + +#if 0 +// internal vsnprintf +static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, CPUState &cpu, MemState &mem, module::vargs &va) +{ + unsigned int flags, width, precision, n; + size_t idx = 0U; + + if (!buffer) { + // use null output function + out = _out_null; + } + + while (*format) + { + // format specifier? %[flags][width][.precision][length] + if (*format != '%') { + // no + out(*format, buffer, idx++, maxlen); + format++; + continue; + } + else { + // yes, evaluate it + format++; + } + + // evaluate flags + flags = 0U; + do { + switch (*format) { + case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break; + case '-': flags |= FLAGS_LEFT; format++; n = 1U; break; + case '+': flags |= FLAGS_PLUS; format++; n = 1U; break; + case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break; + case '#': flags |= FLAGS_HASH; format++; n = 1U; break; + default : n = 0U; break; + } + } while (n); + + // evaluate width field + width = 0U; + if (_is_digit(*format)) { + width = _atoi(&format); + } + else if (*format == '*') { + const int w = va.next(cpu, mem); + if (w < 0) { + flags |= FLAGS_LEFT; // reverse padding + width = (unsigned int)-w; + } + else { + width = (unsigned int)w; + } + format++; + } + + // evaluate precision field + precision = 0U; + if (*format == '.') { + flags |= FLAGS_PRECISION; + format++; + if (_is_digit(*format)) { + precision = _atoi(&format); + } + else if (*format == '*') { + precision = (unsigned int)va.next(cpu, mem); + format++; + } + } + + // evaluate length field + switch (*format) { + case 'l' : + flags |= FLAGS_LONG; + format++; + if (*format == 'l') { + flags |= FLAGS_LONG_LONG; + format++; + } + break; + case 'h' : + flags |= FLAGS_SHORT; + format++; + if (*format == 'h') { + flags |= FLAGS_CHAR; + format++; + } + break; +#if defined(PRINTF_SUPPORT_PTRDIFF_T) + case 't' : + flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; +#endif + case 'j' : + flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + case 'z' : + flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + default : + break; + } + + // evaluate specifier + switch (*format) { + case 'd' : + case 'i' : + case 'u' : + case 'x' : + case 'X' : + case 'o' : + case 'b' : { + // set the base + unsigned int base; + if (*format == 'x' || *format == 'X') { + base = 16U; + } + else if (*format == 'o') { + base = 8U; + } + else if (*format == 'b') { + base = 2U; + flags &= ~FLAGS_HASH; // no hash for bin format + } + else { + base = 10U; + flags &= ~FLAGS_HASH; // no hash for dec format + } + // uppercase + if (*format == 'X') { + flags |= FLAGS_UPPERCASE; + } + + // no plus or space flag for u, x, X, o, b + if ((*format != 'i') && (*format != 'd')) { + flags &= ~(FLAGS_PLUS | FLAGS_SPACE); + } + + // convert the integer + if ((*format == 'i') || (*format == 'd')) { + // signed + if (flags & FLAGS_LONG_LONG) { +#if defined(PRINTF_SUPPORT_LONG_LONG) + const long long value = va.next(cpu, mem); + idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); +#endif + } + else if (flags & FLAGS_LONG) { + const long value = va.next(cpu, mem); + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); + } + else { + const int value = (flags & FLAGS_CHAR) ? (char)va.next(cpu, mem) : (flags & FLAGS_SHORT) ? (short int)va.next(cpu, mem): va.next(cpu, mem); + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); + } + } + else { + // unsigned + if (flags & FLAGS_LONG_LONG) { +#if defined(PRINTF_SUPPORT_LONG_LONG) + idx = _ntoa_long_long(out, buffer, idx, maxlen, va.next(cpu, mem), false, base, precision, width, flags); +#endif + } + else if (flags & FLAGS_LONG) { + idx = _ntoa_long(out, buffer, idx, maxlen, va.next(cpu, mem), false, base, precision, width, flags); + } + else { + const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va.next(cpu, mem) : (flags & FLAGS_SHORT) ? + (unsigned short int)va.next(cpu, mem) : va.next(cpu, mem); + idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags); + } + } + format++; + break; + } +#if defined(PRINTF_SUPPORT_FLOAT) + case 'f' : + case 'F' : + idx = _ftoa(out, buffer, idx, maxlen, va.next(cpu, mem), precision, width, flags); + format++; + break; +#endif // PRINTF_SUPPORT_FLOAT + case 'c' : { + unsigned int l = 1U; + // pre padding + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // char output + out((char)va.next(cpu, mem), buffer, idx++, maxlen); + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 's' : { + const char *p = va.next>(cpu, mem).get(mem); + p = p != nullptr ? p : "(null)"; + unsigned int l = _strlen(p); + // pre padding + if (flags & FLAGS_PRECISION) { + l = (l < precision ? l : precision); + } + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // string output + while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) { + out(*(p++), buffer, idx++, maxlen); + } + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 'p' : { + width = sizeof(void*) * 2U; + flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE; +#if defined(PRINTF_SUPPORT_LONG_LONG) + const bool is_ll = sizeof(uintptr_t) == sizeof(long long); + if (is_ll) { + idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va.next>(cpu, mem).address(), false, 16U, precision, width, flags); + } + else { +#endif + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va.next>(cpu, mem).address()), false, 16U, precision, width, flags); +#if defined(PRINTF_SUPPORT_LONG_LONG) + } +#endif + format++; + break; + } + + case '%' : + out('%', buffer, idx++, maxlen); + format++; + break; + + default : + out(*format, buffer, idx++, maxlen); + format++; + break; + } + } + + // termination + out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); + + // return written chars without terminating \0 + return (int)idx; +} + +/////////////////////////////////////////////////////// + +/** + * Tiny sprintf implementation + * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD! + * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output! + * \param format A string that specifies the format of the output + * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character + */ +inline int sprintf(char* buffer, const char* format, CPUState &cpu, MemState &mem, module::vargs &args) +{ + const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, cpu, mem, args); + return ret; +} + +/** + * Tiny snprintf/vsnprintf implementation + * \param buffer A pointer to the buffer where to store the formatted string + * \param count The maximum number of characters to store in the buffer, including a terminating null character + * \param format A string that specifies the format of the output + * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character + * If the formatted string is truncated the buffer size (count) is returned + */ +inline int snprintf(char* buffer, size_t count, const char* format, CPUState &cpu, MemState &mem, module::vargs &args) +{ + const int ret = _vsnprintf(_out_buffer, buffer, count, format, cpu, mem, args); + return ret; +} + +#endif + +} From cefd3d95ed9a2c484f96bb96d2ac170854c1469b Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 6 Oct 2023 13:33:45 +0300 Subject: [PATCH 4/7] adapting va_arg parameters of printf --- src/Emulator/HLE/Libraries/LibC/printf.h | 541 +++++++++++------------ src/Emulator/HLE/Libraries/LibC/va_ctx.h | 70 +++ 2 files changed, 338 insertions(+), 273 deletions(-) create mode 100644 src/Emulator/HLE/Libraries/LibC/va_ctx.h diff --git a/src/Emulator/HLE/Libraries/LibC/printf.h b/src/Emulator/HLE/Libraries/LibC/printf.h index c9506dc9..5137255d 100644 --- a/src/Emulator/HLE/Libraries/LibC/printf.h +++ b/src/Emulator/HLE/Libraries/LibC/printf.h @@ -10,10 +10,10 @@ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -45,26 +45,28 @@ // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -//copied from Vita3k project at 6/10/2023 (latest update 30/06/2023) -//modifications for adapting va_args parameters +// copied from Vita3k project at 6/10/2023 (latest update 30/06/2023) +// modifications for adapting va_args parameters #pragma once #include -#include #include +#include #include -namespace utils { +#include "va_ctx.h" + +namespace Emulator::HLE::Libraries::LibC { // ntoa conversion buffer size, this must be big enough to hold // one converted numeric number including padded zeros (dynamically created on stack) // 32 byte is a good default -#define PRINTF_NTOA_BUFFER_SIZE 32U +#define PRINTF_NTOA_BUFFER_SIZE 32U // ftoa conversion buffer size, this must be big enough to hold // one converted float number including padded zeros (dynamically created on stack) // 32 byte is a good default -#define PRINTF_FTOA_BUFFER_SIZE 32U +#define PRINTF_FTOA_BUFFER_SIZE 32U // define this to support floating point (%f) #define PRINTF_SUPPORT_FLOAT @@ -76,341 +78,318 @@ namespace utils { // ptrdiff_t is normally defined in as long or long long type #define PRINTF_SUPPORT_PTRDIFF_T - /////////////////////////////////////////////////////////////////////////////// // internal flag definitions -#define FLAGS_ZEROPAD (1U << 0U) -#define FLAGS_LEFT (1U << 1U) -#define FLAGS_PLUS (1U << 2U) -#define FLAGS_SPACE (1U << 3U) -#define FLAGS_HASH (1U << 4U) -#define FLAGS_UPPERCASE (1U << 5U) -#define FLAGS_CHAR (1U << 6U) -#define FLAGS_SHORT (1U << 7U) -#define FLAGS_LONG (1U << 8U) -#define FLAGS_LONG_LONG (1U << 9U) +#define FLAGS_ZEROPAD (1U << 0U) +#define FLAGS_LEFT (1U << 1U) +#define FLAGS_PLUS (1U << 2U) +#define FLAGS_SPACE (1U << 3U) +#define FLAGS_HASH (1U << 4U) +#define FLAGS_UPPERCASE (1U << 5U) +#define FLAGS_CHAR (1U << 6U) +#define FLAGS_SHORT (1U << 7U) +#define FLAGS_LONG (1U << 8U) +#define FLAGS_LONG_LONG (1U << 9U) #define FLAGS_PRECISION (1U << 10U) -#define FLAGS_WIDTH (1U << 11U) - +#define FLAGS_WIDTH (1U << 11U) // output function type typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen); - // wrapper (used as buffer) for output function type typedef struct { - void (*fct)(char character, void* arg); - void* arg; + void (*fct)(char character, void* arg); + void* arg; } out_fct_wrap_type; - // internal buffer output -static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen) -{ - if (idx < maxlen) { - ((char*)buffer)[idx] = character; - } +static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen) { + if (idx < maxlen) { + ((char*)buffer)[idx] = character; + } } - // internal null output -static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen) -{ - (void)character; (void)buffer; (void)idx; (void)maxlen; +static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen) { + (void)character; + (void)buffer; + (void)idx; + (void)maxlen; } - // internal output function wrapper -static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen) -{ - (void)idx; (void)maxlen; - // buffer is the output fct pointer - ((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg); +static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen) { + (void)idx; + (void)maxlen; + // buffer is the output fct pointer + ((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg); } - // internal strlen // \return The length of the string (excluding the terminating 0) -static inline unsigned int _strlen(const char* str) -{ - const char* s; - for (s = str; *s; ++s); - return (unsigned int)(s - str); +static inline unsigned int _strlen(const char* str) { + const char* s; + for (s = str; *s; ++s) + ; + return (unsigned int)(s - str); } - // internal test if char is a digit (0-9) // \return true if char is a digit -static inline bool _is_digit(char ch) -{ - return (ch >= '0') && (ch <= '9'); -} - +static inline bool _is_digit(char ch) { return (ch >= '0') && (ch <= '9'); } // internal ASCII string to unsigned int conversion -static inline unsigned int _atoi(const char** str) -{ - unsigned int i = 0U; - while (_is_digit(**str)) { - i = i * 10U + (unsigned int)(*((*str)++) - '0'); - } - return i; +static inline unsigned int _atoi(const char** str) { + unsigned int i = 0U; + while (_is_digit(**str)) { + i = i * 10U + (unsigned int)(*((*str)++) - '0'); + } + return i; } - // internal itoa format -static inline size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags) -{ - const size_t start_idx = idx; +static inline size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, + unsigned int prec, unsigned int width, unsigned int flags) { + const size_t start_idx = idx; - // pad leading zeros - while (!(flags & FLAGS_LEFT) && (len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = '0'; - } - while (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = '0'; - } + // pad leading zeros + while (!(flags & FLAGS_LEFT) && (len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + while (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } - // handle hash - if (flags & FLAGS_HASH) { - if (((len == prec) || (len == width)) && (len > 0U)) { - len--; - if ((base == 16U) && (len > 0U)) { + // handle hash + if (flags & FLAGS_HASH) { + if (((len == prec) || (len == width)) && (len > 0U)) { + len--; + if ((base == 16U) && (len > 0U)) { + len--; + } + } + if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'x'; + } + if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'X'; + } + if (len < PRINTF_NTOA_BUFFER_SIZE) { + buf[len++] = '0'; + } + } + + // handle sign + if ((len == width) && (negative || (flags & FLAGS_PLUS) || (flags & FLAGS_SPACE))) { len--; - } - } - if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = 'x'; - } - if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = 'X'; } if (len < PRINTF_NTOA_BUFFER_SIZE) { - buf[len++] = '0'; + if (negative) { + buf[len++] = '-'; + } else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } } - } - // handle sign - if ((len == width) && (negative || (flags & FLAGS_PLUS) || (flags & FLAGS_SPACE))) { - len--; - } - if (len < PRINTF_NTOA_BUFFER_SIZE) { - if (negative) { - buf[len++] = '-'; + // pad spaces up to given width + if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { + for (size_t i = len; i < width; i++) { + out(' ', buffer, idx++, maxlen); + } } - else if (flags & FLAGS_PLUS) { - buf[len++] = '+'; // ignore the space if the '+' exists - } - else if (flags & FLAGS_SPACE) { - buf[len++] = ' '; - } - } - // pad spaces up to given width - if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { - for (size_t i = len; i < width; i++) { - out(' ', buffer, idx++, maxlen); + // reverse string + for (size_t i = 0U; i < len; i++) { + out(buf[len - i - 1U], buffer, idx++, maxlen); } - } - // reverse string - for (size_t i = 0U; i < len; i++) { - out(buf[len - i - 1U], buffer, idx++, maxlen); - } - - // append pad spaces up to given width - if (flags & FLAGS_LEFT) { - while (idx - start_idx < width) { - out(' ', buffer, idx++, maxlen); + // append pad spaces up to given width + if (flags & FLAGS_LEFT) { + while (idx - start_idx < width) { + out(' ', buffer, idx++, maxlen); + } } - } - return idx; + return idx; } - // internal itoa for 'long' type -static inline size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags) -{ - char buf[PRINTF_NTOA_BUFFER_SIZE]; - size_t len = 0U; +static inline size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, + unsigned int prec, unsigned int width, unsigned int flags) { + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; - // write if precision != 0 and value is != 0 - if (!(flags & FLAGS_PRECISION) || value) { - do { - const char digit = (char)(value % base); - buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; - value /= base; - } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); - } + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } - return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); } - // internal itoa for 'long long' type #if defined(PRINTF_SUPPORT_LONG_LONG) -static inline size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags) -{ - char buf[PRINTF_NTOA_BUFFER_SIZE]; - size_t len = 0U; +static inline size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, + unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags) { + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; - // write if precision != 0 and value is != 0 - if (!(flags & FLAGS_PRECISION) || value) { - do { - const char digit = (char)(value % base); - buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; - value /= base; - } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); - } + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } - return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); } #endif // PRINTF_SUPPORT_LONG_LONG - #if defined(PRINTF_SUPPORT_FLOAT) -static inline size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) -{ - char buf[PRINTF_FTOA_BUFFER_SIZE]; - size_t len = 0U; - double diff = 0.0; +static inline size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, + unsigned int flags) { + char buf[PRINTF_FTOA_BUFFER_SIZE]; + size_t len = 0U; + double diff = 0.0; - // if input is larger than thres_max, revert to exponential - const double thres_max = (double)0x7FFFFFFF; + // if input is larger than thres_max, revert to exponential + const double thres_max = (double)0x7FFFFFFF; - // powers of 10 - static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + // powers of 10 + static const double pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; - // test for negative - bool negative = false; - if (value < 0) { - negative = true; - value = 0 - value; - } - - // set default precision to 6, if not set explicitly - if (!(flags & FLAGS_PRECISION)) { - prec = 6U; - } - // limit precision to 9, cause a prec >= 10 can lead to overflow errors - while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) { - buf[len++] = '0'; - prec--; - } - - int whole = (int)value; - double tmp = (value - whole) * pow10[prec]; - unsigned long frac = (unsigned long)tmp; - diff = tmp - frac; - - if (diff > 0.5) { - ++frac; - // handle rollover, e.g. case 0.99 with prec 1 is 1.0 - if (frac >= pow10[prec]) { - frac = 0; - ++whole; + // test for negative + bool negative = false; + if (value < 0) { + negative = true; + value = 0 - value; } - } - else if ((diff == 0.5) && ((frac == 0U) || (frac & 1U))) { - // if halfway, round up if odd, OR if last digit is 0 - ++frac; - } - // TBD: for very large numbers switch back to native sprintf for exponentials. Anyone want to write code to replace this? - // Normal printf behavior is to print EVERY whole number digit which can be 100s of characters overflowing your buffers == bad - if (value > thres_max) { - return 0U; - } + // set default precision to 6, if not set explicitly + if (!(flags & FLAGS_PRECISION)) { + prec = 6U; + } + // limit precision to 9, cause a prec >= 10 can lead to overflow errors + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) { + buf[len++] = '0'; + prec--; + } + + int whole = (int)value; + double tmp = (value - whole) * pow10[prec]; + unsigned long frac = (unsigned long)tmp; + diff = tmp - frac; - if (prec == 0U) { - diff = value - (double)whole; if (diff > 0.5) { - // greater than 0.5, round up, e.g. 1.6 -> 2 - ++whole; + ++frac; + // handle rollover, e.g. case 0.99 with prec 1 is 1.0 + if (frac >= pow10[prec]) { + frac = 0; + ++whole; + } + } else if ((diff == 0.5) && ((frac == 0U) || (frac & 1U))) { + // if halfway, round up if odd, OR if last digit is 0 + ++frac; } - else if ((diff == 0.5) && (whole & 1)) { - // exactly 0.5 and ODD, then round up - // 1.5 -> 2, but 2.5 -> 2 - ++whole; + + // TBD: for very large numbers switch back to native sprintf for exponentials. Anyone want to write code to replace this? + // Normal printf behavior is to print EVERY whole number digit which can be 100s of characters overflowing your buffers == bad + if (value > thres_max) { + return 0U; } - } - else { - unsigned int count = prec; - // now do fractional part, as an unsigned number + + if (prec == 0U) { + diff = value - (double)whole; + if (diff > 0.5) { + // greater than 0.5, round up, e.g. 1.6 -> 2 + ++whole; + } else if ((diff == 0.5) && (whole & 1)) { + // exactly 0.5 and ODD, then round up + // 1.5 -> 2, but 2.5 -> 2 + ++whole; + } + } else { + unsigned int count = prec; + // now do fractional part, as an unsigned number + while (len < PRINTF_FTOA_BUFFER_SIZE) { + --count; + buf[len++] = (char)(48U + (frac % 10U)); + if (!(frac /= 10U)) { + break; + } + } + // add extra 0s + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) { + buf[len++] = '0'; + } + if (len < PRINTF_FTOA_BUFFER_SIZE) { + // add decimal + buf[len++] = '.'; + } + } + + // do whole part, number is reversed while (len < PRINTF_FTOA_BUFFER_SIZE) { - --count; - buf[len++] = (char)(48U + (frac % 10U)); - if (!(frac /= 10U)) { - break; - } + buf[len++] = (char)(48 + (whole % 10)); + if (!(whole /= 10)) { + break; + } } - // add extra 0s - while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) { - buf[len++] = '0'; + + // pad leading zeros + while (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + + // handle sign + if ((len == width) && (negative || (flags & FLAGS_PLUS) || (flags & FLAGS_SPACE))) { + len--; } if (len < PRINTF_FTOA_BUFFER_SIZE) { - // add decimal - buf[len++] = '.'; + if (negative) { + buf[len++] = '-'; + } else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } } - } - // do whole part, number is reversed - while (len < PRINTF_FTOA_BUFFER_SIZE) { - buf[len++] = (char)(48 + (whole % 10)); - if (!(whole /= 10)) { - break; + // pad spaces up to given width + if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { + for (size_t i = len; i < width; i++) { + out(' ', buffer, idx++, maxlen); + } } - } - // pad leading zeros - while (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { - buf[len++] = '0'; - } - - // handle sign - if ((len == width) && (negative || (flags & FLAGS_PLUS) || (flags & FLAGS_SPACE))) { - len--; - } - if (len < PRINTF_FTOA_BUFFER_SIZE) { - if (negative) { - buf[len++] = '-'; + // reverse string + for (size_t i = 0U; i < len; i++) { + out(buf[len - i - 1U], buffer, idx++, maxlen); } - else if (flags & FLAGS_PLUS) { - buf[len++] = '+'; // ignore the space if the '+' exists - } - else if (flags & FLAGS_SPACE) { - buf[len++] = ' '; - } - } - // pad spaces up to given width - if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { - for (size_t i = len; i < width; i++) { - out(' ', buffer, idx++, maxlen); + // append pad spaces up to given width + if (flags & FLAGS_LEFT) { + while (idx < width) { + out(' ', buffer, idx++, maxlen); + } } - } - // reverse string - for (size_t i = 0U; i < len; i++) { - out(buf[len - i - 1U], buffer, idx++, maxlen); - } - - // append pad spaces up to given width - if (flags & FLAGS_LEFT) { - while (idx < width) { - out(' ', buffer, idx++, maxlen); - } - } - - return idx; + return idx; } #endif // PRINTF_SUPPORT_FLOAT -#if 0 + // internal vsnprintf -static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, CPUState &cpu, MemState &mem, module::vargs &va) +static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, VaList* va_list) { unsigned int flags, width, precision, n; size_t idx = 0U; @@ -453,7 +432,8 @@ static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen width = _atoi(&format); } else if (*format == '*') { - const int w = va.next(cpu, mem); + const int w = vaArgInteger(va_list); // const int w = va.next(cpu, mem); + if (w < 0) { flags |= FLAGS_LEFT; // reverse padding width = (unsigned int)-w; @@ -473,7 +453,7 @@ static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen precision = _atoi(&format); } else if (*format == '*') { - precision = (unsigned int)va.next(cpu, mem); + precision = vaArgInteger(va_list); // precision = (unsigned int)va.next(cpu, mem); format++; } } @@ -554,16 +534,19 @@ static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen // signed if (flags & FLAGS_LONG_LONG) { #if defined(PRINTF_SUPPORT_LONG_LONG) - const long long value = va.next(cpu, mem); + auto value = vaArgLongLong(va_list); // const long long value = va.next(cpu, mem); idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); #endif } else if (flags & FLAGS_LONG) { - const long value = va.next(cpu, mem); + auto value = vaArgLong(va_list); // const long value = va.next(cpu, mem); idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); } else { - const int value = (flags & FLAGS_CHAR) ? (char)va.next(cpu, mem) : (flags & FLAGS_SHORT) ? (short int)va.next(cpu, mem): va.next(cpu, mem); + //const int value = (flags & FLAGS_CHAR) ? (char)va.next(cpu, mem) : (flags & FLAGS_SHORT) ? (short int)va.next(cpu, mem): va.next(cpu, mem); + const int value = (flags & FLAGS_CHAR) ? static_cast(vaArgInteger(va_list)) + : (flags & FLAGS_SHORT) ? static_cast(vaArgInteger(va_list)) + : vaArgInteger(va_list); idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); } } @@ -571,15 +554,20 @@ static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen // unsigned if (flags & FLAGS_LONG_LONG) { #if defined(PRINTF_SUPPORT_LONG_LONG) - idx = _ntoa_long_long(out, buffer, idx, maxlen, va.next(cpu, mem), false, base, precision, width, flags); + //idx = _ntoa_long_long(out, buffer, idx, maxlen, va.next(cpu, mem), false, base, precision, width, flags); + idx = _ntoa_long_long(out, buffer, idx, maxlen, static_cast(vaArgLongLong(va_list)), false, base, precision, width, flags); #endif } else if (flags & FLAGS_LONG) { - idx = _ntoa_long(out, buffer, idx, maxlen, va.next(cpu, mem), false, base, precision, width, flags); + // idx = _ntoa_long(out, buffer, idx, maxlen, va.next(cpu, mem), false, base, precision, width, flags); + idx = _ntoa_long(out, buffer, idx, maxlen, static_cast(vaArgLong(va_list)), false, base, precision, width, flags); } else { - const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va.next(cpu, mem) : (flags & FLAGS_SHORT) ? - (unsigned short int)va.next(cpu, mem) : va.next(cpu, mem); + //const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va.next(cpu, mem) : (flags & FLAGS_SHORT) ? + // (unsigned short int)va.next(cpu, mem) : va.next(cpu, mem); + const unsigned int value = (flags & FLAGS_CHAR) ? static_cast(vaArgInteger(va_list)) + : (flags & FLAGS_SHORT) ? static_cast(vaArgInteger(va_list)) + : static_cast(vaArgInteger(va_list)); idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags); } } @@ -589,7 +577,8 @@ static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen #if defined(PRINTF_SUPPORT_FLOAT) case 'f' : case 'F' : - idx = _ftoa(out, buffer, idx, maxlen, va.next(cpu, mem), precision, width, flags); + //idx = _ftoa(out, buffer, idx, maxlen, va.next(cpu, mem), precision, width, flags); + idx = _ftoa(out, buffer, idx, maxlen, vaArgDouble(va_list), precision, width, flags); format++; break; #endif // PRINTF_SUPPORT_FLOAT @@ -602,7 +591,8 @@ static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen } } // char output - out((char)va.next(cpu, mem), buffer, idx++, maxlen); + //out((char)va.next(cpu, mem), buffer, idx++, maxlen); + out(static_cast(vaArgInteger(va_list)), buffer, idx++, maxlen); // post padding if (flags & FLAGS_LEFT) { while (l++ < width) { @@ -614,7 +604,7 @@ static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen } case 's' : { - const char *p = va.next>(cpu, mem).get(mem); + const char* p = vaArgPtr(va_list); // const char *p = va.next>(cpu, mem).get(mem); p = p != nullptr ? p : "(null)"; unsigned int l = _strlen(p); // pre padding @@ -646,11 +636,15 @@ static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen #if defined(PRINTF_SUPPORT_LONG_LONG) const bool is_ll = sizeof(uintptr_t) == sizeof(long long); if (is_ll) { - idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va.next>(cpu, mem).address(), false, 16U, precision, width, flags); + //idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va.next>(cpu, mem).address(), false, 16U, precision, width, flags); + idx = _ntoa_long_long(out, buffer, idx, maxlen, reinterpret_cast(vaArgPtr(va_list)), false, 16U, precision, width, flags); } else { #endif - idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va.next>(cpu, mem).address()), false, 16U, precision, width, flags); + //idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va.next>(cpu, mem).address()), false, 16U, precision, width, flags); + idx = _ntoa_long(out, buffer, idx, maxlen, static_cast(reinterpret_cast(vaArgPtr(va_list))), false, 16U, + precision, width, + flags); #if defined(PRINTF_SUPPORT_LONG_LONG) } #endif @@ -677,6 +671,7 @@ static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen return (int)idx; } +#if 0 /////////////////////////////////////////////////////// /** @@ -708,4 +703,4 @@ inline int snprintf(char* buffer, size_t count, const char* format, CPUState &cp #endif -} +} // namespace Emulator::HLE::Libraries::LibC diff --git a/src/Emulator/HLE/Libraries/LibC/va_ctx.h b/src/Emulator/HLE/Libraries/LibC/va_ctx.h new file mode 100644 index 00000000..2dd613bc --- /dev/null +++ b/src/Emulator/HLE/Libraries/LibC/va_ctx.h @@ -0,0 +1,70 @@ +#include + +namespace Emulator::HLE::Libraries::LibC { + +// https://stackoverflow.com/questions/4958384/what-is-the-format-of-the-x86-64-va-list-structure + +struct VaList { + u32 gp_offset; + u32 fp_offset; + void* overflow_arg_area; + void* reg_save_area; +}; + +template +T vaArgRegSaveAreaGp(VaList* l) { + auto* addr = reinterpret_cast(static_cast(l->reg_save_area) + l->gp_offset); + l->gp_offset += Size; + return *addr; +} +template +T vaArgOverflowArgArea(VaList* l) { + auto ptr = ((reinterpret_cast(l->overflow_arg_area) + (Align - 1)) & ~(Align - 1)); + auto* addr = reinterpret_cast(ptr); + l->overflow_arg_area = reinterpret_cast(ptr + Size); + return *addr; +} + +template +T vaArgRegSaveAreaFp(VaList* l) { + auto* addr = reinterpret_cast(static_cast(l->reg_save_area) + l->fp_offset); + l->fp_offset += Size; + return *addr; +} + +inline int vaArgInteger(VaList* l) { + if (l->gp_offset <= 40) { + return vaArgRegSaveAreaGp(l); + } + return vaArgOverflowArgArea(l); +} + +inline long long vaArgLongLong(VaList* l) { + if (l->gp_offset <= 40) { + return vaArgRegSaveAreaGp(l); + } + return vaArgOverflowArgArea(l); +} +inline long vaArgLong(VaList* l) { + if (l->gp_offset <= 40) { + return vaArgRegSaveAreaGp(l); + } + return vaArgOverflowArgArea(l); +} + +inline double vaArgDouble(VaList* l) { + if (l->fp_offset <= 160) { + return vaArgRegSaveAreaFp(l); + } + return vaArgOverflowArgArea(l); +} + +template +T* vaArgPtr(VaList* l) { + if (l->gp_offset <= 40) { + return vaArgRegSaveAreaGp(l); + } + return vaArgOverflowArgArea(l); +} + +} // namespace Emulator::HLE::Libraries::LibC \ No newline at end of file From 551455e56e834c6738e2d520664f4119186121e9 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 6 Oct 2023 14:19:09 +0300 Subject: [PATCH 5/7] printf implementation --- CMakeLists.txt | 2 +- src/Core/PS4/HLE/LibC.cpp | 9 ++--- src/Emulator/HLE/Libraries/LibC/libc.cpp | 9 +++++ src/Emulator/HLE/Libraries/LibC/libc.h | 10 ++++++ src/Emulator/HLE/Libraries/LibC/printf.h | 9 +++++ src/Emulator/HLE/Libraries/LibC/va_ctx.h | 44 +++++++++++++++++++++--- 6 files changed, 72 insertions(+), 11 deletions(-) create mode 100644 src/Emulator/HLE/Libraries/LibC/libc.cpp create mode 100644 src/Emulator/HLE/Libraries/LibC/libc.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b07d8996..1be51375 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,7 +55,7 @@ add_executable(shadps4 src/Core/PS4/HLE/Kernel/cpu_management.cpp src/Core/PS4/HLE/Kernel/cpu_management.h - "src/Util/Singleton.h" "src/Util/Disassembler.cpp" "src/Util/Disassembler.h" "src/Core/PS4/Util/aerolib.h" "src/Core/PS4/Loader/SymbolsResolver.h" "src/Core/PS4/Loader/SymbolsResolver.cpp" "src/Core/PS4/HLE/Libs.cpp" "src/Core/PS4/HLE/Libs.h" "src/Core/PS4/HLE/LibC.cpp" "src/Core/PS4/HLE/LibC.h" "src/Lib/Timer.cpp" "src/Lib/Timer.h" "src/Core/PS4/HLE/LibKernel.cpp" "src/Core/PS4/HLE/LibKernel.h" "src/Core/PS4/HLE/LibSceGnmDriver.cpp" "src/Core/PS4/HLE/LibSceGnmDriver.h" "src/Core/PS4/HLE/Kernel/ThreadManagement.cpp" "src/Core/PS4/HLE/Kernel/ThreadManagement.h" "src/Core/PS4/HLE/ErrorCodes.h" "src/debug.h" "src/Core/PS4/HLE/Kernel/memory_management.cpp" "src/Core/PS4/HLE/Kernel/memory_management.h" "src/Core/PS4/GPU/gpu_memory.cpp" "src/Core/PS4/GPU/gpu_memory.h" "src/emulator.cpp" "src/emulator.h" "src/Core/PS4/HLE/Kernel/Objects/event_queue.h" "src/Core/PS4/HLE/Kernel/Objects/event_queue.cpp" "src/Core/PS4/HLE/Graphics/Objects/video_out_ctx.cpp" "src/Core/PS4/HLE/Graphics/Objects/video_out_ctx.h" "src/Core/PS4/HLE/Graphics/graphics_ctx.h" "src/vulkan_util.cpp" "src/vulkan_util.h" "src/Core/PS4/GPU/video_out_buffer.cpp" "src/Core/PS4/GPU/video_out_buffer.h" "src/Core/PS4/HLE/Graphics/graphics_render.cpp" "src/Core/PS4/HLE/Graphics/graphics_render.h" "src/Core/PS4/GPU/tile_manager.cpp" "src/Core/PS4/GPU/tile_manager.h" "src/version.h") + "src/Util/Singleton.h" "src/Util/Disassembler.cpp" "src/Util/Disassembler.h" "src/Core/PS4/Util/aerolib.h" "src/Core/PS4/Loader/SymbolsResolver.h" "src/Core/PS4/Loader/SymbolsResolver.cpp" "src/Core/PS4/HLE/Libs.cpp" "src/Core/PS4/HLE/Libs.h" "src/Core/PS4/HLE/LibC.cpp" "src/Core/PS4/HLE/LibC.h" "src/Lib/Timer.cpp" "src/Lib/Timer.h" "src/Core/PS4/HLE/LibKernel.cpp" "src/Core/PS4/HLE/LibKernel.h" "src/Core/PS4/HLE/LibSceGnmDriver.cpp" "src/Core/PS4/HLE/LibSceGnmDriver.h" "src/Core/PS4/HLE/Kernel/ThreadManagement.cpp" "src/Core/PS4/HLE/Kernel/ThreadManagement.h" "src/Core/PS4/HLE/ErrorCodes.h" "src/debug.h" "src/Core/PS4/HLE/Kernel/memory_management.cpp" "src/Core/PS4/HLE/Kernel/memory_management.h" "src/Core/PS4/GPU/gpu_memory.cpp" "src/Core/PS4/GPU/gpu_memory.h" "src/emulator.cpp" "src/emulator.h" "src/Core/PS4/HLE/Kernel/Objects/event_queue.h" "src/Core/PS4/HLE/Kernel/Objects/event_queue.cpp" "src/Core/PS4/HLE/Graphics/Objects/video_out_ctx.cpp" "src/Core/PS4/HLE/Graphics/Objects/video_out_ctx.h" "src/Core/PS4/HLE/Graphics/graphics_ctx.h" "src/vulkan_util.cpp" "src/vulkan_util.h" "src/Core/PS4/GPU/video_out_buffer.cpp" "src/Core/PS4/GPU/video_out_buffer.h" "src/Core/PS4/HLE/Graphics/graphics_render.cpp" "src/Core/PS4/HLE/Graphics/graphics_render.h" "src/Core/PS4/GPU/tile_manager.cpp" "src/Core/PS4/GPU/tile_manager.h" "src/version.h" "src/Emulator/HLE/Libraries/LibC/printf.h" "src/Emulator/HLE/Libraries/LibC/va_ctx.h" "src/Emulator/HLE/Libraries/LibC/libc.cpp" "src/Emulator/HLE/Libraries/LibC/libc.h") find_package(OpenGL REQUIRED) target_link_libraries(shadps4 PUBLIC fmt mincore spdlog IMGUI SDL3-shared ${OPENGL_LIBRARY} vulkan-1 spirv-tools-opt spirv-tools) diff --git a/src/Core/PS4/HLE/LibC.cpp b/src/Core/PS4/HLE/LibC.cpp index f6ccc148..4ff9bc27 100644 --- a/src/Core/PS4/HLE/LibC.cpp +++ b/src/Core/PS4/HLE/LibC.cpp @@ -5,6 +5,8 @@ #include "../Loader/Elf.h" #include "Libs.h" +#include "Emulator/HLE/Libraries/LibC/libc.h" + namespace HLE::Libs::LibC { @@ -86,11 +88,6 @@ static PS4_SYSV_ABI int atexit(void (*func)()) { } static PS4_SYSV_ABI void _Assert() { BREAKPOINT(); } -static PS4_SYSV_ABI int printf(const char* s) { - puts(s); - return 0; // not correct -} - void LibC_Register(SymbolsResolver* sym) { LIB_FUNCTION("bzQExy189ZI", "libc", 1, "libc", 1, 1, init_env); LIB_FUNCTION("3GPpjQdAMTw", "libc", 1, "libc", 1, 1, __cxa_guard_acquire); @@ -101,7 +98,7 @@ void LibC_Register(SymbolsResolver* sym) { LIB_FUNCTION("uMei1W9uyNo", "libc", 1, "libc", 1, 1, exit); LIB_FUNCTION("8G2LB+A3rzg", "libc", 1, "libc", 1, 1, atexit); LIB_FUNCTION("-QgqOT5u2Vk", "libc", 1, "libc", 1, 1, _Assert); - LIB_FUNCTION("hcuQgD53UxM", "libc", 1, "libc", 1, 1, printf); + LIB_FUNCTION("hcuQgD53UxM", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::printf); LIB_OBJ("P330P3dFF68", "libc", 1, "libc", 1, 1, &HLE::Libs::LibC::g_need_sceLibc); } diff --git a/src/Emulator/HLE/Libraries/LibC/libc.cpp b/src/Emulator/HLE/Libraries/LibC/libc.cpp new file mode 100644 index 00000000..ae9e8eee --- /dev/null +++ b/src/Emulator/HLE/Libraries/LibC/libc.cpp @@ -0,0 +1,9 @@ +#include "libc.h" + +namespace Emulator::HLE::Libraries::LibC { + +PS4_SYSV_ABI int printf(VA_ARGS) { + VA_CTX(ctx); + return printf_ctx(&ctx); +} +}; // namespace Emulator::HLE::Libraries::LibC \ No newline at end of file diff --git a/src/Emulator/HLE/Libraries/LibC/libc.h b/src/Emulator/HLE/Libraries/LibC/libc.h new file mode 100644 index 00000000..4da2bb6e --- /dev/null +++ b/src/Emulator/HLE/Libraries/LibC/libc.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include "printf.h" + +namespace Emulator::HLE::Libraries::LibC { + + //HLE functions + PS4_SYSV_ABI int printf(VA_ARGS); +} \ No newline at end of file diff --git a/src/Emulator/HLE/Libraries/LibC/printf.h b/src/Emulator/HLE/Libraries/LibC/printf.h index 5137255d..7201f079 100644 --- a/src/Emulator/HLE/Libraries/LibC/printf.h +++ b/src/Emulator/HLE/Libraries/LibC/printf.h @@ -56,6 +56,7 @@ #include #include "va_ctx.h" +#include namespace Emulator::HLE::Libraries::LibC { // ntoa conversion buffer size, this must be big enough to hold @@ -671,6 +672,14 @@ static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen return (int)idx; } +static int printf_ctx(VaCtx* ctx) { + const char* format = vaArgPtr(&ctx->va_list); + char buffer[256]; + int result= _vsnprintf(_out_buffer, buffer, (size_t)-1, format, &ctx->va_list); + puts(buffer); + return result; +} + #if 0 /////////////////////////////////////////////////////// diff --git a/src/Emulator/HLE/Libraries/LibC/va_ctx.h b/src/Emulator/HLE/Libraries/LibC/va_ctx.h index 2dd613bc..a2d78a52 100644 --- a/src/Emulator/HLE/Libraries/LibC/va_ctx.h +++ b/src/Emulator/HLE/Libraries/LibC/va_ctx.h @@ -1,4 +1,30 @@ #include +#include + +#define VA_ARGS \ + uint64_t rdi, uint64_t rsi, uint64_t rdx, uint64_t rcx, uint64_t r8, uint64_t r9, uint64_t overflow_arg_area, __m128 xmm0, __m128 xmm1, \ + __m128 xmm2, __m128 xmm3, __m128 xmm4, __m128 xmm5, __m128 xmm6, __m128 xmm7, ... + +#define VA_CTX(ctx) \ + alignas(16) VaCtx ctx; \ + (ctx).reg_save_area.gp[0] = rdi; \ + (ctx).reg_save_area.gp[1] = rsi; \ + (ctx).reg_save_area.gp[2] = rdx; \ + (ctx).reg_save_area.gp[3] = rcx; \ + (ctx).reg_save_area.gp[4] = r8; \ + (ctx).reg_save_area.gp[5] = r9; \ + (ctx).reg_save_area.fp[0] = xmm0; \ + (ctx).reg_save_area.fp[1] = xmm1; \ + (ctx).reg_save_area.fp[2] = xmm2; \ + (ctx).reg_save_area.fp[3] = xmm3; \ + (ctx).reg_save_area.fp[4] = xmm4; \ + (ctx).reg_save_area.fp[5] = xmm5; \ + (ctx).reg_save_area.fp[6] = xmm6; \ + (ctx).reg_save_area.fp[7] = xmm7; \ + (ctx).va_list.reg_save_area = &(ctx).reg_save_area; \ + (ctx).va_list.gp_offset = offsetof(VaRegSave, gp); \ + (ctx).va_list.fp_offset = offsetof(VaRegSave, fp); \ + (ctx).va_list.overflow_arg_area = &overflow_arg_area; namespace Emulator::HLE::Libraries::LibC { @@ -11,15 +37,25 @@ struct VaList { void* reg_save_area; }; +struct VaRegSave { + u64 gp[6]; + __m128 fp[8]; +}; + +struct VaCtx { + VaRegSave reg_save_area; + VaList va_list; +}; + template T vaArgRegSaveAreaGp(VaList* l) { - auto* addr = reinterpret_cast(static_cast(l->reg_save_area) + l->gp_offset); + auto* addr = reinterpret_cast(static_cast(l->reg_save_area) + l->gp_offset); l->gp_offset += Size; return *addr; } -template +template T vaArgOverflowArgArea(VaList* l) { - auto ptr = ((reinterpret_cast(l->overflow_arg_area) + (Align - 1)) & ~(Align - 1)); + auto ptr = ((reinterpret_cast(l->overflow_arg_area) + (Align - 1)) & ~(Align - 1)); auto* addr = reinterpret_cast(ptr); l->overflow_arg_area = reinterpret_cast(ptr + Size); return *addr; @@ -27,7 +63,7 @@ T vaArgOverflowArgArea(VaList* l) { template T vaArgRegSaveAreaFp(VaList* l) { - auto* addr = reinterpret_cast(static_cast(l->reg_save_area) + l->fp_offset); + auto* addr = reinterpret_cast(static_cast(l->reg_save_area) + l->fp_offset); l->fp_offset += Size; return *addr; } From e31365aea3695a38e00dba1c419d4c65b31ccf58 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 6 Oct 2023 14:46:12 +0300 Subject: [PATCH 6/7] small adjustments to printf --- src/Emulator/HLE/Libraries/LibC/printf.h | 565 +++++++++++------------ 1 file changed, 273 insertions(+), 292 deletions(-) diff --git a/src/Emulator/HLE/Libraries/LibC/printf.h b/src/Emulator/HLE/Libraries/LibC/printf.h index 7201f079..1ed0cd84 100644 --- a/src/Emulator/HLE/Libraries/LibC/printf.h +++ b/src/Emulator/HLE/Libraries/LibC/printf.h @@ -50,13 +50,14 @@ #pragma once +#include + #include #include #include #include #include "va_ctx.h" -#include namespace Emulator::HLE::Libraries::LibC { // ntoa conversion buffer size, this must be big enough to hold @@ -388,328 +389,308 @@ static inline size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t ma } #endif // PRINTF_SUPPORT_FLOAT - // internal vsnprintf -static inline int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, VaList* va_list) -{ - unsigned int flags, width, precision, n; - size_t idx = 0U; +static inline int _vsnprintf(out_fct_type out, char* buffer, const char* format, VaList* va_list) { + unsigned int flags, width, precision, n; + size_t idx = 0U; + auto maxlen = static_cast(-1); - if (!buffer) { - // use null output function - out = _out_null; - } - - while (*format) - { - // format specifier? %[flags][width][.precision][length] - if (*format != '%') { - // no - out(*format, buffer, idx++, maxlen); - format++; - continue; - } - else { - // yes, evaluate it - format++; + if (!buffer) { + // use null output function + out = _out_null; } - // evaluate flags - flags = 0U; - do { - switch (*format) { - case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break; - case '-': flags |= FLAGS_LEFT; format++; n = 1U; break; - case '+': flags |= FLAGS_PLUS; format++; n = 1U; break; - case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break; - case '#': flags |= FLAGS_HASH; format++; n = 1U; break; - default : n = 0U; break; - } - } while (n); - - // evaluate width field - width = 0U; - if (_is_digit(*format)) { - width = _atoi(&format); - } - else if (*format == '*') { - const int w = vaArgInteger(va_list); // const int w = va.next(cpu, mem); - - if (w < 0) { - flags |= FLAGS_LEFT; // reverse padding - width = (unsigned int)-w; - } - else { - width = (unsigned int)w; - } - format++; - } - - // evaluate precision field - precision = 0U; - if (*format == '.') { - flags |= FLAGS_PRECISION; - format++; - if (_is_digit(*format)) { - precision = _atoi(&format); - } - else if (*format == '*') { - precision = vaArgInteger(va_list); // precision = (unsigned int)va.next(cpu, mem); - format++; - } - } - - // evaluate length field - switch (*format) { - case 'l' : - flags |= FLAGS_LONG; - format++; - if (*format == 'l') { - flags |= FLAGS_LONG_LONG; - format++; + while (*format) { + // format specifier? %[flags][width][.precision][length] + if (*format != '%') { + // no + out(*format, buffer, idx++, maxlen); + format++; + continue; + } else { + // yes, evaluate it + format++; } - break; - case 'h' : - flags |= FLAGS_SHORT; - format++; - if (*format == 'h') { - flags |= FLAGS_CHAR; - format++; + + // evaluate flags + flags = 0U; + do { + switch (*format) { + case '0': + flags |= FLAGS_ZEROPAD; + format++; + n = 1U; + break; + case '-': + flags |= FLAGS_LEFT; + format++; + n = 1U; + break; + case '+': + flags |= FLAGS_PLUS; + format++; + n = 1U; + break; + case ' ': + flags |= FLAGS_SPACE; + format++; + n = 1U; + break; + case '#': + flags |= FLAGS_HASH; + format++; + n = 1U; + break; + default: n = 0U; break; + } + } while (n); + + // evaluate width field + width = 0U; + if (_is_digit(*format)) { + width = _atoi(&format); + } else if (*format == '*') { + const int w = vaArgInteger(va_list); // const int w = va.next(cpu, mem); + + if (w < 0) { + flags |= FLAGS_LEFT; // reverse padding + width = (unsigned int)-w; + } else { + width = (unsigned int)w; + } + format++; } - break; + + // evaluate precision field + precision = 0U; + if (*format == '.') { + flags |= FLAGS_PRECISION; + format++; + if (_is_digit(*format)) { + precision = _atoi(&format); + } else if (*format == '*') { + precision = vaArgInteger(va_list); // precision = (unsigned int)va.next(cpu, mem); + format++; + } + } + + // evaluate length field + switch (*format) { + case 'l': + flags |= FLAGS_LONG; + format++; + if (*format == 'l') { + flags |= FLAGS_LONG_LONG; + format++; + } + break; + case 'h': + flags |= FLAGS_SHORT; + format++; + if (*format == 'h') { + flags |= FLAGS_CHAR; + format++; + } + break; #if defined(PRINTF_SUPPORT_PTRDIFF_T) - case 't' : - flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); - format++; - break; + case 't': + flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; #endif - case 'j' : - flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); - format++; - break; - case 'z' : - flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); - format++; - break; - default : - break; - } - - // evaluate specifier - switch (*format) { - case 'd' : - case 'i' : - case 'u' : - case 'x' : - case 'X' : - case 'o' : - case 'b' : { - // set the base - unsigned int base; - if (*format == 'x' || *format == 'X') { - base = 16U; - } - else if (*format == 'o') { - base = 8U; - } - else if (*format == 'b') { - base = 2U; - flags &= ~FLAGS_HASH; // no hash for bin format - } - else { - base = 10U; - flags &= ~FLAGS_HASH; // no hash for dec format - } - // uppercase - if (*format == 'X') { - flags |= FLAGS_UPPERCASE; + case 'j': + flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + case 'z': + flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + default: break; } - // no plus or space flag for u, x, X, o, b - if ((*format != 'i') && (*format != 'd')) { - flags &= ~(FLAGS_PLUS | FLAGS_SPACE); - } + // evaluate specifier + switch (*format) { + case 'd': + case 'i': + case 'u': + case 'x': + case 'X': + case 'o': + case 'b': { + // set the base + unsigned int base; + if (*format == 'x' || *format == 'X') { + base = 16U; + } else if (*format == 'o') { + base = 8U; + } else if (*format == 'b') { + base = 2U; + flags &= ~FLAGS_HASH; // no hash for bin format + } else { + base = 10U; + flags &= ~FLAGS_HASH; // no hash for dec format + } + // uppercase + if (*format == 'X') { + flags |= FLAGS_UPPERCASE; + } - // convert the integer - if ((*format == 'i') || (*format == 'd')) { - // signed - if (flags & FLAGS_LONG_LONG) { + // no plus or space flag for u, x, X, o, b + if ((*format != 'i') && (*format != 'd')) { + flags &= ~(FLAGS_PLUS | FLAGS_SPACE); + } + + // convert the integer + if ((*format == 'i') || (*format == 'd')) { + // signed + if (flags & FLAGS_LONG_LONG) { #if defined(PRINTF_SUPPORT_LONG_LONG) - auto value = vaArgLongLong(va_list); // const long long value = va.next(cpu, mem); - idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); + auto value = vaArgLongLong(va_list); // const long long value = va.next(cpu, mem); + idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, + precision, width, flags); #endif - } - else if (flags & FLAGS_LONG) { - auto value = vaArgLong(va_list); // const long value = va.next(cpu, mem); - idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); - } - else { - //const int value = (flags & FLAGS_CHAR) ? (char)va.next(cpu, mem) : (flags & FLAGS_SHORT) ? (short int)va.next(cpu, mem): va.next(cpu, mem); - const int value = (flags & FLAGS_CHAR) ? static_cast(vaArgInteger(va_list)) - : (flags & FLAGS_SHORT) ? static_cast(vaArgInteger(va_list)) - : vaArgInteger(va_list); - idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); - } - } - else { - // unsigned - if (flags & FLAGS_LONG_LONG) { + } else if (flags & FLAGS_LONG) { + auto value = vaArgLong(va_list); // const long value = va.next(cpu, mem); + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, + flags); + } else { + // const int value = (flags & FLAGS_CHAR) ? (char)va.next(cpu, mem) : (flags & FLAGS_SHORT) ? (short + // int)va.next(cpu, mem): va.next(cpu, mem); + const int value = (flags & FLAGS_CHAR) ? static_cast(vaArgInteger(va_list)) + : (flags & FLAGS_SHORT) ? static_cast(vaArgInteger(va_list)) + : vaArgInteger(va_list); + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, + flags); + } + } else { + // unsigned + if (flags & FLAGS_LONG_LONG) { #if defined(PRINTF_SUPPORT_LONG_LONG) - //idx = _ntoa_long_long(out, buffer, idx, maxlen, va.next(cpu, mem), false, base, precision, width, flags); - idx = _ntoa_long_long(out, buffer, idx, maxlen, static_cast(vaArgLongLong(va_list)), false, base, precision, width, flags); + // idx = _ntoa_long_long(out, buffer, idx, maxlen, va.next(cpu, mem), false, base, precision, width, + // flags); + idx = + _ntoa_long_long(out, buffer, idx, maxlen, static_cast(vaArgLongLong(va_list)), false, base, precision, width, flags); #endif - } - else if (flags & FLAGS_LONG) { - // idx = _ntoa_long(out, buffer, idx, maxlen, va.next(cpu, mem), false, base, precision, width, flags); - idx = _ntoa_long(out, buffer, idx, maxlen, static_cast(vaArgLong(va_list)), false, base, precision, width, flags); - } - else { - //const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va.next(cpu, mem) : (flags & FLAGS_SHORT) ? - // (unsigned short int)va.next(cpu, mem) : va.next(cpu, mem); - const unsigned int value = (flags & FLAGS_CHAR) ? static_cast(vaArgInteger(va_list)) - : (flags & FLAGS_SHORT) ? static_cast(vaArgInteger(va_list)) - : static_cast(vaArgInteger(va_list)); - idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags); - } - } - format++; - break; - } + } else if (flags & FLAGS_LONG) { + // idx = _ntoa_long(out, buffer, idx, maxlen, va.next(cpu, mem), false, base, precision, width, flags); + idx = _ntoa_long(out, buffer, idx, maxlen, static_cast(vaArgLong(va_list)), false, base, precision, width, flags); + } else { + // const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va.next(cpu, mem) : (flags & FLAGS_SHORT) ? + // (unsigned short int)va.next(cpu, mem) : va.next(cpu, mem); + const unsigned int value = (flags & FLAGS_CHAR) ? static_cast(vaArgInteger(va_list)) + : (flags & FLAGS_SHORT) ? static_cast(vaArgInteger(va_list)) + : static_cast(vaArgInteger(va_list)); + idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags); + } + } + format++; + break; + } #if defined(PRINTF_SUPPORT_FLOAT) - case 'f' : - case 'F' : - //idx = _ftoa(out, buffer, idx, maxlen, va.next(cpu, mem), precision, width, flags); - idx = _ftoa(out, buffer, idx, maxlen, vaArgDouble(va_list), precision, width, flags); - format++; - break; + case 'f': + case 'F': + // idx = _ftoa(out, buffer, idx, maxlen, va.next(cpu, mem), precision, width, flags); + idx = _ftoa(out, buffer, idx, maxlen, vaArgDouble(va_list), precision, width, flags); + format++; + break; #endif // PRINTF_SUPPORT_FLOAT - case 'c' : { - unsigned int l = 1U; - // pre padding - if (!(flags & FLAGS_LEFT)) { - while (l++ < width) { - out(' ', buffer, idx++, maxlen); - } - } - // char output - //out((char)va.next(cpu, mem), buffer, idx++, maxlen); - out(static_cast(vaArgInteger(va_list)), buffer, idx++, maxlen); - // post padding - if (flags & FLAGS_LEFT) { - while (l++ < width) { - out(' ', buffer, idx++, maxlen); - } - } - format++; - break; - } + case 'c': { + unsigned int l = 1U; + // pre padding + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // char output + // out((char)va.next(cpu, mem), buffer, idx++, maxlen); + out(static_cast(vaArgInteger(va_list)), buffer, idx++, maxlen); + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } - case 's' : { - const char* p = vaArgPtr(va_list); // const char *p = va.next>(cpu, mem).get(mem); - p = p != nullptr ? p : "(null)"; - unsigned int l = _strlen(p); - // pre padding - if (flags & FLAGS_PRECISION) { - l = (l < precision ? l : precision); - } - if (!(flags & FLAGS_LEFT)) { - while (l++ < width) { - out(' ', buffer, idx++, maxlen); - } - } - // string output - while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) { - out(*(p++), buffer, idx++, maxlen); - } - // post padding - if (flags & FLAGS_LEFT) { - while (l++ < width) { - out(' ', buffer, idx++, maxlen); - } - } - format++; - break; - } + case 's': { + const char* p = vaArgPtr(va_list); // const char *p = va.next>(cpu, mem).get(mem); + p = p != nullptr ? p : "(null)"; + unsigned int l = _strlen(p); + // pre padding + if (flags & FLAGS_PRECISION) { + l = (l < precision ? l : precision); + } + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // string output + while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) { + out(*(p++), buffer, idx++, maxlen); + } + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } - case 'p' : { - width = sizeof(void*) * 2U; - flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE; + case 'p': { + width = sizeof(void*) * 2U; + flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE; #if defined(PRINTF_SUPPORT_LONG_LONG) - const bool is_ll = sizeof(uintptr_t) == sizeof(long long); - if (is_ll) { - //idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va.next>(cpu, mem).address(), false, 16U, precision, width, flags); - idx = _ntoa_long_long(out, buffer, idx, maxlen, reinterpret_cast(vaArgPtr(va_list)), false, 16U, precision, width, flags); - } - else { + const bool is_ll = sizeof(uintptr_t) == sizeof(long long); + if (is_ll) { + // idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va.next>(cpu, mem).address(), false, 16U, precision, + // width, flags); + idx = _ntoa_long_long(out, buffer, idx, maxlen, reinterpret_cast(vaArgPtr(va_list)), false, 16U, precision, + width, flags); + } else { #endif - //idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va.next>(cpu, mem).address()), false, 16U, precision, width, flags); - idx = _ntoa_long(out, buffer, idx, maxlen, static_cast(reinterpret_cast(vaArgPtr(va_list))), false, 16U, - precision, width, - flags); + // idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va.next>(cpu, mem).address()), false, 16U, + // precision, width, flags); + idx = _ntoa_long(out, buffer, idx, maxlen, static_cast(reinterpret_cast(vaArgPtr(va_list))), false, + 16U, precision, width, flags); #if defined(PRINTF_SUPPORT_LONG_LONG) - } + } #endif - format++; - break; - } + format++; + break; + } - case '%' : - out('%', buffer, idx++, maxlen); - format++; - break; + case '%': + out('%', buffer, idx++, maxlen); + format++; + break; - default : - out(*format, buffer, idx++, maxlen); - format++; - break; + default: + out(*format, buffer, idx++, maxlen); + format++; + break; + } } - } - // termination - out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); + // termination + out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); - // return written chars without terminating \0 - return (int)idx; + // return written chars without terminating \0 + return (int)idx; } static int printf_ctx(VaCtx* ctx) { - const char* format = vaArgPtr(&ctx->va_list); - char buffer[256]; - int result= _vsnprintf(_out_buffer, buffer, (size_t)-1, format, &ctx->va_list); - puts(buffer); - return result; + const char* format = vaArgPtr(&ctx->va_list); + char buffer[256]; + int result = _vsnprintf(_out_buffer, buffer, format, &ctx->va_list); + printf("%s", buffer); + return result; } -#if 0 -/////////////////////////////////////////////////////// - -/** - * Tiny sprintf implementation - * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD! - * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output! - * \param format A string that specifies the format of the output - * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character - */ -inline int sprintf(char* buffer, const char* format, CPUState &cpu, MemState &mem, module::vargs &args) -{ - const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, cpu, mem, args); - return ret; -} - -/** - * Tiny snprintf/vsnprintf implementation - * \param buffer A pointer to the buffer where to store the formatted string - * \param count The maximum number of characters to store in the buffer, including a terminating null character - * \param format A string that specifies the format of the output - * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character - * If the formatted string is truncated the buffer size (count) is returned - */ -inline int snprintf(char* buffer, size_t count, const char* format, CPUState &cpu, MemState &mem, module::vargs &args) -{ - const int ret = _vsnprintf(_out_buffer, buffer, count, format, cpu, mem, args); - return ret; -} - -#endif - } // namespace Emulator::HLE::Libraries::LibC From 5a2ee268f877258386d485c5702a4e0ff9d74cbf Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 6 Oct 2023 16:05:34 +0300 Subject: [PATCH 7/7] libc cleanups --- src/Core/PS4/HLE/LibC.cpp | 19 +++++-------------- src/Core/PS4/HLE/LibC.h | 5 +---- src/Emulator/HLE/Libraries/LibC/libc.cpp | 20 ++++++++++++++++++++ src/Emulator/HLE/Libraries/LibC/libc.h | 11 ++++++++--- 4 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/Core/PS4/HLE/LibC.cpp b/src/Core/PS4/HLE/LibC.cpp index 4ff9bc27..71e97a90 100644 --- a/src/Core/PS4/HLE/LibC.cpp +++ b/src/Core/PS4/HLE/LibC.cpp @@ -71,32 +71,23 @@ void PS4_SYSV_ABI __cxa_guard_release(u64* guard_object) { } } -int PS4_SYSV_ABI memcmp(const void* s1, const void* s2, size_t n) { return ::memcmp(s1, s2, n); } -void* PS4_SYSV_ABI memcpy(void* dest, const void* src, size_t n) { return ::memcpy(dest, src, n); } static PS4_SYSV_ABI void catchReturnFromMain(int status) { // dummy } -static PS4_SYSV_ABI void exit(int code) { ::exit(code); } -static PS4_SYSV_ABI int atexit(void (*func)()) { - int rt = ::atexit(func); - if (rt != 0) { - BREAKPOINT(); - } - return rt; -} + static PS4_SYSV_ABI void _Assert() { BREAKPOINT(); } void LibC_Register(SymbolsResolver* sym) { LIB_FUNCTION("bzQExy189ZI", "libc", 1, "libc", 1, 1, init_env); LIB_FUNCTION("3GPpjQdAMTw", "libc", 1, "libc", 1, 1, __cxa_guard_acquire); LIB_FUNCTION("9rAeANT2tyE", "libc", 1, "libc", 1, 1, __cxa_guard_release); - LIB_FUNCTION("DfivPArhucg", "libc", 1, "libc", 1, 1, memcmp); - LIB_FUNCTION("Q3VBxCXhUHs", "libc", 1, "libc", 1, 1, memcpy); + LIB_FUNCTION("DfivPArhucg", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::memcmp); + LIB_FUNCTION("Q3VBxCXhUHs", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::memcpy); LIB_FUNCTION("XKRegsFpEpk", "libc", 1, "libc", 1, 1, catchReturnFromMain); - LIB_FUNCTION("uMei1W9uyNo", "libc", 1, "libc", 1, 1, exit); - LIB_FUNCTION("8G2LB+A3rzg", "libc", 1, "libc", 1, 1, atexit); + LIB_FUNCTION("uMei1W9uyNo", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::exit); + LIB_FUNCTION("8G2LB+A3rzg", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::atexit); LIB_FUNCTION("-QgqOT5u2Vk", "libc", 1, "libc", 1, 1, _Assert); LIB_FUNCTION("hcuQgD53UxM", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::printf); diff --git a/src/Core/PS4/HLE/LibC.h b/src/Core/PS4/HLE/LibC.h index ee82b993..ea3915e2 100644 --- a/src/Core/PS4/HLE/LibC.h +++ b/src/Core/PS4/HLE/LibC.h @@ -7,12 +7,9 @@ namespace HLE::Libs::LibC { //functions static PS4_SYSV_ABI void init_env(); - static PS4_SYSV_ABI void exit(int code); static PS4_SYSV_ABI void _Assert(); static PS4_SYSV_ABI void catchReturnFromMain(int status); int PS4_SYSV_ABI __cxa_guard_acquire(u64* guard_object); void PS4_SYSV_ABI __cxa_guard_release(u64* guard_object); - int PS4_SYSV_ABI memcmp(const void* s1, const void* s2, size_t n); - void* PS4_SYSV_ABI memcpy(void* dest, const void* src, size_t n); - + }; \ No newline at end of file diff --git a/src/Emulator/HLE/Libraries/LibC/libc.cpp b/src/Emulator/HLE/Libraries/LibC/libc.cpp index ae9e8eee..7d99a1f2 100644 --- a/src/Emulator/HLE/Libraries/LibC/libc.cpp +++ b/src/Emulator/HLE/Libraries/LibC/libc.cpp @@ -1,9 +1,29 @@ #include "libc.h" +#include + +#include +#include + namespace Emulator::HLE::Libraries::LibC { PS4_SYSV_ABI int printf(VA_ARGS) { VA_CTX(ctx); return printf_ctx(&ctx); } + +PS4_SYSV_ABI void exit(int code) { std::exit(code); } + +PS4_SYSV_ABI int atexit(void (*func)()) { + int rt = std::atexit(func); + if (rt != 0) { + BREAKPOINT(); + } + return rt; +} + +int PS4_SYSV_ABI memcmp(const void* s1, const void* s2, size_t n) { return std::memcmp(s1, s2, n); } + +void* PS4_SYSV_ABI memcpy(void* dest, const void* src, size_t n) { return std::memcpy(dest, src, n); } + }; // namespace Emulator::HLE::Libraries::LibC \ No newline at end of file diff --git a/src/Emulator/HLE/Libraries/LibC/libc.h b/src/Emulator/HLE/Libraries/LibC/libc.h index 4da2bb6e..c9f632fd 100644 --- a/src/Emulator/HLE/Libraries/LibC/libc.h +++ b/src/Emulator/HLE/Libraries/LibC/libc.h @@ -1,10 +1,15 @@ #pragma once #include + #include "printf.h" namespace Emulator::HLE::Libraries::LibC { - //HLE functions - PS4_SYSV_ABI int printf(VA_ARGS); -} \ No newline at end of file +// HLE functions +PS4_SYSV_ABI int printf(VA_ARGS); +PS4_SYSV_ABI void exit(int code); +PS4_SYSV_ABI int atexit(void (*func)()); +int PS4_SYSV_ABI memcmp(const void* s1, const void* s2, size_t n); +void* PS4_SYSV_ABI memcpy(void* dest, const void* src, size_t n); +} // namespace Emulator::HLE::Libraries::LibC \ No newline at end of file