OLD | NEW |
(Empty) | |
| 1 #include <elf.h> |
| 2 #include <limits.h> |
| 3 #include <sys/mman.h> |
| 4 #include <string.h> |
| 5 #include <stddef.h> |
| 6 #include "pthread_impl.h" |
| 7 #include "libc.h" |
| 8 #include "atomic.h" |
| 9 #include "syscall.h" |
| 10 |
| 11 int __init_tp(void *p) |
| 12 { |
| 13 pthread_t td = p; |
| 14 td->self = td; |
| 15 int r = __set_thread_area(TP_ADJ(p)); |
| 16 if (r < 0) return -1; |
| 17 if (!r) libc.can_do_threads = 1; |
| 18 td->tid = __syscall(SYS_set_tid_address, &td->tid); |
| 19 td->locale = &libc.global_locale; |
| 20 td->robust_list.head = &td->robust_list.head; |
| 21 return 0; |
| 22 } |
| 23 |
| 24 static struct builtin_tls { |
| 25 char c; |
| 26 struct pthread pt; |
| 27 void *space[16]; |
| 28 } builtin_tls[1]; |
| 29 #define MIN_TLS_ALIGN offsetof(struct builtin_tls, pt) |
| 30 |
| 31 static struct tls_module main_tls; |
| 32 |
| 33 void *__copy_tls(unsigned char *mem) |
| 34 { |
| 35 pthread_t td; |
| 36 struct tls_module *p; |
| 37 size_t i; |
| 38 void **dtv; |
| 39 |
| 40 #ifdef TLS_ABOVE_TP |
| 41 dtv = (void **)(mem + libc.tls_size) - (libc.tls_cnt + 1); |
| 42 |
| 43 mem += -((uintptr_t)mem + sizeof(struct pthread)) & (libc.tls_align-1); |
| 44 td = (pthread_t)mem; |
| 45 mem += sizeof(struct pthread); |
| 46 |
| 47 for (i=1, p=libc.tls_head; p; i++, p=p->next) { |
| 48 dtv[i] = mem + p->offset; |
| 49 memcpy(dtv[i], p->image, p->len); |
| 50 } |
| 51 #else |
| 52 dtv = (void **)mem; |
| 53 |
| 54 mem += libc.tls_size - sizeof(struct pthread); |
| 55 mem -= (uintptr_t)mem & (libc.tls_align-1); |
| 56 td = (pthread_t)mem; |
| 57 |
| 58 for (i=1, p=libc.tls_head; p; i++, p=p->next) { |
| 59 dtv[i] = mem - p->offset; |
| 60 memcpy(dtv[i], p->image, p->len); |
| 61 } |
| 62 #endif |
| 63 dtv[0] = (void *)libc.tls_cnt; |
| 64 td->dtv = td->dtv_copy = dtv; |
| 65 return td; |
| 66 } |
| 67 |
| 68 #if ULONG_MAX == 0xffffffff |
| 69 typedef Elf32_Phdr Phdr; |
| 70 #else |
| 71 typedef Elf64_Phdr Phdr; |
| 72 #endif |
| 73 |
| 74 static void static_init_tls(size_t *aux) |
| 75 { |
| 76 unsigned char *p; |
| 77 size_t n; |
| 78 Phdr *phdr, *tls_phdr=0; |
| 79 size_t base = 0; |
| 80 void *mem; |
| 81 |
| 82 for (p=(void *)aux[AT_PHDR],n=aux[AT_PHNUM]; n; n--,p+=aux[AT_PHENT]) { |
| 83 phdr = (void *)p; |
| 84 if (phdr->p_type == PT_PHDR) |
| 85 base = aux[AT_PHDR] - phdr->p_vaddr; |
| 86 if (phdr->p_type == PT_TLS) |
| 87 tls_phdr = phdr; |
| 88 } |
| 89 |
| 90 if (tls_phdr) { |
| 91 main_tls.image = (void *)(base + tls_phdr->p_vaddr); |
| 92 main_tls.len = tls_phdr->p_filesz; |
| 93 main_tls.size = tls_phdr->p_memsz; |
| 94 main_tls.align = tls_phdr->p_align; |
| 95 libc.tls_cnt = 1; |
| 96 libc.tls_head = &main_tls; |
| 97 } |
| 98 |
| 99 main_tls.size += (-main_tls.size - (uintptr_t)main_tls.image) |
| 100 & (main_tls.align-1); |
| 101 if (main_tls.align < MIN_TLS_ALIGN) main_tls.align = MIN_TLS_ALIGN; |
| 102 #ifndef TLS_ABOVE_TP |
| 103 main_tls.offset = main_tls.size; |
| 104 #endif |
| 105 |
| 106 libc.tls_align = main_tls.align; |
| 107 libc.tls_size = 2*sizeof(void *) + sizeof(struct pthread) |
| 108 + main_tls.size + main_tls.align |
| 109 + MIN_TLS_ALIGN-1 & -MIN_TLS_ALIGN; |
| 110 |
| 111 if (libc.tls_size > sizeof builtin_tls) { |
| 112 #ifndef SYS_mmap2 |
| 113 #define SYS_mmap2 SYS_mmap |
| 114 #endif |
| 115 mem = (void *)__syscall( |
| 116 SYS_mmap2, |
| 117 0, libc.tls_size, PROT_READ|PROT_WRITE, |
| 118 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); |
| 119 /* -4095...-1 cast to void * will crash on dereference anyway, |
| 120 * so don't bloat the init code checking for error codes and |
| 121 * explicitly calling a_crash(). */ |
| 122 } else { |
| 123 mem = builtin_tls; |
| 124 } |
| 125 |
| 126 /* Failure to initialize thread pointer is always fatal. */ |
| 127 if (__init_tp(__copy_tls(mem)) < 0) |
| 128 a_crash(); |
| 129 } |
| 130 |
| 131 weak_alias(static_init_tls, __init_tls); |
OLD | NEW |