From 313f281ee81acda5e469cc7093d04c32c5d49c55 Mon Sep 17 00:00:00 2001 From: Maschell Date: Wed, 21 Jun 2023 11:13:02 +0200 Subject: [PATCH] Fix reent usage for modules --- Makefile | 2 +- include/wums/meta.h | 38 ++++++----- libraries/libwums/crt.c | 27 -------- libraries/libwums/crt.cpp | 54 +++++++++++++++ libraries/libwums/wums_reent.cpp | 78 ++++++++++++++++++++++ libraries/libwums/wums_reent.h | 3 + libraries/libwums/wums_thread_specific.cpp | 55 +++++++++++++++ libraries/libwums/wums_thread_specific.h | 18 +++++ 8 files changed, 231 insertions(+), 44 deletions(-) delete mode 100644 libraries/libwums/crt.c create mode 100644 libraries/libwums/crt.cpp create mode 100644 libraries/libwums/wums_reent.cpp create mode 100644 libraries/libwums/wums_reent.h create mode 100644 libraries/libwums/wums_thread_specific.cpp create mode 100644 libraries/libwums/wums_thread_specific.h diff --git a/Makefile b/Makefile index 83f9453..1d4c60a 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ CFLAGS := -g -Wall -Werror -save-temps \ CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -D__WUM__ -CXXFLAGS := $(CFLAGS) -std=gnu++17 +CXXFLAGS := $(CFLAGS) -fno-exceptions -fno-rtti -std=gnu++20 ASFLAGS := -g $(MACHDEP) diff --git a/include/wums/meta.h b/include/wums/meta.h index 3d792a7..0134d18 100644 --- a/include/wums/meta.h +++ b/include/wums/meta.h @@ -39,22 +39,28 @@ extern "C" { #endif -#define WUMS_MODULE_EXPORT_NAME(x) \ - WUMS_META(export_name, x); \ - WUMS_META(wums, "0.3.2"); \ - WUMS_USE_WUT_MALLOC(); \ - WUMS_USE_WUT_SOCKETS(); \ - WUMS_USE_WUT_NEWLIB(); \ - WUMS_USE_WUT_STDCPP(); \ - WUMS___INIT_WRAPPER(); \ - WUMS___FINI_WRAPPER(); \ - __EXTERN_C_MACRO void abort(); \ - void abort() { \ - OSFatal(x ": abort() called. Uncaught exception?"); \ - while (1) \ - ; \ - } \ - WUMS_META(buildtimestamp, __DATE__ " " __TIME__) +#define WUMS_VERSION "0.3.2" + +#define WUMS_MODULE_EXPORT_NAME(__module_name) \ + WUMS_META(export_name, __module_name); \ + WUMS_META(wums, WUMS_VERSION); \ + WUMS_USE_WUT_MALLOC(); \ + WUMS_USE_WUT_SOCKETS(); \ + WUMS_USE_WUT_NEWLIB(); \ + WUMS_USE_WUT_STDCPP(); \ + WUMS___INIT_WRAPPER(); \ + WUMS___FINI_WRAPPER(); \ + __EXTERN_C_MACRO void abort(); \ + void abort() { \ + OSFatal(__module_name ": abort() called. Uncaught exception?"); \ + while (1) \ + ; \ + } \ + WUMS_META(buildtimestamp, __DATE__ " " __TIME__); \ + extern const char wums_meta_info_dump[] WUMS_SECTION("meta"); \ + const char wums_meta_info_dump[] = "(module: " __module_name ";" \ + "wums " WUMS_VERSION ";" \ + "buildtime: " __DATE__ " " __TIME__ ")" #define WUMS_MODULE_AUTHOR(x) WUMS_META(author, x) #define WUMS_MODULE_VERSION(x) WUMS_META(version, x) diff --git a/libraries/libwums/crt.c b/libraries/libwums/crt.c deleted file mode 100644 index 93dbf77..0000000 --- a/libraries/libwums/crt.c +++ /dev/null @@ -1,27 +0,0 @@ -int main(int argc, char **argv) { - return 0; -} - -extern __attribute__((weak)) void __wut_socket_init_devoptab(); -extern __attribute__((weak)) void __wut_socket_fini_devoptab(); - -static int __wut_socket_devoptab_added = 0; - -extern void socket_lib_init(); - -void __attribute__((weak)) __init_wut_socket() { - if (!&__wut_socket_init_devoptab) return; - if (!__wut_socket_devoptab_added) { - socket_lib_init(); - __wut_socket_init_devoptab(); - __wut_socket_devoptab_added = 1; - } -} - -void __attribute__((weak)) __fini_wut_socket() { - if (!&__wut_socket_init_devoptab || !&__wut_socket_fini_devoptab) return; - if (__wut_socket_devoptab_added) { - __wut_socket_fini_devoptab(); - __wut_socket_devoptab_added = 0; - } -} \ No newline at end of file diff --git a/libraries/libwums/crt.cpp b/libraries/libwums/crt.cpp new file mode 100644 index 0000000..5c030ab --- /dev/null +++ b/libraries/libwums/crt.cpp @@ -0,0 +1,54 @@ +#include "wums_reent.h" +#include "wums_thread_specific.h" + +extern "C" void OSFatal(const char *); + +int main(int argc, char **argv) { + OSFatal("This file needs to be run with the Wii U Module Loader."); + return 0; +} + +extern "C" __attribute__((weak)) void __wut_socket_init_devoptab(); + +extern "C" __attribute__((weak)) void __wut_socket_fini_devoptab(); + +static int __wut_socket_devoptab_added = 0; + +extern "C" __attribute__((weak)) void socket_lib_init(); + +extern "C" void __attribute__((weak)) __init_wut_socket(); + +void __attribute__((weak)) __init_wut_socket() { + if (!&__wut_socket_init_devoptab || !&socket_lib_init) return; + if (!__wut_socket_devoptab_added) { + socket_lib_init(); + __wut_socket_init_devoptab(); + __wut_socket_devoptab_added = 1; + } +} + +extern "C" void __attribute__((weak)) __fini_wut_socket(); + +void __attribute__((weak)) __fini_wut_socket() { + if (!&__wut_socket_init_devoptab || !&__wut_socket_fini_devoptab) return; + if (__wut_socket_devoptab_added) { + __wut_socket_fini_devoptab(); + __wut_socket_devoptab_added = 0; + } +} + +struct _reent *__getreent(void) { + return __wums_getreent(); +} + +extern "C" void __attribute__((weak)) wut_set_thread_specific(__wut_thread_specific_id id, void *value); + +void wut_set_thread_specific(__wut_thread_specific_id id, void *value) { + return wums_set_thread_specific(id, value); +} + +extern "C" void *__attribute__((weak)) wut_get_thread_specific(__wut_thread_specific_id id); + +void *wut_get_thread_specific(__wut_thread_specific_id id) { + return wums_get_thread_specific(id); +} diff --git a/libraries/libwums/wums_reent.cpp b/libraries/libwums/wums_reent.cpp new file mode 100644 index 0000000..7441e9f --- /dev/null +++ b/libraries/libwums/wums_reent.cpp @@ -0,0 +1,78 @@ +#include "wums_thread_specific.h" +#include +#include +#include + +#define __WUMS_CONTEXT_THREAD_SPECIFIC_ID WUT_THREAD_SPECIFIC_1 + +typedef uint32_t OSThread; + +extern const char wums_meta_info_dump[]; + +extern void OSFatal(const char *); +extern void OSReport(const char *, ...); + +extern OSThread *OSGetCurrentThread(); + +typedef void (*OSThreadCleanupCallbackFn)(OSThread *thread, void *stack); + +OSThreadCleanupCallbackFn +OSSetThreadCleanupCallback(OSThread *thread, + OSThreadCleanupCallbackFn callback); + + +struct __wums_thread_context { + struct _reent reent; + OSThreadCleanupCallbackFn savedCleanup; +}; + +static void +__wums_thread_cleanup(OSThread *thread, + void *stack) { + struct __wums_thread_context *context; + + context = (struct __wums_thread_context *) wums_get_thread_specific(__WUMS_CONTEXT_THREAD_SPECIFIC_ID); + if (!context || &context->reent == _GLOBAL_REENT) { + OSReport("[%s] __wums_thread_cleanup: Context was NULL or reent was global\n", wums_meta_info_dump); + OSFatal("__wums_thread_cleanup: Context was NULL or reent was global"); + } + + if (context->savedCleanup) { + context->savedCleanup(thread, stack); + } + + _reclaim_reent(&context->reent); + + // Use global reent during free since the current reent is getting freed + wums_set_thread_specific(__WUMS_CONTEXT_THREAD_SPECIFIC_ID, _GLOBAL_REENT); + + free(context); + + wums_set_thread_specific(__WUMS_CONTEXT_THREAD_SPECIFIC_ID, NULL); +} + +struct _reent * +__wums_getreent(void) { + struct __wums_thread_context *context; + + context = (struct __wums_thread_context *) wums_get_thread_specific(__WUMS_CONTEXT_THREAD_SPECIFIC_ID); + if (!context) { + // Temporarily use global reent during context allocation + wums_set_thread_specific(__WUMS_CONTEXT_THREAD_SPECIFIC_ID, _GLOBAL_REENT); + + context = (struct __wums_thread_context *) malloc(sizeof(*context)); + if (!context) { + OSReport("[%s] __wums_getreent: Failed to allocate reent context\n", wums_meta_info_dump); + OSFatal("__wums_getreent: Failed to allocate reent context"); + wums_set_thread_specific(__WUMS_CONTEXT_THREAD_SPECIFIC_ID, NULL); + return NULL; + } + + _REENT_INIT_PTR(&context->reent); + context->savedCleanup = OSSetThreadCleanupCallback(OSGetCurrentThread(), &__wums_thread_cleanup); + + wums_set_thread_specific(__WUMS_CONTEXT_THREAD_SPECIFIC_ID, context); + } + + return &context->reent; +} diff --git a/libraries/libwums/wums_reent.h b/libraries/libwums/wums_reent.h new file mode 100644 index 0000000..1582765 --- /dev/null +++ b/libraries/libwums/wums_reent.h @@ -0,0 +1,3 @@ +#pragma once + +struct _reent *__wums_getreent(); \ No newline at end of file diff --git a/libraries/libwums/wums_thread_specific.cpp b/libraries/libwums/wums_thread_specific.cpp new file mode 100644 index 0000000..8cb62c0 --- /dev/null +++ b/libraries/libwums/wums_thread_specific.cpp @@ -0,0 +1,55 @@ +#include "wums_thread_specific.h" +#include +#include + +extern "C" void OSFatal(const char *); +extern "C" void OSReport(const char *, ...); + +typedef struct OSThread { + uint8_t other[0x68c]; + void *reserved[5]; +} OSThread; + +static_assert(offsetof(OSThread, reserved) == 0x68c, "OSThread: \"reserved\" at wrong offset"); +static_assert(sizeof(OSThread) == 0x6a0, "OSThread: wrong size"); + +extern "C" const char wums_meta_info_dump[]; + +void wums_set_thread_specific(__wut_thread_specific_id id, void *value) { + OSThread *thread; + asm volatile("lwz %0, -0x20(0)" + : "=r"(thread)); // OSGetCurrentThread() + if (thread != nullptr) { + if (id == WUT_THREAD_SPECIFIC_0) { + thread->reserved[3] = value; + } else if (id == WUT_THREAD_SPECIFIC_1) { + thread->reserved[4] = value; + } else { + OSReport("[%s] wums_set_thread_specific: invalid id\n", wums_meta_info_dump); + OSFatal("wut_set_thread_specific: invalid id"); + } + } else { + OSReport("[%s] wums_set_thread_specific: invalid thread\n", wums_meta_info_dump); + OSFatal("wums_set_thread_specific: invalid thread"); + } +} + +void *wums_get_thread_specific(__wut_thread_specific_id id) { + OSThread *thread; + asm volatile("lwz %0, -0x20(0)" + : "=r"(thread)); // OSGetCurrentThread() + if (thread != nullptr) { + if (id == WUT_THREAD_SPECIFIC_0) { + return thread->reserved[3]; + } else if (id == WUT_THREAD_SPECIFIC_1) { + return thread->reserved[4]; + } else { + OSReport("[%s] wums_get_thread_specific: invalid id\n", wums_meta_info_dump); + OSFatal("wums_get_thread_specific: invalid id"); + } + } else { + OSReport("[%s] wums_get_thread_specific: invalid thread\n", wums_meta_info_dump); + OSFatal("wums_get_thread_specific: invalid thread\n"); + } + return nullptr; +} \ No newline at end of file diff --git a/libraries/libwums/wums_thread_specific.h b/libraries/libwums/wums_thread_specific.h new file mode 100644 index 0000000..6a7d922 --- /dev/null +++ b/libraries/libwums/wums_thread_specific.h @@ -0,0 +1,18 @@ +#pragma once + +typedef enum __wut_thread_specific_id { + WUT_THREAD_SPECIFIC_0 = 0, + WUT_THREAD_SPECIFIC_1 = 1, +} __wut_thread_specific_id; + +#ifdef __cplusplus +extern "C" { +#endif + +void wums_set_thread_specific(__wut_thread_specific_id id, void *value); + +void *wums_get_thread_specific(__wut_thread_specific_id id); + +#ifdef __cplusplus +} +#endif \ No newline at end of file