blob: 772baba32d54fff8b63e69952aeec60fce48a03f [file] [log] [blame]
Rich Felker22e5bbd2019-04-10 17:10:36 -04001#define SYSCALL_NO_TLS 1
Rich Felker8431d792012-10-04 16:35:46 -04002#include <elf.h>
3#include <limits.h>
Rich Felkerefd4d872012-11-08 17:04:20 -05004#include <sys/mman.h>
5#include <string.h>
Rich Felkerbd679592015-03-06 13:27:08 -05006#include <stddef.h>
Rich Felker8431d792012-10-04 16:35:46 -04007#include "pthread_impl.h"
8#include "libc.h"
9#include "atomic.h"
Rich Felker98221c32014-03-23 23:19:30 -040010#include "syscall.h"
Rich Felker8431d792012-10-04 16:35:46 -040011
Rich Felker8f11e612019-02-15 22:29:01 -050012volatile int __thread_list_lock;
13
Rich Felkerdab441a2014-03-24 16:57:11 -040014int __init_tp(void *p)
15{
16 pthread_t td = p;
17 td->self = td;
Rich Felker64e32282014-06-10 03:36:56 -040018 int r = __set_thread_area(TP_ADJ(p));
19 if (r < 0) return -1;
20 if (!r) libc.can_do_threads = 1;
Rich Felkercdba6b22018-05-05 21:33:58 -040021 td->detach_state = DT_JOINABLE;
Rich Felker8f11e612019-02-15 22:29:01 -050022 td->tid = __syscall(SYS_set_tid_address, &__thread_list_lock);
Rich Felker0bc03092014-07-02 19:33:19 -040023 td->locale = &libc.global_locale;
Rich Felker4e98cce2015-04-10 00:54:48 -040024 td->robust_list.head = &td->robust_list.head;
Rich Felker22e5bbd2019-04-10 17:10:36 -040025 td->sysinfo = __sysinfo;
Rich Felker8f11e612019-02-15 22:29:01 -050026 td->next = td->prev = td;
Rich Felkerdab441a2014-03-24 16:57:11 -040027 return 0;
28}
29
Rich Felkerbd679592015-03-06 13:27:08 -050030static struct builtin_tls {
31 char c;
32 struct pthread pt;
33 void *space[16];
34} builtin_tls[1];
35#define MIN_TLS_ALIGN offsetof(struct builtin_tls, pt)
Rich Felkerdab441a2014-03-24 16:57:11 -040036
Rich Felkerd56460c2015-11-12 15:50:26 -050037static struct tls_module main_tls;
Rich Felker8431d792012-10-04 16:35:46 -040038
Rich Felkerdcd60372012-10-05 11:51:50 -040039void *__copy_tls(unsigned char *mem)
Rich Felker8431d792012-10-04 16:35:46 -040040{
Rich Felker6a2eaa32012-10-06 16:51:03 -040041 pthread_t td;
Rich Felkerd56460c2015-11-12 15:50:26 -050042 struct tls_module *p;
43 size_t i;
Rich Felkerb6d701a2018-10-12 00:30:34 -040044 uintptr_t *dtv;
Rich Felkerd56460c2015-11-12 15:50:26 -050045
Rich Felker9ec42832012-10-15 18:51:53 -040046#ifdef TLS_ABOVE_TP
Rich Felkerb6d701a2018-10-12 00:30:34 -040047 dtv = (uintptr_t*)(mem + libc.tls_size) - (libc.tls_cnt + 1);
Rich Felkerd56460c2015-11-12 15:50:26 -050048
49 mem += -((uintptr_t)mem + sizeof(struct pthread)) & (libc.tls_align-1);
Rich Felker9ec42832012-10-15 18:51:53 -040050 td = (pthread_t)mem;
51 mem += sizeof(struct pthread);
Rich Felkerd56460c2015-11-12 15:50:26 -050052
53 for (i=1, p=libc.tls_head; p; i++, p=p->next) {
Rich Felkerb6d701a2018-10-12 00:30:34 -040054 dtv[i] = (uintptr_t)(mem + p->offset) + DTP_OFFSET;
55 memcpy(mem + p->offset, p->image, p->len);
Rich Felkerd56460c2015-11-12 15:50:26 -050056 }
Rich Felker9ec42832012-10-15 18:51:53 -040057#else
Rich Felkerb6d701a2018-10-12 00:30:34 -040058 dtv = (uintptr_t *)mem;
Rich Felkerd56460c2015-11-12 15:50:26 -050059
Rich Felkere172c7b2012-12-25 21:51:11 -050060 mem += libc.tls_size - sizeof(struct pthread);
Rich Felkerd56460c2015-11-12 15:50:26 -050061 mem -= (uintptr_t)mem & (libc.tls_align-1);
Rich Felker6a2eaa32012-10-06 16:51:03 -040062 td = (pthread_t)mem;
Rich Felkerd56460c2015-11-12 15:50:26 -050063
64 for (i=1, p=libc.tls_head; p; i++, p=p->next) {
Rich Felkerb6d701a2018-10-12 00:30:34 -040065 dtv[i] = (uintptr_t)(mem - p->offset) + DTP_OFFSET;
66 memcpy(mem - p->offset, p->image, p->len);
Rich Felkerd56460c2015-11-12 15:50:26 -050067 }
Rich Felker9ec42832012-10-15 18:51:53 -040068#endif
Rich Felkerb6d701a2018-10-12 00:30:34 -040069 dtv[0] = libc.tls_cnt;
Szabolcs Nagy204a69d2015-03-11 12:48:12 +000070 td->dtv = td->dtv_copy = dtv;
Rich Felker6a2eaa32012-10-06 16:51:03 -040071 return td;
72}
73
Rich Felker8431d792012-10-04 16:35:46 -040074#if ULONG_MAX == 0xffffffff
75typedef Elf32_Phdr Phdr;
76#else
77typedef Elf64_Phdr Phdr;
78#endif
79
Rich Felker9b95fd02018-09-05 12:43:34 -040080extern weak hidden const size_t _DYNAMIC[];
Rich Felker5bf7eba2016-12-20 14:19:32 -050081
Rich Felkerd56460c2015-11-12 15:50:26 -050082static void static_init_tls(size_t *aux)
Rich Felker8431d792012-10-04 16:35:46 -040083{
Rich Felkerdab441a2014-03-24 16:57:11 -040084 unsigned char *p;
Rich Felker3a5aa8e2012-11-01 22:58:17 -040085 size_t n;
Rich Felker8431d792012-10-04 16:35:46 -040086 Phdr *phdr, *tls_phdr=0;
87 size_t base = 0;
Rich Felkerdab441a2014-03-24 16:57:11 -040088 void *mem;
Rich Felker8431d792012-10-04 16:35:46 -040089
Rich Felker0a96a372012-10-07 21:43:46 -040090 for (p=(void *)aux[AT_PHDR],n=aux[AT_PHNUM]; n; n--,p+=aux[AT_PHENT]) {
Rich Felker8431d792012-10-04 16:35:46 -040091 phdr = (void *)p;
92 if (phdr->p_type == PT_PHDR)
93 base = aux[AT_PHDR] - phdr->p_vaddr;
Rich Felker5bf7eba2016-12-20 14:19:32 -050094 if (phdr->p_type == PT_DYNAMIC && _DYNAMIC)
95 base = (size_t)_DYNAMIC - phdr->p_vaddr;
Rich Felker8431d792012-10-04 16:35:46 -040096 if (phdr->p_type == PT_TLS)
97 tls_phdr = phdr;
Rich Felker7b3348a2018-09-18 23:54:18 -040098 if (phdr->p_type == PT_GNU_STACK &&
99 phdr->p_memsz > __default_stacksize)
100 __default_stacksize =
101 phdr->p_memsz < DEFAULT_STACK_MAX ?
102 phdr->p_memsz : DEFAULT_STACK_MAX;
Rich Felker8431d792012-10-04 16:35:46 -0400103 }
Rich Felker8431d792012-10-04 16:35:46 -0400104
Rich Felkerdab441a2014-03-24 16:57:11 -0400105 if (tls_phdr) {
Rich Felkerd56460c2015-11-12 15:50:26 -0500106 main_tls.image = (void *)(base + tls_phdr->p_vaddr);
107 main_tls.len = tls_phdr->p_filesz;
108 main_tls.size = tls_phdr->p_memsz;
109 main_tls.align = tls_phdr->p_align;
110 libc.tls_cnt = 1;
111 libc.tls_head = &main_tls;
Rich Felkerdab441a2014-03-24 16:57:11 -0400112 }
Rich Felker6a2eaa32012-10-06 16:51:03 -0400113
Rich Felkerd56460c2015-11-12 15:50:26 -0500114 main_tls.size += (-main_tls.size - (uintptr_t)main_tls.image)
115 & (main_tls.align-1);
Szabolcs Nagy610c5a82018-06-02 01:52:01 +0200116#ifdef TLS_ABOVE_TP
117 main_tls.offset = GAP_ABOVE_TP;
Szabolcs Nagya60b9e02019-05-13 18:47:11 +0000118 main_tls.offset += (-GAP_ABOVE_TP + (uintptr_t)main_tls.image)
119 & (main_tls.align-1);
Szabolcs Nagy610c5a82018-06-02 01:52:01 +0200120#else
Rich Felkerd56460c2015-11-12 15:50:26 -0500121 main_tls.offset = main_tls.size;
122#endif
Szabolcs Nagy610c5a82018-06-02 01:52:01 +0200123 if (main_tls.align < MIN_TLS_ALIGN) main_tls.align = MIN_TLS_ALIGN;
Rich Felker6a2eaa32012-10-06 16:51:03 -0400124
Rich Felkerd56460c2015-11-12 15:50:26 -0500125 libc.tls_align = main_tls.align;
126 libc.tls_size = 2*sizeof(void *) + sizeof(struct pthread)
Szabolcs Nagy610c5a82018-06-02 01:52:01 +0200127#ifdef TLS_ABOVE_TP
128 + main_tls.offset
129#endif
Rich Felkerd56460c2015-11-12 15:50:26 -0500130 + main_tls.size + main_tls.align
Rich Felkerabead1b2015-04-23 18:51:02 -0400131 + MIN_TLS_ALIGN-1 & -MIN_TLS_ALIGN;
Rich Felker6a2eaa32012-10-06 16:51:03 -0400132
Rich Felkerdab441a2014-03-24 16:57:11 -0400133 if (libc.tls_size > sizeof builtin_tls) {
Szabolcs Nagyd86af2a2014-08-13 17:07:44 +0200134#ifndef SYS_mmap2
135#define SYS_mmap2 SYS_mmap
Rich Felker98221c32014-03-23 23:19:30 -0400136#endif
Szabolcs Nagyd86af2a2014-08-13 17:07:44 +0200137 mem = (void *)__syscall(
138 SYS_mmap2,
Rich Felkerdab441a2014-03-24 16:57:11 -0400139 0, libc.tls_size, PROT_READ|PROT_WRITE,
140 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
141 /* -4095...-1 cast to void * will crash on dereference anyway,
142 * so don't bloat the init code checking for error codes and
143 * explicitly calling a_crash(). */
144 } else {
145 mem = builtin_tls;
146 }
Rich Felker98221c32014-03-23 23:19:30 -0400147
Rich Felker19a1fe62015-04-13 19:24:51 -0400148 /* Failure to initialize thread pointer is always fatal. */
149 if (__init_tp(__copy_tls(mem)) < 0)
Rich Felkerdab441a2014-03-24 16:57:11 -0400150 a_crash();
Rich Felker8431d792012-10-04 16:35:46 -0400151}
Rich Felkerd56460c2015-11-12 15:50:26 -0500152
153weak_alias(static_init_tls, __init_tls);