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