blob: 73551e6c4173af5976c3084a728efc4707d8e0a3 [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 Felker5f51d522015-04-23 17:04:31 -040011#ifndef SHARED
12static
13#endif
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 Felker83dc6eb2014-07-05 23:29:55 -040021 td->tid = __syscall(SYS_set_tid_address, &td->tid);
Rich Felker0bc03092014-07-02 19:33:19 -040022 td->locale = &libc.global_locale;
Rich Felker4e98cce2015-04-10 00:54:48 -040023 td->robust_list.head = &td->robust_list.head;
Rich Felkerdab441a2014-03-24 16:57:11 -040024 return 0;
25}
26
Rich Felker8431d792012-10-04 16:35:46 -040027#ifndef SHARED
28
Rich Felkerbd679592015-03-06 13:27:08 -050029static struct builtin_tls {
30 char c;
31 struct pthread pt;
32 void *space[16];
33} builtin_tls[1];
34#define MIN_TLS_ALIGN offsetof(struct builtin_tls, pt)
Rich Felkerdab441a2014-03-24 16:57:11 -040035
Rich Felker7c6c2902013-08-03 16:27:30 -040036struct tls_image {
37 void *image;
38 size_t len, size, align;
Rich Felkerc267fb82015-04-22 02:36:54 -040039} __static_tls;
Rich Felker7c6c2902013-08-03 16:27:30 -040040
41#define T __static_tls
Rich Felker8431d792012-10-04 16:35:46 -040042
Rich Felkerdcd60372012-10-05 11:51:50 -040043void *__copy_tls(unsigned char *mem)
Rich Felker8431d792012-10-04 16:35:46 -040044{
Rich Felker6a2eaa32012-10-06 16:51:03 -040045 pthread_t td;
Rich Felker7c6c2902013-08-03 16:27:30 -040046 if (!T.image) return mem;
Rich Felker6a2eaa32012-10-06 16:51:03 -040047 void **dtv = (void *)mem;
48 dtv[0] = (void *)1;
Rich Felker9ec42832012-10-15 18:51:53 -040049#ifdef TLS_ABOVE_TP
50 mem += sizeof(void *) * 2;
Rich Felker7c6c2902013-08-03 16:27:30 -040051 mem += -((uintptr_t)mem + sizeof(struct pthread)) & (T.align-1);
Rich Felker9ec42832012-10-15 18:51:53 -040052 td = (pthread_t)mem;
53 mem += sizeof(struct pthread);
54#else
Rich Felkere172c7b2012-12-25 21:51:11 -050055 mem += libc.tls_size - sizeof(struct pthread);
Rich Felker7c6c2902013-08-03 16:27:30 -040056 mem -= (uintptr_t)mem & (T.align-1);
Rich Felker6a2eaa32012-10-06 16:51:03 -040057 td = (pthread_t)mem;
Rich Felker7c6c2902013-08-03 16:27:30 -040058 mem -= T.size;
Rich Felker9ec42832012-10-15 18:51:53 -040059#endif
Szabolcs Nagy204a69d2015-03-11 12:48:12 +000060 td->dtv = td->dtv_copy = dtv;
Rich Felker6a2eaa32012-10-06 16:51:03 -040061 dtv[1] = mem;
Rich Felker7c6c2902013-08-03 16:27:30 -040062 memcpy(mem, T.image, T.len);
Rich Felker6a2eaa32012-10-06 16:51:03 -040063 return td;
64}
65
Rich Felker8431d792012-10-04 16:35:46 -040066#if ULONG_MAX == 0xffffffff
67typedef Elf32_Phdr Phdr;
68#else
69typedef Elf64_Phdr Phdr;
70#endif
71
Rich Felker0a96a372012-10-07 21:43:46 -040072void __init_tls(size_t *aux)
Rich Felker8431d792012-10-04 16:35:46 -040073{
Rich Felkerdab441a2014-03-24 16:57:11 -040074 unsigned char *p;
Rich Felker3a5aa8e2012-11-01 22:58:17 -040075 size_t n;
Rich Felker8431d792012-10-04 16:35:46 -040076 Phdr *phdr, *tls_phdr=0;
77 size_t base = 0;
Rich Felkerdab441a2014-03-24 16:57:11 -040078 void *mem;
Rich Felker8431d792012-10-04 16:35:46 -040079
Rich Felker0a96a372012-10-07 21:43:46 -040080 for (p=(void *)aux[AT_PHDR],n=aux[AT_PHNUM]; n; n--,p+=aux[AT_PHENT]) {
Rich Felker8431d792012-10-04 16:35:46 -040081 phdr = (void *)p;
82 if (phdr->p_type == PT_PHDR)
83 base = aux[AT_PHDR] - phdr->p_vaddr;
84 if (phdr->p_type == PT_TLS)
85 tls_phdr = phdr;
86 }
Rich Felker8431d792012-10-04 16:35:46 -040087
Rich Felkerdab441a2014-03-24 16:57:11 -040088 if (tls_phdr) {
89 T.image = (void *)(base + tls_phdr->p_vaddr);
90 T.len = tls_phdr->p_filesz;
91 T.size = tls_phdr->p_memsz;
92 T.align = tls_phdr->p_align;
93 }
Rich Felker6a2eaa32012-10-06 16:51:03 -040094
Rich Felker7c6c2902013-08-03 16:27:30 -040095 T.size += (-T.size - (uintptr_t)T.image) & (T.align-1);
Rich Felkerbd679592015-03-06 13:27:08 -050096 if (T.align < MIN_TLS_ALIGN) T.align = MIN_TLS_ALIGN;
Rich Felker6a2eaa32012-10-06 16:51:03 -040097
Rich Felkerabead1b2015-04-23 18:51:02 -040098 libc.tls_size = 2*sizeof(void *)+T.size+T.align+sizeof(struct pthread)
99 + MIN_TLS_ALIGN-1 & -MIN_TLS_ALIGN;
Rich Felker6a2eaa32012-10-06 16:51:03 -0400100
Rich Felkerdab441a2014-03-24 16:57:11 -0400101 if (libc.tls_size > sizeof builtin_tls) {
Szabolcs Nagyd86af2a2014-08-13 17:07:44 +0200102#ifndef SYS_mmap2
103#define SYS_mmap2 SYS_mmap
Rich Felker98221c32014-03-23 23:19:30 -0400104#endif
Szabolcs Nagyd86af2a2014-08-13 17:07:44 +0200105 mem = (void *)__syscall(
106 SYS_mmap2,
Rich Felkerdab441a2014-03-24 16:57:11 -0400107 0, libc.tls_size, PROT_READ|PROT_WRITE,
108 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
109 /* -4095...-1 cast to void * will crash on dereference anyway,
110 * so don't bloat the init code checking for error codes and
111 * explicitly calling a_crash(). */
112 } else {
113 mem = builtin_tls;
114 }
Rich Felker98221c32014-03-23 23:19:30 -0400115
Rich Felker19a1fe62015-04-13 19:24:51 -0400116 /* Failure to initialize thread pointer is always fatal. */
117 if (__init_tp(__copy_tls(mem)) < 0)
Rich Felkerdab441a2014-03-24 16:57:11 -0400118 a_crash();
Rich Felker8431d792012-10-04 16:35:46 -0400119}
120#else
121void __init_tls(size_t *auxv) { }
122#endif