xref: /netbsd-src/sys/lib/libsa/loadfile_elf32.c (revision 1ca5c1b28139779176bd5c13ad7c5f25c0bcd5f8)
1 /* $NetBSD: loadfile_elf32.c,v 1.6 2001/11/09 19:27:25 christos Exp $ */
2 
3 /*-
4  * Copyright (c) 1997 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9  * NASA Ames Research Center and by Christos Zoulas.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by the NetBSD
22  *	Foundation, Inc. and its contributors.
23  * 4. Neither the name of The NetBSD Foundation nor the names of its
24  *    contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 /* If not included by exec_elf64.c, ELFSIZE won't be defined. */
41 #ifndef ELFSIZE
42 #define	ELFSIZE	32
43 #endif
44 
45 #ifdef _STANDALONE
46 #include <lib/libsa/stand.h>
47 #include <lib/libkern/libkern.h>
48 #else
49 #include <stdio.h>
50 #include <string.h>
51 #include <errno.h>
52 #include <stdlib.h>
53 #include <unistd.h>
54 #include <fcntl.h>
55 #include <err.h>
56 #endif
57 
58 #include <sys/param.h>
59 #include <sys/exec.h>
60 
61 #include "loadfile.h"
62 
63 #if ((ELFSIZE == 32) && defined(BOOT_ELF32)) || \
64     ((ELFSIZE == 64) && defined(BOOT_ELF64))
65 
66 #define	ELFROUND	(ELFSIZE / 8)
67 
68 #ifndef _STANDALONE
69 #include "byteorder.h"
70 
71 /*
72  * Byte swapping may be necessary in the non-_STANDLONE case because
73  * we may be built with a host compiler.
74  */
75 #define	E16(f)								\
76 	f = (bo == ELFDATA2LSB) ? sa_htole16(f) : sa_htobe16(f)
77 #define	E32(f)								\
78 	f = (bo == ELFDATA2LSB) ? sa_htole32(f) : sa_htobe32(f)
79 #define	E64(f)								\
80 	f = (bo == ELFDATA2LSB) ? sa_htole64(f) : sa_htobe64(f)
81 
82 #define	I16(f)								\
83 	f = (bo == ELFDATA2LSB) ? sa_le16toh(f) : sa_be16toh(f)
84 #define	I32(f)								\
85 	f = (bo == ELFDATA2LSB) ? sa_le32toh(f) : sa_be32toh(f)
86 #define	I64(f)								\
87 	f = (bo == ELFDATA2LSB) ? sa_le64toh(f) : sa_be64toh(f)
88 
89 static void
90 internalize_ehdr(Elf_Byte bo, Elf_Ehdr *ehdr)
91 {
92 
93 #if ELFSIZE == 32
94 	I16(ehdr->e_type);
95 	I16(ehdr->e_machine);
96 	I32(ehdr->e_version);
97 	I32(ehdr->e_entry);
98 	I32(ehdr->e_phoff);
99 	I32(ehdr->e_shoff);
100 	I32(ehdr->e_flags);
101 	I16(ehdr->e_ehsize);
102 	I16(ehdr->e_phentsize);
103 	I16(ehdr->e_phnum);
104 	I16(ehdr->e_shentsize);
105 	I16(ehdr->e_shnum);
106 	I16(ehdr->e_shstrndx);
107 #elif ELFSIZE == 64
108 	I16(ehdr->e_type);
109 	I16(ehdr->e_machine);
110 	I32(ehdr->e_version);
111 	I64(ehdr->e_entry);
112 	I64(ehdr->e_phoff);
113 	I64(ehdr->e_shoff);
114 	I32(ehdr->e_flags);
115 	I16(ehdr->e_ehsize);
116 	I16(ehdr->e_phentsize);
117 	I16(ehdr->e_phnum);
118 	I16(ehdr->e_shentsize);
119 	I16(ehdr->e_shnum);
120 	I16(ehdr->e_shstrndx);
121 #else
122 #error ELFSIZE is not 32 or 64
123 #endif
124 }
125 
126 static void
127 externalize_ehdr(Elf_Byte bo, Elf_Ehdr *ehdr)
128 {
129 
130 #if ELFSIZE == 32
131 	E16(ehdr->e_type);
132 	E16(ehdr->e_machine);
133 	E32(ehdr->e_version);
134 	E32(ehdr->e_entry);
135 	E32(ehdr->e_phoff);
136 	E32(ehdr->e_shoff);
137 	E32(ehdr->e_flags);
138 	E16(ehdr->e_ehsize);
139 	E16(ehdr->e_phentsize);
140 	E16(ehdr->e_phnum);
141 	E16(ehdr->e_shentsize);
142 	E16(ehdr->e_shnum);
143 	E16(ehdr->e_shstrndx);
144 #elif ELFSIZE == 64
145 	E16(ehdr->e_type);
146 	E16(ehdr->e_machine);
147 	E32(ehdr->e_version);
148 	E64(ehdr->e_entry);
149 	E64(ehdr->e_phoff);
150 	E64(ehdr->e_shoff);
151 	E32(ehdr->e_flags);
152 	E16(ehdr->e_ehsize);
153 	E16(ehdr->e_phentsize);
154 	E16(ehdr->e_phnum);
155 	E16(ehdr->e_shentsize);
156 	E16(ehdr->e_shnum);
157 	E16(ehdr->e_shstrndx);
158 #else
159 #error ELFSIZE is not 32 or 64
160 #endif
161 }
162 
163 static void
164 internalize_phdr(Elf_Byte bo, Elf_Phdr *phdr)
165 {
166 
167 #if ELFSIZE == 32
168 	I32(phdr->p_type);
169 	I32(phdr->p_offset);
170 	I32(phdr->p_vaddr);
171 	I32(phdr->p_paddr);
172 	I32(phdr->p_filesz);
173 	I32(phdr->p_memsz);
174 	I32(phdr->p_flags);
175 	I32(phdr->p_align);
176 #elif ELFSIZE == 64
177 	I32(phdr->p_type);
178 	I32(phdr->p_offset);
179 	I64(phdr->p_vaddr);
180 	I64(phdr->p_paddr);
181 	I64(phdr->p_filesz);
182 	I64(phdr->p_memsz);
183 	I64(phdr->p_flags);
184 	I64(phdr->p_align);
185 #else
186 #error ELFSIZE is not 32 or 64
187 #endif
188 }
189 
190 static void
191 internalize_shdr(Elf_Byte bo, Elf_Shdr *shdr)
192 {
193 
194 #if ELFSIZE == 32
195 	I32(shdr->sh_name);
196 	I32(shdr->sh_type);
197 	I32(shdr->sh_flags);
198 	I32(shdr->sh_addr);
199 	I32(shdr->sh_offset);
200 	I32(shdr->sh_size);
201 	I32(shdr->sh_link);
202 	I32(shdr->sh_info);
203 	I32(shdr->sh_addralign);
204 	I32(shdr->sh_entsize);
205 #elif ELFSIZE == 64
206 	I32(shdr->sh_name);
207 	I32(shdr->sh_type);
208 	I64(shdr->sh_flags);
209 	I64(shdr->sh_addr);
210 	I64(shdr->sh_offset);
211 	I64(shdr->sh_size);
212 	I32(shdr->sh_link);
213 	I32(shdr->sh_info);
214 	I64(shdr->sh_addralign);
215 	I64(shdr->sh_entsize);
216 #else
217 #error ELFSIZE is not 32 or 64
218 #endif
219 }
220 
221 static void
222 externalize_shdr(Elf_Byte bo, Elf_Shdr *shdr)
223 {
224 
225 #if ELFSIZE == 32
226 	E32(shdr->sh_name);
227 	E32(shdr->sh_type);
228 	E32(shdr->sh_flags);
229 	E32(shdr->sh_addr);
230 	E32(shdr->sh_offset);
231 	E32(shdr->sh_size);
232 	E32(shdr->sh_link);
233 	E32(shdr->sh_info);
234 	E32(shdr->sh_addralign);
235 	E32(shdr->sh_entsize);
236 #elif ELFSIZE == 64
237 	E32(shdr->sh_name);
238 	E32(shdr->sh_type);
239 	E64(shdr->sh_flags);
240 	E64(shdr->sh_addr);
241 	E64(shdr->sh_offset);
242 	E64(shdr->sh_size);
243 	E32(shdr->sh_link);
244 	E32(shdr->sh_info);
245 	E64(shdr->sh_addralign);
246 	E64(shdr->sh_entsize);
247 #else
248 #error ELFSIZE is not 32 or 64
249 #endif
250 }
251 #else /* _STANDALONE */
252 /*
253  * Byte swapping is never necessary in the _STANDALONE case because
254  * we are being built with the target compiler.
255  */
256 #define	internalize_ehdr(bo, ehdr)	/* nothing */
257 #define	externalize_ehdr(bo, ehdr)	/* nothing */
258 
259 #define	internalize_phdr(bo, phdr)	/* nothing */
260 
261 #define	internalize_shdr(bo, shdr)	/* nothing */
262 #define	externalize_shdr(bo, shdr)	/* nothing */
263 #endif /* _STANDALONE */
264 
265 int
266 ELFNAMEEND(loadfile)(fd, elf, marks, flags)
267 	int fd;
268 	Elf_Ehdr *elf;
269 	u_long *marks;
270 	int flags;
271 {
272 	Elf_Shdr *shp;
273 	Elf_Phdr *phdr;
274 	int i, j;
275 	size_t sz;
276 	int first;
277 	paddr_t minp = ~0, maxp = 0, pos = 0;
278 	paddr_t offset = marks[MARK_START], shpp, elfp = NULL;
279 
280 	internalize_ehdr(elf->e_ident[EI_DATA], elf);
281 
282 	sz = elf->e_phnum * sizeof(Elf_Phdr);
283 	phdr = ALLOC(sz);
284 
285 	if (lseek(fd, elf->e_phoff, SEEK_SET) == -1)  {
286 		WARN(("lseek phdr"));
287 		FREE(phdr, sz);
288 		return 1;
289 	}
290 	if (read(fd, phdr, sz) != sz) {
291 		WARN(("read program headers"));
292 		FREE(phdr, sz);
293 		return 1;
294 	}
295 
296 	for (first = 1, i = 0; i < elf->e_phnum; i++) {
297 		internalize_phdr(elf->e_ident[EI_DATA], &phdr[i]);
298 		if (phdr[i].p_type != PT_LOAD ||
299 		    (phdr[i].p_flags & (PF_W|PF_X)) == 0)
300 			continue;
301 
302 #define IS_TEXT(p)	(p.p_flags & PF_X)
303 #define IS_DATA(p)	(p.p_flags & PF_W)
304 #define IS_BSS(p)	(p.p_filesz < p.p_memsz)
305 		/*
306 		 * XXX: Assume first address is lowest
307 		 */
308 		if ((IS_TEXT(phdr[i]) && (flags & LOAD_TEXT)) ||
309 		    (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
310 
311 			/* Read in segment. */
312 			PROGRESS(("%s%lu", first ? "" : "+",
313 			    (u_long)phdr[i].p_filesz));
314 
315 			if (lseek(fd, phdr[i].p_offset, SEEK_SET) == -1)  {
316 				WARN(("lseek text"));
317 				FREE(phdr, sz);
318 				return 1;
319 			}
320 			if (READ(fd, phdr[i].p_vaddr, phdr[i].p_filesz) !=
321 			    phdr[i].p_filesz) {
322 				WARN(("read text"));
323 				FREE(phdr, sz);
324 				return 1;
325 			}
326 			first = 0;
327 
328 		}
329 		if ((IS_TEXT(phdr[i]) && (flags & (LOAD_TEXT|COUNT_TEXT))) ||
330 		    (IS_DATA(phdr[i]) && (flags & (LOAD_DATA|COUNT_TEXT)))) {
331 			pos = phdr[i].p_vaddr;
332 			if (minp > pos)
333 				minp = pos;
334 			pos += phdr[i].p_filesz;
335 			if (maxp < pos)
336 				maxp = pos;
337 		}
338 
339 		/* Zero out bss. */
340 		if (IS_BSS(phdr[i]) && (flags & LOAD_BSS)) {
341 			PROGRESS(("+%lu",
342 			    (u_long)(phdr[i].p_memsz - phdr[i].p_filesz)));
343 			BZERO((phdr[i].p_vaddr + phdr[i].p_filesz),
344 			    phdr[i].p_memsz - phdr[i].p_filesz);
345 		}
346 		if (IS_BSS(phdr[i]) && (flags & (LOAD_BSS|COUNT_BSS))) {
347 			pos += phdr[i].p_memsz - phdr[i].p_filesz;
348 			if (maxp < pos)
349 				maxp = pos;
350 		}
351 	}
352 	FREE(phdr, sz);
353 
354 	/*
355 	 * Copy the ELF and section headers.
356 	 */
357 	maxp = roundup(maxp, ELFROUND);
358 	if (flags & (LOAD_HDR|COUNT_HDR)) {
359 		elfp = maxp;
360 		maxp += sizeof(Elf_Ehdr);
361 	}
362 
363 	if (flags & (LOAD_SYM|COUNT_SYM)) {
364 		if (lseek(fd, elf->e_shoff, SEEK_SET) == -1)  {
365 			WARN(("lseek section headers"));
366 			return 1;
367 		}
368 		sz = elf->e_shnum * sizeof(Elf_Shdr);
369 
370 		shp = ALLOC(sz);
371 
372 		if (read(fd, shp, sz) != sz) {
373 			WARN(("read section headers"));
374 			return 1;
375 		}
376 
377 		shpp = maxp;
378 		maxp += roundup(sz, ELFROUND);
379 
380 #ifndef _STANDALONE
381 		/* Internalize the section headers. */
382 		for (i = 0; i < elf->e_shnum; i++)
383 			internalize_shdr(elf->e_ident[EI_DATA], &shp[i]);
384 #endif /* ! _STANDALONE */
385 
386 		/*
387 		 * Now load the symbol sections themselves.  Make sure
388 		 * the sections are aligned. Don't bother with any
389 		 * string table that isn't referenced by a symbol
390 		 * table.
391 		 */
392 		for (first = 1, i = 0; i < elf->e_shnum; i++) {
393 			switch (shp[i].sh_type) {
394 			case SHT_STRTAB:
395 				for (j = 0; j < elf->e_shnum; j++)
396 					if (shp[j].sh_type == SHT_SYMTAB &&
397 					    shp[j].sh_link == i)
398 						goto havesym;
399 				/* FALLTHROUGH */
400 			default:
401 				/* Not loading this, so zero out the offset. */
402 				shp[i].sh_offset = 0;
403 				break;
404 			havesym:
405 			case SHT_SYMTAB:
406 				if (flags & LOAD_SYM) {
407 					PROGRESS(("%s%ld", first ? " [" : "+",
408 					    (u_long)shp[i].sh_size));
409 					if (lseek(fd, shp[i].sh_offset,
410 					    SEEK_SET) == -1) {
411 						WARN(("lseek symbols"));
412 						FREE(shp, sz);
413 						return 1;
414 					}
415 					if (READ(fd, maxp, shp[i].sh_size) !=
416 					    shp[i].sh_size) {
417 						WARN(("read symbols"));
418 						FREE(shp, sz);
419 						return 1;
420 					}
421 				}
422 				shp[i].sh_offset = maxp - elfp;
423 				maxp += roundup(shp[i].sh_size, ELFROUND);
424 				first = 0;
425 			}
426 			/* Since we don't load .shstrtab, zero the name. */
427 			shp[i].sh_name = 0;
428 		}
429 		if (flags & LOAD_SYM) {
430 #ifndef _STANDALONE
431 			/* Externalize the section headers. */
432 			for (i = 0; i < elf->e_shnum; i++)
433 				externalize_shdr(elf->e_ident[EI_DATA],
434 				    &shp[i]);
435 #endif /* ! _STANDALONE */
436 			BCOPY(shp, shpp, sz);
437 
438 			if (first == 0)
439 				PROGRESS(("]"));
440 		}
441 		FREE(shp, sz);
442 	}
443 
444 	/*
445 	 * Frob the copied ELF header to give information relative
446 	 * to elfp.
447 	 */
448 	if (flags & LOAD_HDR) {
449 		elf->e_phoff = 0;
450 		elf->e_shoff = sizeof(Elf_Ehdr);
451 		elf->e_phentsize = 0;
452 		elf->e_phnum = 0;
453 		elf->e_shstrndx = SHN_UNDEF;
454 		externalize_ehdr(elf->e_ident[EI_DATA], elf);
455 		BCOPY(elf, elfp, sizeof(*elf));
456 		internalize_ehdr(elf->e_ident[EI_DATA], elf);
457 	}
458 
459 	marks[MARK_START] = LOADADDR(minp);
460 	marks[MARK_ENTRY] = LOADADDR(elf->e_entry);
461 	/*
462 	 * Since there can be more than one symbol section in the code
463 	 * and we need to find strtab too in order to do anything
464 	 * useful with the symbols, we just pass the whole elf
465 	 * header back and we let the kernel debugger find the
466 	 * location and number of symbols by itself.
467 	 */
468 	marks[MARK_NSYM] = 1;	/* XXX: Kernel needs >= 0 */
469 	marks[MARK_SYM] = LOADADDR(elfp);
470 	marks[MARK_END] = LOADADDR(maxp);
471 	return 0;
472 }
473 
474 #endif /* (ELFSIZE == 32 && BOOT_ELF32) || (ELFSIZE == 64 && BOOT_ELF64) */
475