headers.c revision 1.50 1 /* $NetBSD: headers.c,v 1.50 2013/05/06 08:02:20 skrll Exp $ */
2
3 /*
4 * Copyright 1996 John D. Polstra.
5 * Copyright 1996 Matt Thomas <matt (at) 3am-software.com>
6 * Copyright 2002 Charles M. Hannum <root (at) ihack.net>
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by John Polstra.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 /*
36 * Dynamic linker for ELF.
37 *
38 * John Polstra <jdp (at) polstra.com>.
39 */
40
41 #include <sys/cdefs.h>
42 #ifndef lint
43 __RCSID("$NetBSD: headers.c,v 1.50 2013/05/06 08:02:20 skrll Exp $");
44 #endif /* not lint */
45
46 #include <err.h>
47 #include <errno.h>
48 #include <fcntl.h>
49 #include <stdarg.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54 #include <sys/types.h>
55 #include <sys/mman.h>
56 #include <sys/bitops.h>
57 #include <dirent.h>
58
59 #include "debug.h"
60 #include "rtld.h"
61
62 /*
63 * Process a shared object's DYNAMIC section, and save the important
64 * information in its Obj_Entry structure.
65 */
66 void
67 _rtld_digest_dynamic(const char *execname, Obj_Entry *obj)
68 {
69 Elf_Dyn *dynp;
70 Needed_Entry **needed_tail = &obj->needed;
71 const Elf_Dyn *dyn_rpath = NULL;
72 bool use_pltrel = false;
73 bool use_pltrela = false;
74 Elf_Addr relsz = 0, relasz = 0;
75 Elf_Addr pltrel = 0, pltrelsz = 0;
76 Elf_Addr init = 0, fini = 0;
77
78 dbg(("headers: digesting PT_DYNAMIC at %p", obj->dynamic));
79 for (dynp = obj->dynamic; dynp->d_tag != DT_NULL; ++dynp) {
80 dbg((" d_tag %ld at %p", (long)dynp->d_tag, dynp));
81 switch (dynp->d_tag) {
82
83 case DT_REL:
84 obj->rel = (const Elf_Rel *)
85 (obj->relocbase + dynp->d_un.d_ptr);
86 break;
87
88 case DT_RELSZ:
89 relsz = dynp->d_un.d_val;
90 break;
91
92 case DT_RELENT:
93 assert(dynp->d_un.d_val == sizeof(Elf_Rel));
94 break;
95
96 case DT_JMPREL:
97 pltrel = dynp->d_un.d_ptr;
98 break;
99
100 case DT_PLTRELSZ:
101 pltrelsz = dynp->d_un.d_val;
102 break;
103
104 case DT_RELA:
105 obj->rela = (const Elf_Rela *)
106 (obj->relocbase + dynp->d_un.d_ptr);
107 break;
108
109 case DT_RELASZ:
110 relasz = dynp->d_un.d_val;
111 break;
112
113 case DT_RELAENT:
114 assert(dynp->d_un.d_val == sizeof(Elf_Rela));
115 break;
116
117 case DT_PLTREL:
118 use_pltrel = dynp->d_un.d_val == DT_REL;
119 use_pltrela = dynp->d_un.d_val == DT_RELA;
120 assert(use_pltrel || use_pltrela);
121 break;
122
123 case DT_SYMTAB:
124 obj->symtab = (const Elf_Sym *)
125 (obj->relocbase + dynp->d_un.d_ptr);
126 break;
127
128 case DT_SYMENT:
129 assert(dynp->d_un.d_val == sizeof(Elf_Sym));
130 break;
131
132 case DT_STRTAB:
133 obj->strtab = (const char *)
134 (obj->relocbase + dynp->d_un.d_ptr);
135 break;
136
137 case DT_STRSZ:
138 obj->strsize = dynp->d_un.d_val;
139 break;
140
141 case DT_VERNEED:
142 obj->verneed = (const Elf_Verneed *)
143 (obj->relocbase + dynp->d_un.d_ptr);
144 break;
145
146 case DT_VERNEEDNUM:
147 obj->verneednum = dynp->d_un.d_val;
148 break;
149
150 case DT_VERDEF:
151 obj->verdef = (const Elf_Verdef *)
152 (obj->relocbase + dynp->d_un.d_ptr);
153 break;
154
155 case DT_VERDEFNUM:
156 obj->verdefnum = dynp->d_un.d_val;
157 break;
158
159 case DT_VERSYM:
160 obj->versyms = (const Elf_Versym *)
161 (obj->relocbase + dynp->d_un.d_ptr);
162 break;
163
164 case DT_HASH:
165 {
166 const Elf_Symindx *hashtab = (const Elf_Symindx *)
167 (obj->relocbase + dynp->d_un.d_ptr);
168
169 if (hashtab[0] > UINT32_MAX)
170 obj->nbuckets = UINT32_MAX;
171 else
172 obj->nbuckets = hashtab[0];
173 obj->nchains = hashtab[1];
174 obj->buckets = hashtab + 2;
175 obj->chains = obj->buckets + obj->nbuckets;
176 /*
177 * Should really be in _rtld_relocate_objects,
178 * but _rtld_symlook_obj might be used before.
179 */
180 if (obj->nbuckets) {
181 fast_divide32_prepare(obj->nbuckets,
182 &obj->nbuckets_m,
183 &obj->nbuckets_s1,
184 &obj->nbuckets_s2);
185 }
186 }
187 break;
188
189 case DT_NEEDED:
190 {
191 Needed_Entry *nep = NEW(Needed_Entry);
192
193 nep->name = dynp->d_un.d_val;
194 nep->obj = NULL;
195 nep->next = NULL;
196
197 *needed_tail = nep;
198 needed_tail = &nep->next;
199 }
200 break;
201
202 case DT_PLTGOT:
203 obj->pltgot = (Elf_Addr *)
204 (obj->relocbase + dynp->d_un.d_ptr);
205 break;
206
207 case DT_TEXTREL:
208 obj->textrel = true;
209 break;
210
211 case DT_SYMBOLIC:
212 obj->symbolic = true;
213 break;
214
215 case DT_RPATH:
216 /*
217 * We have to wait until later to process this, because
218 * we might not have gotten the address of the string
219 * table yet.
220 */
221 dyn_rpath = dynp;
222 break;
223
224 case DT_SONAME:
225 /* Not used by the dynamic linker. */
226 break;
227
228 case DT_INIT:
229 init = dynp->d_un.d_ptr;
230 break;
231
232 #ifdef HAVE_INITFINI_ARRAY
233 case DT_INIT_ARRAY:
234 obj->init_array =
235 (fptr_t *)(obj->relocbase + dynp->d_un.d_ptr);
236 dbg(("headers: DT_INIT_ARRAY at %p",
237 obj->init_array));
238 break;
239
240 case DT_INIT_ARRAYSZ:
241 obj->init_arraysz = dynp->d_un.d_val / sizeof(fptr_t);
242 dbg(("headers: DT_INIT_ARRAYZ %zu",
243 obj->init_arraysz));
244 break;
245 #endif
246
247 case DT_FINI:
248 fini = dynp->d_un.d_ptr;
249 break;
250
251 #ifdef HAVE_INITFINI_ARRAY
252 case DT_FINI_ARRAY:
253 obj->fini_array =
254 (fptr_t *)(obj->relocbase + dynp->d_un.d_ptr);
255 dbg(("headers: DT_FINI_ARRAY at %p",
256 obj->fini_array));
257 break;
258
259 case DT_FINI_ARRAYSZ:
260 obj->fini_arraysz = dynp->d_un.d_val / sizeof(fptr_t);
261 dbg(("headers: DT_FINI_ARRAYZ %zu",
262 obj->fini_arraysz));
263 break;
264 #endif
265
266 /*
267 * Don't process DT_DEBUG on MIPS as the dynamic section
268 * is mapped read-only. DT_MIPS_RLD_MAP is used instead.
269 * XXX: n32/n64 may use DT_DEBUG, not sure yet.
270 */
271 #ifndef __mips__
272 case DT_DEBUG:
273 #ifdef RTLD_LOADER
274 dynp->d_un.d_ptr = (Elf_Addr)&_rtld_debug;
275 #endif
276 break;
277 #endif
278
279 #ifdef __mips__
280 case DT_MIPS_LOCAL_GOTNO:
281 obj->local_gotno = dynp->d_un.d_val;
282 break;
283
284 case DT_MIPS_SYMTABNO:
285 obj->symtabno = dynp->d_un.d_val;
286 break;
287
288 case DT_MIPS_GOTSYM:
289 obj->gotsym = dynp->d_un.d_val;
290 break;
291
292 case DT_MIPS_RLD_MAP:
293 #ifdef RTLD_LOADER
294 *((Elf_Addr *)(dynp->d_un.d_ptr)) = (Elf_Addr)
295 &_rtld_debug;
296 #endif
297 break;
298 #endif
299 #ifdef __powerpc__
300 case DT_PPC_GOT:
301 obj->gotptr = (Elf_Addr *)(obj->relocbase + dynp->d_un.d_ptr);
302 break;
303 #endif
304 case DT_FLAGS_1:
305 obj->z_now =
306 ((dynp->d_un.d_val & DF_1_BIND_NOW) != 0);
307 obj->z_nodelete =
308 ((dynp->d_un.d_val & DF_1_NODELETE) != 0);
309 obj->z_initfirst =
310 ((dynp->d_un.d_val & DF_1_INITFIRST) != 0);
311 obj->z_noopen =
312 ((dynp->d_un.d_val & DF_1_NOOPEN) != 0);
313 break;
314 }
315 }
316
317 obj->rellim = (const Elf_Rel *)((const uint8_t *)obj->rel + relsz);
318 obj->relalim = (const Elf_Rela *)((const uint8_t *)obj->rela + relasz);
319 if (use_pltrel) {
320 obj->pltrel = (const Elf_Rel *)(obj->relocbase + pltrel);
321 obj->pltrellim = (const Elf_Rel *)(obj->relocbase + pltrel + pltrelsz);
322 obj->pltrelalim = 0;
323 /* On PPC and SPARC, at least, REL(A)SZ may include JMPREL.
324 Trim rel(a)lim to save time later. */
325 if (obj->rellim && obj->pltrel &&
326 obj->rellim > obj->pltrel &&
327 obj->rellim <= obj->pltrellim)
328 obj->rellim = obj->pltrel;
329 } else if (use_pltrela) {
330 obj->pltrela = (const Elf_Rela *)(obj->relocbase + pltrel);
331 obj->pltrellim = 0;
332 obj->pltrelalim = (const Elf_Rela *)(obj->relocbase + pltrel + pltrelsz);
333 /* On PPC and SPARC, at least, REL(A)SZ may include JMPREL.
334 Trim rel(a)lim to save time later. */
335 if (obj->relalim && obj->pltrela &&
336 obj->relalim > obj->pltrela &&
337 obj->relalim <= obj->pltrelalim)
338 obj->relalim = obj->pltrela;
339 }
340
341 #if defined(RTLD_LOADER) && defined(__HAVE_FUNCTION_DESCRIPTORS)
342 if (init != 0)
343 obj->init = (void (*)(void))
344 _rtld_function_descriptor_alloc(obj, NULL, init);
345 if (fini != 0)
346 obj->fini = (void (*)(void))
347 _rtld_function_descriptor_alloc(obj, NULL, fini);
348 #else
349 if (init != 0)
350 obj->init = (void (*)(void))
351 (obj->relocbase + init);
352 if (fini != 0)
353 obj->fini = (void (*)(void))
354 (obj->relocbase + fini);
355 #endif
356
357 if (dyn_rpath != NULL) {
358 _rtld_add_paths(execname, &obj->rpaths, obj->strtab +
359 dyn_rpath->d_un.d_val);
360 }
361 }
362
363 /*
364 * Process a shared object's program header. This is used only for the
365 * main program, when the kernel has already loaded the main program
366 * into memory before calling the dynamic linker. It creates and
367 * returns an Obj_Entry structure.
368 */
369 Obj_Entry *
370 _rtld_digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry)
371 {
372 Obj_Entry *obj;
373 const Elf_Phdr *phlimit = phdr + phnum;
374 const Elf_Phdr *ph;
375 int nsegs = 0;
376 Elf_Addr vaddr;
377
378 obj = _rtld_obj_new();
379
380 for (ph = phdr; ph < phlimit; ++ph) {
381 if (ph->p_type != PT_PHDR)
382 continue;
383
384 obj->phdr = (void *)(uintptr_t)ph->p_vaddr;
385 obj->phsize = ph->p_memsz;
386 obj->relocbase = (caddr_t)((uintptr_t)phdr - (uintptr_t)ph->p_vaddr);
387 dbg(("headers: phdr %p (%p) phsize %zu relocbase %p",
388 obj->phdr, phdr, obj->phsize, obj->relocbase));
389 break;
390 }
391
392 for (ph = phdr; ph < phlimit; ++ph) {
393 vaddr = (Elf_Addr)(uintptr_t)(obj->relocbase + ph->p_vaddr);
394 switch (ph->p_type) {
395
396 case PT_INTERP:
397 obj->interp = (const char *)(uintptr_t)vaddr;
398 dbg(("headers: %s %p phsize %zu",
399 "PT_INTERP", (void *)(uintptr_t)vaddr,
400 ph->p_memsz));
401 break;
402
403 case PT_LOAD:
404 assert(nsegs < 2);
405 if (nsegs == 0) { /* First load segment */
406 obj->vaddrbase = round_down(vaddr);
407 obj->mapbase = (caddr_t)(uintptr_t)obj->vaddrbase;
408 obj->textsize = round_up(vaddr + ph->p_memsz) -
409 obj->vaddrbase;
410 } else { /* Last load segment */
411 obj->mapsize = round_up(vaddr + ph->p_memsz) -
412 obj->vaddrbase;
413 }
414 ++nsegs;
415 dbg(("headers: %s %p phsize %zu",
416 "PT_LOAD", (void *)(uintptr_t)vaddr,
417 ph->p_memsz));
418 break;
419
420 case PT_DYNAMIC:
421 obj->dynamic = (Elf_Dyn *)(uintptr_t)vaddr;
422 dbg(("headers: %s %p phsize %zu",
423 "PT_DYNAMIC", (void *)(uintptr_t)vaddr,
424 ph->p_memsz));
425 break;
426
427 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
428 case PT_TLS:
429 obj->tlsindex = 1;
430 obj->tlssize = ph->p_memsz;
431 obj->tlsalign = ph->p_align;
432 obj->tlsinitsize = ph->p_filesz;
433 obj->tlsinit = (void *)(uintptr_t)ph->p_vaddr;
434 dbg(("headers: %s %p phsize %zu",
435 "PT_TLS", (void *)(uintptr_t)vaddr,
436 ph->p_memsz));
437 break;
438 #endif
439 #ifdef __ARM_EABI__
440 case PT_ARM_EXIDX:
441 obj->exidx_start = (void *)(uintptr_t)vaddr;
442 obj->exidx_sz = ph->p_memsz;
443 dbg(("headers: %s %p phsize %zu",
444 "PT_ARM_EXIDX", (void *)(uintptr_t)vaddr,
445 ph->p_memsz));
446 break;
447 #endif
448 }
449 }
450 assert(nsegs == 2);
451
452 obj->entry = entry;
453 return obj;
454 }
455