From 3f9513e62cc6a0cff487da73c202a8c43646d1ad Mon Sep 17 00:00:00 2001 From: fincs Date: Wed, 25 Nov 2015 21:46:54 +0100 Subject: [PATCH] Add TLS (thread local storage) support --- libctru/Makefile | 4 ++-- libctru/source/console.c | 1 - libctru/source/internal.h | 3 +++ libctru/source/system/readtp.s | 9 +++++++++ libctru/source/system/syscalls.c | 9 +++++++++ libctru/source/thread.c | 24 +++++++++++++++++++++--- 6 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 libctru/source/system/readtp.s diff --git a/libctru/Makefile b/libctru/Makefile index 5c72c83..bf53ac7 100644 --- a/libctru/Makefile +++ b/libctru/Makefile @@ -40,11 +40,11 @@ INCLUDES := include #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft CFLAGS := -g -Wall -Werror -O2 -mword-relocations \ -ffunction-sections -fno-strict-aliasing \ - -fomit-frame-pointer -ffast-math \ + -fomit-frame-pointer \ $(ARCH) CFLAGS += $(INCLUDE) -DARM11 -D_3DS diff --git a/libctru/source/console.c b/libctru/source/console.c index e195638..1044758 100644 --- a/libctru/source/console.c +++ b/libctru/source/console.c @@ -610,7 +610,6 @@ static void newRow() { } consoleClearLine('2'); - gfxFlushBuffers(); } } //--------------------------------------------------------------------------------- diff --git a/libctru/source/internal.h b/libctru/source/internal.h index 269c9c3..65ba9a6 100644 --- a/libctru/source/internal.h +++ b/libctru/source/internal.h @@ -20,6 +20,9 @@ typedef struct // Pointer to this thread's newlib state struct _reent* reent; + // Pointer to this thread's thread-local segment + void* tls_tp; // !! Keep offset in sync inside __aeabi_read_tp !! + // FS session override u32 fs_magic; Handle fs_session; diff --git a/libctru/source/system/readtp.s b/libctru/source/system/readtp.s new file mode 100644 index 0000000..2b229cc --- /dev/null +++ b/libctru/source/system/readtp.s @@ -0,0 +1,9 @@ +.arm +.section .text.__aeabi_read_tp, "ax", %progbits +.global __aeabi_read_tp +.type __aeabi_read_tp, %function +.align 2 +__aeabi_read_tp: + mrc p15, 0, r0, c13, c0, 3 + ldr r0, [r0, #0xC] @ Read ThreadVars.tls_tp + bx lr diff --git a/libctru/source/system/syscalls.c b/libctru/source/system/syscalls.c index a27482b..711f79a 100644 --- a/libctru/source/system/syscalls.c +++ b/libctru/source/system/syscalls.c @@ -13,6 +13,10 @@ void __ctru_exit(int rc); int __libctru_gtod(struct _reent *ptr, struct timeval *tp, struct timezone *tz); +extern const u8 __tdata_lma[]; +extern const u8 __tdata_lma_end[]; +extern u8 __tls_start[]; + static struct _reent* __ctru_get_reent() { ThreadVars* tv = getThreadVars(); @@ -46,4 +50,9 @@ void __system_initSyscalls(void) tv->magic = THREADVARS_MAGIC; tv->reent = _impure_ptr; tv->thread_ptr = NULL; + tv->tls_tp = __tls_start-8; // ARM ELF TLS ABI mandates an 8-byte header + + u32 tls_size = __tdata_lma_end - __tdata_lma; + if (tls_size) + memcpy(__tls_start, __tdata_lma, tls_size); } diff --git a/libctru/source/thread.c b/libctru/source/thread.c index 382534c..1b21c48 100644 --- a/libctru/source/thread.c +++ b/libctru/source/thread.c @@ -2,6 +2,11 @@ #include #include +extern const u8 __tdata_lma[]; +extern const u8 __tdata_lma_end[]; +extern u8 __tls_start[]; +extern u8 __tls_end[]; + struct Thread_tag { Handle handle; @@ -26,6 +31,7 @@ static void _thread_begin(void* arg) tv->magic = THREADVARS_MAGIC; tv->reent = &t->reent; tv->thread_ptr = t; + tv->tls_tp = (u8*)t->stacktop-8; // ARM ELF TLS ABI mandates an 8-byte header t->ep(t->arg); threadExit(0); } @@ -34,9 +40,16 @@ Thread threadCreate(ThreadFunc entrypoint, void* arg, size_t stack_size, int pri { size_t stackoffset = (sizeof(struct Thread_tag)+7)&~7; size_t allocsize = stackoffset + ((stack_size+7)&~7); - if (allocsize < stackoffset) return NULL; // guard against overflow - if ((allocsize-stackoffset) < stack_size) return NULL; // guard against overflow - Thread t = (Thread)malloc(allocsize); + size_t tlssize = __tls_end-__tls_start; + size_t tlsloadsize = __tdata_lma_end-__tdata_lma; + size_t tbsssize = tlssize-tlsloadsize; + + // Guard against overflow + if (allocsize < stackoffset) return NULL; + if ((allocsize-stackoffset) < stack_size) return NULL; + if ((allocsize+tlssize) < allocsize) return NULL; + + Thread t = (Thread)malloc(allocsize+tlssize); if (!t) return NULL; t->ep = entrypoint; @@ -45,6 +58,11 @@ Thread threadCreate(ThreadFunc entrypoint, void* arg, size_t stack_size, int pri t->finished = false; t->stacktop = (u8*)t + allocsize; + if (tlsloadsize) + memcpy(t->stacktop, __tdata_lma, tlsloadsize); + if (tbsssize) + memset((u8*)t->stacktop+tlsloadsize, 0, tbsssize); + // Set up child thread's reent struct, inheriting standard file handles _REENT_INIT_PTR(&t->reent); struct _reent* cur = getThreadVars()->reent;