/* $NetBSD: loadfile.c,v 1.10 2000/12/03 02:53:04 tsutsui Exp $ */ /* $OpenBSD: loadfile_elf.c,v 1.17 2020/10/26 04:04:31 visa Exp $ */ /*- * Copyright (c) 1997 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 and by Christos Zoulas. * * 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. */ /* * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ralph Campbell. * * 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. * * @(#)boot.c 8.1 (Berkeley) 6/10/93 */ #include int ELFNAME(exec)(int, Elf_Ehdr *, uint64_t *, int); int ELFNAME(exec)(int fd, Elf_Ehdr *elf, uint64_t *marks, int flags) { Elf_Shdr *shp; Elf_Phdr *phdr; Elf_Off off; int i; size_t sz; int first; int havesyms; paddr_t minp = ~0, maxp = 0, pos = 0; paddr_t offset = marks[MARK_START], shpp, elfp; sz = elf->e_phnum * sizeof(Elf_Phdr); phdr = ALLOC(sz); if (lseek(fd, (off_t)elf->e_phoff, SEEK_SET) == -1) { WARN(("lseek phdr")); FREE(phdr, sz); return 1; } if (read(fd, phdr, sz) != sz) { WARN(("read program headers")); FREE(phdr, sz); return 1; } for (first = 1, i = 0; i < elf->e_phnum; i++) { if (phdr[i].p_type == PT_OPENBSD_RANDOMIZE) { /* Fill segment if asked for. */ if (flags & LOAD_RANDOM) { extern struct rc4_ctx randomctx; rc4_getbytes(&randomctx, (void *)LOADADDR(phdr[i].p_paddr), phdr[i].p_filesz); } if (flags & (LOAD_RANDOM | COUNT_RANDOM)) { marks[MARK_RANDOM] = LOADADDR(phdr[i].p_paddr); marks[MARK_ERANDOM] = marks[MARK_RANDOM] + phdr[i].p_filesz; } continue; } if (phdr[i].p_type != PT_LOAD || (phdr[i].p_flags & (PF_W|PF_R|PF_X)) == 0) continue; #ifdef CHECK_PHDR if (CHECK_PHDR(ELFSIZE, &phdr[i])) { FREE(phdr, sz); return 1; } #endif #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) /* * XXX: Assume first address is lowest */ if ((IS_TEXT(phdr[i]) && (flags & LOAD_TEXT)) || (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) { /* Read in segment. */ PROGRESS(("%s%lu", first ? "" : "+", (u_long)phdr[i].p_filesz)); if (lseek(fd, (off_t)phdr[i].p_offset, SEEK_SET) == -1) { WARN(("lseek text")); FREE(phdr, sz); return 1; } if (READ(fd, phdr[i].p_paddr, phdr[i].p_filesz) != phdr[i].p_filesz) { WARN(("read text")); FREE(phdr, sz); return 1; } first = 0; } if ((IS_TEXT(phdr[i]) && (flags & (LOAD_TEXT | COUNT_TEXT))) || (IS_DATA(phdr[i]) && (flags & (LOAD_DATA | COUNT_TEXT)))) { pos = phdr[i].p_paddr; 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_paddr + 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; } } FREE(phdr, sz); /* * Copy the ELF and section headers. */ elfp = maxp = roundup(maxp, sizeof(Elf_Addr)); if (flags & (LOAD_HDR | COUNT_HDR)) maxp += sizeof(Elf_Ehdr); if (flags & (LOAD_SYM | COUNT_SYM)) { if (lseek(fd, (off_t)elf->e_shoff, SEEK_SET) == -1) { WARN(("lseek section headers")); return 1; } sz = elf->e_shnum * sizeof(Elf_Shdr); shp = ALLOC(sz); if (read(fd, shp, sz) != sz) { WARN(("read section headers")); FREE(shp, sz); return 1; } shpp = maxp; maxp += roundup(sz, sizeof(Elf_Addr)); size_t shstrsz = shp[elf->e_shstrndx].sh_size; char *shstr = ALLOC(shstrsz); if (lseek(fd, (off_t)shp[elf->e_shstrndx].sh_offset, SEEK_SET) == -1) { WARN(("lseek section header string table")); FREE(shstr, shstrsz); FREE(shp, sz); return 1; } if (read(fd, shstr, shstrsz) != shstrsz) { WARN(("read section header string table")); FREE(shstr, shstrsz); FREE(shp, sz); return 1; } /* * Now load the symbol sections themselves. Make sure the * sections are aligned. Don't bother with string tables if * there are no symbol sections. */ off = roundup((sizeof(Elf_Ehdr) + sz), sizeof(Elf_Addr)); for (havesyms = i = 0; i < elf->e_shnum; i++) if (shp[i].sh_type == SHT_SYMTAB) havesyms = 1; for (first = 1, i = 0; i < elf->e_shnum; i++) { if (shp[i].sh_type == SHT_SYMTAB || shp[i].sh_type == SHT_STRTAB || !strcmp(shstr + shp[i].sh_name, ".debug_line") || !strcmp(shstr + shp[i].sh_name, ELF_CTF)) { if (havesyms && (flags & LOAD_SYM)) { PROGRESS(("%s%ld", first ? " [" : "+", (u_long)shp[i].sh_size)); if (lseek(fd, (off_t)shp[i].sh_offset, SEEK_SET) == -1) { WARN(("lseek symbols")); FREE(shstr, shstrsz); FREE(shp, sz); return 1; } if (READ(fd, maxp, shp[i].sh_size) != shp[i].sh_size) { WARN(("read symbols")); FREE(shstr, shstrsz); FREE(shp, sz); return 1; } } maxp += roundup(shp[i].sh_size, sizeof(Elf_Addr)); shp[i].sh_offset = off; shp[i].sh_flags |= SHF_ALLOC; off += roundup(shp[i].sh_size, sizeof(Elf_Addr)); first = 0; } } if (flags & LOAD_SYM) { BCOPY(shp, shpp, sz); if (havesyms && first == 0) PROGRESS(("]")); } FREE(shstr, shstrsz); FREE(shp, sz); } /* * Frob the copied 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; BCOPY(elf, elfp, sizeof(*elf)); } marks[MARK_START] = LOADADDR(minp); marks[MARK_ENTRY] = LOADADDR(elf->e_entry); marks[MARK_VENTRY] = elf->e_entry; marks[MARK_NSYM] = 1; /* XXX: Kernel needs >= 0 */ marks[MARK_SYM] = LOADADDR(elfp); marks[MARK_END] = LOADADDR(maxp); return 0; }