1 /* $NetBSD: loadfile_elf32.c,v 1.29 2011/02/17 21:15:31 christos Exp $ */
4 * Copyright (c) 1997, 2008 The NetBSD Foundation, Inc.
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.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
33 /* If not included by exec_elf64.c, ELFSIZE won't be defined. */
39 #include <lib/libsa/stand.h>
40 #include <lib/libkern/libkern.h>
51 #include <sys/param.h>
56 #if ((ELFSIZE == 32) && defined(BOOT_ELF32)) || \
57 ((ELFSIZE == 64) && defined(BOOT_ELF64))
59 #define ELFROUND (ELFSIZE / 8)
62 #include "byteorder.h"
65 * Byte swapping may be necessary in the non-_STANDLONE case because
66 * we may be built with a host compiler.
69 f = (bo == ELFDATA2LSB) ? sa_htole16(f) : sa_htobe16(f)
71 f = (bo == ELFDATA2LSB) ? sa_htole32(f) : sa_htobe32(f)
73 f = (bo == ELFDATA2LSB) ? sa_htole64(f) : sa_htobe64(f)
76 f = (bo == ELFDATA2LSB) ? sa_le16toh(f) : sa_be16toh(f)
78 f = (bo == ELFDATA2LSB) ? sa_le32toh(f) : sa_be32toh(f)
80 f = (bo == ELFDATA2LSB) ? sa_le64toh(f) : sa_be64toh(f)
83 internalize_ehdr(Elf_Byte bo
, Elf_Ehdr
*ehdr
)
95 I16(ehdr
->e_phentsize
);
97 I16(ehdr
->e_shentsize
);
99 I16(ehdr
->e_shstrndx
);
102 I16(ehdr
->e_machine
);
103 I32(ehdr
->e_version
);
109 I16(ehdr
->e_phentsize
);
111 I16(ehdr
->e_shentsize
);
113 I16(ehdr
->e_shstrndx
);
115 #error ELFSIZE is not 32 or 64
120 externalize_ehdr(Elf_Byte bo
, Elf_Ehdr
*ehdr
)
125 E16(ehdr
->e_machine
);
126 E32(ehdr
->e_version
);
132 E16(ehdr
->e_phentsize
);
134 E16(ehdr
->e_shentsize
);
136 E16(ehdr
->e_shstrndx
);
139 E16(ehdr
->e_machine
);
140 E32(ehdr
->e_version
);
146 E16(ehdr
->e_phentsize
);
148 E16(ehdr
->e_shentsize
);
150 E16(ehdr
->e_shstrndx
);
152 #error ELFSIZE is not 32 or 64
157 internalize_phdr(Elf_Byte bo
, Elf_Phdr
*phdr
)
179 #error ELFSIZE is not 32 or 64
184 internalize_shdr(Elf_Byte bo
, Elf_Shdr
*shdr
)
192 I32(shdr
->sh_offset
);
196 I32(shdr
->sh_addralign
);
197 I32(shdr
->sh_entsize
);
203 I64(shdr
->sh_offset
);
207 I64(shdr
->sh_addralign
);
208 I64(shdr
->sh_entsize
);
210 #error ELFSIZE is not 32 or 64
215 externalize_shdr(Elf_Byte bo
, Elf_Shdr
*shdr
)
223 E32(shdr
->sh_offset
);
227 E32(shdr
->sh_addralign
);
228 E32(shdr
->sh_entsize
);
234 E64(shdr
->sh_offset
);
238 E64(shdr
->sh_addralign
);
239 E64(shdr
->sh_entsize
);
241 #error ELFSIZE is not 32 or 64
244 #else /* _STANDALONE */
246 * Byte swapping is never necessary in the _STANDALONE case because
247 * we are being built with the target compiler.
249 #define internalize_ehdr(bo, ehdr) /* nothing */
250 #define externalize_ehdr(bo, ehdr) /* nothing */
252 #define internalize_phdr(bo, phdr) /* nothing */
254 #define internalize_shdr(bo, shdr) /* nothing */
255 #define externalize_shdr(bo, shdr) /* nothing */
256 #endif /* _STANDALONE */
259 ELFNAMEEND(loadfile
)(int fd
, Elf_Ehdr
*elf
, u_long
*marks
, int flags
)
267 Elf_Addr minp
= ~0, maxp
= 0, pos
= 0, elfp
= 0;
268 u_long offset
= marks
[MARK_START
];
272 uint8_t name
[ELF_NOTE_NETBSD_NAMESZ
+ 1];
273 uint8_t desc
[ELF_NOTE_NETBSD_DESCSZ
];
276 int boot_load_ctf
= 1;
278 /* some ports dont use the offset */
281 internalize_ehdr(elf
->e_ident
[EI_DATA
], elf
);
283 sz
= elf
->e_phnum
* sizeof(Elf_Phdr
);
286 if (lseek(fd
, elf
->e_phoff
, SEEK_SET
) == -1) {
287 WARN(("lseek phdr"));
290 nr
= read(fd
, phdr
, sz
);
292 WARN(("read program headers"));
297 WARN(("read program headers"));
301 for (first
= 1, i
= 0; i
< elf
->e_phnum
; i
++) {
302 internalize_phdr(elf
->e_ident
[EI_DATA
], &phdr
[i
]);
304 #ifndef MD_LOADSEG /* Allow processor ABI specific segment loads */
305 #define MD_LOADSEG(a) /*CONSTCOND*/0
307 if (MD_LOADSEG(&phdr
[i
]))
310 if (phdr
[i
].p_type
!= PT_LOAD
||
311 (phdr
[i
].p_flags
& (PF_W
|PF_X
)) == 0)
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)
318 * XXX: Assume first address is lowest
320 if ((IS_TEXT(phdr
[i
]) && (flags
& LOAD_TEXT
)) ||
321 (IS_DATA(phdr
[i
]) && (flags
& LOAD_DATA
))) {
324 if (marks
[MARK_DATA
] == 0 && IS_DATA(phdr
[i
]))
325 marks
[MARK_DATA
] = LOADADDR(phdr
[i
].p_vaddr
);
327 /* Read in segment. */
328 PROGRESS(("%s%lu", first
? "" : "+",
329 (u_long
)phdr
[i
].p_filesz
));
331 if (lseek(fd
, phdr
[i
].p_offset
, SEEK_SET
) == -1) {
332 WARN(("lseek text"));
335 nr
= READ(fd
, phdr
[i
].p_vaddr
, phdr
[i
].p_filesz
);
337 WARN(("read text error"));
340 if (nr
!= (ssize_t
)phdr
[i
].p_filesz
) {
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
;
353 pos
+= phdr
[i
].p_filesz
;
359 if (IS_BSS(phdr
[i
]) && (flags
& LOAD_BSS
)) {
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
);
365 if (IS_BSS(phdr
[i
]) && (flags
& (LOAD_BSS
|COUNT_BSS
))) {
366 pos
+= phdr
[i
].p_memsz
- phdr
[i
].p_filesz
;
374 * Copy the ELF and section headers.
376 maxp
= roundup(maxp
, ELFROUND
);
377 if (flags
& (LOAD_HDR
|COUNT_HDR
)) {
379 maxp
+= sizeof(Elf_Ehdr
);
382 if (flags
& (LOAD_SYM
|COUNT_SYM
)) {
383 if (lseek(fd
, elf
->e_shoff
, SEEK_SET
) == -1) {
384 WARN(("lseek section headers"));
387 sz
= elf
->e_shnum
* sizeof(Elf_Shdr
);
391 nr
= read(fd
, shp
, sz
);
393 WARN(("read section headers"));
398 WARN(("read section headers"));
403 maxp
+= roundup(sz
, ELFROUND
);
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 */
412 * First load the section names section.
414 if (boot_load_ctf
&& (elf
->e_shstrndx
!= 0)) {
415 if (flags
& LOAD_SYM
) {
416 if (lseek(fd
, shp
[elf
->e_shstrndx
].sh_offset
,
418 WARN(("lseek symbols"));
422 shp
[elf
->e_shstrndx
].sh_size
);
424 WARN(("read symbols"));
428 (ssize_t
)shp
[elf
->e_shstrndx
].sh_size
) {
430 WARN(("read symbols"));
434 shstr
= ALLOC(shp
[elf
->e_shstrndx
].sh_size
);
435 if (lseek(fd
, shp
[elf
->e_shstrndx
].sh_offset
,
437 WARN(("lseek symbols"));
441 shp
[elf
->e_shstrndx
].sh_size
);
443 WARN(("read symbols"));
447 shp
[elf
->e_shstrndx
].sh_offset
= maxp
- elfp
;
448 maxp
+= roundup(shp
[elf
->e_shstrndx
].sh_size
, ELFROUND
);
452 * Now load the symbol sections themselves. Make sure
453 * the sections are aligned. Don't bother with any
454 * string table that isn't referenced by a symbol
457 for (first
= 1, i
= 0; i
< elf
->e_shnum
; i
++) {
458 if (i
== elf
->e_shstrndx
) {
459 /* already loaded this section */
462 switch (shp
[i
].sh_type
) {
464 if (boot_load_ctf
&& shstr
) {
465 /* got a CTF section? */
466 if (strncmp(".SUNW_ctf",
467 &shstr
[shp
[i
].sh_name
],
473 /* Not loading this, so zero out the offset. */
474 shp
[i
].sh_offset
= 0;
477 for (j
= 0; j
< elf
->e_shnum
; j
++)
478 if (shp
[j
].sh_type
== SHT_SYMTAB
&&
479 shp
[j
].sh_link
== (unsigned int)i
)
483 /* Not loading this, so zero out the offset. */
484 shp
[i
].sh_offset
= 0;
488 if (flags
& LOAD_SYM
) {
489 PROGRESS(("%s%ld", first
? " [" : "+",
490 (u_long
)shp
[i
].sh_size
));
491 if (lseek(fd
, shp
[i
].sh_offset
,
493 WARN(("lseek symbols"));
496 nr
= READ(fd
, maxp
, shp
[i
].sh_size
);
498 WARN(("read symbols"));
501 if (nr
!= (ssize_t
)shp
[i
].sh_size
) {
503 WARN(("read symbols"));
507 shp
[i
].sh_offset
= maxp
- elfp
;
508 maxp
+= roundup(shp
[i
].sh_size
, ELFROUND
);
512 if ((flags
& LOAD_NOTE
) == 0)
514 if (shp
[i
].sh_size
< sizeof(note
)) {
515 shp
[i
].sh_offset
= 0;
518 if (lseek(fd
, shp
[i
].sh_offset
, SEEK_SET
)
520 WARN(("lseek note"));
523 nr
= read(fd
, ¬e
, sizeof(note
));
528 if (note
.nh
.n_namesz
==
529 ELF_NOTE_NETBSD_NAMESZ
&&
531 ELF_NOTE_NETBSD_DESCSZ
&&
533 ELF_NOTE_TYPE_NETBSD_TAG
&&
534 memcmp(note
.name
, ELF_NOTE_NETBSD_NAME
,
535 sizeof(note
.name
)) == 0) {
536 memcpy(&netbsd_version
, ¬e
.desc
,
537 sizeof(netbsd_version
));
539 shp
[i
].sh_offset
= 0;
543 if (flags
& LOAD_SYM
) {
545 /* Externalize the section headers. */
546 for (i
= 0; i
< elf
->e_shnum
; i
++)
547 externalize_shdr(elf
->e_ident
[EI_DATA
],
549 #endif /* ! _STANDALONE */
550 BCOPY(shp
, shpp
, sz
);
559 DEALLOC(shstr
, shp
[elf
->e_shstrndx
].sh_size
);
563 * Frob the copied ELF header to give information relative
566 if (flags
& LOAD_HDR
) {
568 elf
->e_shoff
= sizeof(Elf_Ehdr
);
569 elf
->e_phentsize
= 0;
571 externalize_ehdr(elf
->e_ident
[EI_DATA
], elf
);
572 BCOPY(elf
, elfp
, sizeof(*elf
));
573 internalize_ehdr(elf
->e_ident
[EI_DATA
], elf
);
576 marks
[MARK_START
] = LOADADDR(minp
);
577 marks
[MARK_ENTRY
] = LOADADDR(elf
->e_entry
);
579 * Since there can be more than one symbol section in the code
580 * and we need to find strtab too in order to do anything
581 * useful with the symbols, we just pass the whole elf
582 * header back and we let the kernel debugger find the
583 * location and number of symbols by itself.
585 marks
[MARK_NSYM
] = 1; /* XXX: Kernel needs >= 0 */
586 marks
[MARK_SYM
] = LOADADDR(elfp
);
587 marks
[MARK_END
] = LOADADDR(maxp
);
602 u_int32_t netbsd_version
;
604 main(int argc
, char *argv
[])
607 u_long marks
[MARK_MAX
];
610 (void)fprintf(stderr
, "Usage: %s <file>\n", getprogname());
613 if ((fd
= open(argv
[1], O_RDONLY
)) == -1)
614 err(1, "Can't open `%s'", argv
[1]);
615 if (read(fd
, &elf
, sizeof(elf
)) != sizeof(elf
))
616 err(1, "Can't read `%s'", argv
[1]);
617 memset(marks
, 0, sizeof(marks
));
618 marks
[MARK_START
] = (u_long
)malloc(2LL * 1024 * 2024 * 1024);
619 ELFNAMEEND(loadfile
)(fd
, &elf
, marks
, LOAD_ALL
);
620 printf("%d\n", netbsd_version
);
625 #endif /* (ELFSIZE == 32 && BOOT_ELF32) || (ELFSIZE == 64 && BOOT_ELF64) */