xref: /netbsd-src/libexec/ld.elf_so/headers.c (revision c2f76ff004a2cb67efe5b12d97bd3ef7fe89e18d)
1 /*	$NetBSD: headers.c,v 1.39 2011/01/16 01:22:29 matt 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.39 2011/01/16 01:22:29 matt 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_HASH:
140 			{
141 				const Elf_Symindx *hashtab = (const Elf_Symindx *)
142 				    (obj->relocbase + dynp->d_un.d_ptr);
143 
144 				if (hashtab[0] > UINT32_MAX)
145 					obj->nbuckets = UINT32_MAX;
146 				else
147 					obj->nbuckets = hashtab[0];
148 				obj->nchains = hashtab[1];
149 				obj->buckets = hashtab + 2;
150 				obj->chains = obj->buckets + obj->nbuckets;
151 				/*
152 				 * Should really be in _rtld_relocate_objects,
153 				 * but _rtld_symlook_obj might be used before.
154 				 */
155 				if (obj->nbuckets) {
156 					fast_divide32_prepare(obj->nbuckets,
157 					    &obj->nbuckets_m,
158 					    &obj->nbuckets_s1,
159 					    &obj->nbuckets_s2);
160 				}
161 			}
162 			break;
163 
164 		case DT_NEEDED:
165 			{
166 				Needed_Entry *nep = NEW(Needed_Entry);
167 
168 				nep->name = dynp->d_un.d_val;
169 				nep->obj = NULL;
170 				nep->next = NULL;
171 
172 				*needed_tail = nep;
173 				needed_tail = &nep->next;
174 			}
175 			break;
176 
177 		case DT_PLTGOT:
178 			obj->pltgot = (Elf_Addr *)
179 			    (obj->relocbase + dynp->d_un.d_ptr);
180 			break;
181 
182 		case DT_TEXTREL:
183 			obj->textrel = true;
184 			break;
185 
186 		case DT_SYMBOLIC:
187 			obj->symbolic = true;
188 			break;
189 
190 		case DT_RPATH:
191 			/*
192 		         * We have to wait until later to process this, because
193 			 * we might not have gotten the address of the string
194 			 * table yet.
195 		         */
196 			dyn_rpath = dynp;
197 			break;
198 
199 		case DT_SONAME:
200 			/* Not used by the dynamic linker. */
201 			break;
202 
203 		case DT_INIT:
204 			init = dynp->d_un.d_ptr;
205 			break;
206 
207 		case DT_FINI:
208 			fini = dynp->d_un.d_ptr;
209 			break;
210 
211 		/*
212 		 * Don't process DT_DEBUG on MIPS as the dynamic section
213 		 * is mapped read-only. DT_MIPS_RLD_MAP is used instead.
214 		 * XXX: n32/n64 may use DT_DEBUG, not sure yet.
215 		 */
216 #ifndef __mips__
217 		case DT_DEBUG:
218 #ifdef RTLD_LOADER
219 			dynp->d_un.d_ptr = (Elf_Addr)&_rtld_debug;
220 #endif
221 			break;
222 #endif
223 
224 #ifdef __mips__
225 		case DT_MIPS_LOCAL_GOTNO:
226 			obj->local_gotno = dynp->d_un.d_val;
227 			break;
228 
229 		case DT_MIPS_SYMTABNO:
230 			obj->symtabno = dynp->d_un.d_val;
231 			break;
232 
233 		case DT_MIPS_GOTSYM:
234 			obj->gotsym = dynp->d_un.d_val;
235 			break;
236 
237 		case DT_MIPS_RLD_MAP:
238 #ifdef RTLD_LOADER
239 			*((Elf_Addr *)(dynp->d_un.d_ptr)) = (Elf_Addr)
240 			    &_rtld_debug;
241 #endif
242 			break;
243 #endif
244 #ifdef __powerpc__
245 		case DT_PPC_GOT:
246 			obj->gotptr = (Elf_Addr *)(obj->relocbase + dynp->d_un.d_ptr);
247 			break;
248 #endif
249 		case DT_FLAGS_1:
250 			obj->z_now =
251 			    ((dynp->d_un.d_val & DF_1_BIND_NOW) != 0);
252 			obj->z_nodelete =
253 			    ((dynp->d_un.d_val & DF_1_NODELETE) != 0);
254 			obj->z_initfirst =
255 			    ((dynp->d_un.d_val & DF_1_INITFIRST) != 0);
256 			obj->z_noopen =
257 			    ((dynp->d_un.d_val & DF_1_NOOPEN) != 0);
258 			break;
259 		}
260 	}
261 
262 	obj->rellim = (const Elf_Rel *)((const uint8_t *)obj->rel + relsz);
263 	obj->relalim = (const Elf_Rela *)((const uint8_t *)obj->rela + relasz);
264 	if (use_pltrel) {
265 		obj->pltrel = (const Elf_Rel *)(obj->relocbase + pltrel);
266 		obj->pltrellim = (const Elf_Rel *)(obj->relocbase + pltrel + pltrelsz);
267 		obj->pltrelalim = 0;
268 		/* On PPC and SPARC, at least, REL(A)SZ may include JMPREL.
269 		   Trim rel(a)lim to save time later. */
270 		if (obj->rellim && obj->pltrel &&
271 		    obj->rellim > obj->pltrel &&
272 		    obj->rellim <= obj->pltrellim)
273 			obj->rellim = obj->pltrel;
274 	} else if (use_pltrela) {
275 		obj->pltrela = (const Elf_Rela *)(obj->relocbase + pltrel);
276 		obj->pltrellim = 0;
277 		obj->pltrelalim = (const Elf_Rela *)(obj->relocbase + pltrel + pltrelsz);
278 		/* On PPC and SPARC, at least, REL(A)SZ may include JMPREL.
279 		   Trim rel(a)lim to save time later. */
280 		if (obj->relalim && obj->pltrela &&
281 		    obj->relalim > obj->pltrela &&
282 		    obj->relalim <= obj->pltrelalim)
283 			obj->relalim = obj->pltrela;
284 	}
285 
286 #if defined(RTLD_LOADER) && defined(__HAVE_FUNCTION_DESCRIPTORS)
287 	if (init != 0)
288 		obj->init = (void (*)(void))
289 		    _rtld_function_descriptor_alloc(obj, NULL, init);
290 	if (fini != 0)
291 		obj->fini = (void (*)(void))
292 		    _rtld_function_descriptor_alloc(obj, NULL, fini);
293 #else
294 	if (init != 0)
295 		obj->init = (void (*)(void))
296 		    (obj->relocbase + init);
297 	if (fini != 0)
298 		obj->fini = (void (*)(void))
299 		    (obj->relocbase + fini);
300 #endif
301 
302 	if (dyn_rpath != NULL) {
303 		_rtld_add_paths(execname, &obj->rpaths, obj->strtab +
304 		    dyn_rpath->d_un.d_val);
305 	}
306 }
307 
308 /*
309  * Process a shared object's program header.  This is used only for the
310  * main program, when the kernel has already loaded the main program
311  * into memory before calling the dynamic linker.  It creates and
312  * returns an Obj_Entry structure.
313  */
314 Obj_Entry *
315 _rtld_digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry)
316 {
317 	Obj_Entry      *obj;
318 	const Elf_Phdr *phlimit = phdr + phnum;
319 	const Elf_Phdr *ph;
320 	int             nsegs = 0;
321 	Elf_Addr	vaddr;
322 
323 	obj = _rtld_obj_new();
324 
325 	for (ph = phdr; ph < phlimit; ++ph) {
326 		if (ph->p_type != PT_PHDR)
327 			continue;
328 
329 		obj->phdr = (void *)(uintptr_t)phdr->p_vaddr;
330 		obj->phsize = phdr->p_memsz;
331 		obj->relocbase = (caddr_t)((uintptr_t)phdr - (uintptr_t)ph->p_vaddr);
332 		dbg(("headers: phdr %p phsize %zu relocbase %lx", obj->phdr,
333 		    obj->phsize, (long)obj->relocbase));
334 		break;
335 	}
336 	assert(obj->phdr == phdr);
337 
338 	for (ph = phdr; ph < phlimit; ++ph) {
339 		vaddr = (Elf_Addr)(uintptr_t)(obj->relocbase + ph->p_vaddr);
340 		switch (ph->p_type) {
341 
342 		case PT_INTERP:
343 			obj->interp = (const char *)(uintptr_t)vaddr;
344 			break;
345 
346 		case PT_LOAD:
347 			assert(nsegs < 2);
348 			if (nsegs == 0) {	/* First load segment */
349 				obj->vaddrbase = round_down(vaddr);
350 				obj->mapbase = (caddr_t)(uintptr_t)obj->vaddrbase;
351 				obj->textsize = round_up(vaddr + ph->p_memsz) -
352 				    obj->vaddrbase;
353 			} else {		/* Last load segment */
354 				obj->mapsize = round_up(vaddr + ph->p_memsz) -
355 				    obj->vaddrbase;
356 			}
357 			++nsegs;
358 			break;
359 
360 		case PT_DYNAMIC:
361 			obj->dynamic = (Elf_Dyn *)(uintptr_t)vaddr;
362 			break;
363 		}
364 	}
365 	assert(nsegs == 2);
366 
367 	obj->entry = entry;
368 	return obj;
369 }
370