xref: /netbsd-src/libexec/ld.elf_so/headers.c (revision 84d0ab551791493d2630bbef27063a9d514b9108)
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@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(
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