/* * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 * The President and Fellows of Harvard College. * * 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 UNIVERSITY 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 UNIVERSITY 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. */ /* * Code to load an ELF-format executable into the current address space. * * It makes the following address space calls: * - first, as_define_region once for each segment of the program; * - then, as_prepare_load; * - then it loads each chunk of the program; * - finally, as_complete_load. * * This gives the VM code enough flexibility to deal with even grossly * mis-linked executables if that proves desirable. Under normal * circumstances, as_prepare_load and as_complete_load probably don't * need to do anything. * * If you wanted to support memory-mapped executables you would need * to rearrange this to map each segment. * * To support dynamically linked executables with shared libraries * you'd need to change this to load the "ELF interpreter" (dynamic * linker). And you'd have to write a dynamic linker... */ #include #include #include #include #include #include #include #include #include /* * Load a segment at virtual address VADDR. The segment in memory * extends from VADDR up to (but not including) VADDR+MEMSIZE. The * segment on disk is located at file offset OFFSET and has length * FILESIZE. * * FILESIZE may be less than MEMSIZE; if so the remaining portion of * the in-memory segment should be zero-filled. * * Note that uiomove will catch it if someone tries to load an * executable whose load address is in kernel space. If you should * change this code to not use uiomove, be sure to check for this case * explicitly. */ static int load_segment(struct addrspace *as, struct vnode *v, off_t offset, vaddr_t vaddr, size_t memsize, size_t filesize, int is_executable) { struct iovec iov; struct uio u; int result; if (filesize > memsize) { kprintf("ELF: warning: segment filesize > segment memsize\n"); filesize = memsize; } DEBUG(DB_EXEC, "ELF: Loading %lu bytes to 0x%lx\n", (unsigned long) filesize, (unsigned long) vaddr); iov.iov_ubase = (userptr_t)vaddr; iov.iov_len = memsize; // length of the memory space u.uio_iov = &iov; u.uio_iovcnt = 1; u.uio_resid = filesize; // amount to read from the file u.uio_offset = offset; u.uio_segflg = is_executable ? UIO_USERISPACE : UIO_USERSPACE; u.uio_rw = UIO_READ; u.uio_space = as; result = VOP_READ(v, &u); if (result) { return result; } if (u.uio_resid != 0) { /* short read; problem with executable? */ kprintf("ELF: short read on segment - file truncated?\n"); return ENOEXEC; } /* * If memsize > filesize, the remaining space should be * zero-filled. There is no need to do this explicitly, * because the VM system should provide pages that do not * contain other processes' data, i.e., are already zeroed. * * During development of your VM system, it may have bugs that * cause it to (maybe only sometimes) not provide zero-filled * pages, which can cause user programs to fail in strange * ways. Explicitly zeroing program BSS may help identify such * bugs, so the following disabled code is provided as a * diagnostic tool. Note that it must be disabled again before * you submit your code for grading. */ #if 0 { size_t fillamt; fillamt = memsize - filesize; if (fillamt > 0) { DEBUG(DB_EXEC, "ELF: Zero-filling %lu more bytes\n", (unsigned long) fillamt); u.uio_resid += fillamt; result = uiomovezeros(fillamt, &u); } } #endif return result; } /* * Load an ELF executable user program into the current address space. * * Returns the entry point (initial PC) for the program in ENTRYPOINT. */ int load_elf(struct vnode *v, vaddr_t *entrypoint) { Elf_Ehdr eh; /* Executable header */ Elf_Phdr ph; /* "Program header" = segment header */ int result, i; struct iovec iov; struct uio ku; struct addrspace *as; as = curproc_getas(); /* * Read the executable header from offset 0 in the file. */ uio_kinit(&iov, &ku, &eh, sizeof(eh), 0, UIO_READ); result = VOP_READ(v, &ku); if (result) { return result; } if (ku.uio_resid != 0) { /* short read; problem with executable? */ kprintf("ELF: short read on header - file truncated?\n"); return ENOEXEC; } /* * Check to make sure it's a 32-bit ELF-version-1 executable * for our processor type. If it's not, we can't run it. * * Ignore EI_OSABI and EI_ABIVERSION - properly, we should * define our own, but that would require tinkering with the * linker to have it emit our magic numbers instead of the * default ones. (If the linker even supports these fields, * which were not in the original elf spec.) */ if (eh.e_ident[EI_MAG0] != ELFMAG0 || eh.e_ident[EI_MAG1] != ELFMAG1 || eh.e_ident[EI_MAG2] != ELFMAG2 || eh.e_ident[EI_MAG3] != ELFMAG3 || eh.e_ident[EI_CLASS] != ELFCLASS32 || eh.e_ident[EI_DATA] != ELFDATA2MSB || eh.e_ident[EI_VERSION] != EV_CURRENT || eh.e_version != EV_CURRENT || eh.e_type!=ET_EXEC || eh.e_machine!=EM_MACHINE) { return ENOEXEC; } /* * Go through the list of segments and set up the address space. * * Ordinarily there will be one code segment, one read-only * data segment, and one data/bss segment, but there might * conceivably be more. You don't need to support such files * if it's unduly awkward to do so. * * Note that the expression eh.e_phoff + i*eh.e_phentsize is * mandated by the ELF standard - we use sizeof(ph) to load, * because that's the structure we know, but the file on disk * might have a larger structure, so we must use e_phentsize * to find where the phdr starts. */ for (i=0; iloading = false; as_activate(); return 0; }