diff options
Diffstat (limited to 'main/musl/0001-v1.0.0-to-2b74315d.patch')
-rw-r--r-- | main/musl/0001-v1.0.0-to-2b74315d.patch | 810 |
1 files changed, 810 insertions, 0 deletions
diff --git a/main/musl/0001-v1.0.0-to-2b74315d.patch b/main/musl/0001-v1.0.0-to-2b74315d.patch new file mode 100644 index 0000000000..57ca3e469c --- /dev/null +++ b/main/musl/0001-v1.0.0-to-2b74315d.patch @@ -0,0 +1,810 @@ +git diff v1.0.0...2b74315d8a31ad8fbcd369116c82e055e0ec3fb7 + +diff --git a/src/conf/confstr.c b/src/conf/confstr.c +index 4332f72..6e9c23a 100644 +--- a/src/conf/confstr.c ++++ b/src/conf/confstr.c +@@ -13,5 +13,5 @@ size_t confstr(int name, char *buf, size_t len) + } + // snprintf is overkill but avoid wasting code size to implement + // this completely useless function and its truncation semantics +- return snprintf(buf, len, "%s", s); ++ return snprintf(buf, len, "%s", s) + 1; + } +diff --git a/src/env/__init_security.c b/src/env/__init_security.c +index 6204c5e..da5ae94 100644 +--- a/src/env/__init_security.c ++++ b/src/env/__init_security.c +@@ -15,9 +15,7 @@ void __init_security(size_t *aux) + struct pollfd pfd[3] = { {.fd=0}, {.fd=1}, {.fd=2} }; + int i; + +-#ifndef SHARED + __init_ssp((void *)aux[AT_RANDOM]); +-#endif + + if (aux[AT_UID]==aux[AT_EUID] && aux[AT_GID]==aux[AT_EGID] + && !aux[AT_SECURE]) return; +diff --git a/src/env/__init_tls.c b/src/env/__init_tls.c +index 5c17681..8ac0036 100644 +--- a/src/env/__init_tls.c ++++ b/src/env/__init_tls.c +@@ -5,9 +5,30 @@ + #include "pthread_impl.h" + #include "libc.h" + #include "atomic.h" ++#include "syscall.h" ++ ++int __init_tp(void *p) ++{ ++ pthread_t td = p; ++ td->self = td; ++ if (__set_thread_area(TP_ADJ(p)) < 0) ++ return -1; ++ td->tid = td->pid = __syscall(SYS_set_tid_address, &td->tid); ++ td->errno_ptr = &td->errno_val; ++ /* Currently, both of these predicates depend in the same thing: ++ * successful initialization of the thread pointer. However, in ++ * the future, we may support setups where setting the thread ++ * pointer is possible but threads other than the main thread ++ * cannot work, so it's best to keep the predicates separate. */ ++ libc.has_thread_pointer = 1; ++ libc.can_do_threads = 1; ++ return 0; ++} + + #ifndef SHARED + ++static long long builtin_tls[(sizeof(struct pthread) + 64)/sizeof(long long)]; ++ + struct tls_image { + void *image; + size_t len, size, align; +@@ -61,10 +82,11 @@ typedef Elf64_Phdr Phdr; + + void __init_tls(size_t *aux) + { +- unsigned char *p, *mem; ++ unsigned char *p; + size_t n; + Phdr *phdr, *tls_phdr=0; + size_t base = 0; ++ void *mem; + + libc.tls_size = sizeof(struct pthread); + +@@ -75,21 +97,38 @@ void __init_tls(size_t *aux) + if (phdr->p_type == PT_TLS) + tls_phdr = phdr; + } +- if (!tls_phdr) return; + +- T.image = (void *)(base + tls_phdr->p_vaddr); +- T.len = tls_phdr->p_filesz; +- T.size = tls_phdr->p_memsz; +- T.align = tls_phdr->p_align; ++ if (tls_phdr) { ++ T.image = (void *)(base + tls_phdr->p_vaddr); ++ T.len = tls_phdr->p_filesz; ++ T.size = tls_phdr->p_memsz; ++ T.align = tls_phdr->p_align; ++ } + + T.size += (-T.size - (uintptr_t)T.image) & (T.align-1); + if (T.align < 4*sizeof(size_t)) T.align = 4*sizeof(size_t); + + libc.tls_size = 2*sizeof(void *)+T.size+T.align+sizeof(struct pthread); + +- mem = __mmap(0, libc.tls_size, PROT_READ|PROT_WRITE, +- MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); +- if (!__install_initial_tls(__copy_tls(mem))) a_crash(); ++ if (libc.tls_size > sizeof builtin_tls) { ++ mem = (void *)__syscall( ++#ifdef SYS_mmap2 ++ SYS_mmap2, ++#else ++ SYS_mmap, ++#endif ++ 0, libc.tls_size, PROT_READ|PROT_WRITE, ++ MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); ++ /* -4095...-1 cast to void * will crash on dereference anyway, ++ * so don't bloat the init code checking for error codes and ++ * explicitly calling a_crash(). */ ++ } else { ++ mem = builtin_tls; ++ } ++ ++ /* Failure to initialize thread pointer is fatal if TLS is used. */ ++ if (__init_tp(__copy_tls(mem)) < 0 && tls_phdr) ++ a_crash(); + } + #else + void __init_tls(size_t *auxv) { } +diff --git a/src/env/__stack_chk_fail.c b/src/env/__stack_chk_fail.c +index daa1b07..87ac473 100644 +--- a/src/env/__stack_chk_fail.c ++++ b/src/env/__stack_chk_fail.c +@@ -1,18 +1,16 @@ + #include <string.h> + #include <stdint.h> + #include "pthread_impl.h" +-#include "atomic.h" + + uintptr_t __stack_chk_guard; + + void __init_ssp(void *entropy) + { +- pthread_t self = __pthread_self_init(); +- uintptr_t canary; +- if (entropy) memcpy(&canary, entropy, sizeof canary); +- else canary = (uintptr_t)&canary * 1103515245; +- a_cas_l(&__stack_chk_guard, 0, canary); +- self->canary = __stack_chk_guard; ++ if (entropy) memcpy(&__stack_chk_guard, entropy, sizeof(uintptr_t)); ++ else __stack_chk_guard = (uintptr_t)&__stack_chk_guard * 1103515245; ++ ++ if (libc.has_thread_pointer) ++ __pthread_self()->canary = __stack_chk_guard; + } + + void __stack_chk_fail(void) +diff --git a/src/errno/__errno_location.c b/src/errno/__errno_location.c +index 3e92d7c..8419107 100644 +--- a/src/errno/__errno_location.c ++++ b/src/errno/__errno_location.c +@@ -3,6 +3,6 @@ + int *__errno_location(void) + { + static int e; +- if (libc.main_thread) return __pthread_self()->errno_ptr; ++ if (libc.has_thread_pointer) return __pthread_self()->errno_ptr; + return &e; + } +diff --git a/src/internal/libc.h b/src/internal/libc.h +index d625b56..fb4d9bc 100644 +--- a/src/internal/libc.h ++++ b/src/internal/libc.h +@@ -6,12 +6,12 @@ + #include <limits.h> + + struct __libc { +- void *main_thread; ++ int has_thread_pointer; ++ int can_do_threads; + int threaded; + int secure; + size_t *auxv; + volatile int threads_minus_1; +- int canceldisable; + FILE *ofl_head; + int ofl_lock[2]; + size_t tls_size; +diff --git a/src/internal/syscall_ret.c b/src/internal/syscall_ret.c +index d99f4a5..a3f4713 100644 +--- a/src/internal/syscall_ret.c ++++ b/src/internal/syscall_ret.c +@@ -1,4 +1,5 @@ + #include <errno.h> ++#include "syscall.h" + + long __syscall_ret(unsigned long r) + { +diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c +index a1bdf0f..1517281 100644 +--- a/src/ldso/dynlink.c ++++ b/src/ldso/dynlink.c +@@ -56,6 +56,7 @@ struct dso { + + Phdr *phdr; + int phnum; ++ size_t phentsize; + int refcnt; + Sym *syms; + uint32_t *hashtab; +@@ -74,6 +75,7 @@ struct dso { + char *rpath_orig, *rpath; + void *tls_image; + size_t tls_len, tls_size, tls_align, tls_id, tls_offset; ++ size_t relro_start, relro_end; + void **new_dtv; + unsigned char *new_tls; + int new_dtv_idx, new_tls_idx; +@@ -89,8 +91,7 @@ struct symdef { + + #include "reloc.h" + +-void __init_ssp(size_t *); +-void *__install_initial_tls(void *); ++int __init_tp(void *); + void __init_libc(char **, char *); + + const char *__libc_get_version(void); +@@ -98,7 +99,6 @@ const char *__libc_get_version(void); + static struct dso *head, *tail, *ldso, *fini_head; + static char *env_path, *sys_path; + static unsigned long long gencnt; +-static int ssp_used; + static int runtime; + static int ldd_mode; + static int ldso_fail; +@@ -108,6 +108,7 @@ static pthread_rwlock_t lock; + static struct debug debug; + static size_t tls_cnt, tls_offset, tls_align = 4*sizeof(size_t); + static pthread_mutex_t init_fini_lock = { ._m_type = PTHREAD_MUTEX_RECURSIVE }; ++static long long builtin_tls[(sizeof(struct pthread) + 64)/sizeof(long long)]; + + struct debug *_dl_debug_addr = &debug; + +@@ -198,13 +199,6 @@ static struct symdef find_sym(struct dso *dso, const char *s, int need_def) + { + uint32_t h = 0, gh = 0; + struct symdef def = {0}; +- if (dso->ghashtab) { +- gh = gnu_hash(s); +- if (gh == 0x1f4039c9 && !strcmp(s, "__stack_chk_fail")) ssp_used = 1; +- } else { +- h = sysv_hash(s); +- if (h == 0x595a4cc && !strcmp(s, "__stack_chk_fail")) ssp_used = 1; +- } + for (; dso; dso=dso->next) { + Sym *sym; + if (!dso->global) continue; +@@ -280,27 +274,32 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri + * and "donate" them to the heap by setting up minimal malloc + * structures and then freeing them. */ + +-static void reclaim(unsigned char *base, size_t start, size_t end) ++static void reclaim(struct dso *dso, size_t start, size_t end) + { + size_t *a, *z; ++ if (start >= dso->relro_start && start < dso->relro_end) start = dso->relro_end; ++ if (end >= dso->relro_start && end < dso->relro_end) end = dso->relro_start; + start = start + 6*sizeof(size_t)-1 & -4*sizeof(size_t); + end = (end & -4*sizeof(size_t)) - 2*sizeof(size_t); + if (start>end || end-start < 4*sizeof(size_t)) return; +- a = (size_t *)(base + start); +- z = (size_t *)(base + end); ++ a = (size_t *)(dso->base + start); ++ z = (size_t *)(dso->base + end); + a[-2] = 1; + a[-1] = z[0] = end-start + 2*sizeof(size_t) | 1; + z[1] = 1; + free(a); + } + +-static void reclaim_gaps(unsigned char *base, Phdr *ph, size_t phent, size_t phcnt) ++static void reclaim_gaps(struct dso *dso) + { +- for (; phcnt--; ph=(void *)((char *)ph+phent)) { ++ Phdr *ph = dso->phdr; ++ size_t phcnt = dso->phnum; ++ ++ for (; phcnt--; ph=(void *)((char *)ph+dso->phentsize)) { + if (ph->p_type!=PT_LOAD) continue; + if ((ph->p_flags&(PF_R|PF_W))!=(PF_R|PF_W)) continue; +- reclaim(base, ph->p_vaddr & -PAGE_SIZE, ph->p_vaddr); +- reclaim(base, ph->p_vaddr+ph->p_memsz, ++ reclaim(dso, ph->p_vaddr & -PAGE_SIZE, ph->p_vaddr); ++ reclaim(dso, ph->p_vaddr+ph->p_memsz, + ph->p_vaddr+ph->p_memsz+PAGE_SIZE-1 & -PAGE_SIZE); + } + } +@@ -343,13 +342,16 @@ static void *map_library(int fd, struct dso *dso) + ph = ph0 = (void *)((char *)buf + eh->e_phoff); + } + for (i=eh->e_phnum; i; i--, ph=(void *)((char *)ph+eh->e_phentsize)) { +- if (ph->p_type == PT_DYNAMIC) ++ if (ph->p_type == PT_DYNAMIC) { + dyn = ph->p_vaddr; +- if (ph->p_type == PT_TLS) { ++ } else if (ph->p_type == PT_TLS) { + tls_image = ph->p_vaddr; + dso->tls_align = ph->p_align; + dso->tls_len = ph->p_filesz; + dso->tls_size = ph->p_memsz; ++ } else if (ph->p_type == PT_GNU_RELRO) { ++ dso->relro_start = ph->p_vaddr & -PAGE_SIZE; ++ dso->relro_end = (ph->p_vaddr + ph->p_memsz) & -PAGE_SIZE; + } + if (ph->p_type != PT_LOAD) continue; + if (ph->p_vaddr < addr_min) { +@@ -393,6 +395,7 @@ static void *map_library(int fd, struct dso *dso) + dso->phdr = (void *)(base + ph->p_vaddr + + (eh->e_phoff-ph->p_offset)); + dso->phnum = eh->e_phnum; ++ dso->phentsize = eh->e_phentsize; + } + /* Reuse the existing mapping for the lowest-address LOAD */ + if ((ph->p_vaddr & -PAGE_SIZE) == addr_min) continue; +@@ -418,12 +421,12 @@ static void *map_library(int fd, struct dso *dso) + goto error; + break; + } +- if (!runtime) reclaim_gaps(base, ph0, eh->e_phentsize, eh->e_phnum); + dso->map = map; + dso->map_len = map_len; + dso->base = base; + dso->dynv = (void *)(base+dyn); + if (dso->tls_size) dso->tls_image = (void *)(base+tls_image); ++ if (!runtime) reclaim_gaps(dso); + free(allocated_buf); + return map; + noexec: +@@ -673,9 +676,10 @@ static struct dso *load_library(const char *name, struct dso *needed_by) + /* Add a shortname only if name arg was not an explicit pathname. */ + if (pathname != name) p->shortname = strrchr(p->name, '/')+1; + if (p->tls_image) { +- if (runtime && !__pthread_self_init()) { ++ if (runtime && !libc.has_thread_pointer) { + munmap(map, p->map_len); + free(p); ++ errno = ENOSYS; + return 0; + } + p->tls_id = ++tls_cnt; +@@ -764,22 +768,32 @@ static void reloc_all(struct dso *p) + 2+(dyn[DT_PLTREL]==DT_RELA)); + do_relocs(p, (void *)(p->base+dyn[DT_REL]), dyn[DT_RELSZ], 2); + do_relocs(p, (void *)(p->base+dyn[DT_RELA]), dyn[DT_RELASZ], 3); ++ ++ if (p->relro_start != p->relro_end && ++ mprotect(p->base+p->relro_start, p->relro_end-p->relro_start, PROT_READ) < 0) { ++ snprintf(errbuf, sizeof errbuf, ++ "Error relocating %s: RELRO protection failed: %m", ++ p->name); ++ if (runtime) longjmp(*rtld_fail, 1); ++ dprintf(2, "%s\n", errbuf); ++ ldso_fail = 1; ++ } ++ + p->relocated = 1; + } + } + +-static size_t find_dyn(Phdr *ph, size_t cnt, size_t stride) ++static void kernel_mapped_dso(struct dso *p) + { +- for (; cnt--; ph = (void *)((char *)ph + stride)) +- if (ph->p_type == PT_DYNAMIC) +- return ph->p_vaddr; +- return 0; +-} +- +-static void find_map_range(Phdr *ph, size_t cnt, size_t stride, struct dso *p) +-{ +- size_t min_addr = -1, max_addr = 0; +- for (; cnt--; ph = (void *)((char *)ph + stride)) { ++ size_t min_addr = -1, max_addr = 0, cnt; ++ Phdr *ph = p->phdr; ++ for (cnt = p->phnum; cnt--; ph = (void *)((char *)ph + p->phentsize)) { ++ if (ph->p_type == PT_DYNAMIC) { ++ p->dynv = (void *)(p->base + ph->p_vaddr); ++ } else if (ph->p_type == PT_GNU_RELRO) { ++ p->relro_start = ph->p_vaddr & -PAGE_SIZE; ++ p->relro_end = (ph->p_vaddr + ph->p_memsz) & -PAGE_SIZE; ++ } + if (ph->p_type != PT_LOAD) continue; + if (ph->p_vaddr < min_addr) + min_addr = ph->p_vaddr; +@@ -790,6 +804,7 @@ static void find_map_range(Phdr *ph, size_t cnt, size_t stride, struct dso *p) + max_addr = (max_addr + PAGE_SIZE-1) & -PAGE_SIZE; + p->map = p->base + min_addr; + p->map_len = max_addr - min_addr; ++ p->kernel_mapped = 1; + } + + static void do_fini() +@@ -866,10 +881,13 @@ void *__copy_tls(unsigned char *mem) + pthread_t td; + struct dso *p; + +- if (!tls_cnt) return mem; +- + void **dtv = (void *)mem; + dtv[0] = (void *)tls_cnt; ++ if (!tls_cnt) { ++ td = (void *)(dtv+1); ++ td->dtv = dtv; ++ return td; ++ } + + #ifdef TLS_ABOVE_TP + mem += sizeof(void *) * (tls_cnt+1); +@@ -962,6 +980,7 @@ void *__dynlink(int argc, char **argv) + size_t vdso_base; + size_t *auxv; + char **envp = argv+argc+1; ++ void *initial_tls; + + /* Find aux vector just past environ[] */ + for (i=argc+1; argv[i]; i++) +@@ -996,13 +1015,11 @@ void *__dynlink(int argc, char **argv) + lib->base = (void *)aux[AT_BASE]; + lib->name = lib->shortname = "libc.so"; + lib->global = 1; +- lib->kernel_mapped = 1; + ehdr = (void *)lib->base; + lib->phnum = ehdr->e_phnum; + lib->phdr = (void *)(aux[AT_BASE]+ehdr->e_phoff); +- find_map_range(lib->phdr, ehdr->e_phnum, ehdr->e_phentsize, lib); +- lib->dynv = (void *)(lib->base + find_dyn(lib->phdr, +- ehdr->e_phnum, ehdr->e_phentsize)); ++ lib->phentsize = ehdr->e_phentsize; ++ kernel_mapped_dso(lib); + decode_dyn(lib); + + if (aux[AT_PHDR]) { +@@ -1011,6 +1028,7 @@ void *__dynlink(int argc, char **argv) + /* Find load address of the main program, via AT_PHDR vs PT_PHDR. */ + app->phdr = phdr = (void *)aux[AT_PHDR]; + app->phnum = aux[AT_PHNUM]; ++ app->phentsize = aux[AT_PHENT]; + for (i=aux[AT_PHNUM]; i; i--, phdr=(void *)((char *)phdr + aux[AT_PHENT])) { + if (phdr->p_type == PT_PHDR) + app->base = (void *)(aux[AT_PHDR] - phdr->p_vaddr); +@@ -1030,11 +1048,7 @@ void *__dynlink(int argc, char **argv) + app->name = (char *)aux[AT_EXECFN]; + else + app->name = argv[0]; +- app->kernel_mapped = 1; +- app->dynv = (void *)(app->base + find_dyn( +- (void *)aux[AT_PHDR], aux[AT_PHNUM], aux[AT_PHENT])); +- find_map_range((void *)aux[AT_PHDR], +- aux[AT_PHNUM], aux[AT_PHENT], app); ++ kernel_mapped_dso(app); + } else { + int fd; + char *ldname = argv[0]; +@@ -1100,6 +1114,7 @@ void *__dynlink(int argc, char **argv) + ehdr = (void *)vdso_base; + vdso->phdr = phdr = (void *)(vdso_base + ehdr->e_phoff); + vdso->phnum = ehdr->e_phnum; ++ vdso->phentsize = ehdr->e_phentsize; + for (i=ehdr->e_phnum; i; i--, phdr=(void *)((char *)phdr + ehdr->e_phentsize)) { + if (phdr->p_type == PT_DYNAMIC) + vdso->dynv = (void *)(vdso_base + phdr->p_offset); +@@ -1127,10 +1142,8 @@ void *__dynlink(int argc, char **argv) + /* PAST THIS POINT, ALL LIBC INTERFACES ARE FULLY USABLE. */ + + /* Donate unused parts of app and library mapping to malloc */ +- reclaim_gaps(app->base, (void *)aux[AT_PHDR], aux[AT_PHENT], aux[AT_PHNUM]); +- ehdr = (void *)lib->base; +- reclaim_gaps(lib->base, (void *)(lib->base+ehdr->e_phoff), +- ehdr->e_phentsize, ehdr->e_phnum); ++ reclaim_gaps(app); ++ reclaim_gaps(lib); + + /* Load preload/needed libraries, add their symbols to the global + * namespace, and perform all remaining relocations. The main +@@ -1140,19 +1153,29 @@ void *__dynlink(int argc, char **argv) + load_deps(app); + make_global(app); + ++#ifndef DYNAMIC_IS_RO ++ for (i=0; app->dynv[i]; i+=2) ++ if (app->dynv[i]==DT_DEBUG) ++ app->dynv[i+1] = (size_t)&debug; ++#endif ++ + reloc_all(app->next); + reloc_all(app); + + update_tls_size(); +- if (tls_cnt) { +- void *mem = mmap(0, libc.tls_size, PROT_READ|PROT_WRITE, +- MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); +- if (mem==MAP_FAILED || +- !__install_initial_tls(__copy_tls(mem))) { ++ if (libc.tls_size > sizeof builtin_tls) { ++ initial_tls = calloc(libc.tls_size, 1); ++ if (!initial_tls) { + dprintf(2, "%s: Error getting %zu bytes thread-local storage: %m\n", + argv[0], libc.tls_size); + _exit(127); + } ++ } else { ++ initial_tls = builtin_tls; ++ } ++ if (__init_tp(__copy_tls(initial_tls)) < 0 && tls_cnt) { ++ dprintf(2, "%s: Thread-local storage not supported by kernel.\n", argv[0]); ++ _exit(127); + } + + if (ldso_fail) _exit(127); +@@ -1164,11 +1187,6 @@ void *__dynlink(int argc, char **argv) + * all memory used by the dynamic linker. */ + runtime = 1; + +-#ifndef DYNAMIC_IS_RO +- for (i=0; app->dynv[i]; i+=2) +- if (app->dynv[i]==DT_DEBUG) +- app->dynv[i+1] = (size_t)&debug; +-#endif + debug.ver = 1; + debug.bp = _dl_debug_state; + debug.head = head; +@@ -1176,7 +1194,6 @@ void *__dynlink(int argc, char **argv) + debug.state = 0; + _dl_debug_state(); + +- if (ssp_used) __init_ssp((void *)aux[AT_RANDOM]); + __init_libc(envp, argv[0]); + atexit(do_fini); + errno = 0; +@@ -1258,9 +1275,6 @@ void *dlopen(const char *file, int mode) + } + + update_tls_size(); +- +- if (ssp_used) __init_ssp(libc.auxv); +- + _dl_debug_state(); + orig_tail = tail; + end: +diff --git a/src/process/fork.c b/src/process/fork.c +index 1a82f42..864c7d7 100644 +--- a/src/process/fork.c ++++ b/src/process/fork.c +@@ -17,12 +17,11 @@ pid_t fork(void) + __fork_handler(-1); + __block_all_sigs(&set); + ret = syscall(SYS_fork); +- if (libc.main_thread && !ret) { ++ if (libc.has_thread_pointer && !ret) { + pthread_t self = __pthread_self(); +- self->tid = self->pid = syscall(SYS_getpid); ++ self->tid = self->pid = __syscall(SYS_getpid); + memset(&self->robust_list, 0, sizeof self->robust_list); + libc.threads_minus_1 = 0; +- libc.main_thread = self; + } + __restore_sigs(&set); + __fork_handler(!ret); +diff --git a/src/signal/sigaction.c b/src/signal/sigaction.c +index f7ff4a6..d5f4774 100644 +--- a/src/signal/sigaction.c ++++ b/src/signal/sigaction.c +@@ -8,9 +8,7 @@ + + void __restore(), __restore_rt(); + +-static pthread_t dummy(void) { return 0; } +-weak_alias(dummy, __pthread_self_def); +- ++static int unmask_done; + static unsigned long handler_set[_NSIG/(8*sizeof(long))]; + + void __get_handler_set(sigset_t *set) +@@ -29,7 +27,20 @@ int __libc_sigaction(int sig, const struct sigaction *restrict sa, struct sigact + if ((uintptr_t)sa->sa_handler > 1UL) { + a_or_l(handler_set+(sig-1)/(8*sizeof(long)), + 1UL<<(sig-1)%(8*sizeof(long))); +- __pthread_self_def(); ++ ++ /* If pthread_create has not yet been called, ++ * implementation-internal signals might not ++ * yet have been unblocked. They must be ++ * unblocked before any signal handler is ++ * installed, so that an application cannot ++ * receive an illegal sigset_t (with them ++ * blocked) as part of the ucontext_t passed ++ * to the signal handler. */ ++ if (!libc.threaded && !unmask_done) { ++ __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK, ++ SIGPT_SET, 0, _NSIG/8); ++ unmask_done = 1; ++ } + } + ksa.handler = sa->sa_handler; + ksa.flags = sa->sa_flags | SA_RESTORER; +diff --git a/src/stdio/__stdio_read.c b/src/stdio/__stdio_read.c +index 05e56f9..6cd7b07 100644 +--- a/src/stdio/__stdio_read.c ++++ b/src/stdio/__stdio_read.c +@@ -16,13 +16,9 @@ size_t __stdio_read(FILE *f, unsigned char *buf, size_t len) + }; + ssize_t cnt; + +- if (libc.main_thread) { +- pthread_cleanup_push(cleanup, f); +- cnt = syscall_cp(SYS_readv, f->fd, iov, 2); +- pthread_cleanup_pop(0); +- } else { +- cnt = syscall(SYS_readv, f->fd, iov, 2); +- } ++ pthread_cleanup_push(cleanup, f); ++ cnt = syscall_cp(SYS_readv, f->fd, iov, 2); ++ pthread_cleanup_pop(0); + if (cnt <= 0) { + f->flags |= F_EOF ^ ((F_ERR^F_EOF) & cnt); + f->rpos = f->rend = 0; +diff --git a/src/stdio/__stdio_write.c b/src/stdio/__stdio_write.c +index e52e91a..8c89389 100644 +--- a/src/stdio/__stdio_write.c ++++ b/src/stdio/__stdio_write.c +@@ -19,13 +19,9 @@ size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len) + int iovcnt = 2; + ssize_t cnt; + for (;;) { +- if (libc.main_thread) { +- pthread_cleanup_push(cleanup, f); +- cnt = syscall_cp(SYS_writev, f->fd, iov, iovcnt); +- pthread_cleanup_pop(0); +- } else { +- cnt = syscall(SYS_writev, f->fd, iov, iovcnt); +- } ++ pthread_cleanup_push(cleanup, f); ++ cnt = syscall_cp(SYS_writev, f->fd, iov, iovcnt); ++ pthread_cleanup_pop(0); + if (cnt == rem) { + f->wend = f->buf + f->buf_size; + f->wpos = f->wbase = f->buf; +diff --git a/src/thread/cancel_impl.c b/src/thread/cancel_impl.c +index c835813..525d290 100644 +--- a/src/thread/cancel_impl.c ++++ b/src/thread/cancel_impl.c +@@ -20,7 +20,7 @@ long (__syscall_cp)(syscall_arg_t nr, + pthread_t self; + long r; + +- if (!libc.main_thread || (self = __pthread_self())->canceldisable) ++ if (!libc.has_thread_pointer || (self = __pthread_self())->canceldisable) + return __syscall(nr, u, v, w, x, y, z); + + r = __syscall_cp_asm(&self->cancel, nr, u, v, w, x, y, z); +@@ -57,6 +57,7 @@ static void cancel_handler(int sig, siginfo_t *si, void *ctx) + + void __testcancel() + { ++ if (!libc.has_thread_pointer) return; + pthread_t self = pthread_self(); + if (self->cancel && !self->canceldisable) + __cancel(); +diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c +index ee6c31c..e0b5ef1 100644 +--- a/src/thread/pthread_create.c ++++ b/src/thread/pthread_create.c +@@ -77,6 +77,7 @@ _Noreturn void pthread_exit(void *result) + + void __do_cleanup_push(struct __ptcb *cb) + { ++ if (!libc.has_thread_pointer) return; + struct pthread *self = pthread_self(); + cb->__next = self->cancelbuf; + self->cancelbuf = cb; +@@ -84,6 +85,7 @@ void __do_cleanup_push(struct __ptcb *cb) + + void __do_cleanup_pop(struct __ptcb *cb) + { ++ if (!libc.has_thread_pointer) return; + __pthread_self()->cancelbuf = cb->__next; + } + +@@ -110,6 +112,8 @@ static int start(void *p) + /* pthread_key_create.c overrides this */ + static const size_t dummy = 0; + weak_alias(dummy, __pthread_tsd_size); ++static void *const dummy_tsd[1] = { 0 }; ++weak_alias(dummy_tsd, __pthread_tsd_main); + + static FILE *const dummy_file = 0; + weak_alias(dummy_file, __stdin_used); +@@ -127,7 +131,7 @@ int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp + { + int ret; + size_t size, guard; +- struct pthread *self = pthread_self(), *new; ++ struct pthread *self, *new; + unsigned char *map = 0, *stack = 0, *tsd = 0, *stack_limit; + unsigned flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND + | CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS +@@ -135,13 +139,16 @@ int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp + int do_sched = 0; + pthread_attr_t attr = {0}; + +- if (!self) return ENOSYS; ++ if (!libc.can_do_threads) return ENOSYS; ++ self = __pthread_self(); + if (!libc.threaded) { + for (FILE *f=libc.ofl_head; f; f=f->next) + init_file_lock(f); + init_file_lock(__stdin_used); + init_file_lock(__stdout_used); + init_file_lock(__stderr_used); ++ __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK, SIGPT_SET, 0, _NSIG/8); ++ self->tsd = (void **)__pthread_tsd_main; + libc.threaded = 1; + } + if (attrp) attr = *attrp; +diff --git a/src/thread/pthread_key_create.c b/src/thread/pthread_key_create.c +index c29935c..ef8a755 100644 +--- a/src/thread/pthread_key_create.c ++++ b/src/thread/pthread_key_create.c +@@ -14,7 +14,13 @@ int pthread_key_create(pthread_key_t *k, void (*dtor)(void *)) + unsigned i = (uintptr_t)&k / 16 % PTHREAD_KEYS_MAX; + unsigned j = i; + +- __pthread_self_init(); ++ if (libc.has_thread_pointer) { ++ pthread_t self = __pthread_self(); ++ /* This can only happen in the main thread before ++ * pthread_create has been called. */ ++ if (!self->tsd) self->tsd = __pthread_tsd_main; ++ } ++ + if (!dtor) dtor = nodtor; + do { + if (!a_cas_p(keys+j, 0, (void *)dtor)) { +diff --git a/src/thread/pthread_self.c b/src/thread/pthread_self.c +index aed4b5f..5f9e651 100644 +--- a/src/thread/pthread_self.c ++++ b/src/thread/pthread_self.c +@@ -1,45 +1,6 @@ + #include "pthread_impl.h" + +-static struct pthread *main_thread = &(struct pthread){0}; +- +-/* pthread_key_create.c overrides this */ +-static const void *dummy[1] = { 0 }; +-weak_alias(dummy, __pthread_tsd_main); +- +-static int init_main_thread() +-{ +- __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK, +- SIGPT_SET, 0, _NSIG/8); +- if (__set_thread_area(TP_ADJ(main_thread)) < 0) return -1; +- main_thread->canceldisable = libc.canceldisable; +- main_thread->tsd = (void **)__pthread_tsd_main; +- main_thread->errno_ptr = __errno_location(); +- main_thread->self = main_thread; +- main_thread->tid = main_thread->pid = +- __syscall(SYS_set_tid_address, &main_thread->tid); +- if (!main_thread->dtv) +- main_thread->dtv = (void *)dummy; +- libc.main_thread = main_thread; +- return 0; +-} +- +-pthread_t __pthread_self_def() ++pthread_t pthread_self() + { +- static int init, failed; +- if (!init) { +- if (failed) return 0; +- if (init_main_thread() < 0) failed = 1; +- if (failed) return 0; +- init = 1; +- } + return __pthread_self(); + } +- +-weak_alias(__pthread_self_def, pthread_self); +-weak_alias(__pthread_self_def, __pthread_self_init); +- +-void *__install_initial_tls(void *p) +-{ +- main_thread = p; +- return __pthread_self_def(); +-} +diff --git a/src/thread/pthread_setcancelstate.c b/src/thread/pthread_setcancelstate.c +index ba2b231..060bcdc 100644 +--- a/src/thread/pthread_setcancelstate.c ++++ b/src/thread/pthread_setcancelstate.c +@@ -3,13 +3,9 @@ + int pthread_setcancelstate(int new, int *old) + { + if (new > 1U) return EINVAL; +- if (libc.main_thread) { +- struct pthread *self = __pthread_self(); +- if (old) *old = self->canceldisable; +- self->canceldisable = new; +- } else { +- if (old) *old = libc.canceldisable; +- libc.canceldisable = new; +- } ++ if (!libc.has_thread_pointer) return ENOSYS; ++ struct pthread *self = __pthread_self(); ++ if (old) *old = self->canceldisable; ++ self->canceldisable = new; + return 0; + } |