headers.c revision 1.21.4.1 1 1.21.4.1 matt /* $NetBSD: headers.c,v 1.21.4.1 2007/11/06 23:12:08 matt 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.21.4.1 matt __RCSID("$NetBSD: headers.c,v 1.21.4.1 2007/11/06 23:12:08 matt 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.1 cgd #include <dirent.h>
57 1.1 cgd
58 1.1 cgd #include "debug.h"
59 1.1 cgd #include "rtld.h"
60 1.1 cgd
61 1.1 cgd /*
62 1.1 cgd * Process a shared object's DYNAMIC section, and save the important
63 1.1 cgd * information in its Obj_Entry structure.
64 1.1 cgd */
65 1.1 cgd void
66 1.21.4.1 matt _rtld_digest_dynamic(const char *execname, Obj_Entry *obj)
67 1.1 cgd {
68 1.4 christos Elf_Dyn *dynp;
69 1.4 christos Needed_Entry **needed_tail = &obj->needed;
70 1.4 christos const Elf_Dyn *dyn_rpath = NULL;
71 1.15 mycroft Elf_Sword plttype = DT_NULL;
72 1.8 mycroft Elf_Addr relsz = 0, relasz = 0;
73 1.13 mycroft Elf_Addr pltrel = 0, pltrelsz = 0;
74 1.10 fredette Elf_Addr init = 0, fini = 0;
75 1.4 christos
76 1.5 kleink for (dynp = obj->dynamic; dynp->d_tag != DT_NULL; ++dynp) {
77 1.4 christos switch (dynp->d_tag) {
78 1.4 christos
79 1.5 kleink case DT_REL:
80 1.4 christos obj->rel = (const Elf_Rel *)
81 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
82 1.4 christos break;
83 1.4 christos
84 1.5 kleink case DT_RELSZ:
85 1.4 christos relsz = dynp->d_un.d_val;
86 1.4 christos break;
87 1.4 christos
88 1.5 kleink case DT_RELENT:
89 1.4 christos assert(dynp->d_un.d_val == sizeof(Elf_Rel));
90 1.4 christos break;
91 1.4 christos
92 1.5 kleink case DT_JMPREL:
93 1.13 mycroft pltrel = dynp->d_un.d_ptr;
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.9 kleink 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.9 kleink 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.13 mycroft assert(plttype == DT_REL || plttype == DT_RELA);
116 1.4 christos break;
117 1.4 christos
118 1.5 kleink case DT_SYMTAB:
119 1.4 christos obj->symtab = (const Elf_Sym *)
120 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
121 1.4 christos break;
122 1.4 christos
123 1.5 kleink case DT_SYMENT:
124 1.4 christos assert(dynp->d_un.d_val == sizeof(Elf_Sym));
125 1.4 christos break;
126 1.4 christos
127 1.5 kleink case DT_STRTAB:
128 1.4 christos obj->strtab = (const char *)
129 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
130 1.4 christos break;
131 1.4 christos
132 1.5 kleink case DT_STRSZ:
133 1.4 christos obj->strsize = dynp->d_un.d_val;
134 1.4 christos break;
135 1.4 christos
136 1.5 kleink case DT_HASH:
137 1.4 christos {
138 1.4 christos const Elf_Word *hashtab = (const Elf_Word *)
139 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
140 1.4 christos
141 1.4 christos obj->nbuckets = hashtab[0];
142 1.4 christos obj->nchains = hashtab[1];
143 1.4 christos obj->buckets = hashtab + 2;
144 1.4 christos obj->chains = obj->buckets + obj->nbuckets;
145 1.4 christos }
146 1.4 christos break;
147 1.4 christos
148 1.5 kleink case DT_NEEDED:
149 1.4 christos {
150 1.4 christos Needed_Entry *nep = NEW(Needed_Entry);
151 1.4 christos
152 1.4 christos nep->name = dynp->d_un.d_val;
153 1.4 christos nep->obj = NULL;
154 1.4 christos nep->next = NULL;
155 1.4 christos
156 1.4 christos *needed_tail = nep;
157 1.4 christos needed_tail = &nep->next;
158 1.4 christos }
159 1.4 christos break;
160 1.4 christos
161 1.5 kleink case DT_PLTGOT:
162 1.4 christos obj->pltgot = (Elf_Addr *)
163 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
164 1.4 christos break;
165 1.4 christos
166 1.5 kleink case DT_TEXTREL:
167 1.4 christos obj->textrel = true;
168 1.4 christos break;
169 1.4 christos
170 1.5 kleink case DT_SYMBOLIC:
171 1.4 christos obj->symbolic = true;
172 1.4 christos break;
173 1.4 christos
174 1.5 kleink case DT_RPATH:
175 1.4 christos /*
176 1.4 christos * We have to wait until later to process this, because
177 1.4 christos * we might not have gotten the address of the string
178 1.4 christos * table yet.
179 1.4 christos */
180 1.4 christos dyn_rpath = dynp;
181 1.4 christos break;
182 1.4 christos
183 1.5 kleink case DT_SONAME:
184 1.4 christos /* Not used by the dynamic linker. */
185 1.4 christos break;
186 1.4 christos
187 1.5 kleink case DT_INIT:
188 1.10 fredette init = dynp->d_un.d_ptr;
189 1.4 christos break;
190 1.4 christos
191 1.5 kleink case DT_FINI:
192 1.10 fredette fini = dynp->d_un.d_ptr;
193 1.4 christos break;
194 1.1 cgd
195 1.20 simonb /*
196 1.20 simonb * Don't process DT_DEBUG on MIPS as the dynamic section
197 1.20 simonb * is mapped read-only. DT_MIPS_RLD_MAP is used instead.
198 1.20 simonb * XXX: n32/n64 may use DT_DEBUG, not sure yet.
199 1.20 simonb */
200 1.20 simonb #ifndef __mips__
201 1.5 kleink case DT_DEBUG:
202 1.1 cgd #ifdef RTLD_LOADER
203 1.4 christos dynp->d_un.d_ptr = (Elf_Addr)&_rtld_debug;
204 1.1 cgd #endif
205 1.4 christos break;
206 1.20 simonb #endif
207 1.2 mhitch
208 1.14 mycroft #ifdef __mips__
209 1.4 christos case DT_MIPS_LOCAL_GOTNO:
210 1.4 christos obj->local_gotno = dynp->d_un.d_val;
211 1.4 christos break;
212 1.4 christos
213 1.4 christos case DT_MIPS_SYMTABNO:
214 1.4 christos obj->symtabno = dynp->d_un.d_val;
215 1.4 christos break;
216 1.4 christos
217 1.4 christos case DT_MIPS_GOTSYM:
218 1.4 christos obj->gotsym = dynp->d_un.d_val;
219 1.4 christos break;
220 1.2 mhitch
221 1.4 christos case DT_MIPS_RLD_MAP:
222 1.2 mhitch #ifdef RTLD_LOADER
223 1.4 christos *((Elf_Addr *)(dynp->d_un.d_ptr)) = (Elf_Addr)
224 1.4 christos &_rtld_debug;
225 1.2 mhitch #endif
226 1.4 christos break;
227 1.2 mhitch #endif
228 1.4 christos }
229 1.1 cgd }
230 1.1 cgd
231 1.4 christos obj->rellim = (const Elf_Rel *)((caddr_t)obj->rel + relsz);
232 1.9 kleink obj->relalim = (const Elf_Rela *)((caddr_t)obj->rela + relasz);
233 1.8 mycroft if (plttype == DT_REL) {
234 1.13 mycroft obj->pltrel = (const Elf_Rel *)(obj->relocbase + pltrel);
235 1.13 mycroft obj->pltrellim = (const Elf_Rel *)(obj->relocbase + pltrel + pltrelsz);
236 1.13 mycroft obj->pltrelalim = 0;
237 1.13 mycroft /* On PPC and SPARC, at least, REL(A)SZ may include JMPREL.
238 1.13 mycroft Trim rel(a)lim to save time later. */
239 1.13 mycroft if (obj->rellim && obj->pltrel &&
240 1.13 mycroft obj->rellim > obj->pltrel &&
241 1.13 mycroft obj->rellim <= obj->pltrellim)
242 1.11 mycroft obj->rellim = obj->pltrel;
243 1.15 mycroft } else if (plttype == DT_RELA) {
244 1.13 mycroft obj->pltrela = (const Elf_Rela *)(obj->relocbase + pltrel);
245 1.13 mycroft obj->pltrellim = 0;
246 1.13 mycroft obj->pltrelalim = (const Elf_Rela *)(obj->relocbase + pltrel + pltrelsz);
247 1.13 mycroft /* On PPC and SPARC, at least, REL(A)SZ may include JMPREL.
248 1.13 mycroft Trim rel(a)lim to save time later. */
249 1.13 mycroft if (obj->relalim && obj->pltrela &&
250 1.13 mycroft obj->relalim > obj->pltrela &&
251 1.13 mycroft obj->relalim <= obj->pltrelalim)
252 1.11 mycroft obj->relalim = obj->pltrela;
253 1.8 mycroft }
254 1.10 fredette
255 1.10 fredette #if defined(RTLD_LOADER) && defined(__HAVE_FUNCTION_DESCRIPTORS)
256 1.10 fredette if (init != 0)
257 1.18 skrll obj->init = (void (*)(void))
258 1.10 fredette _rtld_function_descriptor_alloc(obj, NULL, init);
259 1.10 fredette if (fini != 0)
260 1.18 skrll obj->fini = (void (*)(void))
261 1.10 fredette _rtld_function_descriptor_alloc(obj, NULL, fini);
262 1.10 fredette #else
263 1.10 fredette if (init != 0)
264 1.18 skrll obj->init = (void (*)(void))
265 1.10 fredette (obj->relocbase + init);
266 1.10 fredette if (fini != 0)
267 1.18 skrll obj->fini = (void (*)(void))
268 1.10 fredette (obj->relocbase + fini);
269 1.10 fredette #endif
270 1.4 christos
271 1.4 christos if (dyn_rpath != NULL) {
272 1.21.4.1 matt _rtld_add_paths(execname, &obj->rpaths, obj->strtab +
273 1.12 mycroft dyn_rpath->d_un.d_val);
274 1.4 christos }
275 1.1 cgd }
276 1.1 cgd
277 1.1 cgd /*
278 1.1 cgd * Process a shared object's program header. This is used only for the
279 1.1 cgd * main program, when the kernel has already loaded the main program
280 1.1 cgd * into memory before calling the dynamic linker. It creates and
281 1.1 cgd * returns an Obj_Entry structure.
282 1.1 cgd */
283 1.1 cgd Obj_Entry *
284 1.18 skrll _rtld_digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry)
285 1.1 cgd {
286 1.6 mycroft Obj_Entry *obj;
287 1.4 christos const Elf_Phdr *phlimit = phdr + phnum;
288 1.4 christos const Elf_Phdr *ph;
289 1.4 christos int nsegs = 0;
290 1.4 christos
291 1.6 mycroft obj = _rtld_obj_new();
292 1.4 christos for (ph = phdr; ph < phlimit; ++ph) {
293 1.4 christos switch (ph->p_type) {
294 1.4 christos
295 1.5 kleink case PT_PHDR:
296 1.4 christos assert((const Elf_Phdr *) ph->p_vaddr == phdr);
297 1.6 mycroft break;
298 1.6 mycroft
299 1.6 mycroft case PT_INTERP:
300 1.6 mycroft obj->interp = (const char *) ph->p_vaddr;
301 1.4 christos break;
302 1.4 christos
303 1.5 kleink case PT_LOAD:
304 1.4 christos assert(nsegs < 2);
305 1.4 christos if (nsegs == 0) { /* First load segment */
306 1.4 christos obj->vaddrbase = round_down(ph->p_vaddr);
307 1.4 christos obj->mapbase = (caddr_t) obj->vaddrbase;
308 1.4 christos obj->relocbase = obj->mapbase - obj->vaddrbase;
309 1.4 christos obj->textsize = round_up(ph->p_vaddr +
310 1.4 christos ph->p_memsz) - obj->vaddrbase;
311 1.4 christos } else { /* Last load segment */
312 1.4 christos obj->mapsize = round_up(ph->p_vaddr +
313 1.4 christos ph->p_memsz) - obj->vaddrbase;
314 1.4 christos }
315 1.4 christos ++nsegs;
316 1.4 christos break;
317 1.4 christos
318 1.5 kleink case PT_DYNAMIC:
319 1.4 christos obj->dynamic = (Elf_Dyn *) ph->p_vaddr;
320 1.4 christos break;
321 1.4 christos }
322 1.1 cgd }
323 1.4 christos assert(nsegs == 2);
324 1.1 cgd
325 1.4 christos obj->entry = entry;
326 1.4 christos return obj;
327 1.1 cgd }
328