headers.c revision 1.4.4.1 1 1.4.4.1 wrstuden /* $NetBSD: headers.c,v 1.4.4.1 1999/12/27 18:30:14 wrstuden 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.4.4.1 wrstuden Elf_Sword plttype = DT_REL;
67 1.4 christos Elf_Word relsz = 0, relasz = 0;
68 1.4 christos Elf_Word pltrelsz = 0, pltrelasz = 0;
69 1.4 christos
70 1.4.4.1 wrstuden for (dynp = obj->dynamic; dynp->d_tag != DT_NULL; ++dynp) {
71 1.4 christos switch (dynp->d_tag) {
72 1.4 christos
73 1.4.4.1 wrstuden 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.4.4.1 wrstuden case DT_RELSZ:
79 1.4 christos relsz = dynp->d_un.d_val;
80 1.4 christos break;
81 1.4 christos
82 1.4.4.1 wrstuden 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.4.4.1 wrstuden case DT_JMPREL:
87 1.4.4.1 wrstuden 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.4.4.1 wrstuden case DT_PLTRELSZ:
97 1.4.4.1 wrstuden if (plttype == DT_REL) {
98 1.4 christos pltrelsz = dynp->d_un.d_val;
99 1.4 christos } else {
100 1.4 christos pltrelasz = dynp->d_un.d_val;
101 1.4 christos }
102 1.4 christos break;
103 1.4 christos
104 1.4.4.1 wrstuden case DT_RELA:
105 1.4 christos obj->rela = (const Elf_RelA *)
106 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
107 1.4 christos break;
108 1.4 christos
109 1.4.4.1 wrstuden case DT_RELASZ:
110 1.4 christos relasz = dynp->d_un.d_val;
111 1.4 christos break;
112 1.4 christos
113 1.4.4.1 wrstuden case DT_RELAENT:
114 1.4 christos assert(dynp->d_un.d_val == sizeof(Elf_RelA));
115 1.4 christos break;
116 1.4 christos
117 1.4.4.1 wrstuden case DT_PLTREL:
118 1.4 christos plttype = dynp->d_un.d_val;
119 1.4.4.1 wrstuden assert(plttype == DT_REL ||
120 1.4.4.1 wrstuden plttype == DT_RELA);
121 1.4.4.1 wrstuden if (plttype == DT_RELA) {
122 1.4 christos obj->pltrela = (const Elf_RelA *) obj->pltrel;
123 1.4 christos obj->pltrel = NULL;
124 1.4 christos pltrelasz = pltrelsz;
125 1.4 christos pltrelsz = 0;
126 1.4 christos }
127 1.4 christos break;
128 1.4 christos
129 1.4.4.1 wrstuden case DT_SYMTAB:
130 1.4 christos obj->symtab = (const Elf_Sym *)
131 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
132 1.4 christos break;
133 1.4 christos
134 1.4.4.1 wrstuden case DT_SYMENT:
135 1.4 christos assert(dynp->d_un.d_val == sizeof(Elf_Sym));
136 1.4 christos break;
137 1.4 christos
138 1.4.4.1 wrstuden case DT_STRTAB:
139 1.4 christos obj->strtab = (const char *)
140 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
141 1.4 christos break;
142 1.4 christos
143 1.4.4.1 wrstuden case DT_STRSZ:
144 1.4 christos obj->strsize = dynp->d_un.d_val;
145 1.4 christos break;
146 1.4 christos
147 1.4.4.1 wrstuden case DT_HASH:
148 1.4 christos {
149 1.4 christos const Elf_Word *hashtab = (const Elf_Word *)
150 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
151 1.4 christos
152 1.4 christos obj->nbuckets = hashtab[0];
153 1.4 christos obj->nchains = hashtab[1];
154 1.4 christos obj->buckets = hashtab + 2;
155 1.4 christos obj->chains = obj->buckets + obj->nbuckets;
156 1.4 christos }
157 1.4 christos break;
158 1.4 christos
159 1.4.4.1 wrstuden case DT_NEEDED:
160 1.4 christos assert(!obj->rtld);
161 1.4 christos {
162 1.4 christos Needed_Entry *nep = NEW(Needed_Entry);
163 1.4 christos
164 1.4 christos nep->name = dynp->d_un.d_val;
165 1.4 christos nep->obj = NULL;
166 1.4 christos nep->next = NULL;
167 1.4 christos
168 1.4 christos *needed_tail = nep;
169 1.4 christos needed_tail = &nep->next;
170 1.4 christos }
171 1.4 christos break;
172 1.4 christos
173 1.4.4.1 wrstuden case DT_PLTGOT:
174 1.4 christos obj->pltgot = (Elf_Addr *)
175 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
176 1.4 christos break;
177 1.4 christos
178 1.4.4.1 wrstuden case DT_TEXTREL:
179 1.4 christos obj->textrel = true;
180 1.4 christos break;
181 1.4 christos
182 1.4.4.1 wrstuden case DT_SYMBOLIC:
183 1.4 christos obj->symbolic = true;
184 1.4 christos break;
185 1.4 christos
186 1.4.4.1 wrstuden case DT_RPATH:
187 1.4 christos /*
188 1.4 christos * We have to wait until later to process this, because
189 1.4 christos * we might not have gotten the address of the string
190 1.4 christos * table yet.
191 1.4 christos */
192 1.4 christos dyn_rpath = dynp;
193 1.4 christos break;
194 1.4 christos
195 1.4.4.1 wrstuden case DT_SONAME:
196 1.4 christos /* Not used by the dynamic linker. */
197 1.4 christos break;
198 1.4 christos
199 1.4.4.1 wrstuden case DT_INIT:
200 1.4 christos obj->init = (void (*) __P((void)))
201 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
202 1.4 christos break;
203 1.4 christos
204 1.4.4.1 wrstuden case DT_FINI:
205 1.4 christos obj->fini = (void (*) __P((void)))
206 1.4 christos (obj->relocbase + dynp->d_un.d_ptr);
207 1.4 christos break;
208 1.1 cgd
209 1.4.4.1 wrstuden case DT_DEBUG:
210 1.1 cgd #ifdef RTLD_LOADER
211 1.4 christos dynp->d_un.d_ptr = (Elf_Addr)&_rtld_debug;
212 1.1 cgd #endif
213 1.4 christos break;
214 1.2 mhitch
215 1.2 mhitch #if defined(__mips__)
216 1.4 christos case DT_MIPS_LOCAL_GOTNO:
217 1.4 christos obj->local_gotno = dynp->d_un.d_val;
218 1.4 christos break;
219 1.4 christos
220 1.4 christos case DT_MIPS_SYMTABNO:
221 1.4 christos obj->symtabno = dynp->d_un.d_val;
222 1.4 christos break;
223 1.4 christos
224 1.4 christos case DT_MIPS_GOTSYM:
225 1.4 christos obj->gotsym = dynp->d_un.d_val;
226 1.4 christos break;
227 1.2 mhitch
228 1.4 christos case DT_MIPS_RLD_MAP:
229 1.2 mhitch #ifdef RTLD_LOADER
230 1.4 christos *((Elf_Addr *)(dynp->d_un.d_ptr)) = (Elf_Addr)
231 1.4 christos &_rtld_debug;
232 1.2 mhitch #endif
233 1.4 christos break;
234 1.2 mhitch #endif
235 1.4 christos }
236 1.1 cgd }
237 1.1 cgd
238 1.4 christos obj->rellim = (const Elf_Rel *)((caddr_t)obj->rel + relsz);
239 1.4 christos obj->relalim = (const Elf_RelA *)((caddr_t)obj->rela + relasz);
240 1.4 christos obj->pltrellim = (const Elf_Rel *)((caddr_t)obj->pltrel + pltrelsz);
241 1.4 christos obj->pltrelalim = (const Elf_RelA *)((caddr_t)obj->pltrela + pltrelasz);
242 1.4 christos
243 1.4 christos if (dyn_rpath != NULL) {
244 1.4 christos _rtld_add_paths(&obj->rpaths, obj->strtab +
245 1.4 christos dyn_rpath->d_un.d_val, true);
246 1.4 christos }
247 1.1 cgd }
248 1.1 cgd
249 1.1 cgd /*
250 1.1 cgd * Process a shared object's program header. This is used only for the
251 1.1 cgd * main program, when the kernel has already loaded the main program
252 1.1 cgd * into memory before calling the dynamic linker. It creates and
253 1.1 cgd * returns an Obj_Entry structure.
254 1.1 cgd */
255 1.1 cgd Obj_Entry *
256 1.4 christos _rtld_digest_phdr(phdr, phnum, entry)
257 1.4 christos const Elf_Phdr *phdr;
258 1.4 christos int phnum;
259 1.4 christos caddr_t entry;
260 1.1 cgd {
261 1.4.4.1 wrstuden Obj_Entry *obj;
262 1.4 christos const Elf_Phdr *phlimit = phdr + phnum;
263 1.4 christos const Elf_Phdr *ph;
264 1.4 christos int nsegs = 0;
265 1.4 christos
266 1.4.4.1 wrstuden obj = _rtld_obj_new();
267 1.4 christos for (ph = phdr; ph < phlimit; ++ph) {
268 1.4 christos switch (ph->p_type) {
269 1.4 christos
270 1.4.4.1 wrstuden case PT_PHDR:
271 1.4 christos assert((const Elf_Phdr *) ph->p_vaddr == phdr);
272 1.4 christos obj->phdr = (const Elf_Phdr *) ph->p_vaddr;
273 1.4 christos obj->phsize = ph->p_memsz;
274 1.4 christos break;
275 1.4 christos
276 1.4.4.1 wrstuden case PT_INTERP:
277 1.4.4.1 wrstuden obj->interp = (const char *) ph->p_vaddr;
278 1.4.4.1 wrstuden break;
279 1.4.4.1 wrstuden
280 1.4.4.1 wrstuden case PT_LOAD:
281 1.4 christos assert(nsegs < 2);
282 1.4 christos if (nsegs == 0) { /* First load segment */
283 1.4 christos obj->vaddrbase = round_down(ph->p_vaddr);
284 1.4 christos obj->mapbase = (caddr_t) obj->vaddrbase;
285 1.4 christos obj->relocbase = obj->mapbase - obj->vaddrbase;
286 1.4 christos obj->textsize = round_up(ph->p_vaddr +
287 1.4 christos ph->p_memsz) - obj->vaddrbase;
288 1.4 christos } else { /* Last load segment */
289 1.4 christos obj->mapsize = round_up(ph->p_vaddr +
290 1.4 christos ph->p_memsz) - obj->vaddrbase;
291 1.4 christos }
292 1.4 christos ++nsegs;
293 1.4 christos break;
294 1.4 christos
295 1.4.4.1 wrstuden case PT_DYNAMIC:
296 1.4 christos obj->dynamic = (Elf_Dyn *) ph->p_vaddr;
297 1.4 christos break;
298 1.4 christos }
299 1.1 cgd }
300 1.4 christos assert(nsegs == 2);
301 1.1 cgd
302 1.4 christos obj->entry = entry;
303 1.4 christos return obj;
304 1.1 cgd }
305