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