blob: 96d0e2843da00caf57d101a61291fece78369153 [file] [log] [blame]
Rich Felker8431d792012-10-04 16:35:46 -04001#include <elf.h>
2#include <limits.h>
Rich Felkerefd4d872012-11-08 17:04:20 -05003#include <sys/mman.h>
4#include <string.h>
Rich Felkerbd679592015-03-06 13:27:08 -05005#include <stddef.h>
Rich Felker8431d792012-10-04 16:35:46 -04006#include "pthread_impl.h"
7#include "libc.h"
8#include "atomic.h"
Rich Felker98221c32014-03-23 23:19:30 -04009#include "syscall.h"
Rich Felker8431d792012-10-04 16:35:46 -040010
Rich Felkerdab441a2014-03-24 16:57:11 -040011int __init_tp(void *p)
12{
13 pthread_t td = p;
14 td->self = td;
Rich Felker64e32282014-06-10 03:36:56 -040015 int r = __set_thread_area(TP_ADJ(p));
16 if (r < 0) return -1;
17 if (!r) libc.can_do_threads = 1;
Rich Felkercdba6b22018-05-05 21:33:58 -040018 td->detach_state = DT_JOINABLE;
19 td->tid = __syscall(SYS_set_tid_address, &td->detach_state);
Rich Felker0bc03092014-07-02 19:33:19 -040020 td->locale = &libc.global_locale;
Rich Felker4e98cce2015-04-10 00:54:48 -040021 td->robust_list.head = &td->robust_list.head;
Rich Felkerdab441a2014-03-24 16:57:11 -040022 return 0;
23}
24
Rich Felkerbd679592015-03-06 13:27:08 -050025static 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 Felkerdab441a2014-03-24 16:57:11 -040031
Rich Felkerd56460c2015-11-12 15:50:26 -050032static struct tls_module main_tls;
Rich Felker8431d792012-10-04 16:35:46 -040033
Rich Felkerdcd60372012-10-05 11:51:50 -040034void *__copy_tls(unsigned char *mem)
Rich Felker8431d792012-10-04 16:35:46 -040035{
Rich Felker6a2eaa32012-10-06 16:51:03 -040036 pthread_t td;
Rich Felkerd56460c2015-11-12 15:50:26 -050037 struct tls_module *p;
38 size_t i;
39 void **dtv;
40
Rich Felker9ec42832012-10-15 18:51:53 -040041#ifdef TLS_ABOVE_TP
Rich Felkerd56460c2015-11-12 15:50:26 -050042 dtv = (void **)(mem + libc.tls_size) - (libc.tls_cnt + 1);
43
44 mem += -((uintptr_t)mem + sizeof(struct pthread)) & (libc.tls_align-1);
Rich Felker9ec42832012-10-15 18:51:53 -040045 td = (pthread_t)mem;
46 mem += sizeof(struct pthread);
Rich Felkerd56460c2015-11-12 15:50:26 -050047
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 Felker9ec42832012-10-15 18:51:53 -040052#else
Rich Felkerd56460c2015-11-12 15:50:26 -050053 dtv = (void **)mem;
54
Rich Felkere172c7b2012-12-25 21:51:11 -050055 mem += libc.tls_size - sizeof(struct pthread);
Rich Felkerd56460c2015-11-12 15:50:26 -050056 mem -= (uintptr_t)mem & (libc.tls_align-1);
Rich Felker6a2eaa32012-10-06 16:51:03 -040057 td = (pthread_t)mem;
Rich Felkerd56460c2015-11-12 15:50:26 -050058
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 Felker9ec42832012-10-15 18:51:53 -040063#endif
Rich Felkerd56460c2015-11-12 15:50:26 -050064 dtv[0] = (void *)libc.tls_cnt;
Szabolcs Nagy204a69d2015-03-11 12:48:12 +000065 td->dtv = td->dtv_copy = dtv;
Rich Felker6a2eaa32012-10-06 16:51:03 -040066 return td;
67}
68
Rich Felker8431d792012-10-04 16:35:46 -040069#if ULONG_MAX == 0xffffffff
70typedef Elf32_Phdr Phdr;
71#else
72typedef Elf64_Phdr Phdr;
73#endif
74
Rich Felker9b95fd02018-09-05 12:43:34 -040075extern weak hidden const size_t _DYNAMIC[];
Rich Felker5bf7eba2016-12-20 14:19:32 -050076
Rich Felkerd56460c2015-11-12 15:50:26 -050077static void static_init_tls(size_t *aux)
Rich Felker8431d792012-10-04 16:35:46 -040078{
Rich Felkerdab441a2014-03-24 16:57:11 -040079 unsigned char *p;
Rich Felker3a5aa8e2012-11-01 22:58:17 -040080 size_t n;
Rich Felker8431d792012-10-04 16:35:46 -040081 Phdr *phdr, *tls_phdr=0;
82 size_t base = 0;
Rich Felkerdab441a2014-03-24 16:57:11 -040083 void *mem;
Rich Felker8431d792012-10-04 16:35:46 -040084
Rich Felker0a96a372012-10-07 21:43:46 -040085 for (p=(void *)aux[AT_PHDR],n=aux[AT_PHNUM]; n; n--,p+=aux[AT_PHENT]) {
Rich Felker8431d792012-10-04 16:35:46 -040086 phdr = (void *)p;
87 if (phdr->p_type == PT_PHDR)
88 base = aux[AT_PHDR] - phdr->p_vaddr;
Rich Felker5bf7eba2016-12-20 14:19:32 -050089 if (phdr->p_type == PT_DYNAMIC && _DYNAMIC)
90 base = (size_t)_DYNAMIC - phdr->p_vaddr;
Rich Felker8431d792012-10-04 16:35:46 -040091 if (phdr->p_type == PT_TLS)
92 tls_phdr = phdr;
Rich Felker7b3348a2018-09-18 23:54:18 -040093 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 Felker8431d792012-10-04 16:35:46 -040098 }
Rich Felker8431d792012-10-04 16:35:46 -040099
Rich Felkerdab441a2014-03-24 16:57:11 -0400100 if (tls_phdr) {
Rich Felkerd56460c2015-11-12 15:50:26 -0500101 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 Felkerdab441a2014-03-24 16:57:11 -0400107 }
Rich Felker6a2eaa32012-10-06 16:51:03 -0400108
Rich Felkerd56460c2015-11-12 15:50:26 -0500109 main_tls.size += (-main_tls.size - (uintptr_t)main_tls.image)
110 & (main_tls.align-1);
Szabolcs Nagy610c5a82018-06-02 01:52:01 +0200111#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 Felkerd56460c2015-11-12 15:50:26 -0500115 main_tls.offset = main_tls.size;
116#endif
Szabolcs Nagy610c5a82018-06-02 01:52:01 +0200117 if (main_tls.align < MIN_TLS_ALIGN) main_tls.align = MIN_TLS_ALIGN;
Rich Felker6a2eaa32012-10-06 16:51:03 -0400118
Rich Felkerd56460c2015-11-12 15:50:26 -0500119 libc.tls_align = main_tls.align;
120 libc.tls_size = 2*sizeof(void *) + sizeof(struct pthread)
Szabolcs Nagy610c5a82018-06-02 01:52:01 +0200121#ifdef TLS_ABOVE_TP
122 + main_tls.offset
123#endif
Rich Felkerd56460c2015-11-12 15:50:26 -0500124 + main_tls.size + main_tls.align
Rich Felkerabead1b2015-04-23 18:51:02 -0400125 + MIN_TLS_ALIGN-1 & -MIN_TLS_ALIGN;
Rich Felker6a2eaa32012-10-06 16:51:03 -0400126
Rich Felkerdab441a2014-03-24 16:57:11 -0400127 if (libc.tls_size > sizeof builtin_tls) {
Szabolcs Nagyd86af2a2014-08-13 17:07:44 +0200128#ifndef SYS_mmap2
129#define SYS_mmap2 SYS_mmap
Rich Felker98221c32014-03-23 23:19:30 -0400130#endif
Szabolcs Nagyd86af2a2014-08-13 17:07:44 +0200131 mem = (void *)__syscall(
132 SYS_mmap2,
Rich Felkerdab441a2014-03-24 16:57:11 -0400133 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 Felker98221c32014-03-23 23:19:30 -0400141
Rich Felker19a1fe62015-04-13 19:24:51 -0400142 /* Failure to initialize thread pointer is always fatal. */
143 if (__init_tp(__copy_tls(mem)) < 0)
Rich Felkerdab441a2014-03-24 16:57:11 -0400144 a_crash();
Rich Felker8431d792012-10-04 16:35:46 -0400145}
Rich Felkerd56460c2015-11-12 15:50:26 -0500146
147weak_alias(static_init_tls, __init_tls);