xref: /netbsd-src/sys/lib/libsa/loadfile_elf32.c (revision 267197ec1eebfcb9810ea27a89625b6ddf68e3e7)
1 /* $NetBSD: loadfile_elf32.c,v 1.21 2007/12/29 17:54:42 tsutsui 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)(int fd, Elf_Ehdr *elf, u_long *marks, int flags)
267 {
268 	Elf_Shdr *shp;
269 	Elf_Phdr *phdr;
270 	int i, j;
271 	ssize_t sz;
272 	int first;
273 	paddr_t minp = ~0, maxp = 0, pos = 0;
274 	paddr_t offset = marks[MARK_START], shpp, elfp = 0;
275 	ssize_t nr;
276 
277 	/* some ports dont use the offset */
278 	offset = offset;
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 		goto freephdr;
288 	}
289 	nr = read(fd, phdr, sz);
290 	if (nr == -1) {
291 		WARN(("read program headers"));
292 		goto freephdr;
293 	}
294 	if (nr != sz) {
295 		errno = EIO;
296 		WARN(("read program headers"));
297 		goto freephdr;
298 	}
299 
300 	for (first = 1, i = 0; i < elf->e_phnum; i++) {
301 		internalize_phdr(elf->e_ident[EI_DATA], &phdr[i]);
302 
303 #ifndef MD_LOADSEG /* Allow processor ABI specific segment loads */
304 #define MD_LOADSEG(a) /*CONSTCOND*/0
305 #endif
306 		if (MD_LOADSEG(&phdr[i]))
307 			goto loadseg;
308 
309 
310 		if (phdr[i].p_type != PT_LOAD ||
311 		    (phdr[i].p_flags & (PF_W|PF_X)) == 0)
312 			continue;
313 
314 #define IS_TEXT(p)	(p.p_flags & PF_X)
315 #define IS_DATA(p)	(p.p_flags & PF_W)
316 #define IS_BSS(p)	(p.p_filesz < p.p_memsz)
317 		/*
318 		 * XXX: Assume first address is lowest
319 		 */
320 		if ((IS_TEXT(phdr[i]) && (flags & LOAD_TEXT)) ||
321 		    (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
322 
323 		loadseg:
324 			if (marks[MARK_DATA] == 0 && IS_DATA(phdr[i]))
325 				marks[MARK_DATA] = LOADADDR(phdr[i].p_vaddr);
326 
327 			/* Read in segment. */
328 			PROGRESS(("%s%lu", first ? "" : "+",
329 			    (u_long)phdr[i].p_filesz));
330 
331 			if (lseek(fd, phdr[i].p_offset, SEEK_SET) == -1)  {
332 				WARN(("lseek text"));
333 				goto freephdr;
334 			}
335 			nr = READ(fd, phdr[i].p_vaddr, phdr[i].p_filesz);
336 			if (nr == -1) {
337 				WARN(("read text error"));
338 				goto freephdr;
339 			}
340 			if (nr != (ssize_t)phdr[i].p_filesz) {
341 				errno = EIO;
342 				WARN(("read text"));
343 				goto freephdr;
344 			}
345 			first = 0;
346 
347 		}
348 		if ((IS_TEXT(phdr[i]) && (flags & (LOAD_TEXT|COUNT_TEXT))) ||
349 		    (IS_DATA(phdr[i]) && (flags & (LOAD_DATA|COUNT_TEXT)))) {
350 			pos = phdr[i].p_vaddr;
351 			if (minp > pos)
352 				minp = pos;
353 			pos += phdr[i].p_filesz;
354 			if (maxp < pos)
355 				maxp = pos;
356 		}
357 
358 		/* Zero out bss. */
359 		if (IS_BSS(phdr[i]) && (flags & LOAD_BSS)) {
360 			PROGRESS(("+%lu",
361 			    (u_long)(phdr[i].p_memsz - phdr[i].p_filesz)));
362 			BZERO((phdr[i].p_vaddr + phdr[i].p_filesz),
363 			    phdr[i].p_memsz - phdr[i].p_filesz);
364 		}
365 		if (IS_BSS(phdr[i]) && (flags & (LOAD_BSS|COUNT_BSS))) {
366 			pos += phdr[i].p_memsz - phdr[i].p_filesz;
367 			if (maxp < pos)
368 				maxp = pos;
369 		}
370 	}
371 	DEALLOC(phdr, sz);
372 
373 	/*
374 	 * Copy the ELF and section headers.
375 	 */
376 	maxp = roundup(maxp, ELFROUND);
377 	if (flags & (LOAD_HDR|COUNT_HDR)) {
378 		elfp = maxp;
379 		maxp += sizeof(Elf_Ehdr);
380 	}
381 
382 	if (flags & (LOAD_SYM|COUNT_SYM)) {
383 		if (lseek(fd, elf->e_shoff, SEEK_SET) == -1)  {
384 			WARN(("lseek section headers"));
385 			return 1;
386 		}
387 		sz = elf->e_shnum * sizeof(Elf_Shdr);
388 
389 		shp = ALLOC(sz);
390 
391 		nr = read(fd, shp, sz);
392 		if (nr == -1) {
393 			WARN(("read section headers"));
394 			goto freeshp;
395 		}
396 		if (nr != sz) {
397 			errno = EIO;
398 			WARN(("read section headers"));
399 			goto freeshp;
400 		}
401 
402 		shpp = maxp;
403 		maxp += roundup(sz, ELFROUND);
404 
405 #ifndef _STANDALONE
406 		/* Internalize the section headers. */
407 		for (i = 0; i < elf->e_shnum; i++)
408 			internalize_shdr(elf->e_ident[EI_DATA], &shp[i]);
409 #endif /* ! _STANDALONE */
410 
411 		/*
412 		 * Now load the symbol sections themselves.  Make sure
413 		 * the sections are aligned. Don't bother with any
414 		 * string table that isn't referenced by a symbol
415 		 * table.
416 		 */
417 		for (first = 1, i = 0; i < elf->e_shnum; i++) {
418 			switch (shp[i].sh_type) {
419 			case SHT_STRTAB:
420 				for (j = 0; j < elf->e_shnum; j++)
421 					if (shp[j].sh_type == SHT_SYMTAB &&
422 					    shp[j].sh_link == (unsigned int)i)
423 						goto havesym;
424 				/* FALLTHROUGH */
425 			default:
426 				/* Not loading this, so zero out the offset. */
427 				shp[i].sh_offset = 0;
428 				break;
429 			havesym:
430 			case SHT_SYMTAB:
431 				if (flags & LOAD_SYM) {
432 					PROGRESS(("%s%ld", first ? " [" : "+",
433 					    (u_long)shp[i].sh_size));
434 					if (lseek(fd, shp[i].sh_offset,
435 					    SEEK_SET) == -1) {
436 						WARN(("lseek symbols"));
437 						goto freeshp;
438 					}
439 					nr = READ(fd, maxp, shp[i].sh_size);
440 					if (nr == -1) {
441 						WARN(("read symbols"));
442 						goto freeshp;
443 					}
444 					if (nr != (ssize_t)shp[i].sh_size) {
445 						errno = EIO;
446 						WARN(("read symbols"));
447 						goto freeshp;
448 					}
449 				}
450 				shp[i].sh_offset = maxp - elfp;
451 				maxp += roundup(shp[i].sh_size, ELFROUND);
452 				first = 0;
453 			}
454 			/* Since we don't load .shstrtab, zero the name. */
455 			shp[i].sh_name = 0;
456 		}
457 		if (flags & LOAD_SYM) {
458 #ifndef _STANDALONE
459 			/* Externalize the section headers. */
460 			for (i = 0; i < elf->e_shnum; i++)
461 				externalize_shdr(elf->e_ident[EI_DATA],
462 				    &shp[i]);
463 #endif /* ! _STANDALONE */
464 			BCOPY(shp, shpp, sz);
465 
466 			if (first == 0)
467 				PROGRESS(("]"));
468 		}
469 		DEALLOC(shp, sz);
470 	}
471 
472 	/*
473 	 * Frob the copied ELF header to give information relative
474 	 * to elfp.
475 	 */
476 	if (flags & LOAD_HDR) {
477 		elf->e_phoff = 0;
478 		elf->e_shoff = sizeof(Elf_Ehdr);
479 		elf->e_phentsize = 0;
480 		elf->e_phnum = 0;
481 		elf->e_shstrndx = SHN_UNDEF;
482 		externalize_ehdr(elf->e_ident[EI_DATA], elf);
483 		BCOPY(elf, elfp, sizeof(*elf));
484 		internalize_ehdr(elf->e_ident[EI_DATA], elf);
485 	}
486 
487 	marks[MARK_START] = LOADADDR(minp);
488 	marks[MARK_ENTRY] = LOADADDR(elf->e_entry);
489 	/*
490 	 * Since there can be more than one symbol section in the code
491 	 * and we need to find strtab too in order to do anything
492 	 * useful with the symbols, we just pass the whole elf
493 	 * header back and we let the kernel debugger find the
494 	 * location and number of symbols by itself.
495 	 */
496 	marks[MARK_NSYM] = 1;	/* XXX: Kernel needs >= 0 */
497 	marks[MARK_SYM] = LOADADDR(elfp);
498 	marks[MARK_END] = LOADADDR(maxp);
499 	return 0;
500 freephdr:
501 	DEALLOC(phdr, sz);
502 	return 1;
503 freeshp:
504 	DEALLOC(shp, sz);
505 	return 1;
506 }
507 
508 #endif /* (ELFSIZE == 32 && BOOT_ELF32) || (ELFSIZE == 64 && BOOT_ELF64) */
509