Rich Felker | 8431d79 | 2012-10-04 16:35:46 -0400 | [diff] [blame] | 1 | #include <elf.h> |
| 2 | #include <limits.h> |
Rich Felker | efd4d87 | 2012-11-08 17:04:20 -0500 | [diff] [blame] | 3 | #include <sys/mman.h> |
| 4 | #include <string.h> |
Rich Felker | bd67959 | 2015-03-06 13:27:08 -0500 | [diff] [blame] | 5 | #include <stddef.h> |
Rich Felker | 8431d79 | 2012-10-04 16:35:46 -0400 | [diff] [blame] | 6 | #include "pthread_impl.h" |
| 7 | #include "libc.h" |
| 8 | #include "atomic.h" |
Rich Felker | 98221c3 | 2014-03-23 23:19:30 -0400 | [diff] [blame] | 9 | #include "syscall.h" |
Rich Felker | 8431d79 | 2012-10-04 16:35:46 -0400 | [diff] [blame] | 10 | |
Rich Felker | dab441a | 2014-03-24 16:57:11 -0400 | [diff] [blame] | 11 | int __init_tp(void *p) |
| 12 | { |
| 13 | pthread_t td = p; |
| 14 | td->self = td; |
Rich Felker | 64e3228 | 2014-06-10 03:36:56 -0400 | [diff] [blame] | 15 | int r = __set_thread_area(TP_ADJ(p)); |
| 16 | if (r < 0) return -1; |
| 17 | if (!r) libc.can_do_threads = 1; |
Rich Felker | cdba6b2 | 2018-05-05 21:33:58 -0400 | [diff] [blame] | 18 | td->detach_state = DT_JOINABLE; |
| 19 | td->tid = __syscall(SYS_set_tid_address, &td->detach_state); |
Rich Felker | 0bc0309 | 2014-07-02 19:33:19 -0400 | [diff] [blame] | 20 | td->locale = &libc.global_locale; |
Rich Felker | 4e98cce | 2015-04-10 00:54:48 -0400 | [diff] [blame] | 21 | td->robust_list.head = &td->robust_list.head; |
Rich Felker | dab441a | 2014-03-24 16:57:11 -0400 | [diff] [blame] | 22 | return 0; |
| 23 | } |
| 24 | |
Rich Felker | bd67959 | 2015-03-06 13:27:08 -0500 | [diff] [blame] | 25 | static struct builtin_tls { |
| 26 | char c; |
| 27 | struct pthread pt; |
| 28 | void *space[16]; |
| 29 | } builtin_tls[1]; |
| 30 | #define MIN_TLS_ALIGN offsetof(struct builtin_tls, pt) |
Rich Felker | dab441a | 2014-03-24 16:57:11 -0400 | [diff] [blame] | 31 | |
Rich Felker | d56460c | 2015-11-12 15:50:26 -0500 | [diff] [blame] | 32 | static struct tls_module main_tls; |
Rich Felker | 8431d79 | 2012-10-04 16:35:46 -0400 | [diff] [blame] | 33 | |
Rich Felker | dcd6037 | 2012-10-05 11:51:50 -0400 | [diff] [blame] | 34 | void *__copy_tls(unsigned char *mem) |
Rich Felker | 8431d79 | 2012-10-04 16:35:46 -0400 | [diff] [blame] | 35 | { |
Rich Felker | 6a2eaa3 | 2012-10-06 16:51:03 -0400 | [diff] [blame] | 36 | pthread_t td; |
Rich Felker | d56460c | 2015-11-12 15:50:26 -0500 | [diff] [blame] | 37 | struct tls_module *p; |
| 38 | size_t i; |
| 39 | void **dtv; |
| 40 | |
Rich Felker | 9ec4283 | 2012-10-15 18:51:53 -0400 | [diff] [blame] | 41 | #ifdef TLS_ABOVE_TP |
Rich Felker | d56460c | 2015-11-12 15:50:26 -0500 | [diff] [blame] | 42 | dtv = (void **)(mem + libc.tls_size) - (libc.tls_cnt + 1); |
| 43 | |
| 44 | mem += -((uintptr_t)mem + sizeof(struct pthread)) & (libc.tls_align-1); |
Rich Felker | 9ec4283 | 2012-10-15 18:51:53 -0400 | [diff] [blame] | 45 | td = (pthread_t)mem; |
| 46 | mem += sizeof(struct pthread); |
Rich Felker | d56460c | 2015-11-12 15:50:26 -0500 | [diff] [blame] | 47 | |
| 48 | for (i=1, p=libc.tls_head; p; i++, p=p->next) { |
| 49 | dtv[i] = mem + p->offset; |
| 50 | memcpy(dtv[i], p->image, p->len); |
| 51 | } |
Rich Felker | 9ec4283 | 2012-10-15 18:51:53 -0400 | [diff] [blame] | 52 | #else |
Rich Felker | d56460c | 2015-11-12 15:50:26 -0500 | [diff] [blame] | 53 | dtv = (void **)mem; |
| 54 | |
Rich Felker | e172c7b | 2012-12-25 21:51:11 -0500 | [diff] [blame] | 55 | mem += libc.tls_size - sizeof(struct pthread); |
Rich Felker | d56460c | 2015-11-12 15:50:26 -0500 | [diff] [blame] | 56 | mem -= (uintptr_t)mem & (libc.tls_align-1); |
Rich Felker | 6a2eaa3 | 2012-10-06 16:51:03 -0400 | [diff] [blame] | 57 | td = (pthread_t)mem; |
Rich Felker | d56460c | 2015-11-12 15:50:26 -0500 | [diff] [blame] | 58 | |
| 59 | for (i=1, p=libc.tls_head; p; i++, p=p->next) { |
| 60 | dtv[i] = mem - p->offset; |
| 61 | memcpy(dtv[i], p->image, p->len); |
| 62 | } |
Rich Felker | 9ec4283 | 2012-10-15 18:51:53 -0400 | [diff] [blame] | 63 | #endif |
Rich Felker | d56460c | 2015-11-12 15:50:26 -0500 | [diff] [blame] | 64 | dtv[0] = (void *)libc.tls_cnt; |
Szabolcs Nagy | 204a69d | 2015-03-11 12:48:12 +0000 | [diff] [blame] | 65 | td->dtv = td->dtv_copy = dtv; |
Rich Felker | 6a2eaa3 | 2012-10-06 16:51:03 -0400 | [diff] [blame] | 66 | return td; |
| 67 | } |
| 68 | |
Rich Felker | 8431d79 | 2012-10-04 16:35:46 -0400 | [diff] [blame] | 69 | #if ULONG_MAX == 0xffffffff |
| 70 | typedef Elf32_Phdr Phdr; |
| 71 | #else |
| 72 | typedef Elf64_Phdr Phdr; |
| 73 | #endif |
| 74 | |
Rich Felker | 9b95fd0 | 2018-09-05 12:43:34 -0400 | [diff] [blame] | 75 | extern weak hidden const size_t _DYNAMIC[]; |
Rich Felker | 5bf7eba | 2016-12-20 14:19:32 -0500 | [diff] [blame] | 76 | |
Rich Felker | d56460c | 2015-11-12 15:50:26 -0500 | [diff] [blame] | 77 | static void static_init_tls(size_t *aux) |
Rich Felker | 8431d79 | 2012-10-04 16:35:46 -0400 | [diff] [blame] | 78 | { |
Rich Felker | dab441a | 2014-03-24 16:57:11 -0400 | [diff] [blame] | 79 | unsigned char *p; |
Rich Felker | 3a5aa8e | 2012-11-01 22:58:17 -0400 | [diff] [blame] | 80 | size_t n; |
Rich Felker | 8431d79 | 2012-10-04 16:35:46 -0400 | [diff] [blame] | 81 | Phdr *phdr, *tls_phdr=0; |
| 82 | size_t base = 0; |
Rich Felker | dab441a | 2014-03-24 16:57:11 -0400 | [diff] [blame] | 83 | void *mem; |
Rich Felker | 8431d79 | 2012-10-04 16:35:46 -0400 | [diff] [blame] | 84 | |
Rich Felker | 0a96a37 | 2012-10-07 21:43:46 -0400 | [diff] [blame] | 85 | for (p=(void *)aux[AT_PHDR],n=aux[AT_PHNUM]; n; n--,p+=aux[AT_PHENT]) { |
Rich Felker | 8431d79 | 2012-10-04 16:35:46 -0400 | [diff] [blame] | 86 | phdr = (void *)p; |
| 87 | if (phdr->p_type == PT_PHDR) |
| 88 | base = aux[AT_PHDR] - phdr->p_vaddr; |
Rich Felker | 5bf7eba | 2016-12-20 14:19:32 -0500 | [diff] [blame] | 89 | if (phdr->p_type == PT_DYNAMIC && _DYNAMIC) |
| 90 | base = (size_t)_DYNAMIC - phdr->p_vaddr; |
Rich Felker | 8431d79 | 2012-10-04 16:35:46 -0400 | [diff] [blame] | 91 | if (phdr->p_type == PT_TLS) |
| 92 | tls_phdr = phdr; |
Rich Felker | 7b3348a | 2018-09-18 23:54:18 -0400 | [diff] [blame^] | 93 | if (phdr->p_type == PT_GNU_STACK && |
| 94 | phdr->p_memsz > __default_stacksize) |
| 95 | __default_stacksize = |
| 96 | phdr->p_memsz < DEFAULT_STACK_MAX ? |
| 97 | phdr->p_memsz : DEFAULT_STACK_MAX; |
Rich Felker | 8431d79 | 2012-10-04 16:35:46 -0400 | [diff] [blame] | 98 | } |
Rich Felker | 8431d79 | 2012-10-04 16:35:46 -0400 | [diff] [blame] | 99 | |
Rich Felker | dab441a | 2014-03-24 16:57:11 -0400 | [diff] [blame] | 100 | if (tls_phdr) { |
Rich Felker | d56460c | 2015-11-12 15:50:26 -0500 | [diff] [blame] | 101 | main_tls.image = (void *)(base + tls_phdr->p_vaddr); |
| 102 | main_tls.len = tls_phdr->p_filesz; |
| 103 | main_tls.size = tls_phdr->p_memsz; |
| 104 | main_tls.align = tls_phdr->p_align; |
| 105 | libc.tls_cnt = 1; |
| 106 | libc.tls_head = &main_tls; |
Rich Felker | dab441a | 2014-03-24 16:57:11 -0400 | [diff] [blame] | 107 | } |
Rich Felker | 6a2eaa3 | 2012-10-06 16:51:03 -0400 | [diff] [blame] | 108 | |
Rich Felker | d56460c | 2015-11-12 15:50:26 -0500 | [diff] [blame] | 109 | main_tls.size += (-main_tls.size - (uintptr_t)main_tls.image) |
| 110 | & (main_tls.align-1); |
Szabolcs Nagy | 610c5a8 | 2018-06-02 01:52:01 +0200 | [diff] [blame] | 111 | #ifdef TLS_ABOVE_TP |
| 112 | main_tls.offset = GAP_ABOVE_TP; |
| 113 | main_tls.offset += -GAP_ABOVE_TP & (main_tls.align-1); |
| 114 | #else |
Rich Felker | d56460c | 2015-11-12 15:50:26 -0500 | [diff] [blame] | 115 | main_tls.offset = main_tls.size; |
| 116 | #endif |
Szabolcs Nagy | 610c5a8 | 2018-06-02 01:52:01 +0200 | [diff] [blame] | 117 | if (main_tls.align < MIN_TLS_ALIGN) main_tls.align = MIN_TLS_ALIGN; |
Rich Felker | 6a2eaa3 | 2012-10-06 16:51:03 -0400 | [diff] [blame] | 118 | |
Rich Felker | d56460c | 2015-11-12 15:50:26 -0500 | [diff] [blame] | 119 | libc.tls_align = main_tls.align; |
| 120 | libc.tls_size = 2*sizeof(void *) + sizeof(struct pthread) |
Szabolcs Nagy | 610c5a8 | 2018-06-02 01:52:01 +0200 | [diff] [blame] | 121 | #ifdef TLS_ABOVE_TP |
| 122 | + main_tls.offset |
| 123 | #endif |
Rich Felker | d56460c | 2015-11-12 15:50:26 -0500 | [diff] [blame] | 124 | + main_tls.size + main_tls.align |
Rich Felker | abead1b | 2015-04-23 18:51:02 -0400 | [diff] [blame] | 125 | + MIN_TLS_ALIGN-1 & -MIN_TLS_ALIGN; |
Rich Felker | 6a2eaa3 | 2012-10-06 16:51:03 -0400 | [diff] [blame] | 126 | |
Rich Felker | dab441a | 2014-03-24 16:57:11 -0400 | [diff] [blame] | 127 | if (libc.tls_size > sizeof builtin_tls) { |
Szabolcs Nagy | d86af2a | 2014-08-13 17:07:44 +0200 | [diff] [blame] | 128 | #ifndef SYS_mmap2 |
| 129 | #define SYS_mmap2 SYS_mmap |
Rich Felker | 98221c3 | 2014-03-23 23:19:30 -0400 | [diff] [blame] | 130 | #endif |
Szabolcs Nagy | d86af2a | 2014-08-13 17:07:44 +0200 | [diff] [blame] | 131 | mem = (void *)__syscall( |
| 132 | SYS_mmap2, |
Rich Felker | dab441a | 2014-03-24 16:57:11 -0400 | [diff] [blame] | 133 | 0, libc.tls_size, PROT_READ|PROT_WRITE, |
| 134 | MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); |
| 135 | /* -4095...-1 cast to void * will crash on dereference anyway, |
| 136 | * so don't bloat the init code checking for error codes and |
| 137 | * explicitly calling a_crash(). */ |
| 138 | } else { |
| 139 | mem = builtin_tls; |
| 140 | } |
Rich Felker | 98221c3 | 2014-03-23 23:19:30 -0400 | [diff] [blame] | 141 | |
Rich Felker | 19a1fe6 | 2015-04-13 19:24:51 -0400 | [diff] [blame] | 142 | /* Failure to initialize thread pointer is always fatal. */ |
| 143 | if (__init_tp(__copy_tls(mem)) < 0) |
Rich Felker | dab441a | 2014-03-24 16:57:11 -0400 | [diff] [blame] | 144 | a_crash(); |
Rich Felker | 8431d79 | 2012-10-04 16:35:46 -0400 | [diff] [blame] | 145 | } |
Rich Felker | d56460c | 2015-11-12 15:50:26 -0500 | [diff] [blame] | 146 | |
| 147 | weak_alias(static_init_tls, __init_tls); |