1 /* $NetBSD: loadfile_elf32.c,v 1.23 2008/05/20 14:41:06 ad 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
)
266 paddr_t minp
= ~0, maxp
= 0, pos
= 0;
267 paddr_t offset
= marks
[MARK_START
], shpp
, elfp
= 0;
271 uint8_t name
[ELF_NOTE_NETBSD_NAMESZ
+ 1];
272 uint8_t desc
[ELF_NOTE_NETBSD_DESCSZ
];
275 /* some ports dont use the offset */
278 internalize_ehdr(elf
->e_ident
[EI_DATA
], elf
);
280 sz
= elf
->e_phnum
* sizeof(Elf_Phdr
);
283 if (lseek(fd
, elf
->e_phoff
, SEEK_SET
) == -1) {
284 WARN(("lseek phdr"));
287 nr
= read(fd
, phdr
, sz
);
289 WARN(("read program headers"));
294 WARN(("read program headers"));
298 for (first
= 1, i
= 0; i
< elf
->e_phnum
; i
++) {
299 internalize_phdr(elf
->e_ident
[EI_DATA
], &phdr
[i
]);
301 #ifndef MD_LOADSEG /* Allow processor ABI specific segment loads */
302 #define MD_LOADSEG(a) /*CONSTCOND*/0
304 if (MD_LOADSEG(&phdr
[i
]))
307 if (phdr
[i
].p_type
!= PT_LOAD
||
308 (phdr
[i
].p_flags
& (PF_W
|PF_X
)) == 0)
311 #define IS_TEXT(p) (p.p_flags & PF_X)
312 #define IS_DATA(p) (p.p_flags & PF_W)
313 #define IS_BSS(p) (p.p_filesz < p.p_memsz)
315 * XXX: Assume first address is lowest
317 if ((IS_TEXT(phdr
[i
]) && (flags
& LOAD_TEXT
)) ||
318 (IS_DATA(phdr
[i
]) && (flags
& LOAD_DATA
))) {
321 if (marks
[MARK_DATA
] == 0 && IS_DATA(phdr
[i
]))
322 marks
[MARK_DATA
] = LOADADDR(phdr
[i
].p_vaddr
);
324 /* Read in segment. */
325 PROGRESS(("%s%lu", first
? "" : "+",
326 (u_long
)phdr
[i
].p_filesz
));
328 if (lseek(fd
, phdr
[i
].p_offset
, SEEK_SET
) == -1) {
329 WARN(("lseek text"));
332 nr
= READ(fd
, phdr
[i
].p_vaddr
, phdr
[i
].p_filesz
);
334 WARN(("read text error"));
337 if (nr
!= (ssize_t
)phdr
[i
].p_filesz
) {
345 if ((IS_TEXT(phdr
[i
]) && (flags
& (LOAD_TEXT
|COUNT_TEXT
))) ||
346 (IS_DATA(phdr
[i
]) && (flags
& (LOAD_DATA
|COUNT_TEXT
)))) {
347 pos
= phdr
[i
].p_vaddr
;
350 pos
+= phdr
[i
].p_filesz
;
356 if (IS_BSS(phdr
[i
]) && (flags
& LOAD_BSS
)) {
358 (u_long
)(phdr
[i
].p_memsz
- phdr
[i
].p_filesz
)));
359 BZERO((phdr
[i
].p_vaddr
+ phdr
[i
].p_filesz
),
360 phdr
[i
].p_memsz
- phdr
[i
].p_filesz
);
362 if (IS_BSS(phdr
[i
]) && (flags
& (LOAD_BSS
|COUNT_BSS
))) {
363 pos
+= phdr
[i
].p_memsz
- phdr
[i
].p_filesz
;
371 * Copy the ELF and section headers.
373 maxp
= roundup(maxp
, ELFROUND
);
374 if (flags
& (LOAD_HDR
|COUNT_HDR
)) {
376 maxp
+= sizeof(Elf_Ehdr
);
379 if (flags
& (LOAD_SYM
|COUNT_SYM
)) {
380 if (lseek(fd
, elf
->e_shoff
, SEEK_SET
) == -1) {
381 WARN(("lseek section headers"));
384 sz
= elf
->e_shnum
* sizeof(Elf_Shdr
);
388 nr
= read(fd
, shp
, sz
);
390 WARN(("read section headers"));
395 WARN(("read section headers"));
400 maxp
+= roundup(sz
, ELFROUND
);
403 /* Internalize the section headers. */
404 for (i
= 0; i
< elf
->e_shnum
; i
++)
405 internalize_shdr(elf
->e_ident
[EI_DATA
], &shp
[i
]);
406 #endif /* ! _STANDALONE */
409 * Now load the symbol sections themselves. Make sure
410 * the sections are aligned. Don't bother with any
411 * string table that isn't referenced by a symbol
414 for (first
= 1, i
= 0; i
< elf
->e_shnum
; i
++) {
415 switch (shp
[i
].sh_type
) {
417 for (j
= 0; j
< elf
->e_shnum
; j
++)
418 if (shp
[j
].sh_type
== SHT_SYMTAB
&&
419 shp
[j
].sh_link
== (unsigned int)i
)
423 /* Not loading this, so zero out the offset. */
424 shp
[i
].sh_offset
= 0;
428 if (flags
& LOAD_SYM
) {
429 PROGRESS(("%s%ld", first
? " [" : "+",
430 (u_long
)shp
[i
].sh_size
));
431 if (lseek(fd
, shp
[i
].sh_offset
,
433 WARN(("lseek symbols"));
436 nr
= READ(fd
, maxp
, shp
[i
].sh_size
);
438 WARN(("read symbols"));
441 if (nr
!= (ssize_t
)shp
[i
].sh_size
) {
443 WARN(("read symbols"));
447 shp
[i
].sh_offset
= maxp
- elfp
;
448 maxp
+= roundup(shp
[i
].sh_size
, ELFROUND
);
452 if ((flags
& LOAD_NOTE
) == 0)
454 if (shp
[i
].sh_size
< sizeof(note
)) {
455 shp
[i
].sh_offset
= 0;
458 if (lseek(fd
, shp
[i
].sh_offset
, SEEK_SET
)
460 WARN(("lseek note"));
463 nr
= read(fd
, ¬e
, sizeof(note
));
468 if (note
.nh
.n_namesz
==
469 ELF_NOTE_NETBSD_NAMESZ
&&
471 ELF_NOTE_NETBSD_DESCSZ
&&
473 ELF_NOTE_TYPE_NETBSD_TAG
&&
474 memcmp(note
.name
, ELF_NOTE_NETBSD_NAME
,
475 sizeof(note
.name
)) == 0) {
476 memcpy(&netbsd_version
, ¬e
.desc
,
477 sizeof(netbsd_version
));
479 shp
[i
].sh_offset
= 0;
482 /* Since we don't load .shstrtab, zero the name. */
485 if (flags
& LOAD_SYM
) {
487 /* Externalize the section headers. */
488 for (i
= 0; i
< elf
->e_shnum
; i
++)
489 externalize_shdr(elf
->e_ident
[EI_DATA
],
491 #endif /* ! _STANDALONE */
492 BCOPY(shp
, shpp
, sz
);
501 * Frob the copied ELF header to give information relative
504 if (flags
& LOAD_HDR
) {
506 elf
->e_shoff
= sizeof(Elf_Ehdr
);
507 elf
->e_phentsize
= 0;
509 elf
->e_shstrndx
= SHN_UNDEF
;
510 externalize_ehdr(elf
->e_ident
[EI_DATA
], elf
);
511 BCOPY(elf
, elfp
, sizeof(*elf
));
512 internalize_ehdr(elf
->e_ident
[EI_DATA
], elf
);
515 marks
[MARK_START
] = LOADADDR(minp
);
516 marks
[MARK_ENTRY
] = LOADADDR(elf
->e_entry
);
518 * Since there can be more than one symbol section in the code
519 * and we need to find strtab too in order to do anything
520 * useful with the symbols, we just pass the whole elf
521 * header back and we let the kernel debugger find the
522 * location and number of symbols by itself.
524 marks
[MARK_NSYM
] = 1; /* XXX: Kernel needs >= 0 */
525 marks
[MARK_SYM
] = LOADADDR(elfp
);
526 marks
[MARK_END
] = LOADADDR(maxp
);
541 u_int32_t netbsd_version
;
543 main(int argc
, char *argv
[])
546 u_long marks
[MARK_MAX
];
549 (void)fprintf(stderr
, "Usage: %s <file>\n", getprogname());
552 if ((fd
= open(argv
[1], O_RDONLY
)) == -1)
553 err(1, "Can't open `%s'", argv
[1]);
554 if (read(fd
, &elf
, sizeof(elf
)) != sizeof(elf
))
555 err(1, "Can't read `%s'", argv
[1]);
556 memset(marks
, 0, sizeof(marks
));
557 marks
[MARK_START
] = (u_long
)malloc(2LL * 1024 * 2024 * 1024);
558 ELFNAMEEND(loadfile
)(fd
, &elf
, marks
, LOAD_ALL
);
559 printf("%d\n", netbsd_version
);
564 #endif /* (ELFSIZE == 32 && BOOT_ELF32) || (ELFSIZE == 64 && BOOT_ELF64) */