Home | History | Annotate | Line # | Download | only in ld.elf_so
headers.c revision 1.1
      1 /*	$NetBSD: headers.c,v 1.1 1996/12/16 20:37:58 cgd 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     }
    205 
    206     obj->rellim     = (const Elf_Rel  *) ((caddr_t) obj->rel     + relsize);
    207     obj->relalim    = (const Elf_RelA *) ((caddr_t) obj->rela    + relasize);
    208     obj->pltrellim  = (const Elf_Rel  *) ((caddr_t) obj->pltrel  + pltrelsize);
    209     obj->pltrelalim = (const Elf_RelA *) ((caddr_t) obj->pltrela + pltrelasize);
    210 
    211     if (dyn_rpath != NULL) {
    212 	_rtld_add_paths(&obj->rpaths, obj->strtab + dyn_rpath->d_un.d_val);
    213     }
    214 }
    215 
    216 /*
    217  * Process a shared object's program header.  This is used only for the
    218  * main program, when the kernel has already loaded the main program
    219  * into memory before calling the dynamic linker.  It creates and
    220  * returns an Obj_Entry structure.
    221  */
    222 Obj_Entry *
    223 _rtld_digest_phdr(
    224     const Elf_Phdr *phdr,
    225     int phnum,
    226     caddr_t entry)
    227 {
    228     Obj_Entry *obj = CNEW(Obj_Entry);
    229     const Elf_Phdr *phlimit = phdr + phnum;
    230     const Elf_Phdr *ph;
    231     int nsegs = 0;
    232 
    233     for (ph = phdr;  ph < phlimit;  ++ph) {
    234 	switch(ph->p_type) {
    235 
    236 	case Elf_pt_phdr:
    237 	    assert((const Elf_Phdr *) ph->p_vaddr == phdr);
    238 	    obj->phdr = (const Elf_Phdr *) ph->p_vaddr;
    239 	    obj->phsize = ph->p_memsz;
    240 	    break;
    241 
    242 	case Elf_pt_load:
    243 	    assert(nsegs < 2);
    244 	    if (nsegs == 0) {	/* First load segment */
    245 		obj->vaddrbase = round_down(ph->p_vaddr);
    246 		obj->mapbase = (caddr_t) obj->vaddrbase;
    247 		obj->relocbase = obj->mapbase - obj->vaddrbase;
    248 		obj->textsize = round_up(ph->p_vaddr + ph->p_memsz) -
    249 		    obj->vaddrbase;
    250 	    } else {		/* Last load segment */
    251 		obj->mapsize = round_up(ph->p_vaddr + ph->p_memsz) -
    252 		    obj->vaddrbase;
    253 	    }
    254 	    ++nsegs;
    255 	    break;
    256 
    257 	case Elf_pt_dynamic:
    258 	    obj->dynamic = (Elf_Dyn *) ph->p_vaddr;
    259 	    break;
    260 	}
    261     }
    262     assert(nsegs == 2);
    263 
    264     obj->entry = entry;
    265     return obj;
    266 }
    267