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