1 /* $OpenBSD: init.c,v 1.6 2017/12/01 23:30:05 guenther Exp $ */ 2 /* 3 * Copyright (c) 2014,2015 Philip Guenther <guenther@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 19 #define _DYN_LOADER 20 21 #include <sys/types.h> 22 #include <sys/syscall.h> 23 24 #ifndef PIC 25 #include <sys/mman.h> 26 #endif 27 28 #include <tib.h> 29 #include <limits.h> /* NAME_MAX */ 30 #include <link.h> 31 #include <stdlib.h> /* atexit */ 32 #include <string.h> 33 #include <unistd.h> 34 35 #include "init.h" 36 37 #define MAX(a,b) (((a)>(b))?(a):(b)) 38 39 #ifdef TIB_EXTRA_ALIGN 40 # define TIB_ALIGN MAX(__alignof__(struct tib), TIB_EXTRA_ALIGN) 41 #else 42 # define TIB_ALIGN __alignof__(struct tib) 43 #endif 44 45 /* XXX should be in an include file shared with csu */ 46 char ***_csu_finish(char **_argv, char **_envp, void (*_cleanup)(void)); 47 48 /* provide definition for this */ 49 int _pagesize = 0; 50 51 /* 52 * In dynamicly linked binaries environ and __progname are overriden by 53 * the definitions in ld.so. 54 */ 55 char **environ __attribute__((weak)) = NULL; 56 char *__progname __attribute__((weak)) = NULL; 57 58 59 #ifndef PIC 60 struct dl_phdr_info _static_phdr_info = { .dlpi_name = "a.out" }; 61 62 static inline void early_static_init(char **_argv, char **_envp); 63 static inline void setup_static_tib(Elf_Phdr *_phdr, int _phnum); 64 65 /* provided by the linker */ 66 extern Elf_Ehdr __executable_start[] __attribute__((weak)); 67 #endif /* PIC */ 68 69 /* 70 * extract useful bits from the auxiliary vector and either 71 * a) register ld.so's cleanup in dynamic links, or 72 * b) init __progname, environ, and the TIB in static links. 73 */ 74 char *** 75 _csu_finish(char **argv, char **envp, void (*cleanup)(void)) 76 { 77 AuxInfo *aux; 78 #ifndef PIC 79 Elf_Phdr *phdr = NULL; 80 int phnum = 0; 81 82 /* static libc in a static link? */ 83 if (cleanup == NULL) 84 early_static_init(argv, envp); 85 #endif /* !PIC */ 86 87 /* Extract useful bits from the auxiliary vector */ 88 while (*envp++ != NULL) 89 ; 90 for (aux = (void *)envp; aux->au_id != AUX_null; aux++) { 91 switch (aux->au_id) { 92 case AUX_pagesz: 93 _pagesize = aux->au_v; 94 break; 95 #ifndef PIC 96 case AUX_base: 97 _static_phdr_info.dlpi_addr = aux->au_v; 98 break; 99 case AUX_phdr: 100 phdr = (void *)aux->au_v; 101 _static_phdr_info.dlpi_phdr = phdr; 102 break; 103 case AUX_phnum: 104 phnum = aux->au_v; 105 _static_phdr_info.dlpi_phnum = phnum; 106 break; 107 #endif /* !PIC */ 108 } 109 } 110 111 #ifndef PIC 112 if (cleanup == NULL && phdr == NULL && __executable_start != NULL) { 113 /* 114 * Static non-PIE processes don't get an AUX vector, 115 * so find the phdrs through the ELF header 116 */ 117 phdr = (void *)((char *)__executable_start + 118 __executable_start->e_phoff); 119 phnum = __executable_start->e_phnum; 120 } 121 /* static libc in a static link? */ 122 if (cleanup == NULL) 123 setup_static_tib(phdr, phnum); 124 #endif /* !PIC */ 125 126 if (cleanup != NULL) 127 atexit(cleanup); 128 129 return &environ; 130 } 131 132 #ifndef PIC 133 /* 134 * static libc in a static link? Then disable kbind and set up 135 * __progname and environ 136 */ 137 static inline void 138 early_static_init(char **argv, char **envp) 139 { 140 static char progname_storage[NAME_MAX+1]; 141 142 /* disable kbind */ 143 syscall(SYS_kbind, (void *)NULL, (size_t)0, (long long)0); 144 145 environ = envp; 146 147 /* set up __progname */ 148 if (*argv != NULL) { /* NULL ptr if argc = 0 */ 149 const char *p = strrchr(*argv, '/'); 150 151 if (p == NULL) 152 p = *argv; 153 else 154 p++; 155 strlcpy(progname_storage, p, sizeof(progname_storage)); 156 } 157 __progname = progname_storage; 158 } 159 160 /* 161 * static TLS handling 162 */ 163 #define ELF_ROUND(x,malign) (((x) + (malign)-1) & ~((malign)-1)) 164 165 /* for static binaries, the location and size of the TLS image */ 166 static void *static_tls; 167 static size_t static_tls_fsize; 168 169 size_t _static_tls_size = 0; 170 int _static_tls_align; 171 int _static_tls_align_offset; 172 173 static inline void 174 setup_static_tib(Elf_Phdr *phdr, int phnum) 175 { 176 struct tib *tib; 177 char *base; 178 int i; 179 180 _static_tls_align = TIB_ALIGN; 181 if (phdr != NULL) { 182 for (i = 0; i < phnum; i++) { 183 if (phdr[i].p_type != PT_TLS) 184 continue; 185 if (phdr[i].p_memsz == 0) 186 break; 187 if (phdr[i].p_memsz < phdr[i].p_filesz) 188 break; /* invalid */ 189 if (phdr[i].p_align > getpagesize()) 190 break; /* nope */ 191 _static_tls_align = MAX(phdr[i].p_align, TIB_ALIGN); 192 #if TLS_VARIANT == 1 193 /* 194 * Variant 1 places the data after the TIB. If the 195 * TLS alignment is larger than the TIB alignment 196 * then we may need to pad in front of the TIB to 197 * place the TLS data on the proper alignment. 198 * Example: p_align=16 sizeof(TIB)=52 align(TIB)=4 199 * - need to offset the TIB 12 bytes from the start 200 * - to place ths TLS data at offset 64 201 */ 202 _static_tls_size = phdr[i].p_memsz; 203 _static_tls_align_offset = 204 ELF_ROUND(sizeof(struct tib), _static_tls_align) - 205 sizeof(struct tib); 206 #elif TLS_VARIANT == 2 207 /* 208 * Variant 2 places the data before the TIB 209 * so we need to round up the size to the 210 * TLS data alignment TIB's alignment. 211 * Example A: p_memsz=24 p_align=16 align(TIB)=8 212 * - need to allocate 32 bytes for TLS as compiler 213 * - will give the first TLS symbol an offset of -32 214 * Example B: p_memsz=4 p_align=4 align(TIB)=8 215 * - need to allocate 8 bytes so that the TIB is 216 * - properly aligned 217 */ 218 _static_tls_size = ELF_ROUND(phdr[i].p_memsz, 219 phdr[i].p_align); 220 _static_tls_align_offset = ELF_ROUND(_static_tls_size, 221 _static_tls_align) - _static_tls_size; 222 #endif 223 if (phdr[i].p_vaddr != 0 && phdr[i].p_filesz != 0) { 224 static_tls = (void *)phdr[i].p_vaddr + 225 _static_phdr_info.dlpi_addr; 226 static_tls_fsize = phdr[i].p_filesz; 227 } 228 break; 229 } 230 } 231 232 base = mmap(NULL, _static_tls_size + _static_tls_align_offset 233 + sizeof *tib, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); 234 235 tib = _static_tls_init(base, NULL); 236 tib->tib_tid = getthrid(); 237 TCB_SET(TIB_TO_TCB(tib)); 238 #if ! TCB_HAVE_MD_GET 239 _libc_single_tcb = TIB_TO_TCB(tib); 240 #endif 241 } 242 243 struct tib * 244 _static_tls_init(char *base, void *thread) 245 { 246 struct tib *tib; 247 248 base += _static_tls_align_offset; 249 # if TLS_VARIANT == 1 250 tib = (struct tib *)base; 251 base += sizeof(struct tib); 252 # elif TLS_VARIANT == 2 253 tib = (struct tib *)(base + _static_tls_size); 254 # endif 255 256 if (_static_tls_size) { 257 if (static_tls != NULL) 258 memcpy(base, static_tls, static_tls_fsize); 259 memset(base + static_tls_fsize, 0, 260 _static_tls_size - static_tls_fsize); 261 } 262 263 TIB_INIT(tib, NULL, thread); 264 return tib; 265 } 266 #endif /* !PIC */ 267