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 */ 43static int static_tls_size; 44/* alignment of static TLS allocation */ 45static int static_tls_align; 46/* base-offset alignment of (first) static TLS allocation */ 47static int static_tls_align_offset; 48 49int _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 */ 57void * 58allocate_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 116void 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 */ 137void 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 152static inline Elf_Addr 153allocate_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 */ 227void 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 */ 255void 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