From: SchOS Project Subject: [PATCH] schos: TLS via global, mallocng decls, optional malloc tracing Three local changes to musl 1.2.5, kept in one patch because they are all "make musl work on SchOS" and share a lifetime. 1. arch/x86_64/pthread_arch.h, src/env/__init_tls.c - TLS. SchOS's kernel saves/restores FS_BASE at the syscall boundary, so arch_prctl(ARCH_SET_FS) is safe from userspace. __get_tp() is redirected through a global uintptr_t (__schos_tp) set at the START of __init_tp(), before __set_thread_area() is called. The rest of __init_tp() runs normally so td->locale and the other pthread fields still initialise. 2. src/malloc/mallocng/glue.h - build fix, NOT optional. mallocng #defines mmap/madvise/mremap to the __-prefixed internals but does not declare them in this configuration; without these prototypes the freestanding build gets implicit declarations and the wrong ABI. This had been applied by hand to the build tree and was MISSING from this patch file, so any 'make distclean' would have silently lost it. 3. src/malloc/mallocng/meta.h, malloc.c - diagnostics, inert by default. get_meta()/alloc_group() tracing that dumps group/meta pointers to fd 2, entirely inside #ifdef SCHOS_MALLOC_DEBUG, which nothing defines. Kept because this is the instrumentation that resolved the boot-crash investigation in docs/architecture/kernel-history.md section 1; build with -DSCHOS_MALLOC_DEBUG to re-enable. --- a/arch/x86_64/pthread_arch.h 2024-03-01 03:07:33.000000000 +0100 +++ b/arch/x86_64/pthread_arch.h 2026-08-01 19:11:51.533102649 +0200 @@ -1,8 +1,13 @@ +#ifdef __SCHOS__ +extern uintptr_t __schos_tp; +static inline uintptr_t __get_tp() { return __schos_tp; } +#else static inline uintptr_t __get_tp() { uintptr_t tp; __asm__ ("mov %%fs:0,%0" : "=r" (tp) ); return tp; } +#endif #define MC_PC gregs[REG_RIP] --- a/src/env/__init_tls.c 2024-03-01 03:07:33.000000000 +0100 +++ b/src/env/__init_tls.c 2026-08-01 19:11:54.666345585 +0200 @@ -11,10 +11,19 @@ volatile int __thread_list_lock; +#ifdef __SCHOS__ +uintptr_t __schos_tp; +#endif + int __init_tp(void *p) { pthread_t td = p; td->self = td; + // Set __schos_tp for __get_tp() before calling __set_thread_area. + // The kernel now correctly saves/restores FS_BASE at the syscall boundary. +#ifdef __SCHOS__ + __schos_tp = (uintptr_t)TP_ADJ(p); +#endif int r = __set_thread_area(TP_ADJ(p)); if (r < 0) return -1; if (!r) libc.can_do_threads = 1; --- a/src/malloc/mallocng/glue.h 2024-03-01 03:07:33.000000000 +0100 +++ b/src/malloc/mallocng/glue.h 2026-08-01 19:11:57.018230131 +0200 @@ -35,6 +35,10 @@ #define brk(p) ((uintptr_t)__syscall(SYS_brk, p)) +void *__mmap(void *, size_t, int, int, int, off_t); +int __madvise(void *, size_t, int); +void *__mremap(void *, size_t, size_t, int, ...); + #define mmap __mmap #define madvise __madvise #define mremap __mremap --- a/src/malloc/mallocng/meta.h 2024-03-01 03:07:33.000000000 +0100 +++ b/src/malloc/mallocng/meta.h 2026-08-01 19:11:57.041611644 +0200 @@ -6,6 +6,24 @@ #include #include "glue.h" +#ifdef SCHOS_MALLOC_DEBUG +static void schos_hex(char *out, uint64_t v) { + static const char digits[] = "0123456789abcdef"; + for (int i = 15; i >= 0; i--) { out[i] = digits[v & 0xf]; v >>= 4; } +} +static void schos_dbg(const char *tag, uint64_t a, uint64_t b, uint64_t c) { + char buf[128]; + int n = 0; + buf[n++]='['; buf[n++]='D'; buf[n++]='B'; buf[n++]='G'; buf[n++]=']'; buf[n++]=' '; + for (const char *p = tag; *p; p++) buf[n++] = *p; + buf[n++]=' '; + schos_hex(buf+n, a); n += 16; buf[n++]=' '; + schos_hex(buf+n, b); n += 16; buf[n++]=' '; + schos_hex(buf+n, c); n += 16; buf[n++]='\n'; + __syscall(SYS_write, 2, buf, n); +} +#endif + __attribute__((__visibility__("hidden"))) extern const uint16_t size_classes[]; @@ -138,6 +156,14 @@ } const struct group *base = (const void *)(p - UNIT*offset - UNIT); const struct meta *meta = base->meta; +#ifdef SCHOS_MALLOC_DEBUG + schos_dbg("get_meta p", (uint64_t)p, (uint64_t)offset, (uint64_t)index); + { + volatile uint64_t *rawbase = (volatile uint64_t *)base; + schos_dbg("get_meta RAW reread base[0..2]", rawbase[0], rawbase[1], rawbase[2]); + } + schos_dbg("get_meta base/meta/meta->mem", (uint64_t)base, (uint64_t)meta, (uint64_t)meta->mem); +#endif assert(meta->mem == base); assert(index <= meta->last_idx); assert(!(meta->avail_mask & (1u<last_idx = cnt-1; m->freeable = 1; m->sizeclass = sc; +#ifdef SCHOS_MALLOC_DEBUG + schos_dbg("alloc_group p/m/cnt", (uint64_t)p, (uint64_t)m, (uint64_t)cnt); + schos_dbg("alloc_group readback mem->meta", (uint64_t)m->mem, (uint64_t)m->mem->meta, (uint64_t)sc); +#endif return m; }