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