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