1 /*
2 * Copyright (c) 2016 Philip Guenther <guenther@openbsd.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 /*
18 * Thread Information Block (TIB) and Thread Local Storage (TLS) handling
19 * (the TCB, Thread Control Block, is part of the TIB)
20 */
21
22 #define _DYN_LOADER
23
24 #include <sys/types.h>
25
26 #include "syscall.h"
27 #include "util.h"
28 #include "resolve.h"
29
30 /* If we need the syscall, use our local syscall definition */
31 #define __set_tcb(tcb) _dl___set_tcb(tcb)
32
33 __dso_hidden void *allocate_tib(size_t);
34
35 #ifdef TIB_EXTRA_ALIGN
36 # define TIB_ALIGN MAXIMUM(__alignof__(struct tib), TIB_EXTRA_ALIGN)
37 #else
38 # define TIB_ALIGN __alignof__(struct tib)
39 #endif
40
41
42 /* size of static TLS allocation */
43 static int static_tls_size;
44 /* alignment of static TLS allocation */
45 static int static_tls_align;
46 /* base-offset alignment of (first) static TLS allocation */
47 static int static_tls_align_offset;
48
49 int _dl_tib_static_done;
50
51 /*
52 * Allocate a TIB for passing to __tfork for a new thread. 'extra'
53 * is the amount of space to allocate on the side of the TIB opposite
54 * of the TLS data: before the TIB for variant 1 and after the TIB
55 * for variant 2. If non-zero, tib_thread is set to point to that area.
56 */
57 void *
allocate_tib(size_t extra)58 allocate_tib(size_t extra)
59 {
60 char *base;
61 struct tib *tib;
62 char *thread = NULL;
63 struct elf_object *obj;
64
65 #if TLS_VARIANT == 1
66 /* round up the extra size to align the TIB and TLS data after it */
67 size_t unpad_extra = (extra <= static_tls_align_offset) ? 0 :
68 ELF_ROUND(extra - static_tls_align_offset, static_tls_align);
69 base = _dl_aligned_alloc(static_tls_align, unpad_extra +
70 static_tls_align_offset + sizeof *tib + static_tls_size);
71 if (base == NULL)
72 return NULL;
73 tib = (struct tib *)(base + unpad_extra + static_tls_align_offset);
74 if (extra)
75 thread = base;
76 #define TLS_ADDR(tibp, offset) ((char *)(tibp) + sizeof(struct tib) + (offset))
77
78 #elif TLS_VARIANT == 2
79 /* round up the TIB size to align the extra area after it */
80 base = _dl_aligned_alloc(static_tls_align, static_tls_size +
81 static_tls_align_offset + ELF_ROUND(sizeof *tib, TIB_EXTRA_ALIGN) +
82 extra);
83 if (base == NULL)
84 return NULL;
85 base += static_tls_align_offset;
86 tib = (struct tib *)(base + static_tls_size);
87 if (extra)
88 thread = (char *)tib + ELF_ROUND(sizeof *tib, TIB_EXTRA_ALIGN);
89 #define TLS_ADDR(tibp, offset) ((char *)(tibp) - (offset))
90
91 #endif
92
93 for (obj = _dl_objects; obj != NULL; obj = obj->next) {
94 if (obj->tls_msize != 0) {
95 char *addr = TLS_ADDR(tib, obj->tls_offset);
96
97 _dl_memset(addr + obj->tls_fsize, 0,
98 obj->tls_msize - obj->tls_fsize);
99 if (obj->tls_static_data != NULL)
100 _dl_bcopy(obj->tls_static_data, addr,
101 obj->tls_fsize);
102 DL_DEB(("\t%s has index %u addr %p msize %u fsize %u\n",
103 obj->load_name, obj->tls_offset,
104 (void *)addr, obj->tls_msize, obj->tls_fsize));
105 }
106 }
107
108 TIB_INIT(tib, NULL, thread);
109
110 DL_DEB(("tib new=%p\n", (void *)tib));
111
112 return (tib);
113 }
114 __strong_alias(_dl_allocate_tib, allocate_tib);
115
116 void
_dl_free_tib(void * tib,size_t extra)117 _dl_free_tib(void *tib, size_t extra)
118 {
119 size_t tib_offset;
120
121 #if TLS_VARIANT == 1
122 tib_offset = (extra <= static_tls_align_offset) ? 0 :
123 ELF_ROUND(extra - static_tls_align_offset, static_tls_align);
124 #elif TLS_VARIANT == 2
125 tib_offset = static_tls_size;
126 #endif
127 tib_offset += static_tls_align_offset;
128
129 DL_DEB(("free tib=%p\n", (void *)tib));
130 _dl_free((char *)tib - tib_offset);
131 }
132
133
134 /*
135 * Record what's necessary for handling TLS for an object.
136 */
137 void
_dl_set_tls(elf_object_t * object,Elf_Phdr * ptls,Elf_Addr libaddr,const char * libname)138 _dl_set_tls(elf_object_t *object, Elf_Phdr *ptls, Elf_Addr libaddr,
139 const char *libname)
140 {
141 if (ptls->p_vaddr != 0 && ptls->p_filesz != 0)
142 object->tls_static_data = (void *)(ptls->p_vaddr + libaddr);
143 object->tls_fsize = ptls->p_filesz;
144 object->tls_msize = ptls->p_memsz;
145 object->tls_align = ptls->p_align;
146
147 DL_DEB(("tls %x %x %x %x\n",
148 object->tls_static_data, object->tls_fsize, object->tls_msize,
149 object->tls_align));
150 }
151
152 static inline Elf_Addr
allocate_tls_offset(Elf_Addr msize,Elf_Addr align,int for_exe)153 allocate_tls_offset(Elf_Addr msize, Elf_Addr align, int for_exe)
154 {
155 Elf_Addr offset;
156
157 if (for_exe && static_tls_size != 0)
158 _dl_die("TLS allocation before executable!");
159
160 #if TLS_VARIANT == 1
161 if (for_exe) {
162 /*
163 * Variant 1 places the data after the TIB. If the
164 * TLS alignment is larger than the TIB alignment
165 * then we may need to pad in front of the TIB to
166 * place the TLS data on the proper alignment.
167 * Example: p_align=16 sizeof(TIB)=52 align(TIB)=4
168 * - need to offset the TIB 12 bytes from the start
169 * - to place ths TLS data at offset 64
170 */
171 static_tls_align = MAXIMUM(align, TIB_ALIGN);
172 static_tls_align_offset =
173 ELF_ROUND(sizeof(struct tib), static_tls_align) -
174 sizeof(struct tib);
175 offset = 0;
176 static_tls_size = msize;
177 } else {
178 /*
179 * If a later object increases the alignment, realign the
180 * existing sections. We push as much padding as possible
181 * to the start there it can overlap the thread structure
182 */
183 if (static_tls_align < align) {
184 static_tls_align_offset += align - static_tls_align;
185 static_tls_align = align;
186 }
187
188 /*
189 * Round up to the required alignment, taking into account
190 * the leading padding and TIB, then allocate the space.
191 */
192 offset = static_tls_align_offset + sizeof(struct tib) +
193 static_tls_size;
194 offset = ELF_ROUND(offset, align) - static_tls_align_offset
195 - sizeof(struct tib);
196 static_tls_size = offset + msize;
197 }
198 #elif TLS_VARIANT == 2
199 /* Realignment is automatic for variant II */
200 if (static_tls_align < align)
201 static_tls_align = align;
202
203 /*
204 * Variant 2 places the data before the TIB so we need to round up
205 * the size to the TLS data alignment TIB's alignment.
206 * Example A: p_memsz=24 p_align=16 align(TIB)=8
207 * - need to allocate 32 bytes for TLS as compiler
208 * - will give the first TLS symbol an offset of -32
209 * Example B: p_memsz=4 p_align=4 align(TIB)=8
210 * - need to allocate 8 bytes so that the TIB is
211 * - properly aligned
212 * So: allocate the space, then round up to the alignment
213 * (these are negative offsets, so rounding up really
214 * rounds the address down)
215 */
216 static_tls_size = ELF_ROUND(static_tls_size + msize, align);
217 offset = static_tls_size;
218 #else
219 # error "unknown TLS_VARIANT"
220 #endif
221 return offset;
222 }
223
224 /*
225 * Calculate the TLS offset for each object with static TLS.
226 */
227 void
_dl_allocate_tls_offsets(void)228 _dl_allocate_tls_offsets(void)
229 {
230 struct elf_object *obj;
231
232 static_tls_align = TIB_ALIGN;
233 for (obj = _dl_objects; obj != NULL; obj = obj->next) {
234 if (obj->tls_msize != 0) {
235 obj->tls_offset = allocate_tls_offset(obj->tls_msize,
236 obj->tls_align, obj->obj_type == OBJTYPE_EXE);
237 }
238 }
239
240 #if TLS_VARIANT == 2
241 static_tls_align_offset = ELF_ROUND(static_tls_size, static_tls_align)
242 - static_tls_size;
243 #endif
244
245 /* no more static TLS allocations after this */
246 _dl_tib_static_done = 1;
247
248 DL_DEB(("static tls size=%x align=%x offset=%x\n",
249 static_tls_size, static_tls_align, static_tls_align_offset));
250 }
251
252 /*
253 * Allocate the TIB + TLS for the initial thread.
254 */
255 void
_dl_allocate_first_tib(void)256 _dl_allocate_first_tib(void)
257 {
258 struct tib *tib;
259
260 tib = allocate_tib(0);
261 tib->tib_tid = _dl_getthrid();
262
263 TCB_SET(TIB_TO_TCB(tib));
264 }
265