os161-1.99
 All Data Structures
loadelf.c
00001 /*
00002  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
00003  *      The President and Fellows of Harvard College.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 
00030 
00031 /*
00032  * Code to load an ELF-format executable into the current address space.
00033  *
00034  * It makes the following address space calls:
00035  *    - first, as_define_region once for each segment of the program;
00036  *    - then, as_prepare_load;
00037  *    - then it loads each chunk of the program;
00038  *    - finally, as_complete_load.
00039  *
00040  * This gives the VM code enough flexibility to deal with even grossly
00041  * mis-linked executables if that proves desirable. Under normal
00042  * circumstances, as_prepare_load and as_complete_load probably don't
00043  * need to do anything.
00044  *
00045  * If you wanted to support memory-mapped executables you would need
00046  * to rearrange this to map each segment.
00047  *
00048  * To support dynamically linked executables with shared libraries
00049  * you'd need to change this to load the "ELF interpreter" (dynamic
00050  * linker). And you'd have to write a dynamic linker...
00051  */
00052 
00053 #include <types.h>
00054 #include <kern/errno.h>
00055 #include <lib.h>
00056 #include <uio.h>
00057 #include <proc.h>
00058 #include <current.h>
00059 #include <addrspace.h>
00060 #include <vnode.h>
00061 #include <elf.h>
00062 
00063 /*
00064  * Load a segment at virtual address VADDR. The segment in memory
00065  * extends from VADDR up to (but not including) VADDR+MEMSIZE. The
00066  * segment on disk is located at file offset OFFSET and has length
00067  * FILESIZE.
00068  *
00069  * FILESIZE may be less than MEMSIZE; if so the remaining portion of
00070  * the in-memory segment should be zero-filled.
00071  *
00072  * Note that uiomove will catch it if someone tries to load an
00073  * executable whose load address is in kernel space. If you should
00074  * change this code to not use uiomove, be sure to check for this case
00075  * explicitly.
00076  */
00077 static
00078 int
00079 load_segment(struct addrspace *as, struct vnode *v,
00080              off_t offset, vaddr_t vaddr, 
00081              size_t memsize, size_t filesize,
00082              int is_executable)
00083 {
00084         struct iovec iov;
00085         struct uio u;
00086         int result;
00087 
00088         if (filesize > memsize) {
00089                 kprintf("ELF: warning: segment filesize > segment memsize\n");
00090                 filesize = memsize;
00091         }
00092 
00093         DEBUG(DB_EXEC, "ELF: Loading %lu bytes to 0x%lx\n", 
00094               (unsigned long) filesize, (unsigned long) vaddr);
00095 
00096         iov.iov_ubase = (userptr_t)vaddr;
00097         iov.iov_len = memsize;           // length of the memory space
00098         u.uio_iov = &iov;
00099         u.uio_iovcnt = 1;
00100         u.uio_resid = filesize;          // amount to read from the file
00101         u.uio_offset = offset;
00102         u.uio_segflg = is_executable ? UIO_USERISPACE : UIO_USERSPACE;
00103         u.uio_rw = UIO_READ;
00104         u.uio_space = as;
00105 
00106         result = VOP_READ(v, &u);
00107         if (result) {
00108                 return result;
00109         }
00110 
00111         if (u.uio_resid != 0) {
00112                 /* short read; problem with executable? */
00113                 kprintf("ELF: short read on segment - file truncated?\n");
00114                 return ENOEXEC;
00115         }
00116 
00117         /*
00118          * If memsize > filesize, the remaining space should be
00119          * zero-filled. There is no need to do this explicitly,
00120          * because the VM system should provide pages that do not
00121          * contain other processes' data, i.e., are already zeroed.
00122          *
00123          * During development of your VM system, it may have bugs that
00124          * cause it to (maybe only sometimes) not provide zero-filled
00125          * pages, which can cause user programs to fail in strange
00126          * ways. Explicitly zeroing program BSS may help identify such
00127          * bugs, so the following disabled code is provided as a
00128          * diagnostic tool. Note that it must be disabled again before
00129          * you submit your code for grading.
00130          */
00131 #if 0
00132         {
00133                 size_t fillamt;
00134 
00135                 fillamt = memsize - filesize;
00136                 if (fillamt > 0) {
00137                         DEBUG(DB_EXEC, "ELF: Zero-filling %lu more bytes\n", 
00138                               (unsigned long) fillamt);
00139                         u.uio_resid += fillamt;
00140                         result = uiomovezeros(fillamt, &u);
00141                 }
00142         }
00143 #endif
00144         
00145         return result;
00146 }
00147 
00148 /*
00149  * Load an ELF executable user program into the current address space.
00150  *
00151  * Returns the entry point (initial PC) for the program in ENTRYPOINT.
00152  */
00153 int
00154 load_elf(struct vnode *v, vaddr_t *entrypoint)
00155 {
00156         Elf_Ehdr eh;   /* Executable header */
00157         Elf_Phdr ph;   /* "Program header" = segment header */
00158         int result, i;
00159         struct iovec iov;
00160         struct uio ku;
00161         struct addrspace *as;
00162 
00163         as = curproc_getas();
00164 
00165         /*
00166          * Read the executable header from offset 0 in the file.
00167          */
00168 
00169         uio_kinit(&iov, &ku, &eh, sizeof(eh), 0, UIO_READ);
00170         result = VOP_READ(v, &ku);
00171         if (result) {
00172                 return result;
00173         }
00174 
00175         if (ku.uio_resid != 0) {
00176                 /* short read; problem with executable? */
00177                 kprintf("ELF: short read on header - file truncated?\n");
00178                 return ENOEXEC;
00179         }
00180 
00181         /*
00182          * Check to make sure it's a 32-bit ELF-version-1 executable
00183          * for our processor type. If it's not, we can't run it.
00184          *
00185          * Ignore EI_OSABI and EI_ABIVERSION - properly, we should
00186          * define our own, but that would require tinkering with the
00187          * linker to have it emit our magic numbers instead of the
00188          * default ones. (If the linker even supports these fields,
00189          * which were not in the original elf spec.)
00190          */
00191 
00192         if (eh.e_ident[EI_MAG0] != ELFMAG0 ||
00193             eh.e_ident[EI_MAG1] != ELFMAG1 ||
00194             eh.e_ident[EI_MAG2] != ELFMAG2 ||
00195             eh.e_ident[EI_MAG3] != ELFMAG3 ||
00196             eh.e_ident[EI_CLASS] != ELFCLASS32 ||
00197             eh.e_ident[EI_DATA] != ELFDATA2MSB ||
00198             eh.e_ident[EI_VERSION] != EV_CURRENT ||
00199             eh.e_version != EV_CURRENT ||
00200             eh.e_type!=ET_EXEC ||
00201             eh.e_machine!=EM_MACHINE) {
00202                 return ENOEXEC;
00203         }
00204 
00205         /*
00206          * Go through the list of segments and set up the address space.
00207          *
00208          * Ordinarily there will be one code segment, one read-only
00209          * data segment, and one data/bss segment, but there might
00210          * conceivably be more. You don't need to support such files
00211          * if it's unduly awkward to do so.
00212          *
00213          * Note that the expression eh.e_phoff + i*eh.e_phentsize is 
00214          * mandated by the ELF standard - we use sizeof(ph) to load,
00215          * because that's the structure we know, but the file on disk
00216          * might have a larger structure, so we must use e_phentsize
00217          * to find where the phdr starts.
00218          */
00219 
00220         for (i=0; i<eh.e_phnum; i++) {
00221                 off_t offset = eh.e_phoff + i*eh.e_phentsize;
00222                 uio_kinit(&iov, &ku, &ph, sizeof(ph), offset, UIO_READ);
00223 
00224                 result = VOP_READ(v, &ku);
00225                 if (result) {
00226                         return result;
00227                 }
00228 
00229                 if (ku.uio_resid != 0) {
00230                         /* short read; problem with executable? */
00231                         kprintf("ELF: short read on phdr - file truncated?\n");
00232                         return ENOEXEC;
00233                 }
00234 
00235                 switch (ph.p_type) {
00236                     case PT_NULL: /* skip */ continue;
00237                     case PT_PHDR: /* skip */ continue;
00238                     case PT_MIPS_REGINFO: /* skip */ continue;
00239                     case PT_LOAD: break;
00240                     default:
00241                         kprintf("loadelf: unknown segment type %d\n", 
00242                                 ph.p_type);
00243                         return ENOEXEC;
00244                 }
00245 
00246                 result = as_define_region(as,
00247                                           ph.p_vaddr, ph.p_memsz,
00248                                           ph.p_flags & PF_R,
00249                                           ph.p_flags & PF_W,
00250                                           ph.p_flags & PF_X);
00251                 if (result) {
00252                         return result;
00253                 }
00254         }
00255 
00256         result = as_prepare_load(as);
00257         if (result) {
00258                 return result;
00259         }
00260 
00261         /*
00262          * Now actually load each segment.
00263          */
00264 
00265         for (i=0; i<eh.e_phnum; i++) {
00266                 off_t offset = eh.e_phoff + i*eh.e_phentsize;
00267                 uio_kinit(&iov, &ku, &ph, sizeof(ph), offset, UIO_READ);
00268 
00269                 result = VOP_READ(v, &ku);
00270                 if (result) {
00271                         return result;
00272                 }
00273 
00274                 if (ku.uio_resid != 0) {
00275                         /* short read; problem with executable? */
00276                         kprintf("ELF: short read on phdr - file truncated?\n");
00277                         return ENOEXEC;
00278                 }
00279 
00280                 switch (ph.p_type) {
00281                     case PT_NULL: /* skip */ continue;
00282                     case PT_PHDR: /* skip */ continue;
00283                     case PT_MIPS_REGINFO: /* skip */ continue;
00284                     case PT_LOAD: break;
00285                     default:
00286                         kprintf("loadelf: unknown segment type %d\n", 
00287                                 ph.p_type);
00288                         return ENOEXEC;
00289                 }
00290 
00291                 result = load_segment(as, v, ph.p_offset, ph.p_vaddr, 
00292                                       ph.p_memsz, ph.p_filesz,
00293                                       ph.p_flags & PF_X);
00294                 if (result) {
00295                         return result;
00296                 }
00297         }
00298 
00299         result = as_complete_load(as);
00300         if (result) {
00301                 return result;
00302         }
00303 
00304         *entrypoint = eh.e_entry;
00305 
00306         return 0;
00307 }
 All Data Structures