#---------------------------------------------------------------------------------
# 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
}\r
\r
consoleClearLine('2');\r
- gfxFlushBuffers();\r
}\r
}\r
//---------------------------------------------------------------------------------\r
// 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;
--- /dev/null
+.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
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();
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);
}
#include <stdlib.h>
#include <string.h>
+extern const u8 __tdata_lma[];
+extern const u8 __tdata_lma_end[];
+extern u8 __tls_start[];
+extern u8 __tls_end[];
+
struct Thread_tag
{
Handle handle;
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);
}
{
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;
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;