NetBSD/sys/lib/libsa/loadfile_elf32.c

828 lines
20 KiB
C

/* $NetBSD: loadfile_elf32.c,v 1.59 2020/09/13 13:31:36 jmcneill Exp $ */
/*
* Copyright (c) 1997, 2008, 2017 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center, by Christos Zoulas, and by Maxime Villard.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* If not included by exec_elf64.c, ELFSIZE won't be defined. */
#ifndef ELFSIZE
#define ELFSIZE 32
#endif
#ifdef _STANDALONE
#include <lib/libsa/stand.h>
#include <lib/libkern/libkern.h>
#else
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <err.h>
#endif
#include <sys/param.h>
#include <sys/exec.h>
#include "loadfile.h"
#if ((ELFSIZE == 32) && defined(BOOT_ELF32)) || \
((ELFSIZE == 64) && defined(BOOT_ELF64))
#define ELFROUND (ELFSIZE / 8)
#ifndef _STANDALONE
/*
* Byte swapping may be necessary in the non-_STANDLONE case because
* we may be built with a host compiler.
*/
#ifndef LIBSA_BIENDIAN_SUPPORT
#define LIBSA_BIENDIAN_SUPPORT
#endif
#endif
#ifdef LIBSA_BIENDIAN_SUPPORT
#include "byteorder.h"
#define E16(f) \
f = (bo == ELFDATA2LSB) ? sa_htole16(f) : sa_htobe16(f)
#define E32(f) \
f = (bo == ELFDATA2LSB) ? sa_htole32(f) : sa_htobe32(f)
#define E64(f) \
f = (bo == ELFDATA2LSB) ? sa_htole64(f) : sa_htobe64(f)
#define I16(f) \
f = (bo == ELFDATA2LSB) ? sa_le16toh(f) : sa_be16toh(f)
#define I32(f) \
f = (bo == ELFDATA2LSB) ? sa_le32toh(f) : sa_be32toh(f)
#define I64(f) \
f = (bo == ELFDATA2LSB) ? sa_le64toh(f) : sa_be64toh(f)
static void
internalize_ehdr(Elf_Byte bo, Elf_Ehdr *ehdr)
{
#if ELFSIZE == 32
I16(ehdr->e_type);
I16(ehdr->e_machine);
I32(ehdr->e_version);
I32(ehdr->e_entry);
I32(ehdr->e_phoff);
I32(ehdr->e_shoff);
I32(ehdr->e_flags);
I16(ehdr->e_ehsize);
I16(ehdr->e_phentsize);
I16(ehdr->e_phnum);
I16(ehdr->e_shentsize);
I16(ehdr->e_shnum);
I16(ehdr->e_shstrndx);
#elif ELFSIZE == 64
I16(ehdr->e_type);
I16(ehdr->e_machine);
I32(ehdr->e_version);
I64(ehdr->e_entry);
I64(ehdr->e_phoff);
I64(ehdr->e_shoff);
I32(ehdr->e_flags);
I16(ehdr->e_ehsize);
I16(ehdr->e_phentsize);
I16(ehdr->e_phnum);
I16(ehdr->e_shentsize);
I16(ehdr->e_shnum);
I16(ehdr->e_shstrndx);
#else
#error ELFSIZE is not 32 or 64
#endif
}
static void
externalize_ehdr(Elf_Byte bo, Elf_Ehdr *ehdr)
{
#if ELFSIZE == 32
E16(ehdr->e_type);
E16(ehdr->e_machine);
E32(ehdr->e_version);
E32(ehdr->e_entry);
E32(ehdr->e_phoff);
E32(ehdr->e_shoff);
E32(ehdr->e_flags);
E16(ehdr->e_ehsize);
E16(ehdr->e_phentsize);
E16(ehdr->e_phnum);
E16(ehdr->e_shentsize);
E16(ehdr->e_shnum);
E16(ehdr->e_shstrndx);
#elif ELFSIZE == 64
E16(ehdr->e_type);
E16(ehdr->e_machine);
E32(ehdr->e_version);
E64(ehdr->e_entry);
E64(ehdr->e_phoff);
E64(ehdr->e_shoff);
E32(ehdr->e_flags);
E16(ehdr->e_ehsize);
E16(ehdr->e_phentsize);
E16(ehdr->e_phnum);
E16(ehdr->e_shentsize);
E16(ehdr->e_shnum);
E16(ehdr->e_shstrndx);
#else
#error ELFSIZE is not 32 or 64
#endif
}
static void
internalize_phdr(Elf_Byte bo, Elf_Phdr *phdr)
{
#if ELFSIZE == 32
I32(phdr->p_type);
I32(phdr->p_offset);
I32(phdr->p_vaddr);
I32(phdr->p_paddr);
I32(phdr->p_filesz);
I32(phdr->p_memsz);
I32(phdr->p_flags);
I32(phdr->p_align);
#elif ELFSIZE == 64
I32(phdr->p_type);
I64(phdr->p_offset);
I64(phdr->p_vaddr);
I64(phdr->p_paddr);
I64(phdr->p_filesz);
I64(phdr->p_memsz);
I32(phdr->p_flags);
I64(phdr->p_align);
#else
#error ELFSIZE is not 32 or 64
#endif
}
static void
internalize_shdr(Elf_Byte bo, Elf_Shdr *shdr)
{
#if ELFSIZE == 32
I32(shdr->sh_name);
I32(shdr->sh_type);
I32(shdr->sh_flags);
I32(shdr->sh_addr);
I32(shdr->sh_offset);
I32(shdr->sh_size);
I32(shdr->sh_link);
I32(shdr->sh_info);
I32(shdr->sh_addralign);
I32(shdr->sh_entsize);
#elif ELFSIZE == 64
I32(shdr->sh_name);
I32(shdr->sh_type);
I64(shdr->sh_flags);
I64(shdr->sh_addr);
I64(shdr->sh_offset);
I64(shdr->sh_size);
I32(shdr->sh_link);
I32(shdr->sh_info);
I64(shdr->sh_addralign);
I64(shdr->sh_entsize);
#else
#error ELFSIZE is not 32 or 64
#endif
}
static void
externalize_shdr(Elf_Byte bo, Elf_Shdr *shdr)
{
#if ELFSIZE == 32
E32(shdr->sh_name);
E32(shdr->sh_type);
E32(shdr->sh_flags);
E32(shdr->sh_addr);
E32(shdr->sh_offset);
E32(shdr->sh_size);
E32(shdr->sh_link);
E32(shdr->sh_info);
E32(shdr->sh_addralign);
E32(shdr->sh_entsize);
#elif ELFSIZE == 64
E32(shdr->sh_name);
E32(shdr->sh_type);
E64(shdr->sh_flags);
E64(shdr->sh_addr);
E64(shdr->sh_offset);
E64(shdr->sh_size);
E32(shdr->sh_link);
E32(shdr->sh_info);
E64(shdr->sh_addralign);
E64(shdr->sh_entsize);
#else
#error ELFSIZE is not 32 or 64
#endif
}
#else /* LIBSA_BIENDIAN_SUPPORT */
/*
* Byte swapping is never necessary in the !LIBSA_BIENDIAN_SUPPORT case
* because we are being built with the target compiler.
*/
#define internalize_ehdr(bo, ehdr) /* nothing */
#define externalize_ehdr(bo, ehdr) /* nothing */
#define internalize_phdr(bo, phdr) /* nothing */
#define internalize_shdr(bo, shdr) /* nothing */
#define externalize_shdr(bo, shdr) /* nothing */
#endif /* LIBSA_BIENDIAN_SUPPORT */
#define IS_TEXT(p) (p.p_flags & PF_X)
#define IS_DATA(p) ((p.p_flags & PF_X) == 0)
#define IS_BSS(p) (p.p_filesz < p.p_memsz)
#ifndef MD_LOADSEG /* Allow processor ABI specific segment loads */
#define MD_LOADSEG(a) /*CONSTCOND*/0
#endif
/* -------------------------------------------------------------------------- */
#define KERNALIGN_SMALL (1 << 12) /* XXX should depend on marks[] */
#define KERNALIGN_LARGE (1 << 21) /* XXX should depend on marks[] */
/*
* Read some data from a file, and put it in the bootloader memory (local).
*/
static int
ELFNAMEEND(readfile_local)(int fd, Elf_Off elfoff, void *addr, size_t size)
{
ssize_t nr;
if (lseek(fd, elfoff, SEEK_SET) == -1) {
WARN(("lseek section headers"));
return -1;
}
nr = read(fd, addr, size);
if (nr == -1) {
WARN(("read section headers"));
return -1;
}
if (nr != (ssize_t)size) {
errno = EIO;
WARN(("read section headers"));
return -1;
}
return 0;
}
/*
* Read some data from a file, and put it in wherever in memory (global).
*/
static int
ELFNAMEEND(readfile_global)(int fd, u_long offset, Elf_Off elfoff,
Elf_Addr addr, size_t size)
{
ssize_t nr;
/* some ports dont use the offset */
(void)&offset;
if (lseek(fd, elfoff, SEEK_SET) == -1) {
WARN(("lseek section"));
return -1;
}
nr = READ(fd, addr, size);
if (nr == -1) {
WARN(("read section"));
return -1;
}
if (nr != (ssize_t)size) {
errno = EIO;
WARN(("read section"));
return -1;
}
return 0;
}
/*
* Load a dynamic ELF binary into memory. Layout of the memory:
* +------------+--------------+------------+------------------------+
* | ELF HEADER | SECT HEADERS | KERN SECTS | REL/RELA/SYM/STR SECTS |
* +------------+--------------+------------+------------------------+
* The ELF HEADER start address is marks[MARK_END]. We then map the rest
* by increasing maxp. An alignment is enforced between the code sections.
*
* The offsets of the KERNEL and SYM+REL sections are relative to the start
* address of the ELF HEADER. We just give the kernel a pointer to the ELF
* HEADER, and we let the kernel find the location and number of symbols by
* itself.
*/
static int
ELFNAMEEND(loadfile_dynamic)(int fd, Elf_Ehdr *elf, u_long *marks, int flags)
{
const u_long offset = marks[MARK_START];
Elf_Shdr *shdr;
Elf_Addr shpp, addr;
int i, j, loaded;
size_t size, shdrsz, align;
Elf_Addr maxp, elfp = 0;
int ret;
maxp = marks[MARK_END] - offset;
internalize_ehdr(elf->e_ident[EI_DATA], elf);
if (elf->e_type != ET_REL) {
errno = EINVAL;
return 1;
}
/* Create a local copy of the SECTION HEADERS. */
shdrsz = elf->e_shnum * sizeof(Elf_Shdr);
shdr = ALLOC(shdrsz);
ret = ELFNAMEEND(readfile_local)(fd, elf->e_shoff, shdr, shdrsz);
if (ret == -1) {
goto out;
}
/*
* Load the ELF HEADER. Update the section offset, to be relative to
* elfp.
*/
elf->e_phoff = 0;
elf->e_shoff = sizeof(Elf_Ehdr);
elf->e_phentsize = 0;
elf->e_phnum = 0;
elfp = maxp;
externalize_ehdr(elf->e_ident[EI_DATA], elf);
BCOPY(elf, elfp, sizeof(*elf));
internalize_ehdr(elf->e_ident[EI_DATA], elf);
maxp += sizeof(Elf_Ehdr);
#ifdef LIBSA_BIENDIAN_SUPPORT
for (i = 0; i < elf->e_shnum; i++)
internalize_shdr(elf->e_ident[EI_DATA], &shdr[i]);
#endif
/* Save location of the SECTION HEADERS. */
shpp = maxp;
maxp += roundup(shdrsz, ELFROUND);
/*
* Load the KERNEL SECTIONS.
*/
maxp = roundup(maxp, KERNALIGN_SMALL);
for (i = 0; i < elf->e_shnum; i++) {
if (!(shdr[i].sh_flags & SHF_ALLOC)) {
continue;
}
size = (size_t)shdr[i].sh_size;
if (size <= KERNALIGN_SMALL) {
align = KERNALIGN_SMALL;
} else {
align = KERNALIGN_LARGE;
}
addr = roundup(maxp, align);
loaded = 0;
switch (shdr[i].sh_type) {
case SHT_NOBITS:
/* Zero out bss. */
BZERO(addr, size);
loaded = 1;
break;
case SHT_PROGBITS:
ret = ELFNAMEEND(readfile_global)(fd, offset,
shdr[i].sh_offset, addr, size);
if (ret == -1) {
goto out;
}
loaded = 1;
break;
default:
loaded = 0;
break;
}
if (loaded) {
shdr[i].sh_offset = addr - elfp;
maxp = roundup(addr + size, align);
}
}
maxp = roundup(maxp, KERNALIGN_LARGE);
/*
* Load the REL/RELA/SYM/STR SECTIONS.
*/
maxp = roundup(maxp, ELFROUND);
for (i = 0; i < elf->e_shnum; i++) {
addr = maxp;
size = (size_t)shdr[i].sh_size;
switch (shdr[i].sh_type) {
case SHT_STRTAB:
for (j = 0; j < elf->e_shnum; j++)
if (shdr[j].sh_type == SHT_SYMTAB &&
shdr[j].sh_link == (unsigned int)i)
goto havesym;
if (elf->e_shstrndx == i)
goto havesym;
/*
* Don't bother with any string table that isn't
* referenced by a symbol table.
*/
shdr[i].sh_offset = 0;
break;
havesym:
case SHT_REL:
case SHT_RELA:
case SHT_SYMTAB:
ret = ELFNAMEEND(readfile_global)(fd, offset,
shdr[i].sh_offset, addr, size);
if (ret == -1) {
goto out;
}
shdr[i].sh_offset = maxp - elfp;
maxp += roundup(size, ELFROUND);
break;
}
}
maxp = roundup(maxp, KERNALIGN_SMALL);
/*
* Finally, load the SECTION HEADERS.
*/
#ifdef LIBSA_BIENDIAN_SUPPORT
for (i = 0; i < elf->e_shnum; i++)
externalize_shdr(elf->e_ident[EI_DATA], &shdr[i]);
#endif
BCOPY(shdr, shpp, shdrsz);
DEALLOC(shdr, shdrsz);
/*
* Just update MARK_SYM and MARK_END without touching the rest.
*/
marks[MARK_SYM] = LOADADDR(elfp);
marks[MARK_END] = LOADADDR(maxp);
return 0;
out:
DEALLOC(shdr, shdrsz);
return 1;
}
/* -------------------------------------------------------------------------- */
/*
* See comment below. This function is in charge of loading the SECTION HEADERS.
*/
static int
ELFNAMEEND(loadsym)(int fd, Elf_Ehdr *elf, Elf_Addr maxp, Elf_Addr elfp,
u_long *marks, int flags, Elf_Addr *nmaxp)
{
const u_long offset = marks[MARK_START];
int boot_load_ctf = 1;
Elf_Shdr *shp;
Elf_Addr shpp;
char *shstr = NULL;
size_t sz;
size_t i, j, shstrsz = 0;
struct __packed {
Elf_Nhdr nh;
uint8_t name[ELF_NOTE_NETBSD_NAMESZ + 1];
uint8_t desc[ELF_NOTE_NETBSD_DESCSZ];
} note;
int first;
int ret;
sz = elf->e_shnum * sizeof(Elf_Shdr);
shp = ALLOC(sz);
ret = ELFNAMEEND(readfile_local)(fd, elf->e_shoff, shp, sz);
if (ret == -1) {
goto out;
}
shpp = maxp;
maxp += roundup(sz, ELFROUND);
#ifdef LIBSA_BIENDIAN_SUPPORT
for (i = 0; i < elf->e_shnum; i++)
internalize_shdr(elf->e_ident[EI_DATA], &shp[i]);
#endif
/*
* First load the section names section. Only useful for CTF.
*/
if (boot_load_ctf && (elf->e_shstrndx != SHN_UNDEF)) {
Elf_Off shstroff = shp[elf->e_shstrndx].sh_offset;
shstrsz = shp[elf->e_shstrndx].sh_size;
if (flags & LOAD_SYM) {
ret = ELFNAMEEND(readfile_global)(fd, offset,
shstroff, maxp, shstrsz);
if (ret == -1) {
goto out;
}
}
/* Create a local copy */
shstr = ALLOC(shstrsz);
ret = ELFNAMEEND(readfile_local)(fd, shstroff, shstr, shstrsz);
if (ret == -1) {
goto out;
}
shp[elf->e_shstrndx].sh_offset = maxp - elfp;
maxp += roundup(shstrsz, ELFROUND);
}
/*
* Now load the symbol sections themselves. Make sure the sections are
* ELFROUND-aligned. Update sh_offset to be relative to elfp. Set it to
* zero when we don't want the sections to be taken care of, the kernel
* will properly skip them.
*/
first = 1;
for (i = 1; i < elf->e_shnum; i++) {
if (i == elf->e_shstrndx) {
/* already loaded this section */
continue;
}
switch (shp[i].sh_type) {
case SHT_PROGBITS:
if (boot_load_ctf && shstr) {
/* got a CTF section? */
if (strncmp(&shstr[shp[i].sh_name],
".SUNW_ctf", 10) == 0) {
goto havesym;
}
}
shp[i].sh_offset = 0;
break;
case SHT_STRTAB:
for (j = 1; j < elf->e_shnum; j++)
if (shp[j].sh_type == SHT_SYMTAB &&
shp[j].sh_link == (unsigned int)i)
goto havesym;
/*
* Don't bother with any string table that isn't
* referenced by a symbol table.
*/
shp[i].sh_offset = 0;
break;
havesym:
case SHT_SYMTAB:
if (flags & LOAD_SYM) {
PROGRESS(("%s%ld", first ? " [" : "+",
(u_long)shp[i].sh_size));
ret = ELFNAMEEND(readfile_global)(fd, offset,
shp[i].sh_offset, maxp, shp[i].sh_size);
if (ret == -1) {
goto out;
}
}
shp[i].sh_offset = maxp - elfp;
maxp += roundup(shp[i].sh_size, ELFROUND);
first = 0;
break;
case SHT_NOTE:
if ((flags & LOAD_NOTE) == 0)
break;
if (shp[i].sh_size < sizeof(note)) {
shp[i].sh_offset = 0;
break;
}
ret = ELFNAMEEND(readfile_local)(fd, shp[i].sh_offset,
&note, sizeof(note));
if (ret == -1) {
goto out;
}
if (note.nh.n_namesz == ELF_NOTE_NETBSD_NAMESZ &&
note.nh.n_descsz == ELF_NOTE_NETBSD_DESCSZ &&
note.nh.n_type == ELF_NOTE_TYPE_NETBSD_TAG &&
memcmp(note.name, ELF_NOTE_NETBSD_NAME,
sizeof(note.name)) == 0) {
memcpy(&netbsd_version, &note.desc,
sizeof(netbsd_version));
}
shp[i].sh_offset = 0;
break;
default:
shp[i].sh_offset = 0;
break;
}
}
if (flags & LOAD_SYM) {
#ifdef LIBSA_BIENDIAN_SUPPORT
for (i = 0; i < elf->e_shnum; i++)
externalize_shdr(elf->e_ident[EI_DATA], &shp[i]);
#endif
BCOPY(shp, shpp, sz);
if (first == 0)
PROGRESS(("]"));
}
*nmaxp = maxp;
DEALLOC(shp, sz);
if (shstr != NULL)
DEALLOC(shstr, shstrsz);
return 0;
out:
DEALLOC(shp, sz);
if (shstr != NULL)
DEALLOC(shstr, shstrsz);
return -1;
}
/* -------------------------------------------------------------------------- */
/*
* Load a static ELF binary into memory. Layout of the memory:
* +-----------------+------------+-----------------+-----------------+
* | KERNEL SEGMENTS | ELF HEADER | SECTION HEADERS | SYMBOL SECTIONS |
* +-----------------+------------+-----------------+-----------------+
* The KERNEL SEGMENTS start address is fixed by the segments themselves. We
* then map the rest by increasing maxp.
*
* The offsets of the SYMBOL SECTIONS are relative to the start address of the
* ELF HEADER. The shdr offset of ELF HEADER points to SECTION HEADERS.
*
* We just give the kernel a pointer to the ELF HEADER, which is enough for it
* to find the location and number of symbols by itself later.
*/
static int
ELFNAMEEND(loadfile_static)(int fd, Elf_Ehdr *elf, u_long *marks, int flags)
{
const u_long offset = marks[MARK_START];
Elf_Phdr *phdr;
int i, first;
size_t sz;
Elf_Addr minp = ~0, maxp = 0, pos = 0, elfp = 0;
int ret;
/* for ports that define progress to nothing */
(void)&first;
/* have not seen a data segment so far */
marks[MARK_DATA] = 0;
internalize_ehdr(elf->e_ident[EI_DATA], elf);
if (elf->e_type != ET_EXEC) {
errno = EINVAL;
return 1;
}
sz = elf->e_phnum * sizeof(Elf_Phdr);
phdr = ALLOC(sz);
ret = ELFNAMEEND(readfile_local)(fd, elf->e_phoff, phdr, sz);
if (ret == -1) {
goto freephdr;
}
first = 1;
for (i = 0; i < elf->e_phnum; i++) {
internalize_phdr(elf->e_ident[EI_DATA], &phdr[i]);
if (MD_LOADSEG(&phdr[i]))
goto loadseg;
if (phdr[i].p_type != PT_LOAD ||
(phdr[i].p_flags & (PF_W|PF_R|PF_X)) == 0)
continue;
if ((IS_TEXT(phdr[i]) && (flags & LOAD_TEXT)) ||
(IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
loadseg:
/* XXX: Assume first address is lowest */
if (marks[MARK_DATA] == 0 && IS_DATA(phdr[i]))
marks[MARK_DATA] = LOADADDR(phdr[i].p_vaddr);
/* Read in segment. */
PROGRESS(("%s%lu", first ? "" : "+",
(u_long)phdr[i].p_filesz));
ret = ELFNAMEEND(readfile_global)(fd, offset,
phdr[i].p_offset, phdr[i].p_vaddr,
phdr[i].p_filesz);
if (ret == -1) {
goto freephdr;
}
first = 0;
}
if ((IS_TEXT(phdr[i]) && (flags & (LOAD_TEXT|COUNT_TEXT))) ||
(IS_DATA(phdr[i]) && (flags & (LOAD_DATA|COUNT_DATA)))) {
/* XXX: Assume first address is lowest */
if (marks[MARK_DATA] == 0 && IS_DATA(phdr[i]))
marks[MARK_DATA] = LOADADDR(phdr[i].p_vaddr);
pos = phdr[i].p_vaddr;
if (minp > pos)
minp = pos;
pos += phdr[i].p_filesz;
if (maxp < pos)
maxp = pos;
}
/* Zero out bss. */
if (IS_BSS(phdr[i]) && (flags & LOAD_BSS)) {
PROGRESS(("+%lu",
(u_long)(phdr[i].p_memsz - phdr[i].p_filesz)));
BZERO((phdr[i].p_vaddr + phdr[i].p_filesz),
phdr[i].p_memsz - phdr[i].p_filesz);
}
if (IS_BSS(phdr[i]) && (flags & (LOAD_BSS|COUNT_BSS))) {
pos += phdr[i].p_memsz - phdr[i].p_filesz;
if (maxp < pos)
maxp = pos;
}
}
DEALLOC(phdr, sz);
maxp = roundup(maxp, ELFROUND);
/*
* Load the ELF HEADER, SECTION HEADERS and possibly the SYMBOL
* SECTIONS.
*/
if (flags & (LOAD_HDR|COUNT_HDR)) {
elfp = maxp;
maxp += sizeof(Elf_Ehdr);
}
if (flags & (LOAD_SYM|COUNT_SYM)) {
if (ELFNAMEEND(loadsym)(fd, elf, maxp, elfp, marks, flags,
&maxp) == -1) {
return 1;
}
}
/*
* Update the ELF HEADER to give information relative to elfp.
*/
if (flags & LOAD_HDR) {
elf->e_phoff = 0;
elf->e_shoff = sizeof(Elf_Ehdr);
elf->e_phentsize = 0;
elf->e_phnum = 0;
externalize_ehdr(elf->e_ident[EI_DATA], elf);
BCOPY(elf, elfp, sizeof(*elf));
internalize_ehdr(elf->e_ident[EI_DATA], elf);
}
marks[MARK_START] = LOADADDR(minp);
marks[MARK_ENTRY] = LOADADDR(elf->e_entry);
marks[MARK_NSYM] = 1; /* XXX: Kernel needs >= 0 */
marks[MARK_SYM] = LOADADDR(elfp);
marks[MARK_END] = LOADADDR(maxp);
return 0;
freephdr:
DEALLOC(phdr, sz);
return 1;
}
/* -------------------------------------------------------------------------- */
int
ELFNAMEEND(loadfile)(int fd, Elf_Ehdr *elf, u_long *marks, int flags)
{
if (flags & LOAD_DYN) {
return ELFNAMEEND(loadfile_dynamic)(fd, elf, marks, flags);
} else {
return ELFNAMEEND(loadfile_static)(fd, elf, marks, flags);
}
}
#endif /* (ELFSIZE == 32 && BOOT_ELF32) || (ELFSIZE == 64 && BOOT_ELF64) */