1 /* $OpenBSD: init.c,v 1.4 2016/05/07 19:05:22 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/exec_elf.h> 23 #include <sys/syscall.h> 24 25 #ifndef PIC 26 #include <sys/mman.h> 27 #endif 28 29 #include <tib.h> 30 #include <limits.h> /* NAME_MAX */ 31 #include <stdlib.h> /* atexit */ 32 #include <string.h> 33 #include <unistd.h> 34 35 /* XXX should be in an include file shared with csu */ 36 char ***_csu_finish(char **_argv, char **_envp, void (*_cleanup)(void)); 37 38 /* provide definition for this */ 39 int _pagesize = 0; 40 41 /* 42 * In dynamicly linked binaries environ and __progname are overriden by 43 * the definitions in ld.so. 44 */ 45 char **environ __attribute__((weak)) = NULL; 46 char *__progname __attribute__((weak)) = NULL; 47 48 49 #ifndef PIC 50 static inline void early_static_init(char **_argv, char **_envp); 51 static inline void setup_static_tib(Elf_Phdr *_phdr, int _phnum); 52 #endif /* PIC */ 53 54 55 /* 56 * extract useful bits from the auxiliary vector and either 57 * a) register ld.so's cleanup in dynamic links, or 58 * b) init __progname, environ, and the TIB in static links. 59 */ 60 char *** 61 _csu_finish(char **argv, char **envp, void (*cleanup)(void)) 62 { 63 AuxInfo *aux; 64 #ifndef PIC 65 Elf_Phdr *phdr = NULL; 66 int phnum = 0; 67 68 /* static libc in a static link? */ 69 if (cleanup == NULL) 70 early_static_init(argv, envp); 71 #endif /* !PIC */ 72 73 /* Extract useful bits from the auxiliary vector */ 74 while (*envp++ != NULL) 75 ; 76 for (aux = (void *)envp; aux->au_id != AUX_null; aux++) { 77 switch (aux->au_id) { 78 case AUX_pagesz: 79 _pagesize = aux->au_v; 80 break; 81 #ifndef PIC 82 case AUX_phdr: 83 phdr = (void *)aux->au_v; 84 break; 85 case AUX_phnum: 86 phnum = aux->au_v; 87 break; 88 #endif /* !PIC */ 89 } 90 } 91 92 #ifndef PIC 93 /* static libc in a static link? */ 94 if (cleanup == NULL) 95 setup_static_tib(phdr, phnum); 96 #endif /* !PIC */ 97 98 if (cleanup != NULL) 99 atexit(cleanup); 100 101 return &environ; 102 } 103 104 #ifndef PIC 105 /* 106 * static libc in a static link? Then disable kbind and set up 107 * __progname and environ 108 */ 109 static inline void 110 early_static_init(char **argv, char **envp) 111 { 112 static char progname_storage[NAME_MAX+1]; 113 114 /* disable kbind */ 115 syscall(SYS_kbind, (void *)NULL, (size_t)0, (long long)0); 116 117 environ = envp; 118 119 /* set up __progname */ 120 if (*argv != NULL) { /* NULL ptr if argc = 0 */ 121 const char *p = strrchr(*argv, '/'); 122 123 if (p == NULL) 124 p = *argv; 125 else 126 p++; 127 strlcpy(progname_storage, p, sizeof(progname_storage)); 128 } 129 __progname = progname_storage; 130 } 131 132 /* 133 * static TLS handling 134 */ 135 #define ELF_ROUND(x,malign) (((x) + (malign)-1) & ~((malign)-1)) 136 137 /* for static binaries, the location and size of the TLS image */ 138 static void *static_tls; 139 static size_t static_tls_fsize; 140 141 size_t _static_tls_size = 0; 142 143 static inline void 144 setup_static_tib(Elf_Phdr *phdr, int phnum) 145 { 146 struct tib *tib; 147 char *base; 148 int i; 149 150 if (phdr != NULL) { 151 for (i = 0; i < phnum; i++) { 152 if (phdr[i].p_type != PT_TLS) 153 continue; 154 if (phdr[i].p_memsz == 0) 155 break; 156 if (phdr[i].p_memsz < phdr[i].p_filesz) 157 break; /* invalid */ 158 #if TLS_VARIANT == 1 159 _static_tls_size = phdr[i].p_memsz; 160 #elif TLS_VARIANT == 2 161 /* 162 * variant 2 places the data before the TIB 163 * so we need to round up to the alignment 164 */ 165 _static_tls_size = ELF_ROUND(phdr[i].p_memsz, 166 phdr[i].p_align); 167 #endif 168 if (phdr[i].p_vaddr != 0 && phdr[i].p_filesz != 0) { 169 static_tls = (void *)phdr[i].p_vaddr; 170 static_tls_fsize = phdr[i].p_filesz; 171 } 172 break; 173 } 174 } 175 176 /* 177 * We call getpagesize() here instead of using _pagesize because 178 * there's no aux-vector in non-PIE static links, so _pagesize 179 * might not be set yet. If so getpagesize() will get the value. 180 */ 181 base = mmap(NULL, ELF_ROUND(_static_tls_size + sizeof *tib, 182 getpagesize()), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); 183 # if TLS_VARIANT == 1 184 tib = (struct tib *)base; 185 # elif TLS_VARIANT == 2 186 tib = (struct tib *)(base + _static_tls_size); 187 # endif 188 189 _static_tls_init(base); 190 TIB_INIT(tib, NULL, NULL); 191 tib->tib_tid = getthrid(); 192 TCB_SET(TIB_TO_TCB(tib)); 193 #if ! TCB_HAVE_MD_GET 194 _libc_single_tcb = TIB_TO_TCB(tib); 195 #endif 196 } 197 198 void 199 _static_tls_init(char *base) 200 { 201 if (_static_tls_size) { 202 #if TLS_VARIANT == 1 203 base += sizeof(struct tib); 204 #endif 205 if (static_tls != NULL) 206 memcpy(base, static_tls, static_tls_fsize); 207 memset(base + static_tls_fsize, 0, 208 _static_tls_size - static_tls_fsize); 209 } 210 } 211 #endif /* !PIC */ 212