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 #include <sys/exec_elf.h> 26 27 #include <tib.h> 28 29 #include "archdep.h" 30 #include "resolve.h" 31 #include "util.h" 32 #include "syscall.h" 33 34 /* If we need the syscall, use our local syscall definition */ 35 #define __set_tcb(tcb) _dl_set_tcb(tcb) 36 37 38 static int static_tls_size; 39 40 int _dl_tib_static_done; 41 42 /* 43 * Allocate a TIB for passing to __tfork for a new thread. 'extra' 44 * is the amount of space to allocate on the side of the TIB opposite 45 * of the TLS data: before the TIB for variant 1 and after the TIB 46 * for variant 2. If non-zero, tib_thread is set to point to that area. 47 */ 48 void * 49 _dl_allocate_tib(size_t extra) 50 { 51 char *base; 52 struct tib *tib; 53 char *thread = NULL; 54 struct elf_object *obj; 55 56 #if TLS_VARIANT == 1 57 /* round up the extra size to align the tib after it */ 58 extra = ELF_ROUND(extra, sizeof(void *)); 59 base = _dl_malloc(extra + sizeof *tib + static_tls_size); 60 if (base == NULL) 61 return NULL; 62 tib = (struct tib *)(base + extra); 63 if (extra) 64 thread = base; 65 #define TLS_ADDR(tibp, offset) ((char *)(tibp) + sizeof(struct tib) + (offset)) 66 67 #elif TLS_VARIANT == 2 68 /* round up the tib size to align the extra area after it */ 69 base = _dl_malloc(ELF_ROUND(sizeof *tib, TIB_EXTRA_ALIGN) + 70 extra + static_tls_size); 71 if (base == NULL) 72 return NULL; 73 tib = (struct tib *)(base + static_tls_size); 74 if (extra) 75 thread = (char *)tib + ELF_ROUND(sizeof *tib, TIB_EXTRA_ALIGN); 76 #define TLS_ADDR(tibp, offset) ((char *)(tibp) - (offset)) 77 78 #endif 79 80 for (obj = _dl_objects; obj != NULL; obj = obj->next) { 81 if (obj->tls_msize != 0) { 82 char *addr = TLS_ADDR(tib, obj->tls_offset); 83 84 _dl_memset(addr + obj->tls_fsize, 0, 85 obj->tls_msize - obj->tls_fsize); 86 if (obj->tls_static_data != NULL) 87 _dl_bcopy(obj->tls_static_data, addr, 88 obj->tls_fsize); 89 DL_DEB(("\t%s has index %u addr %p msize %u fsize %u\n", 90 obj->load_name, obj->tls_offset, 91 (void *)addr, obj->tls_msize, obj->tls_fsize)); 92 } 93 } 94 95 TIB_INIT(tib, NULL, thread); 96 97 DL_DEB(("tib new=%p\n", (void *)tib)); 98 99 return (tib); 100 } 101 102 void 103 _dl_free_tib(void *tib, size_t extra) 104 { 105 size_t tib_offset; 106 107 #if TLS_VARIANT == 1 108 tib_offset = ELF_ROUND(extra, sizeof(void *)); 109 #elif TLS_VARIANT == 2 110 tib_offset = static_tls_size; 111 #endif 112 113 DL_DEB(("free tib=%p\n", (void *)tib)); 114 _dl_free((char *)tib - tib_offset); 115 } 116 117 118 /* 119 * Record what's necessary for handling TLS for an object. 120 */ 121 void 122 _dl_set_tls(elf_object_t *object, Elf_Phdr *ptls, Elf_Addr libaddr, 123 const char *libname) 124 { 125 if (ptls->p_vaddr != 0 && ptls->p_filesz != 0) 126 object->tls_static_data = (void *)(ptls->p_vaddr + libaddr); 127 object->tls_fsize = ptls->p_filesz; 128 object->tls_msize = ptls->p_memsz; 129 object->tls_align = ptls->p_align; 130 131 DL_DEB(("tls %x %x %x %x\n", 132 object->tls_static_data, object->tls_fsize, object->tls_msize, 133 object->tls_align)); 134 } 135 136 static inline Elf_Addr 137 allocate_tls_offset(Elf_Addr msize, Elf_Addr align) 138 { 139 Elf_Addr offset; 140 141 #if TLS_VARIANT == 1 142 /* round up to the required alignment, then allocate the space */ 143 offset = ELF_ROUND(static_tls_size, align); 144 static_tls_size += msize; 145 #elif TLS_VARIANT == 2 146 /* 147 * allocate the space, then round up to the alignment 148 * (these are negative offsets, so rounding up really rounds the 149 * address down) 150 */ 151 static_tls_size = ELF_ROUND(static_tls_size + msize, align); 152 offset = static_tls_size; 153 #else 154 # error "unknown TLS_VARIANT" 155 #endif 156 return offset; 157 } 158 159 /* 160 * Calculate the TLS offset for each object with static TLS. 161 */ 162 void 163 _dl_allocate_tls_offsets(void) 164 { 165 struct elf_object *obj; 166 167 for (obj = _dl_objects; obj != NULL; obj = obj->next) { 168 if (obj->tls_msize != 0) { 169 obj->tls_offset = allocate_tls_offset(obj->tls_msize, 170 obj->tls_align); 171 } 172 } 173 174 /* no more static TLS allocations after this */ 175 _dl_tib_static_done = 1; 176 } 177 178 /* 179 * Allocate the TIB + TLS for the initial thread. 180 */ 181 void 182 _dl_allocate_first_tib(void) 183 { 184 struct tib *tib; 185 186 tib = _dl_allocate_tib(0); 187 tib->tib_tid = _dl_getthrid(); 188 189 TCB_SET(TIB_TO_TCB(tib)); 190 } 191