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