1 /* $NetBSD: headers.c,v 1.18 2003/07/24 10:12:25 skrll Exp $ */ 2 3 /* 4 * Copyright 1996 John D. Polstra. 5 * Copyright 1996 Matt Thomas <matt@3am-software.com> 6 * Copyright 2002 Charles M. Hannum <root@ihack.net> 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by John Polstra. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 /* 36 * Dynamic linker for ELF. 37 * 38 * John Polstra <jdp@polstra.com>. 39 */ 40 41 #include <err.h> 42 #include <errno.h> 43 #include <fcntl.h> 44 #include <stdarg.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <unistd.h> 49 #include <sys/types.h> 50 #include <sys/mman.h> 51 #include <dirent.h> 52 53 #include "debug.h" 54 #include "rtld.h" 55 56 /* 57 * Process a shared object's DYNAMIC section, and save the important 58 * information in its Obj_Entry structure. 59 */ 60 void 61 _rtld_digest_dynamic(Obj_Entry *obj) 62 { 63 Elf_Dyn *dynp; 64 Needed_Entry **needed_tail = &obj->needed; 65 const Elf_Dyn *dyn_rpath = NULL; 66 Elf_Sword plttype = DT_NULL; 67 Elf_Addr relsz = 0, relasz = 0; 68 Elf_Addr pltrel = 0, pltrelsz = 0; 69 Elf_Addr init = 0, fini = 0; 70 71 for (dynp = obj->dynamic; dynp->d_tag != DT_NULL; ++dynp) { 72 switch (dynp->d_tag) { 73 74 case DT_REL: 75 obj->rel = (const Elf_Rel *) 76 (obj->relocbase + dynp->d_un.d_ptr); 77 break; 78 79 case DT_RELSZ: 80 relsz = dynp->d_un.d_val; 81 break; 82 83 case DT_RELENT: 84 assert(dynp->d_un.d_val == sizeof(Elf_Rel)); 85 break; 86 87 case DT_JMPREL: 88 pltrel = dynp->d_un.d_ptr; 89 break; 90 91 case DT_PLTRELSZ: 92 pltrelsz = dynp->d_un.d_val; 93 break; 94 95 case DT_RELA: 96 obj->rela = (const Elf_Rela *) 97 (obj->relocbase + dynp->d_un.d_ptr); 98 break; 99 100 case DT_RELASZ: 101 relasz = dynp->d_un.d_val; 102 break; 103 104 case DT_RELAENT: 105 assert(dynp->d_un.d_val == sizeof(Elf_Rela)); 106 break; 107 108 case DT_PLTREL: 109 plttype = dynp->d_un.d_val; 110 assert(plttype == DT_REL || plttype == DT_RELA); 111 break; 112 113 case DT_SYMTAB: 114 obj->symtab = (const Elf_Sym *) 115 (obj->relocbase + dynp->d_un.d_ptr); 116 break; 117 118 case DT_SYMENT: 119 assert(dynp->d_un.d_val == sizeof(Elf_Sym)); 120 break; 121 122 case DT_STRTAB: 123 obj->strtab = (const char *) 124 (obj->relocbase + dynp->d_un.d_ptr); 125 break; 126 127 case DT_STRSZ: 128 obj->strsize = dynp->d_un.d_val; 129 break; 130 131 case DT_HASH: 132 { 133 const Elf_Word *hashtab = (const Elf_Word *) 134 (obj->relocbase + dynp->d_un.d_ptr); 135 136 obj->nbuckets = hashtab[0]; 137 obj->nchains = hashtab[1]; 138 obj->buckets = hashtab + 2; 139 obj->chains = obj->buckets + obj->nbuckets; 140 } 141 break; 142 143 case DT_NEEDED: 144 { 145 Needed_Entry *nep = NEW(Needed_Entry); 146 147 nep->name = dynp->d_un.d_val; 148 nep->obj = NULL; 149 nep->next = NULL; 150 151 *needed_tail = nep; 152 needed_tail = &nep->next; 153 } 154 break; 155 156 case DT_PLTGOT: 157 obj->pltgot = (Elf_Addr *) 158 (obj->relocbase + dynp->d_un.d_ptr); 159 break; 160 161 case DT_TEXTREL: 162 obj->textrel = true; 163 break; 164 165 case DT_SYMBOLIC: 166 obj->symbolic = true; 167 break; 168 169 case DT_RPATH: 170 /* 171 * We have to wait until later to process this, because 172 * we might not have gotten the address of the string 173 * table yet. 174 */ 175 dyn_rpath = dynp; 176 break; 177 178 case DT_SONAME: 179 /* Not used by the dynamic linker. */ 180 break; 181 182 case DT_INIT: 183 init = dynp->d_un.d_ptr; 184 break; 185 186 case DT_FINI: 187 fini = dynp->d_un.d_ptr; 188 break; 189 190 case DT_DEBUG: 191 #ifdef RTLD_LOADER 192 dynp->d_un.d_ptr = (Elf_Addr)&_rtld_debug; 193 #endif 194 break; 195 196 #ifdef __mips__ 197 case DT_MIPS_LOCAL_GOTNO: 198 obj->local_gotno = dynp->d_un.d_val; 199 break; 200 201 case DT_MIPS_SYMTABNO: 202 obj->symtabno = dynp->d_un.d_val; 203 break; 204 205 case DT_MIPS_GOTSYM: 206 obj->gotsym = dynp->d_un.d_val; 207 break; 208 209 case DT_MIPS_RLD_MAP: 210 #ifdef RTLD_LOADER 211 *((Elf_Addr *)(dynp->d_un.d_ptr)) = (Elf_Addr) 212 &_rtld_debug; 213 #endif 214 break; 215 #endif 216 } 217 } 218 219 obj->rellim = (const Elf_Rel *)((caddr_t)obj->rel + relsz); 220 obj->relalim = (const Elf_Rela *)((caddr_t)obj->rela + relasz); 221 if (plttype == DT_REL) { 222 obj->pltrel = (const Elf_Rel *)(obj->relocbase + pltrel); 223 obj->pltrellim = (const Elf_Rel *)(obj->relocbase + pltrel + pltrelsz); 224 obj->pltrelalim = 0; 225 /* On PPC and SPARC, at least, REL(A)SZ may include JMPREL. 226 Trim rel(a)lim to save time later. */ 227 if (obj->rellim && obj->pltrel && 228 obj->rellim > obj->pltrel && 229 obj->rellim <= obj->pltrellim) 230 obj->rellim = obj->pltrel; 231 } else if (plttype == DT_RELA) { 232 obj->pltrela = (const Elf_Rela *)(obj->relocbase + pltrel); 233 obj->pltrellim = 0; 234 obj->pltrelalim = (const Elf_Rela *)(obj->relocbase + pltrel + pltrelsz); 235 /* On PPC and SPARC, at least, REL(A)SZ may include JMPREL. 236 Trim rel(a)lim to save time later. */ 237 if (obj->relalim && obj->pltrela && 238 obj->relalim > obj->pltrela && 239 obj->relalim <= obj->pltrelalim) 240 obj->relalim = obj->pltrela; 241 } 242 243 #if defined(RTLD_LOADER) && defined(__HAVE_FUNCTION_DESCRIPTORS) 244 if (init != 0) 245 obj->init = (void (*)(void)) 246 _rtld_function_descriptor_alloc(obj, NULL, init); 247 if (fini != 0) 248 obj->fini = (void (*)(void)) 249 _rtld_function_descriptor_alloc(obj, NULL, fini); 250 #else 251 if (init != 0) 252 obj->init = (void (*)(void)) 253 (obj->relocbase + init); 254 if (fini != 0) 255 obj->fini = (void (*)(void)) 256 (obj->relocbase + fini); 257 #endif 258 259 if (dyn_rpath != NULL) { 260 _rtld_add_paths(&obj->rpaths, obj->strtab + 261 dyn_rpath->d_un.d_val); 262 } 263 } 264 265 /* 266 * Process a shared object's program header. This is used only for the 267 * main program, when the kernel has already loaded the main program 268 * into memory before calling the dynamic linker. It creates and 269 * returns an Obj_Entry structure. 270 */ 271 Obj_Entry * 272 _rtld_digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry) 273 { 274 Obj_Entry *obj; 275 const Elf_Phdr *phlimit = phdr + phnum; 276 const Elf_Phdr *ph; 277 int nsegs = 0; 278 279 obj = _rtld_obj_new(); 280 for (ph = phdr; ph < phlimit; ++ph) { 281 switch (ph->p_type) { 282 283 case PT_PHDR: 284 assert((const Elf_Phdr *) ph->p_vaddr == phdr); 285 break; 286 287 case PT_INTERP: 288 obj->interp = (const char *) ph->p_vaddr; 289 break; 290 291 case PT_LOAD: 292 assert(nsegs < 2); 293 if (nsegs == 0) { /* First load segment */ 294 obj->vaddrbase = round_down(ph->p_vaddr); 295 obj->mapbase = (caddr_t) obj->vaddrbase; 296 obj->relocbase = obj->mapbase - obj->vaddrbase; 297 obj->textsize = round_up(ph->p_vaddr + 298 ph->p_memsz) - obj->vaddrbase; 299 } else { /* Last load segment */ 300 obj->mapsize = round_up(ph->p_vaddr + 301 ph->p_memsz) - obj->vaddrbase; 302 } 303 ++nsegs; 304 break; 305 306 case PT_DYNAMIC: 307 obj->dynamic = (Elf_Dyn *) ph->p_vaddr; 308 break; 309 } 310 } 311 assert(nsegs == 2); 312 313 obj->entry = entry; 314 return obj; 315 } 316