xref: /netbsd-src/libexec/ld.elf_so/headers.c (revision 1b9578b8c2c1f848eeb16dabbfd7d1f0d9fdefbd)
1 /*	$NetBSD: headers.c,v 1.41 2011/06/25 05:45:12 nonaka Exp $	 */
2 
3 /*
4  * Copyright 1996 John D. Polstra.
5  * Copyright 1996 Matt Thomas <matt@3am-software.com>
6  * Copyright 2002 Charles M. Hannum <root@ihack.net>
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by John Polstra.
20  * 4. The name of the author may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 /*
36  * Dynamic linker for ELF.
37  *
38  * John Polstra <jdp@polstra.com>.
39  */
40 
41 #include <sys/cdefs.h>
42 #ifndef lint
43 __RCSID("$NetBSD: headers.c,v 1.41 2011/06/25 05:45:12 nonaka Exp $");
44 #endif /* not lint */
45 
46 #include <err.h>
47 #include <errno.h>
48 #include <fcntl.h>
49 #include <stdarg.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54 #include <sys/types.h>
55 #include <sys/mman.h>
56 #include <sys/bitops.h>
57 #include <dirent.h>
58 
59 #include "debug.h"
60 #include "rtld.h"
61 
62 /*
63  * Process a shared object's DYNAMIC section, and save the important
64  * information in its Obj_Entry structure.
65  */
66 void
67 _rtld_digest_dynamic(const char *execname, Obj_Entry *obj)
68 {
69 	Elf_Dyn        *dynp;
70 	Needed_Entry  **needed_tail = &obj->needed;
71 	const Elf_Dyn  *dyn_rpath = NULL;
72 	bool		use_pltrel = false;
73 	bool		use_pltrela = false;
74 	Elf_Addr        relsz = 0, relasz = 0;
75 	Elf_Addr	pltrel = 0, pltrelsz = 0;
76 	Elf_Addr	init = 0, fini = 0;
77 
78 	for (dynp = obj->dynamic; dynp->d_tag != DT_NULL; ++dynp) {
79 		switch (dynp->d_tag) {
80 
81 		case DT_REL:
82 			obj->rel = (const Elf_Rel *)
83 			    (obj->relocbase + dynp->d_un.d_ptr);
84 			break;
85 
86 		case DT_RELSZ:
87 			relsz = dynp->d_un.d_val;
88 			break;
89 
90 		case DT_RELENT:
91 			assert(dynp->d_un.d_val == sizeof(Elf_Rel));
92 			break;
93 
94 		case DT_JMPREL:
95 			pltrel = dynp->d_un.d_ptr;
96 			break;
97 
98 		case DT_PLTRELSZ:
99 			pltrelsz = dynp->d_un.d_val;
100 			break;
101 
102 		case DT_RELA:
103 			obj->rela = (const Elf_Rela *)
104 			    (obj->relocbase + dynp->d_un.d_ptr);
105 			break;
106 
107 		case DT_RELASZ:
108 			relasz = dynp->d_un.d_val;
109 			break;
110 
111 		case DT_RELAENT:
112 			assert(dynp->d_un.d_val == sizeof(Elf_Rela));
113 			break;
114 
115 		case DT_PLTREL:
116 			use_pltrel = dynp->d_un.d_val == DT_REL;
117 			use_pltrela = dynp->d_un.d_val == DT_RELA;
118 			assert(use_pltrel || use_pltrela);
119 			break;
120 
121 		case DT_SYMTAB:
122 			obj->symtab = (const Elf_Sym *)
123 				(obj->relocbase + dynp->d_un.d_ptr);
124 			break;
125 
126 		case DT_SYMENT:
127 			assert(dynp->d_un.d_val == sizeof(Elf_Sym));
128 			break;
129 
130 		case DT_STRTAB:
131 			obj->strtab = (const char *)
132 			    (obj->relocbase + dynp->d_un.d_ptr);
133 			break;
134 
135 		case DT_STRSZ:
136 			obj->strsize = dynp->d_un.d_val;
137 			break;
138 
139 		case DT_VERNEED:
140 			obj->verneed = (const Elf_Verneed *)
141 			    (obj->relocbase + dynp->d_un.d_ptr);
142 			break;
143 
144 		case DT_VERNEEDNUM:
145 			obj->verneednum = dynp->d_un.d_val;
146 			break;
147 
148 		case DT_VERDEF:
149 			obj->verdef = (const Elf_Verdef *)
150 			    (obj->relocbase + dynp->d_un.d_ptr);
151 			break;
152 
153 		case DT_VERDEFNUM:
154 			obj->verdefnum = dynp->d_un.d_val;
155 			break;
156 
157 		case DT_VERSYM:
158 			obj->versyms = (const Elf_Versym *)
159 			    (obj->relocbase + dynp->d_un.d_ptr);
160 			break;
161 
162 		case DT_HASH:
163 			{
164 				const Elf_Symindx *hashtab = (const Elf_Symindx *)
165 				    (obj->relocbase + dynp->d_un.d_ptr);
166 
167 				if (hashtab[0] > UINT32_MAX)
168 					obj->nbuckets = UINT32_MAX;
169 				else
170 					obj->nbuckets = hashtab[0];
171 				obj->nchains = hashtab[1];
172 				obj->buckets = hashtab + 2;
173 				obj->chains = obj->buckets + obj->nbuckets;
174 				/*
175 				 * Should really be in _rtld_relocate_objects,
176 				 * but _rtld_symlook_obj might be used before.
177 				 */
178 				if (obj->nbuckets) {
179 					fast_divide32_prepare(obj->nbuckets,
180 					    &obj->nbuckets_m,
181 					    &obj->nbuckets_s1,
182 					    &obj->nbuckets_s2);
183 				}
184 			}
185 			break;
186 
187 		case DT_NEEDED:
188 			{
189 				Needed_Entry *nep = NEW(Needed_Entry);
190 
191 				nep->name = dynp->d_un.d_val;
192 				nep->obj = NULL;
193 				nep->next = NULL;
194 
195 				*needed_tail = nep;
196 				needed_tail = &nep->next;
197 			}
198 			break;
199 
200 		case DT_PLTGOT:
201 			obj->pltgot = (Elf_Addr *)
202 			    (obj->relocbase + dynp->d_un.d_ptr);
203 			break;
204 
205 		case DT_TEXTREL:
206 			obj->textrel = true;
207 			break;
208 
209 		case DT_SYMBOLIC:
210 			obj->symbolic = true;
211 			break;
212 
213 		case DT_RPATH:
214 			/*
215 		         * We have to wait until later to process this, because
216 			 * we might not have gotten the address of the string
217 			 * table yet.
218 		         */
219 			dyn_rpath = dynp;
220 			break;
221 
222 		case DT_SONAME:
223 			/* Not used by the dynamic linker. */
224 			break;
225 
226 		case DT_INIT:
227 			init = dynp->d_un.d_ptr;
228 			break;
229 
230 		case DT_FINI:
231 			fini = dynp->d_un.d_ptr;
232 			break;
233 
234 		/*
235 		 * Don't process DT_DEBUG on MIPS as the dynamic section
236 		 * is mapped read-only. DT_MIPS_RLD_MAP is used instead.
237 		 * XXX: n32/n64 may use DT_DEBUG, not sure yet.
238 		 */
239 #ifndef __mips__
240 		case DT_DEBUG:
241 #ifdef RTLD_LOADER
242 			dynp->d_un.d_ptr = (Elf_Addr)&_rtld_debug;
243 #endif
244 			break;
245 #endif
246 
247 #ifdef __mips__
248 		case DT_MIPS_LOCAL_GOTNO:
249 			obj->local_gotno = dynp->d_un.d_val;
250 			break;
251 
252 		case DT_MIPS_SYMTABNO:
253 			obj->symtabno = dynp->d_un.d_val;
254 			break;
255 
256 		case DT_MIPS_GOTSYM:
257 			obj->gotsym = dynp->d_un.d_val;
258 			break;
259 
260 		case DT_MIPS_RLD_MAP:
261 #ifdef RTLD_LOADER
262 			*((Elf_Addr *)(dynp->d_un.d_ptr)) = (Elf_Addr)
263 			    &_rtld_debug;
264 #endif
265 			break;
266 #endif
267 #ifdef __powerpc__
268 		case DT_PPC_GOT:
269 			obj->gotptr = (Elf_Addr *)(obj->relocbase + dynp->d_un.d_ptr);
270 			break;
271 #endif
272 		case DT_FLAGS_1:
273 			obj->z_now =
274 			    ((dynp->d_un.d_val & DF_1_BIND_NOW) != 0);
275 			obj->z_nodelete =
276 			    ((dynp->d_un.d_val & DF_1_NODELETE) != 0);
277 			obj->z_initfirst =
278 			    ((dynp->d_un.d_val & DF_1_INITFIRST) != 0);
279 			obj->z_noopen =
280 			    ((dynp->d_un.d_val & DF_1_NOOPEN) != 0);
281 			break;
282 		}
283 	}
284 
285 	obj->rellim = (const Elf_Rel *)((const uint8_t *)obj->rel + relsz);
286 	obj->relalim = (const Elf_Rela *)((const uint8_t *)obj->rela + relasz);
287 	if (use_pltrel) {
288 		obj->pltrel = (const Elf_Rel *)(obj->relocbase + pltrel);
289 		obj->pltrellim = (const Elf_Rel *)(obj->relocbase + pltrel + pltrelsz);
290 		obj->pltrelalim = 0;
291 		/* On PPC and SPARC, at least, REL(A)SZ may include JMPREL.
292 		   Trim rel(a)lim to save time later. */
293 		if (obj->rellim && obj->pltrel &&
294 		    obj->rellim > obj->pltrel &&
295 		    obj->rellim <= obj->pltrellim)
296 			obj->rellim = obj->pltrel;
297 	} else if (use_pltrela) {
298 		obj->pltrela = (const Elf_Rela *)(obj->relocbase + pltrel);
299 		obj->pltrellim = 0;
300 		obj->pltrelalim = (const Elf_Rela *)(obj->relocbase + pltrel + pltrelsz);
301 		/* On PPC and SPARC, at least, REL(A)SZ may include JMPREL.
302 		   Trim rel(a)lim to save time later. */
303 		if (obj->relalim && obj->pltrela &&
304 		    obj->relalim > obj->pltrela &&
305 		    obj->relalim <= obj->pltrelalim)
306 			obj->relalim = obj->pltrela;
307 	}
308 
309 #if defined(RTLD_LOADER) && defined(__HAVE_FUNCTION_DESCRIPTORS)
310 	if (init != 0)
311 		obj->init = (void (*)(void))
312 		    _rtld_function_descriptor_alloc(obj, NULL, init);
313 	if (fini != 0)
314 		obj->fini = (void (*)(void))
315 		    _rtld_function_descriptor_alloc(obj, NULL, fini);
316 #else
317 	if (init != 0)
318 		obj->init = (void (*)(void))
319 		    (obj->relocbase + init);
320 	if (fini != 0)
321 		obj->fini = (void (*)(void))
322 		    (obj->relocbase + fini);
323 #endif
324 
325 	if (dyn_rpath != NULL) {
326 		_rtld_add_paths(execname, &obj->rpaths, obj->strtab +
327 		    dyn_rpath->d_un.d_val);
328 	}
329 }
330 
331 /*
332  * Process a shared object's program header.  This is used only for the
333  * main program, when the kernel has already loaded the main program
334  * into memory before calling the dynamic linker.  It creates and
335  * returns an Obj_Entry structure.
336  */
337 Obj_Entry *
338 _rtld_digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry)
339 {
340 	Obj_Entry      *obj;
341 	const Elf_Phdr *phlimit = phdr + phnum;
342 	const Elf_Phdr *ph;
343 	int             nsegs = 0;
344 	Elf_Addr	vaddr;
345 
346 	obj = _rtld_obj_new();
347 
348 	for (ph = phdr; ph < phlimit; ++ph) {
349 		if (ph->p_type != PT_PHDR)
350 			continue;
351 
352 		obj->phdr = (void *)(uintptr_t)phdr->p_vaddr;
353 		obj->phsize = phdr->p_memsz;
354 		obj->relocbase = (caddr_t)((uintptr_t)phdr - (uintptr_t)ph->p_vaddr);
355 		dbg(("headers: phdr %p phsize %zu relocbase %lx", obj->phdr,
356 		    obj->phsize, (long)obj->relocbase));
357 		break;
358 	}
359 	assert(obj->phdr == phdr);
360 
361 	for (ph = phdr; ph < phlimit; ++ph) {
362 		vaddr = (Elf_Addr)(uintptr_t)(obj->relocbase + ph->p_vaddr);
363 		switch (ph->p_type) {
364 
365 		case PT_INTERP:
366 			obj->interp = (const char *)(uintptr_t)vaddr;
367 			break;
368 
369 		case PT_LOAD:
370 			assert(nsegs < 2);
371 			if (nsegs == 0) {	/* First load segment */
372 				obj->vaddrbase = round_down(vaddr);
373 				obj->mapbase = (caddr_t)(uintptr_t)obj->vaddrbase;
374 				obj->textsize = round_up(vaddr + ph->p_memsz) -
375 				    obj->vaddrbase;
376 			} else {		/* Last load segment */
377 				obj->mapsize = round_up(vaddr + ph->p_memsz) -
378 				    obj->vaddrbase;
379 			}
380 			++nsegs;
381 			break;
382 
383 		case PT_DYNAMIC:
384 			obj->dynamic = (Elf_Dyn *)(uintptr_t)vaddr;
385 			break;
386 
387 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
388 		case PT_TLS:
389 			obj->tlsindex = 1;
390 			obj->tlssize = ph->p_memsz;
391 			obj->tlsalign = ph->p_align;
392 			obj->tlsinitsize = ph->p_filesz;
393 			obj->tlsinit = (void *)(uintptr_t)ph->p_vaddr;
394 			break;
395 #endif
396 		}
397 	}
398 	assert(nsegs == 2);
399 
400 	obj->entry = entry;
401 	return obj;
402 }
403