headers.c revision 1.8 1 1.8 mycroft /* $NetBSD: headers.c,v 1.8 2000/07/26 02:07:34 mycroft 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.1 cgd * All rights reserved.
7 1.1 cgd *
8 1.1 cgd * Redistribution and use in source and binary forms, with or without
9 1.1 cgd * modification, are permitted provided that the following conditions
10 1.1 cgd * are met:
11 1.1 cgd * 1. Redistributions of source code must retain the above copyright
12 1.1 cgd * notice, this list of conditions and the following disclaimer.
13 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
14 1.1 cgd * notice, this list of conditions and the following disclaimer in the
15 1.1 cgd * documentation and/or other materials provided with the distribution.
16 1.1 cgd * 3. All advertising materials mentioning features or use of this software
17 1.1 cgd * must display the following acknowledgement:
18 1.1 cgd * This product includes software developed by John Polstra.
19 1.1 cgd * 4. The name of the author may not be used to endorse or promote products
20 1.1 cgd * derived from this software without specific prior written permission.
21 1.1 cgd *
22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 1.1 cgd * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 1.1 cgd * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 1.1 cgd * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 1.1 cgd * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 1.1 cgd * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 1.1 cgd * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 1.1 cgd * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 1.1 cgd * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 1.1 cgd * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 1.1 cgd */
33 1.1 cgd
34 1.1 cgd /*
35 1.1 cgd * Dynamic linker for ELF.
36 1.1 cgd *
37 1.1 cgd * John Polstra <jdp (at) polstra.com>.
38 1.1 cgd */
39 1.1 cgd
40 1.1 cgd #include <err.h>
41 1.1 cgd #include <errno.h>
42 1.1 cgd #include <fcntl.h>
43 1.1 cgd #include <stdarg.h>
44 1.1 cgd #include <stdio.h>
45 1.1 cgd #include <stdlib.h>
46 1.1 cgd #include <string.h>
47 1.1 cgd #include <unistd.h>
48 1.1 cgd #include <sys/types.h>
49 1.1 cgd #include <sys/mman.h>
50 1.1 cgd #include <dirent.h>
51 1.1 cgd
52 1.1 cgd #include "debug.h"
53 1.1 cgd #include "rtld.h"
54 1.1 cgd
55 1.1 cgd /*
56 1.1 cgd * Process a shared object's DYNAMIC section, and save the important
57 1.1 cgd * information in its Obj_Entry structure.
58 1.1 cgd */
59 1.1 cgd void
60 1.4 christos _rtld_digest_dynamic(obj)
61 1.4 christos 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.5 kleink Elf_Sword plttype = DT_REL;
67 1.8 mycroft Elf_Addr relsz = 0, relasz = 0;
68 1.8 mycroft Elf_Addr pltrelsz = 0;
69 1.4 christos
70 1.5 kleink for (dynp = obj->dynamic; dynp->d_tag != DT_NULL; ++dynp) {
71 1.4 christos switch (dynp->d_tag) {
72 1.4 christos
73 1.5 kleink case DT_REL:
74 1.4 christos obj->rel = (const Elf_Rel *)
75 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
76 1.4 christos break;
77 1.4 christos
78 1.5 kleink case DT_RELSZ:
79 1.4 christos relsz = dynp->d_un.d_val;
80 1.4 christos break;
81 1.4 christos
82 1.5 kleink case DT_RELENT:
83 1.4 christos assert(dynp->d_un.d_val == sizeof(Elf_Rel));
84 1.4 christos break;
85 1.4 christos
86 1.5 kleink case DT_JMPREL:
87 1.5 kleink if (plttype == DT_REL) {
88 1.4 christos obj->pltrel = (const Elf_Rel *)
89 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
90 1.4 christos } else {
91 1.4 christos obj->pltrela = (const Elf_RelA *)
92 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
93 1.4 christos }
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.4 christos 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.4 christos 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.5 kleink assert(plttype == DT_REL ||
116 1.5 kleink plttype == DT_RELA);
117 1.8 mycroft #if !defined(__sparc__) && !defined(__archv9__) && !defined(__sparc_v9__)
118 1.7 eeh /*
119 1.7 eeh * sparc v9 has both DT_PLTREL and DT_JMPREL.
120 1.7 eeh * But they point to different things.
121 1.7 eeh * We want the DT_JMPREL which points to our jump table.
122 1.7 eeh */
123 1.5 kleink if (plttype == DT_RELA) {
124 1.4 christos obj->pltrela = (const Elf_RelA *) obj->pltrel;
125 1.4 christos obj->pltrel = NULL;
126 1.4 christos }
127 1.7 eeh #endif
128 1.4 christos break;
129 1.4 christos
130 1.5 kleink case DT_SYMTAB:
131 1.4 christos obj->symtab = (const Elf_Sym *)
132 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
133 1.4 christos break;
134 1.4 christos
135 1.5 kleink case DT_SYMENT:
136 1.4 christos assert(dynp->d_un.d_val == sizeof(Elf_Sym));
137 1.4 christos break;
138 1.4 christos
139 1.5 kleink case DT_STRTAB:
140 1.4 christos obj->strtab = (const char *)
141 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
142 1.4 christos break;
143 1.4 christos
144 1.5 kleink case DT_STRSZ:
145 1.4 christos obj->strsize = dynp->d_un.d_val;
146 1.4 christos break;
147 1.4 christos
148 1.5 kleink case DT_HASH:
149 1.4 christos {
150 1.4 christos const Elf_Word *hashtab = (const Elf_Word *)
151 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
152 1.4 christos
153 1.4 christos obj->nbuckets = hashtab[0];
154 1.4 christos obj->nchains = hashtab[1];
155 1.4 christos obj->buckets = hashtab + 2;
156 1.4 christos obj->chains = obj->buckets + obj->nbuckets;
157 1.4 christos }
158 1.4 christos break;
159 1.4 christos
160 1.5 kleink case DT_NEEDED:
161 1.4 christos assert(!obj->rtld);
162 1.4 christos {
163 1.4 christos Needed_Entry *nep = NEW(Needed_Entry);
164 1.4 christos
165 1.4 christos nep->name = dynp->d_un.d_val;
166 1.4 christos nep->obj = NULL;
167 1.4 christos nep->next = NULL;
168 1.4 christos
169 1.4 christos *needed_tail = nep;
170 1.4 christos needed_tail = &nep->next;
171 1.4 christos }
172 1.4 christos break;
173 1.4 christos
174 1.5 kleink case DT_PLTGOT:
175 1.4 christos obj->pltgot = (Elf_Addr *)
176 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
177 1.4 christos break;
178 1.4 christos
179 1.5 kleink case DT_TEXTREL:
180 1.4 christos obj->textrel = true;
181 1.4 christos break;
182 1.4 christos
183 1.5 kleink case DT_SYMBOLIC:
184 1.4 christos obj->symbolic = true;
185 1.4 christos break;
186 1.4 christos
187 1.5 kleink case DT_RPATH:
188 1.4 christos /*
189 1.4 christos * We have to wait until later to process this, because
190 1.4 christos * we might not have gotten the address of the string
191 1.4 christos * table yet.
192 1.4 christos */
193 1.4 christos dyn_rpath = dynp;
194 1.4 christos break;
195 1.4 christos
196 1.5 kleink case DT_SONAME:
197 1.4 christos /* Not used by the dynamic linker. */
198 1.4 christos break;
199 1.4 christos
200 1.5 kleink case DT_INIT:
201 1.4 christos obj->init = (void (*) __P((void)))
202 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
203 1.4 christos break;
204 1.4 christos
205 1.5 kleink case DT_FINI:
206 1.4 christos obj->fini = (void (*) __P((void)))
207 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
208 1.4 christos break;
209 1.1 cgd
210 1.5 kleink case DT_DEBUG:
211 1.1 cgd #ifdef RTLD_LOADER
212 1.4 christos dynp->d_un.d_ptr = (Elf_Addr)&_rtld_debug;
213 1.1 cgd #endif
214 1.4 christos break;
215 1.2 mhitch
216 1.2 mhitch #if defined(__mips__)
217 1.4 christos case DT_MIPS_LOCAL_GOTNO:
218 1.4 christos obj->local_gotno = dynp->d_un.d_val;
219 1.4 christos break;
220 1.4 christos
221 1.4 christos case DT_MIPS_SYMTABNO:
222 1.4 christos obj->symtabno = dynp->d_un.d_val;
223 1.4 christos break;
224 1.4 christos
225 1.4 christos case DT_MIPS_GOTSYM:
226 1.4 christos obj->gotsym = dynp->d_un.d_val;
227 1.4 christos break;
228 1.2 mhitch
229 1.4 christos case DT_MIPS_RLD_MAP:
230 1.2 mhitch #ifdef RTLD_LOADER
231 1.4 christos *((Elf_Addr *)(dynp->d_un.d_ptr)) = (Elf_Addr)
232 1.4 christos &_rtld_debug;
233 1.2 mhitch #endif
234 1.4 christos break;
235 1.2 mhitch #endif
236 1.4 christos }
237 1.1 cgd }
238 1.1 cgd
239 1.4 christos obj->rellim = (const Elf_Rel *)((caddr_t)obj->rel + relsz);
240 1.4 christos obj->relalim = (const Elf_RelA *)((caddr_t)obj->rela + relasz);
241 1.8 mycroft if (plttype == DT_REL) {
242 1.8 mycroft obj->pltrellim = (const Elf_Rel *)((caddr_t)obj->pltrel + pltrelsz);
243 1.8 mycroft obj->pltrelalim = 0;
244 1.8 mycroft } else {
245 1.8 mycroft obj->pltrellim = 0;
246 1.8 mycroft obj->pltrelalim = (const Elf_RelA *)((caddr_t)obj->pltrela + pltrelsz);
247 1.8 mycroft }
248 1.4 christos
249 1.4 christos if (dyn_rpath != NULL) {
250 1.4 christos _rtld_add_paths(&obj->rpaths, obj->strtab +
251 1.4 christos dyn_rpath->d_un.d_val, true);
252 1.4 christos }
253 1.1 cgd }
254 1.1 cgd
255 1.1 cgd /*
256 1.1 cgd * Process a shared object's program header. This is used only for the
257 1.1 cgd * main program, when the kernel has already loaded the main program
258 1.1 cgd * into memory before calling the dynamic linker. It creates and
259 1.1 cgd * returns an Obj_Entry structure.
260 1.1 cgd */
261 1.1 cgd Obj_Entry *
262 1.4 christos _rtld_digest_phdr(phdr, phnum, entry)
263 1.4 christos const Elf_Phdr *phdr;
264 1.4 christos int phnum;
265 1.4 christos caddr_t entry;
266 1.1 cgd {
267 1.6 mycroft Obj_Entry *obj;
268 1.4 christos const Elf_Phdr *phlimit = phdr + phnum;
269 1.4 christos const Elf_Phdr *ph;
270 1.4 christos int nsegs = 0;
271 1.4 christos
272 1.6 mycroft obj = _rtld_obj_new();
273 1.4 christos for (ph = phdr; ph < phlimit; ++ph) {
274 1.4 christos switch (ph->p_type) {
275 1.4 christos
276 1.5 kleink case PT_PHDR:
277 1.4 christos assert((const Elf_Phdr *) ph->p_vaddr == phdr);
278 1.4 christos obj->phdr = (const Elf_Phdr *) ph->p_vaddr;
279 1.4 christos obj->phsize = ph->p_memsz;
280 1.6 mycroft break;
281 1.6 mycroft
282 1.6 mycroft case PT_INTERP:
283 1.6 mycroft obj->interp = (const char *) ph->p_vaddr;
284 1.4 christos break;
285 1.4 christos
286 1.5 kleink case PT_LOAD:
287 1.4 christos assert(nsegs < 2);
288 1.4 christos if (nsegs == 0) { /* First load segment */
289 1.4 christos obj->vaddrbase = round_down(ph->p_vaddr);
290 1.4 christos obj->mapbase = (caddr_t) obj->vaddrbase;
291 1.4 christos obj->relocbase = obj->mapbase - obj->vaddrbase;
292 1.4 christos obj->textsize = round_up(ph->p_vaddr +
293 1.4 christos ph->p_memsz) - obj->vaddrbase;
294 1.4 christos } else { /* Last load segment */
295 1.4 christos obj->mapsize = round_up(ph->p_vaddr +
296 1.4 christos ph->p_memsz) - obj->vaddrbase;
297 1.4 christos }
298 1.4 christos ++nsegs;
299 1.4 christos break;
300 1.4 christos
301 1.5 kleink case PT_DYNAMIC:
302 1.4 christos obj->dynamic = (Elf_Dyn *) ph->p_vaddr;
303 1.4 christos break;
304 1.4 christos }
305 1.1 cgd }
306 1.4 christos assert(nsegs == 2);
307 1.1 cgd
308 1.4 christos obj->entry = entry;
309 1.4 christos return obj;
310 1.1 cgd }
311