Home | History | Annotate | Line # | Download | only in ld.elf_so
headers.c revision 1.2
      1 /*	$NetBSD: headers.c,v 1.2 1998/03/25 04:13:01 mhitch Exp $	*/
      2 
      3 /*
      4  * Copyright 1996 John D. Polstra.
      5  * Copyright 1996 Matt Thomas <matt (at) 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 (at) 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(
     61     Obj_Entry *obj)
     62 {
     63     Elf_Dyn *dynp;
     64     Needed_Entry **needed_tail = &obj->needed;
     65     const Elf_Dyn *dyn_rpath = NULL;
     66     enum Elf_e_dynamic_type plttype = Elf_edt_rel;
     67     Elf_Word relsize = 0, relasize = 0, pltrelsize = 0, pltrelasize = 0;
     68 
     69     for (dynp = obj->dynamic;  dynp->d_tag != Elf_edt_null;  ++dynp) {
     70 	switch(dynp->d_tag) {
     71 
     72 	case Elf_edt_rel:
     73 	    obj->rel = (const Elf_Rel *) (obj->relocbase + dynp->d_un.d_ptr);
     74 	    break;
     75 
     76 	case Elf_edt_relsz:
     77 	    relsize = dynp->d_un.d_val;
     78 	    break;
     79 
     80 	case Elf_edt_relent:
     81 	    assert(dynp->d_un.d_val == sizeof(Elf_Rel));
     82 	    break;
     83 
     84 	case Elf_edt_jmprel:
     85 	    if (plttype == Elf_edt_rel) {
     86 		obj->pltrel = (const Elf_Rel *)
     87 		    (obj->relocbase + dynp->d_un.d_ptr);
     88 	    } else {
     89 		obj->pltrela = (const Elf_RelA *)
     90 		    (obj->relocbase + dynp->d_un.d_ptr);
     91 	    }
     92 	    break;
     93 
     94 	case Elf_edt_pltrelsz:
     95 	    if (plttype == Elf_edt_rel) {
     96 		pltrelsize = dynp->d_un.d_val;
     97 	    } else {
     98 		pltrelasize = dynp->d_un.d_val;
     99 	    }
    100 	    break;
    101 
    102 	case Elf_edt_rela:
    103 	    obj->rela = (const Elf_RelA *) (obj->relocbase + dynp->d_un.d_ptr);
    104 	    break;
    105 
    106 	case Elf_edt_relasz:
    107 	    relasize = dynp->d_un.d_val;
    108 	    break;
    109 
    110 	case Elf_edt_relaent:
    111 	    assert(dynp->d_un.d_val == sizeof(Elf_RelA));
    112 	    break;
    113 
    114 	case Elf_edt_pltrel:
    115 	    plttype = dynp->d_un.d_val;
    116 	    assert(plttype == Elf_edt_rel || plttype == Elf_edt_rela);
    117 	    if (plttype == Elf_edt_rela) {
    118 		obj->pltrela = (const Elf_RelA *) obj->pltrel;
    119 		obj->pltrel = NULL;
    120 		pltrelasize = pltrelsize;
    121 		pltrelsize = 0;
    122 	    }
    123 	    break;
    124 
    125 	case Elf_edt_symtab:
    126 	    obj->symtab = (const Elf_Sym *)
    127 		(obj->relocbase + dynp->d_un.d_ptr);
    128 	    break;
    129 
    130 	case Elf_edt_syment:
    131 	    assert(dynp->d_un.d_val == sizeof(Elf_Sym));
    132 	    break;
    133 
    134 	case Elf_edt_strtab:
    135 	    obj->strtab = (const char *) (obj->relocbase + dynp->d_un.d_ptr);
    136 	    break;
    137 
    138 	case Elf_edt_strsz:
    139 	    obj->strsize = dynp->d_un.d_val;
    140 	    break;
    141 
    142 	case Elf_edt_hash:
    143 	    {
    144 		const Elf_Word *hashtab = (const Elf_Word *)
    145 		    (obj->relocbase + dynp->d_un.d_ptr);
    146 		obj->nbuckets = hashtab[0];
    147 		obj->nchains = hashtab[1];
    148 		obj->buckets = hashtab + 2;
    149 		obj->chains = obj->buckets + obj->nbuckets;
    150 	    }
    151 	    break;
    152 
    153 	case Elf_edt_needed:
    154 	    assert(!obj->rtld);
    155 	    {
    156 		Needed_Entry *nep = NEW(Needed_Entry);
    157 		nep->name = dynp->d_un.d_val;
    158 		nep->obj = NULL;
    159 		nep->next = NULL;
    160 
    161 		*needed_tail = nep;
    162 		needed_tail = &nep->next;
    163 	    }
    164 	    break;
    165 
    166 	case Elf_edt_pltgot:
    167 	    obj->pltgot = (Elf_Addr *) (obj->relocbase + dynp->d_un.d_ptr);
    168 	    break;
    169 
    170 	case Elf_edt_textrel:
    171 	    obj->textrel = true;
    172 	    break;
    173 
    174 	case Elf_edt_symbolic:
    175 	    obj->symbolic = true;
    176 	    break;
    177 
    178 	case Elf_edt_rpath:
    179 	    /*
    180 	     * We have to wait until later to process this, because we
    181 	     * might not have gotten the address of the string table yet.
    182 	     */
    183 	    dyn_rpath = dynp;
    184 	    break;
    185 
    186 	case Elf_edt_soname:
    187 	    /* Not used by the dynamic linker. */
    188 	    break;
    189 
    190 	case Elf_edt_init:
    191 	    obj->init = (void (*)(void)) (obj->relocbase + dynp->d_un.d_ptr);
    192 	    break;
    193 
    194 	case Elf_edt_fini:
    195 	    obj->fini = (void (*)(void)) (obj->relocbase + dynp->d_un.d_ptr);
    196 	    break;
    197 
    198 	case Elf_edt_debug:
    199 #ifdef RTLD_LOADER
    200 	    dynp->d_un.d_ptr = (Elf_Addr) &_rtld_debug;
    201 #endif
    202 	    break;
    203 
    204 #if defined(__mips__)
    205 	case DT_MIPS_LOCAL_GOTNO:
    206 	    obj->local_gotno = dynp->d_un.d_val;
    207 	    break;
    208 
    209 	case DT_MIPS_SYMTABNO:
    210 	    obj->symtabno = dynp->d_un.d_val;
    211 	    break;
    212 
    213 	case DT_MIPS_GOTSYM:
    214 	    obj->gotsym = dynp->d_un.d_val;
    215 	    break;
    216 
    217 	case DT_MIPS_RLD_MAP:
    218 #ifdef RTLD_LOADER
    219 	    *((Elf_Addr *)(dynp->d_un.d_ptr)) = (Elf_Addr) &_rtld_debug;
    220 #endif
    221 	    break;
    222 #endif
    223 	}
    224     }
    225 
    226     obj->rellim     = (const Elf_Rel  *) ((caddr_t) obj->rel     + relsize);
    227     obj->relalim    = (const Elf_RelA *) ((caddr_t) obj->rela    + relasize);
    228     obj->pltrellim  = (const Elf_Rel  *) ((caddr_t) obj->pltrel  + pltrelsize);
    229     obj->pltrelalim = (const Elf_RelA *) ((caddr_t) obj->pltrela + pltrelasize);
    230 
    231     if (dyn_rpath != NULL) {
    232 	_rtld_add_paths(&obj->rpaths, obj->strtab + dyn_rpath->d_un.d_val);
    233     }
    234 }
    235 
    236 /*
    237  * Process a shared object's program header.  This is used only for the
    238  * main program, when the kernel has already loaded the main program
    239  * into memory before calling the dynamic linker.  It creates and
    240  * returns an Obj_Entry structure.
    241  */
    242 Obj_Entry *
    243 _rtld_digest_phdr(
    244     const Elf_Phdr *phdr,
    245     int phnum,
    246     caddr_t entry)
    247 {
    248     Obj_Entry *obj = CNEW(Obj_Entry);
    249     const Elf_Phdr *phlimit = phdr + phnum;
    250     const Elf_Phdr *ph;
    251     int nsegs = 0;
    252 
    253     for (ph = phdr;  ph < phlimit;  ++ph) {
    254 	switch(ph->p_type) {
    255 
    256 	case Elf_pt_phdr:
    257 	    assert((const Elf_Phdr *) ph->p_vaddr == phdr);
    258 	    obj->phdr = (const Elf_Phdr *) ph->p_vaddr;
    259 	    obj->phsize = ph->p_memsz;
    260 	    break;
    261 
    262 	case Elf_pt_load:
    263 	    assert(nsegs < 2);
    264 	    if (nsegs == 0) {	/* First load segment */
    265 		obj->vaddrbase = round_down(ph->p_vaddr);
    266 		obj->mapbase = (caddr_t) obj->vaddrbase;
    267 		obj->relocbase = obj->mapbase - obj->vaddrbase;
    268 		obj->textsize = round_up(ph->p_vaddr + ph->p_memsz) -
    269 		    obj->vaddrbase;
    270 	    } else {		/* Last load segment */
    271 		obj->mapsize = round_up(ph->p_vaddr + ph->p_memsz) -
    272 		    obj->vaddrbase;
    273 	    }
    274 	    ++nsegs;
    275 	    break;
    276 
    277 	case Elf_pt_dynamic:
    278 	    obj->dynamic = (Elf_Dyn *) ph->p_vaddr;
    279 	    break;
    280 	}
    281     }
    282     assert(nsegs == 2);
    283 
    284     obj->entry = entry;
    285     return obj;
    286 }
    287