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