headers.c revision 1.68 1 1.68 thorpej /* $NetBSD: headers.c,v 1.68 2020/03/04 01:21:17 thorpej 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.17 mycroft * Copyright 2002 Charles M. Hannum <root (at) ihack.net>
7 1.1 cgd * All rights reserved.
8 1.1 cgd *
9 1.1 cgd * Redistribution and use in source and binary forms, with or without
10 1.1 cgd * modification, are permitted provided that the following conditions
11 1.1 cgd * are met:
12 1.1 cgd * 1. Redistributions of source code must retain the above copyright
13 1.1 cgd * notice, this list of conditions and the following disclaimer.
14 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
15 1.1 cgd * notice, this list of conditions and the following disclaimer in the
16 1.1 cgd * documentation and/or other materials provided with the distribution.
17 1.1 cgd * 3. All advertising materials mentioning features or use of this software
18 1.1 cgd * must display the following acknowledgement:
19 1.1 cgd * This product includes software developed by John Polstra.
20 1.1 cgd * 4. The name of the author may not be used to endorse or promote products
21 1.1 cgd * derived from this software without specific prior written permission.
22 1.1 cgd *
23 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 1.1 cgd * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 1.1 cgd * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 1.1 cgd * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 1.1 cgd * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 1.1 cgd * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 1.1 cgd * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 1.1 cgd * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 1.1 cgd * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 1.1 cgd * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 1.1 cgd */
34 1.1 cgd
35 1.1 cgd /*
36 1.1 cgd * Dynamic linker for ELF.
37 1.1 cgd *
38 1.1 cgd * John Polstra <jdp (at) polstra.com>.
39 1.1 cgd */
40 1.1 cgd
41 1.19 skrll #include <sys/cdefs.h>
42 1.19 skrll #ifndef lint
43 1.68 thorpej __RCSID("$NetBSD: headers.c,v 1.68 2020/03/04 01:21:17 thorpej Exp $");
44 1.19 skrll #endif /* not lint */
45 1.19 skrll
46 1.1 cgd #include <err.h>
47 1.1 cgd #include <errno.h>
48 1.1 cgd #include <fcntl.h>
49 1.1 cgd #include <stdarg.h>
50 1.1 cgd #include <stdio.h>
51 1.1 cgd #include <stdlib.h>
52 1.1 cgd #include <string.h>
53 1.1 cgd #include <unistd.h>
54 1.1 cgd #include <sys/types.h>
55 1.1 cgd #include <sys/mman.h>
56 1.29 joerg #include <sys/bitops.h>
57 1.1 cgd #include <dirent.h>
58 1.1 cgd
59 1.1 cgd #include "debug.h"
60 1.1 cgd #include "rtld.h"
61 1.1 cgd
62 1.1 cgd /*
63 1.1 cgd * Process a shared object's DYNAMIC section, and save the important
64 1.1 cgd * information in its Obj_Entry structure.
65 1.1 cgd */
66 1.1 cgd void
67 1.22 christos _rtld_digest_dynamic(const char *execname, Obj_Entry *obj)
68 1.1 cgd {
69 1.4 christos Elf_Dyn *dynp;
70 1.4 christos Needed_Entry **needed_tail = &obj->needed;
71 1.51 christos const Elf_Dyn *dyn_soname = NULL;
72 1.4 christos const Elf_Dyn *dyn_rpath = NULL;
73 1.30 joerg bool use_pltrel = false;
74 1.30 joerg bool use_pltrela = false;
75 1.8 mycroft Elf_Addr relsz = 0, relasz = 0;
76 1.13 mycroft Elf_Addr pltrel = 0, pltrelsz = 0;
77 1.58 christos #ifdef RTLD_LOADER
78 1.10 fredette Elf_Addr init = 0, fini = 0;
79 1.58 christos #endif
80 1.4 christos
81 1.49 skrll dbg(("headers: digesting PT_DYNAMIC at %p", obj->dynamic));
82 1.5 kleink for (dynp = obj->dynamic; dynp->d_tag != DT_NULL; ++dynp) {
83 1.49 skrll dbg((" d_tag %ld at %p", (long)dynp->d_tag, dynp));
84 1.4 christos switch (dynp->d_tag) {
85 1.4 christos
86 1.5 kleink case DT_REL:
87 1.4 christos obj->rel = (const Elf_Rel *)
88 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
89 1.4 christos break;
90 1.4 christos
91 1.5 kleink case DT_RELSZ:
92 1.4 christos relsz = dynp->d_un.d_val;
93 1.4 christos break;
94 1.4 christos
95 1.5 kleink case DT_RELENT:
96 1.4 christos assert(dynp->d_un.d_val == sizeof(Elf_Rel));
97 1.4 christos break;
98 1.4 christos
99 1.5 kleink case DT_JMPREL:
100 1.13 mycroft pltrel = dynp->d_un.d_ptr;
101 1.4 christos break;
102 1.4 christos
103 1.5 kleink case DT_PLTRELSZ:
104 1.8 mycroft pltrelsz = dynp->d_un.d_val;
105 1.4 christos break;
106 1.4 christos
107 1.5 kleink case DT_RELA:
108 1.9 kleink obj->rela = (const Elf_Rela *)
109 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
110 1.4 christos break;
111 1.4 christos
112 1.5 kleink case DT_RELASZ:
113 1.4 christos relasz = dynp->d_un.d_val;
114 1.4 christos break;
115 1.4 christos
116 1.5 kleink case DT_RELAENT:
117 1.9 kleink assert(dynp->d_un.d_val == sizeof(Elf_Rela));
118 1.4 christos break;
119 1.4 christos
120 1.5 kleink case DT_PLTREL:
121 1.30 joerg use_pltrel = dynp->d_un.d_val == DT_REL;
122 1.30 joerg use_pltrela = dynp->d_un.d_val == DT_RELA;
123 1.30 joerg assert(use_pltrel || use_pltrela);
124 1.4 christos break;
125 1.4 christos
126 1.5 kleink case DT_SYMTAB:
127 1.4 christos obj->symtab = (const Elf_Sym *)
128 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
129 1.4 christos break;
130 1.4 christos
131 1.5 kleink case DT_SYMENT:
132 1.4 christos assert(dynp->d_un.d_val == sizeof(Elf_Sym));
133 1.4 christos break;
134 1.4 christos
135 1.5 kleink case DT_STRTAB:
136 1.4 christos obj->strtab = (const char *)
137 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
138 1.4 christos break;
139 1.4 christos
140 1.5 kleink case DT_STRSZ:
141 1.4 christos obj->strsize = dynp->d_un.d_val;
142 1.4 christos break;
143 1.4 christos
144 1.41 nonaka case DT_VERNEED:
145 1.41 nonaka obj->verneed = (const Elf_Verneed *)
146 1.41 nonaka (obj->relocbase + dynp->d_un.d_ptr);
147 1.41 nonaka break;
148 1.41 nonaka
149 1.41 nonaka case DT_VERNEEDNUM:
150 1.41 nonaka obj->verneednum = dynp->d_un.d_val;
151 1.41 nonaka break;
152 1.41 nonaka
153 1.41 nonaka case DT_VERDEF:
154 1.41 nonaka obj->verdef = (const Elf_Verdef *)
155 1.41 nonaka (obj->relocbase + dynp->d_un.d_ptr);
156 1.41 nonaka break;
157 1.41 nonaka
158 1.41 nonaka case DT_VERDEFNUM:
159 1.41 nonaka obj->verdefnum = dynp->d_un.d_val;
160 1.41 nonaka break;
161 1.41 nonaka
162 1.41 nonaka case DT_VERSYM:
163 1.41 nonaka obj->versyms = (const Elf_Versym *)
164 1.41 nonaka (obj->relocbase + dynp->d_un.d_ptr);
165 1.41 nonaka break;
166 1.41 nonaka
167 1.5 kleink case DT_HASH:
168 1.4 christos {
169 1.66 kamil uint32_t nbuckets, nchains;
170 1.31 skrll const Elf_Symindx *hashtab = (const Elf_Symindx *)
171 1.31 skrll (obj->relocbase + dynp->d_un.d_ptr);
172 1.4 christos
173 1.29 joerg if (hashtab[0] > UINT32_MAX)
174 1.66 kamil nbuckets = UINT32_MAX;
175 1.29 joerg else
176 1.66 kamil nbuckets = hashtab[0];
177 1.66 kamil obj->nbuckets = nbuckets;
178 1.66 kamil obj->nchains = (nchains = hashtab[1]);
179 1.4 christos obj->buckets = hashtab + 2;
180 1.4 christos obj->chains = obj->buckets + obj->nbuckets;
181 1.66 kamil
182 1.66 kamil /* Validity check */
183 1.66 kamil if (!obj->buckets || !nbuckets || !nchains)
184 1.66 kamil continue;
185 1.66 kamil
186 1.66 kamil obj->sysv_hash = true;
187 1.66 kamil
188 1.66 kamil /*
189 1.66 kamil * Should really be in _rtld_relocate_objects,
190 1.66 kamil * but _rtld_symlook_obj might be used before.
191 1.66 kamil */
192 1.66 kamil fast_divide32_prepare(obj->nbuckets,
193 1.66 kamil &obj->nbuckets_m,
194 1.66 kamil &obj->nbuckets_s1,
195 1.66 kamil &obj->nbuckets_s2);
196 1.66 kamil }
197 1.66 kamil break;
198 1.66 kamil
199 1.66 kamil case DT_GNU_HASH:
200 1.66 kamil {
201 1.66 kamil uint32_t nmaskwords;
202 1.66 kamil uint32_t nbuckets, symndx;
203 1.66 kamil int bloom_size32;
204 1.66 kamil bool nmw_power2;
205 1.66 kamil const Elf_Symindx *hashtab = (const Elf_Symindx *)
206 1.66 kamil (obj->relocbase + dynp->d_un.d_ptr);
207 1.66 kamil
208 1.66 kamil if (hashtab[0] > UINT32_MAX)
209 1.66 kamil nbuckets = UINT32_MAX;
210 1.66 kamil else
211 1.66 kamil nbuckets = hashtab[0];
212 1.66 kamil obj->nbuckets_gnu = nbuckets;
213 1.66 kamil
214 1.66 kamil nmaskwords = hashtab[2];
215 1.66 kamil bloom_size32 = nmaskwords * (ELFSIZE / 32);
216 1.66 kamil
217 1.67 kamil obj->buckets_gnu = (const uint32_t *)(hashtab + 4 + bloom_size32);
218 1.66 kamil
219 1.66 kamil nmw_power2 = powerof2(nmaskwords);
220 1.66 kamil
221 1.66 kamil /* Validity check */
222 1.66 kamil if (!nmw_power2 || !nbuckets || !obj->buckets_gnu)
223 1.66 kamil continue;
224 1.66 kamil
225 1.66 kamil obj->gnu_hash = true;
226 1.66 kamil
227 1.66 kamil obj->mask_bm_gnu = nmaskwords - 1;
228 1.66 kamil obj->symndx_gnu = (symndx = hashtab[1]);
229 1.66 kamil obj->shift2_gnu = hashtab[3];
230 1.66 kamil obj->bloom_gnu = (const Elf_Addr *)(hashtab + 4);
231 1.66 kamil obj->chains_gnu = obj->buckets_gnu + nbuckets - symndx;
232 1.66 kamil
233 1.29 joerg /*
234 1.29 joerg * Should really be in _rtld_relocate_objects,
235 1.29 joerg * but _rtld_symlook_obj might be used before.
236 1.29 joerg */
237 1.66 kamil fast_divide32_prepare(nbuckets,
238 1.66 kamil &obj->nbuckets_m_gnu,
239 1.66 kamil &obj->nbuckets_s1_gnu,
240 1.66 kamil &obj->nbuckets_s2_gnu);
241 1.66 kamil
242 1.66 kamil dbg(("found GNU Hash: buckets=%p "
243 1.66 kamil "nbuckets=%lu chains=%p nchains=%u "
244 1.66 kamil "bloom=%p mask_bm=%u shift2=%u "
245 1.66 kamil "symndx=%u",
246 1.66 kamil obj->buckets_gnu, obj->nbuckets_gnu,
247 1.66 kamil obj->chains_gnu, obj->nchains_gnu,
248 1.66 kamil obj->bloom_gnu, obj->mask_bm_gnu,
249 1.66 kamil obj->shift2_gnu, obj->symndx_gnu));
250 1.4 christos }
251 1.4 christos break;
252 1.4 christos
253 1.5 kleink case DT_NEEDED:
254 1.4 christos {
255 1.4 christos Needed_Entry *nep = NEW(Needed_Entry);
256 1.4 christos
257 1.4 christos nep->name = dynp->d_un.d_val;
258 1.4 christos nep->obj = NULL;
259 1.4 christos nep->next = NULL;
260 1.4 christos
261 1.4 christos *needed_tail = nep;
262 1.4 christos needed_tail = &nep->next;
263 1.4 christos }
264 1.4 christos break;
265 1.4 christos
266 1.5 kleink case DT_PLTGOT:
267 1.4 christos obj->pltgot = (Elf_Addr *)
268 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
269 1.4 christos break;
270 1.4 christos
271 1.5 kleink case DT_TEXTREL:
272 1.4 christos obj->textrel = true;
273 1.4 christos break;
274 1.4 christos
275 1.5 kleink case DT_SYMBOLIC:
276 1.4 christos obj->symbolic = true;
277 1.4 christos break;
278 1.4 christos
279 1.5 kleink case DT_RPATH:
280 1.65 martin case DT_RUNPATH:
281 1.4 christos /*
282 1.4 christos * We have to wait until later to process this, because
283 1.4 christos * we might not have gotten the address of the string
284 1.4 christos * table yet.
285 1.4 christos */
286 1.4 christos dyn_rpath = dynp;
287 1.4 christos break;
288 1.4 christos
289 1.5 kleink case DT_SONAME:
290 1.51 christos dyn_soname = dynp;
291 1.4 christos break;
292 1.4 christos
293 1.5 kleink case DT_INIT:
294 1.58 christos #ifdef RTLD_LOADER
295 1.10 fredette init = dynp->d_un.d_ptr;
296 1.58 christos #endif
297 1.4 christos break;
298 1.4 christos
299 1.43 matt #ifdef HAVE_INITFINI_ARRAY
300 1.43 matt case DT_INIT_ARRAY:
301 1.59 joerg obj->init_array =
302 1.59 joerg (Elf_Addr *)(obj->relocbase + dynp->d_un.d_ptr);
303 1.49 skrll dbg(("headers: DT_INIT_ARRAY at %p",
304 1.49 skrll obj->init_array));
305 1.43 matt break;
306 1.43 matt
307 1.43 matt case DT_INIT_ARRAYSZ:
308 1.43 matt obj->init_arraysz = dynp->d_un.d_val / sizeof(fptr_t);
309 1.49 skrll dbg(("headers: DT_INIT_ARRAYZ %zu",
310 1.49 skrll obj->init_arraysz));
311 1.43 matt break;
312 1.43 matt #endif
313 1.43 matt
314 1.5 kleink case DT_FINI:
315 1.58 christos #ifdef RTLD_LOADER
316 1.10 fredette fini = dynp->d_un.d_ptr;
317 1.58 christos #endif
318 1.4 christos break;
319 1.1 cgd
320 1.43 matt #ifdef HAVE_INITFINI_ARRAY
321 1.43 matt case DT_FINI_ARRAY:
322 1.43 matt obj->fini_array =
323 1.55 joerg (Elf_Addr *)(obj->relocbase + dynp->d_un.d_ptr);
324 1.49 skrll dbg(("headers: DT_FINI_ARRAY at %p",
325 1.49 skrll obj->fini_array));
326 1.43 matt break;
327 1.43 matt
328 1.43 matt case DT_FINI_ARRAYSZ:
329 1.50 skrll obj->fini_arraysz = dynp->d_un.d_val / sizeof(fptr_t);
330 1.49 skrll dbg(("headers: DT_FINI_ARRAYZ %zu",
331 1.49 skrll obj->fini_arraysz));
332 1.43 matt break;
333 1.43 matt #endif
334 1.43 matt
335 1.20 simonb /*
336 1.20 simonb * Don't process DT_DEBUG on MIPS as the dynamic section
337 1.20 simonb * is mapped read-only. DT_MIPS_RLD_MAP is used instead.
338 1.20 simonb * XXX: n32/n64 may use DT_DEBUG, not sure yet.
339 1.20 simonb */
340 1.20 simonb #ifndef __mips__
341 1.5 kleink case DT_DEBUG:
342 1.1 cgd #ifdef RTLD_LOADER
343 1.4 christos dynp->d_un.d_ptr = (Elf_Addr)&_rtld_debug;
344 1.1 cgd #endif
345 1.4 christos break;
346 1.20 simonb #endif
347 1.2 mhitch
348 1.14 mycroft #ifdef __mips__
349 1.4 christos case DT_MIPS_LOCAL_GOTNO:
350 1.4 christos obj->local_gotno = dynp->d_un.d_val;
351 1.4 christos break;
352 1.4 christos
353 1.4 christos case DT_MIPS_SYMTABNO:
354 1.4 christos obj->symtabno = dynp->d_un.d_val;
355 1.4 christos break;
356 1.4 christos
357 1.4 christos case DT_MIPS_GOTSYM:
358 1.4 christos obj->gotsym = dynp->d_un.d_val;
359 1.4 christos break;
360 1.2 mhitch
361 1.4 christos case DT_MIPS_RLD_MAP:
362 1.2 mhitch #ifdef RTLD_LOADER
363 1.4 christos *((Elf_Addr *)(dynp->d_un.d_ptr)) = (Elf_Addr)
364 1.4 christos &_rtld_debug;
365 1.2 mhitch #endif
366 1.4 christos break;
367 1.2 mhitch #endif
368 1.39 matt #ifdef __powerpc__
369 1.53 matt #ifdef _LP64
370 1.53 matt case DT_PPC64_GLINK:
371 1.54 matt obj->glink = (Elf_Addr)(uintptr_t)obj->relocbase + dynp->d_un.d_ptr;
372 1.53 matt break;
373 1.53 matt #else
374 1.39 matt case DT_PPC_GOT:
375 1.39 matt obj->gotptr = (Elf_Addr *)(obj->relocbase + dynp->d_un.d_ptr);
376 1.39 matt break;
377 1.39 matt #endif
378 1.53 matt #endif
379 1.23 ad case DT_FLAGS_1:
380 1.38 skrll obj->z_now =
381 1.63 christos ((dynp->d_un.d_val & DF_1_NOW) != 0);
382 1.38 skrll obj->z_nodelete =
383 1.38 skrll ((dynp->d_un.d_val & DF_1_NODELETE) != 0);
384 1.38 skrll obj->z_initfirst =
385 1.23 ad ((dynp->d_un.d_val & DF_1_INITFIRST) != 0);
386 1.38 skrll obj->z_noopen =
387 1.38 skrll ((dynp->d_un.d_val & DF_1_NOOPEN) != 0);
388 1.23 ad break;
389 1.4 christos }
390 1.1 cgd }
391 1.1 cgd
392 1.28 lukem obj->rellim = (const Elf_Rel *)((const uint8_t *)obj->rel + relsz);
393 1.28 lukem obj->relalim = (const Elf_Rela *)((const uint8_t *)obj->rela + relasz);
394 1.30 joerg if (use_pltrel) {
395 1.13 mycroft obj->pltrel = (const Elf_Rel *)(obj->relocbase + pltrel);
396 1.13 mycroft obj->pltrellim = (const Elf_Rel *)(obj->relocbase + pltrel + pltrelsz);
397 1.13 mycroft obj->pltrelalim = 0;
398 1.13 mycroft /* On PPC and SPARC, at least, REL(A)SZ may include JMPREL.
399 1.13 mycroft Trim rel(a)lim to save time later. */
400 1.13 mycroft if (obj->rellim && obj->pltrel &&
401 1.13 mycroft obj->rellim > obj->pltrel &&
402 1.13 mycroft obj->rellim <= obj->pltrellim)
403 1.11 mycroft obj->rellim = obj->pltrel;
404 1.30 joerg } else if (use_pltrela) {
405 1.13 mycroft obj->pltrela = (const Elf_Rela *)(obj->relocbase + pltrel);
406 1.13 mycroft obj->pltrellim = 0;
407 1.13 mycroft obj->pltrelalim = (const Elf_Rela *)(obj->relocbase + pltrel + pltrelsz);
408 1.13 mycroft /* On PPC and SPARC, at least, REL(A)SZ may include JMPREL.
409 1.13 mycroft Trim rel(a)lim to save time later. */
410 1.13 mycroft if (obj->relalim && obj->pltrela &&
411 1.13 mycroft obj->relalim > obj->pltrela &&
412 1.13 mycroft obj->relalim <= obj->pltrelalim)
413 1.11 mycroft obj->relalim = obj->pltrela;
414 1.8 mycroft }
415 1.10 fredette
416 1.66 kamil /* If the ELF Hash is present, "nchains" is the same in both hashes. */
417 1.66 kamil if (!obj->sysv_hash && obj->gnu_hash) {
418 1.66 kamil uint_fast32_t i, nbucket, symndx;
419 1.66 kamil
420 1.66 kamil /* Otherwise, count the entries from the GNU Hash chain. */
421 1.66 kamil nbucket = obj->nbuckets_gnu;
422 1.66 kamil symndx = obj->symndx_gnu;
423 1.66 kamil
424 1.66 kamil for (i = 0; i < nbucket; i++) {
425 1.66 kamil Elf_Word bkt = obj->buckets_gnu[i];
426 1.66 kamil if (bkt == 0)
427 1.66 kamil continue;
428 1.66 kamil const uint32_t *hashval = &obj->chains_gnu[bkt];
429 1.66 kamil do {
430 1.66 kamil symndx++;
431 1.66 kamil } while ((*hashval++ & 1U) == 0);
432 1.66 kamil }
433 1.66 kamil obj->nchains_gnu = (uint32_t)symndx;
434 1.66 kamil }
435 1.66 kamil
436 1.57 joerg #ifdef RTLD_LOADER
437 1.10 fredette if (init != 0)
438 1.57 joerg obj->init = (Elf_Addr) obj->relocbase + init;
439 1.10 fredette if (fini != 0)
440 1.57 joerg obj->fini = (Elf_Addr) obj->relocbase + fini;
441 1.57 joerg #endif
442 1.4 christos
443 1.4 christos if (dyn_rpath != NULL) {
444 1.22 christos _rtld_add_paths(execname, &obj->rpaths, obj->strtab +
445 1.12 mycroft dyn_rpath->d_un.d_val);
446 1.4 christos }
447 1.51 christos if (dyn_soname != NULL) {
448 1.51 christos _rtld_object_add_name(obj, obj->strtab +
449 1.51 christos dyn_soname->d_un.d_val);
450 1.51 christos }
451 1.1 cgd }
452 1.1 cgd
453 1.1 cgd /*
454 1.1 cgd * Process a shared object's program header. This is used only for the
455 1.1 cgd * main program, when the kernel has already loaded the main program
456 1.1 cgd * into memory before calling the dynamic linker. It creates and
457 1.1 cgd * returns an Obj_Entry structure.
458 1.1 cgd */
459 1.1 cgd Obj_Entry *
460 1.18 skrll _rtld_digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry)
461 1.1 cgd {
462 1.6 mycroft Obj_Entry *obj;
463 1.4 christos const Elf_Phdr *phlimit = phdr + phnum;
464 1.4 christos const Elf_Phdr *ph;
465 1.62 joerg bool first_seg = true;
466 1.62 joerg Elf_Addr vaddr;
467 1.62 joerg size_t size;
468 1.4 christos
469 1.6 mycroft obj = _rtld_obj_new();
470 1.36 skrll
471 1.36 skrll for (ph = phdr; ph < phlimit; ++ph) {
472 1.36 skrll if (ph->p_type != PT_PHDR)
473 1.36 skrll continue;
474 1.50 skrll
475 1.60 joerg obj->relocbase = (caddr_t)((uintptr_t)phdr - (uintptr_t)ph->p_vaddr);
476 1.60 joerg obj->phdr = phdr; /* Equivalent to relocbase + p_vaddr. */
477 1.46 matt obj->phsize = ph->p_memsz;
478 1.49 skrll dbg(("headers: phdr %p (%p) phsize %zu relocbase %p",
479 1.49 skrll obj->phdr, phdr, obj->phsize, obj->relocbase));
480 1.36 skrll break;
481 1.36 skrll }
482 1.50 skrll
483 1.4 christos for (ph = phdr; ph < phlimit; ++ph) {
484 1.37 skrll vaddr = (Elf_Addr)(uintptr_t)(obj->relocbase + ph->p_vaddr);
485 1.4 christos switch (ph->p_type) {
486 1.4 christos
487 1.6 mycroft case PT_INTERP:
488 1.27 mrg obj->interp = (const char *)(uintptr_t)vaddr;
489 1.52 skrll dbg(("headers: %s %p phsize %" PRImemsz,
490 1.49 skrll "PT_INTERP", (void *)(uintptr_t)vaddr,
491 1.49 skrll ph->p_memsz));
492 1.4 christos break;
493 1.4 christos
494 1.5 kleink case PT_LOAD:
495 1.62 joerg size = round_up(vaddr + ph->p_memsz) - obj->vaddrbase;
496 1.62 joerg if (first_seg) { /* First load segment */
497 1.24 christos obj->vaddrbase = round_down(vaddr);
498 1.27 mrg obj->mapbase = (caddr_t)(uintptr_t)obj->vaddrbase;
499 1.62 joerg obj->textsize = size;
500 1.62 joerg obj->mapsize = size;
501 1.62 joerg first_seg = false;
502 1.4 christos } else { /* Last load segment */
503 1.62 joerg obj->mapsize = MAX(obj->mapsize, size);
504 1.4 christos }
505 1.52 skrll dbg(("headers: %s %p phsize %" PRImemsz,
506 1.49 skrll "PT_LOAD", (void *)(uintptr_t)vaddr,
507 1.49 skrll ph->p_memsz));
508 1.4 christos break;
509 1.4 christos
510 1.5 kleink case PT_DYNAMIC:
511 1.27 mrg obj->dynamic = (Elf_Dyn *)(uintptr_t)vaddr;
512 1.52 skrll dbg(("headers: %s %p phsize %" PRImemsz,
513 1.49 skrll "PT_DYNAMIC", (void *)(uintptr_t)vaddr,
514 1.49 skrll ph->p_memsz));
515 1.4 christos break;
516 1.40 joerg
517 1.61 christos #ifdef GNU_RELRO
518 1.61 christos case PT_GNU_RELRO:
519 1.68 thorpej /* rounding happens later. */
520 1.68 thorpej obj->relro_page = obj->relocbase + ph->p_vaddr;
521 1.68 thorpej obj->relro_size = ph->p_memsz;
522 1.61 christos dbg(("headers: %s %p phsize %" PRImemsz,
523 1.61 christos "PT_GNU_RELRO", (void *)(uintptr_t)vaddr,
524 1.61 christos ph->p_memsz));
525 1.61 christos break;
526 1.61 christos #endif
527 1.61 christos
528 1.40 joerg #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
529 1.40 joerg case PT_TLS:
530 1.40 joerg obj->tlsindex = 1;
531 1.40 joerg obj->tlssize = ph->p_memsz;
532 1.40 joerg obj->tlsalign = ph->p_align;
533 1.40 joerg obj->tlsinitsize = ph->p_filesz;
534 1.64 joerg obj->tlsinit = (void *)(obj->relocbase +
535 1.64 joerg (uintptr_t)ph->p_vaddr);
536 1.52 skrll dbg(("headers: %s %p phsize %" PRImemsz,
537 1.49 skrll "PT_TLS", (void *)(uintptr_t)vaddr,
538 1.49 skrll ph->p_memsz));
539 1.40 joerg break;
540 1.40 joerg #endif
541 1.44 matt #ifdef __ARM_EABI__
542 1.44 matt case PT_ARM_EXIDX:
543 1.44 matt obj->exidx_start = (void *)(uintptr_t)vaddr;
544 1.44 matt obj->exidx_sz = ph->p_memsz;
545 1.52 skrll dbg(("headers: %s %p phsize %" PRImemsz,
546 1.49 skrll "PT_ARM_EXIDX", (void *)(uintptr_t)vaddr,
547 1.49 skrll ph->p_memsz));
548 1.44 matt break;
549 1.44 matt #endif
550 1.4 christos }
551 1.1 cgd }
552 1.1 cgd
553 1.4 christos obj->entry = entry;
554 1.4 christos return obj;
555 1.1 cgd }
556