xref: /netbsd-src/sys/lib/libsa/loadfile_elf32.c (revision e89934bbf778a6d6d6894877c4da59d0c7835b0f)
1 /* $NetBSD: loadfile_elf32.c,v 1.34 2017/01/06 09:14:36 maxv Exp $ */
2 
3 /*
4  * Copyright (c) 1997, 2008 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  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /* If not included by exec_elf64.c, ELFSIZE won't be defined. */
34 #ifndef ELFSIZE
35 #define	ELFSIZE	32
36 #endif
37 
38 #ifdef _STANDALONE
39 #include <lib/libsa/stand.h>
40 #include <lib/libkern/libkern.h>
41 #else
42 #include <stdio.h>
43 #include <string.h>
44 #include <errno.h>
45 #include <stdlib.h>
46 #include <unistd.h>
47 #include <fcntl.h>
48 #include <err.h>
49 #endif
50 
51 #include <sys/param.h>
52 #include <sys/exec.h>
53 
54 #include "loadfile.h"
55 
56 #if ((ELFSIZE == 32) && defined(BOOT_ELF32)) || \
57     ((ELFSIZE == 64) && defined(BOOT_ELF64))
58 
59 #define	ELFROUND	(ELFSIZE / 8)
60 
61 #ifndef _STANDALONE
62 #include "byteorder.h"
63 
64 /*
65  * Byte swapping may be necessary in the non-_STANDLONE case because
66  * we may be built with a host compiler.
67  */
68 #define	E16(f)								\
69 	f = (bo == ELFDATA2LSB) ? sa_htole16(f) : sa_htobe16(f)
70 #define	E32(f)								\
71 	f = (bo == ELFDATA2LSB) ? sa_htole32(f) : sa_htobe32(f)
72 #define	E64(f)								\
73 	f = (bo == ELFDATA2LSB) ? sa_htole64(f) : sa_htobe64(f)
74 
75 #define	I16(f)								\
76 	f = (bo == ELFDATA2LSB) ? sa_le16toh(f) : sa_be16toh(f)
77 #define	I32(f)								\
78 	f = (bo == ELFDATA2LSB) ? sa_le32toh(f) : sa_be32toh(f)
79 #define	I64(f)								\
80 	f = (bo == ELFDATA2LSB) ? sa_le64toh(f) : sa_be64toh(f)
81 
82 static void
83 internalize_ehdr(Elf_Byte bo, Elf_Ehdr *ehdr)
84 {
85 
86 #if ELFSIZE == 32
87 	I16(ehdr->e_type);
88 	I16(ehdr->e_machine);
89 	I32(ehdr->e_version);
90 	I32(ehdr->e_entry);
91 	I32(ehdr->e_phoff);
92 	I32(ehdr->e_shoff);
93 	I32(ehdr->e_flags);
94 	I16(ehdr->e_ehsize);
95 	I16(ehdr->e_phentsize);
96 	I16(ehdr->e_phnum);
97 	I16(ehdr->e_shentsize);
98 	I16(ehdr->e_shnum);
99 	I16(ehdr->e_shstrndx);
100 #elif ELFSIZE == 64
101 	I16(ehdr->e_type);
102 	I16(ehdr->e_machine);
103 	I32(ehdr->e_version);
104 	I64(ehdr->e_entry);
105 	I64(ehdr->e_phoff);
106 	I64(ehdr->e_shoff);
107 	I32(ehdr->e_flags);
108 	I16(ehdr->e_ehsize);
109 	I16(ehdr->e_phentsize);
110 	I16(ehdr->e_phnum);
111 	I16(ehdr->e_shentsize);
112 	I16(ehdr->e_shnum);
113 	I16(ehdr->e_shstrndx);
114 #else
115 #error ELFSIZE is not 32 or 64
116 #endif
117 }
118 
119 static void
120 externalize_ehdr(Elf_Byte bo, Elf_Ehdr *ehdr)
121 {
122 
123 #if ELFSIZE == 32
124 	E16(ehdr->e_type);
125 	E16(ehdr->e_machine);
126 	E32(ehdr->e_version);
127 	E32(ehdr->e_entry);
128 	E32(ehdr->e_phoff);
129 	E32(ehdr->e_shoff);
130 	E32(ehdr->e_flags);
131 	E16(ehdr->e_ehsize);
132 	E16(ehdr->e_phentsize);
133 	E16(ehdr->e_phnum);
134 	E16(ehdr->e_shentsize);
135 	E16(ehdr->e_shnum);
136 	E16(ehdr->e_shstrndx);
137 #elif ELFSIZE == 64
138 	E16(ehdr->e_type);
139 	E16(ehdr->e_machine);
140 	E32(ehdr->e_version);
141 	E64(ehdr->e_entry);
142 	E64(ehdr->e_phoff);
143 	E64(ehdr->e_shoff);
144 	E32(ehdr->e_flags);
145 	E16(ehdr->e_ehsize);
146 	E16(ehdr->e_phentsize);
147 	E16(ehdr->e_phnum);
148 	E16(ehdr->e_shentsize);
149 	E16(ehdr->e_shnum);
150 	E16(ehdr->e_shstrndx);
151 #else
152 #error ELFSIZE is not 32 or 64
153 #endif
154 }
155 
156 static void
157 internalize_phdr(Elf_Byte bo, Elf_Phdr *phdr)
158 {
159 
160 #if ELFSIZE == 32
161 	I32(phdr->p_type);
162 	I32(phdr->p_offset);
163 	I32(phdr->p_vaddr);
164 	I32(phdr->p_paddr);
165 	I32(phdr->p_filesz);
166 	I32(phdr->p_memsz);
167 	I32(phdr->p_flags);
168 	I32(phdr->p_align);
169 #elif ELFSIZE == 64
170 	I32(phdr->p_type);
171 	I32(phdr->p_offset);
172 	I64(phdr->p_vaddr);
173 	I64(phdr->p_paddr);
174 	I64(phdr->p_filesz);
175 	I64(phdr->p_memsz);
176 	I64(phdr->p_flags);
177 	I64(phdr->p_align);
178 #else
179 #error ELFSIZE is not 32 or 64
180 #endif
181 }
182 
183 static void
184 internalize_shdr(Elf_Byte bo, Elf_Shdr *shdr)
185 {
186 
187 #if ELFSIZE == 32
188 	I32(shdr->sh_name);
189 	I32(shdr->sh_type);
190 	I32(shdr->sh_flags);
191 	I32(shdr->sh_addr);
192 	I32(shdr->sh_offset);
193 	I32(shdr->sh_size);
194 	I32(shdr->sh_link);
195 	I32(shdr->sh_info);
196 	I32(shdr->sh_addralign);
197 	I32(shdr->sh_entsize);
198 #elif ELFSIZE == 64
199 	I32(shdr->sh_name);
200 	I32(shdr->sh_type);
201 	I64(shdr->sh_flags);
202 	I64(shdr->sh_addr);
203 	I64(shdr->sh_offset);
204 	I64(shdr->sh_size);
205 	I32(shdr->sh_link);
206 	I32(shdr->sh_info);
207 	I64(shdr->sh_addralign);
208 	I64(shdr->sh_entsize);
209 #else
210 #error ELFSIZE is not 32 or 64
211 #endif
212 }
213 
214 static void
215 externalize_shdr(Elf_Byte bo, Elf_Shdr *shdr)
216 {
217 
218 #if ELFSIZE == 32
219 	E32(shdr->sh_name);
220 	E32(shdr->sh_type);
221 	E32(shdr->sh_flags);
222 	E32(shdr->sh_addr);
223 	E32(shdr->sh_offset);
224 	E32(shdr->sh_size);
225 	E32(shdr->sh_link);
226 	E32(shdr->sh_info);
227 	E32(shdr->sh_addralign);
228 	E32(shdr->sh_entsize);
229 #elif ELFSIZE == 64
230 	E32(shdr->sh_name);
231 	E32(shdr->sh_type);
232 	E64(shdr->sh_flags);
233 	E64(shdr->sh_addr);
234 	E64(shdr->sh_offset);
235 	E64(shdr->sh_size);
236 	E32(shdr->sh_link);
237 	E32(shdr->sh_info);
238 	E64(shdr->sh_addralign);
239 	E64(shdr->sh_entsize);
240 #else
241 #error ELFSIZE is not 32 or 64
242 #endif
243 }
244 #else /* _STANDALONE */
245 /*
246  * Byte swapping is never necessary in the _STANDALONE case because
247  * we are being built with the target compiler.
248  */
249 #define	internalize_ehdr(bo, ehdr)	/* nothing */
250 #define	externalize_ehdr(bo, ehdr)	/* nothing */
251 
252 #define	internalize_phdr(bo, phdr)	/* nothing */
253 
254 #define	internalize_shdr(bo, shdr)	/* nothing */
255 #define	externalize_shdr(bo, shdr)	/* nothing */
256 #endif /* _STANDALONE */
257 
258 #define IS_TEXT(p)	(p.p_flags & PF_X)
259 #define IS_DATA(p)	(p.p_flags & PF_W)
260 #define IS_BSS(p)	(p.p_filesz < p.p_memsz)
261 
262 /*
263  * Load the ELF binary into memory. Layout of the memory:
264  * +-----------------+------------+-----------------+-----------------+
265  * | KERNEL SEGMENTS | ELF HEADER | SECTION HEADERS | SYMBOL SECTIONS |
266  * +-----------------+------------+-----------------+-----------------+
267  * The KERNEL SEGMENTS start address is fixed by the segments themselves. We
268  * then map the rest by increasing maxp.
269  *
270  * The offsets of the SYMBOL SECTIONS are relative to the start address of the
271  * ELF HEADER. The shdr offset of ELF HEADER points to SECTION HEADERS.
272  *
273  * We just give the kernel a pointer to the ELF HEADER, which is enough for it
274  * to find the location and number of symbols by itself later.
275  */
276 
277 int
278 ELFNAMEEND(loadfile)(int fd, Elf_Ehdr *elf, u_long *marks, int flags)
279 {
280 	Elf_Shdr *shp;
281 	Elf_Phdr *phdr;
282 	int i, j;
283 	ssize_t sz;
284 	int first;
285 	Elf_Addr shpp;
286 	Elf_Addr minp = ~0, maxp = 0, pos = 0, elfp = 0;
287 	u_long offset = marks[MARK_START];
288 	ssize_t nr;
289 	struct __packed {
290 		Elf_Nhdr nh;
291 		uint8_t name[ELF_NOTE_NETBSD_NAMESZ + 1];
292 		uint8_t desc[ELF_NOTE_NETBSD_DESCSZ];
293 	} note;
294 	char *shstr = NULL;
295 	size_t shstrsz = 0;
296 	int boot_load_ctf = 1;
297 
298 	/* some ports dont use the offset */
299 	(void)&offset;
300 
301 	/* have not seen a data segment so far */
302 	marks[MARK_DATA] = 0;
303 
304 	internalize_ehdr(elf->e_ident[EI_DATA], elf);
305 
306 	sz = elf->e_phnum * sizeof(Elf_Phdr);
307 	phdr = ALLOC(sz);
308 
309 	if (lseek(fd, elf->e_phoff, SEEK_SET) == -1)  {
310 		WARN(("lseek phdr"));
311 		goto freephdr;
312 	}
313 	nr = read(fd, phdr, sz);
314 	if (nr == -1) {
315 		WARN(("read program headers"));
316 		goto freephdr;
317 	}
318 	if (nr != sz) {
319 		errno = EIO;
320 		WARN(("read program headers"));
321 		goto freephdr;
322 	}
323 
324 	for (first = 1, i = 0; i < elf->e_phnum; i++) {
325 		internalize_phdr(elf->e_ident[EI_DATA], &phdr[i]);
326 
327 #ifndef MD_LOADSEG /* Allow processor ABI specific segment loads */
328 #define MD_LOADSEG(a) /*CONSTCOND*/0
329 #endif
330 		if (MD_LOADSEG(&phdr[i]))
331 			goto loadseg;
332 
333 		if (phdr[i].p_type != PT_LOAD ||
334 		    (phdr[i].p_flags & (PF_W|PF_X)) == 0)
335 			continue;
336 
337 		if ((IS_TEXT(phdr[i]) && (flags & LOAD_TEXT)) ||
338 		    (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
339 		loadseg:
340 			/* XXX: Assume first address is lowest */
341 			if (marks[MARK_DATA] == 0 && IS_DATA(phdr[i]))
342 				marks[MARK_DATA] = LOADADDR(phdr[i].p_vaddr);
343 
344 			/* Read in segment. */
345 			PROGRESS(("%s%lu", first ? "" : "+",
346 			    (u_long)phdr[i].p_filesz));
347 
348 			if (lseek(fd, phdr[i].p_offset, SEEK_SET) == -1)  {
349 				WARN(("lseek text"));
350 				goto freephdr;
351 			}
352 			nr = READ(fd, phdr[i].p_vaddr, phdr[i].p_filesz);
353 			if (nr == -1) {
354 				WARN(("read text error"));
355 				goto freephdr;
356 			}
357 			if (nr != (ssize_t)phdr[i].p_filesz) {
358 				errno = EIO;
359 				WARN(("read text"));
360 				goto freephdr;
361 			}
362 			first = 0;
363 		}
364 		if ((IS_TEXT(phdr[i]) && (flags & (LOAD_TEXT|COUNT_TEXT))) ||
365 		    (IS_DATA(phdr[i]) && (flags & (LOAD_DATA|COUNT_DATA)))) {
366 			pos = phdr[i].p_vaddr;
367 			if (minp > pos)
368 				minp = pos;
369 			pos += phdr[i].p_filesz;
370 			if (maxp < pos)
371 				maxp = pos;
372 		}
373 
374 		/* Zero out bss. */
375 		if (IS_BSS(phdr[i]) && (flags & LOAD_BSS)) {
376 			PROGRESS(("+%lu",
377 			    (u_long)(phdr[i].p_memsz - phdr[i].p_filesz)));
378 			BZERO((phdr[i].p_vaddr + phdr[i].p_filesz),
379 			    phdr[i].p_memsz - phdr[i].p_filesz);
380 		}
381 		if (IS_BSS(phdr[i]) && (flags & (LOAD_BSS|COUNT_BSS))) {
382 			pos += phdr[i].p_memsz - phdr[i].p_filesz;
383 			if (maxp < pos)
384 				maxp = pos;
385 		}
386 	}
387 	DEALLOC(phdr, sz);
388 
389 	/*
390 	 * Copy the ELF and section headers.
391 	 */
392 	maxp = roundup(maxp, ELFROUND);
393 	if (flags & (LOAD_HDR|COUNT_HDR)) {
394 		elfp = maxp;
395 		maxp += sizeof(Elf_Ehdr);
396 	}
397 
398 	if (flags & (LOAD_SYM|COUNT_SYM)) {
399 		if (lseek(fd, elf->e_shoff, SEEK_SET) == -1)  {
400 			WARN(("lseek section headers"));
401 			return 1;
402 		}
403 		sz = elf->e_shnum * sizeof(Elf_Shdr);
404 
405 		shp = ALLOC(sz);
406 
407 		nr = read(fd, shp, sz);
408 		if (nr == -1) {
409 			WARN(("read section headers"));
410 			goto freeshp;
411 		}
412 		if (nr != sz) {
413 			errno = EIO;
414 			WARN(("read section headers"));
415 			goto freeshp;
416 		}
417 
418 		shpp = maxp;
419 		maxp += roundup(sz, ELFROUND);
420 
421 #ifndef _STANDALONE
422 		/* Internalize the section headers. */
423 		for (i = 0; i < elf->e_shnum; i++)
424 			internalize_shdr(elf->e_ident[EI_DATA], &shp[i]);
425 #endif
426 
427 		/*
428 		 * First load the section names section.
429 		 */
430 		if (boot_load_ctf && (elf->e_shstrndx != 0)) {
431 			if (flags & LOAD_SYM) {
432 				if (lseek(fd, shp[elf->e_shstrndx].sh_offset,
433 				    SEEK_SET) == -1) {
434 					WARN(("lseek symbols"));
435 					goto freeshp;
436 				}
437 				nr = READ(fd, maxp,
438 				    shp[elf->e_shstrndx].sh_size);
439 				if (nr == -1) {
440 					WARN(("read symbols"));
441 					goto freeshp;
442 				}
443 				if (nr !=
444 				    (ssize_t)shp[elf->e_shstrndx].sh_size) {
445 					errno = EIO;
446 					WARN(("read symbols"));
447 					goto freeshp;
448 				}
449 
450 				shstr = ALLOC(shp[elf->e_shstrndx].sh_size);
451 				shstrsz = shp[elf->e_shstrndx].sh_size;
452 				if (lseek(fd, shp[elf->e_shstrndx].sh_offset,
453 				    SEEK_SET) == -1) {
454 					WARN(("lseek symbols"));
455 					goto freeshp;
456 				}
457 				nr = read(fd, shstr,
458 				    shp[elf->e_shstrndx].sh_size);
459 				if (nr == -1) {
460 					WARN(("read symbols"));
461 					goto freeshp;
462 				}
463 			}
464 			shp[elf->e_shstrndx].sh_offset = maxp - elfp;
465 			maxp += roundup(shp[elf->e_shstrndx].sh_size, ELFROUND);
466 		}
467 
468 		/*
469 		 * Now load the symbol sections themselves.  Make sure
470 		 * the sections are aligned. Don't bother with any
471 		 * string table that isn't referenced by a symbol
472 		 * table.
473 		 */
474 		for (first = 1, i = 0; i < elf->e_shnum; i++) {
475 			if (i == elf->e_shstrndx) {
476 				/* already loaded this section */
477 				continue;
478 			}
479 			switch (shp[i].sh_type) {
480 			case SHT_PROGBITS:
481 				if (boot_load_ctf && shstr) {
482 					/* got a CTF section? */
483 					if (strncmp(".SUNW_ctf",
484 					    &shstr[shp[i].sh_name], 10) == 0) {
485 						goto havesym;
486 					}
487 				}
488 
489 				/* Not loading this, so zero out the offset. */
490 				shp[i].sh_offset = 0;
491 				break;
492 			case SHT_STRTAB:
493 				for (j = 0; j < elf->e_shnum; j++)
494 					if (shp[j].sh_type == SHT_SYMTAB &&
495 					    shp[j].sh_link == (unsigned int)i)
496 						goto havesym;
497 				/* FALLTHROUGH */
498 			default:
499 				/* Not loading this, so zero out the offset. */
500 				shp[i].sh_offset = 0;
501 				break;
502 			havesym:
503 			case SHT_SYMTAB:
504 				if (flags & LOAD_SYM) {
505 					PROGRESS(("%s%ld", first ? " [" : "+",
506 					    (u_long)shp[i].sh_size));
507 					if (lseek(fd, shp[i].sh_offset,
508 					    SEEK_SET) == -1) {
509 						WARN(("lseek symbols"));
510 						goto freeshp;
511 					}
512 					nr = READ(fd, maxp, shp[i].sh_size);
513 					if (nr == -1) {
514 						WARN(("read symbols"));
515 						goto freeshp;
516 					}
517 					if (nr != (ssize_t)shp[i].sh_size) {
518 						errno = EIO;
519 						WARN(("read symbols"));
520 						goto freeshp;
521 					}
522 				}
523 				shp[i].sh_offset = maxp - elfp;
524 				maxp += roundup(shp[i].sh_size, ELFROUND);
525 				first = 0;
526 				break;
527 			case SHT_NOTE:
528 				if ((flags & LOAD_NOTE) == 0)
529 					break;
530 				if (shp[i].sh_size < sizeof(note)) {
531 					shp[i].sh_offset = 0;
532 					break;
533 				}
534 				if (lseek(fd, shp[i].sh_offset, SEEK_SET)
535 				    == -1) {
536 					WARN(("lseek note"));
537 					goto freeshp;
538 				}
539 				nr = read(fd, &note, sizeof(note));
540 				if (nr == -1) {
541 					WARN(("read note"));
542 					goto freeshp;
543 				}
544 				if (note.nh.n_namesz ==
545 				    ELF_NOTE_NETBSD_NAMESZ &&
546 				    note.nh.n_descsz ==
547 				    ELF_NOTE_NETBSD_DESCSZ &&
548 				    note.nh.n_type ==
549 				    ELF_NOTE_TYPE_NETBSD_TAG &&
550 				    memcmp(note.name, ELF_NOTE_NETBSD_NAME,
551 				    sizeof(note.name)) == 0) {
552 					memcpy(&netbsd_version, &note.desc,
553 					    sizeof(netbsd_version));
554 				}
555 				shp[i].sh_offset = 0;
556 				break;
557 			}
558 		}
559 		if (flags & LOAD_SYM) {
560 #ifndef _STANDALONE
561 			/* Externalize the section headers. */
562 			for (i = 0; i < elf->e_shnum; i++)
563 				externalize_shdr(elf->e_ident[EI_DATA],
564 				    &shp[i]);
565 #endif
566 			BCOPY(shp, shpp, sz);
567 
568 			if (first == 0)
569 				PROGRESS(("]"));
570 		}
571 		DEALLOC(shp, sz);
572 	}
573 
574 	if (shstr) {
575 	    DEALLOC(shstr, shstrsz);
576 	}
577 
578 	/*
579 	 * Frob the copied ELF header to give information relative
580 	 * to elfp.
581 	 */
582 	if (flags & LOAD_HDR) {
583 		elf->e_phoff = 0;
584 		elf->e_shoff = sizeof(Elf_Ehdr);
585 		elf->e_phentsize = 0;
586 		elf->e_phnum = 0;
587 		externalize_ehdr(elf->e_ident[EI_DATA], elf);
588 		BCOPY(elf, elfp, sizeof(*elf));
589 		internalize_ehdr(elf->e_ident[EI_DATA], elf);
590 	}
591 
592 	marks[MARK_START] = LOADADDR(minp);
593 	marks[MARK_ENTRY] = LOADADDR(elf->e_entry);
594 	/*
595 	 * Since there can be more than one symbol section in the code
596 	 * and we need to find strtab too in order to do anything
597 	 * useful with the symbols, we just pass the whole elf
598 	 * header back and we let the kernel debugger find the
599 	 * location and number of symbols by itself.
600 	 */
601 	marks[MARK_NSYM] = 1;	/* XXX: Kernel needs >= 0 */
602 	marks[MARK_SYM] = LOADADDR(elfp);
603 	marks[MARK_END] = LOADADDR(maxp);
604 	return 0;
605 
606 freephdr:
607 	DEALLOC(phdr, sz);
608 	return 1;
609 
610 freeshp:
611 	DEALLOC(shp, sz);
612 	return 1;
613 }
614 
615 #ifdef TEST
616 #include <stdlib.h>
617 #include <fcntl.h>
618 #include <err.h>
619 #include <stdio.h>
620 u_int32_t netbsd_version;
621 int
622 main(int argc, char *argv[])
623 {
624 	int fd;
625 	u_long marks[MARK_MAX];
626 	Elf_Ehdr elf;
627 	if (argc != 2) {
628 		(void)fprintf(stderr, "Usage: %s <file>\n", getprogname());
629 		return 1;
630 	}
631 	if ((fd = open(argv[1], O_RDONLY)) == -1)
632 		err(1, "Can't open `%s'", argv[1]);
633 	if (read(fd, &elf, sizeof(elf)) != sizeof(elf))
634 		err(1, "Can't read `%s'", argv[1]);
635 	memset(marks, 0, sizeof(marks));
636 	marks[MARK_START] = (u_long)malloc(2LL * 1024 * 2024 * 1024);
637 	ELFNAMEEND(loadfile)(fd, &elf, marks, LOAD_ALL);
638 	printf("%d\n", netbsd_version);
639 	return 0;
640 }
641 #endif
642 
643 #endif /* (ELFSIZE == 32 && BOOT_ELF32) || (ELFSIZE == 64 && BOOT_ELF64) */
644