loadelf.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. /*
  2. * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
  3. * The President and Fellows of Harvard College.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the University nor the names of its contributors
  14. * may be used to endorse or promote products derived from this software
  15. * without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. */
  29. /*
  30. * Code to load an ELF-format executable into the current address space.
  31. *
  32. * It makes the following address space calls:
  33. * - first, as_define_region once for each segment of the program;
  34. * - then, as_prepare_load;
  35. * - then it loads each chunk of the program;
  36. * - finally, as_complete_load.
  37. *
  38. * This gives the VM code enough flexibility to deal with even grossly
  39. * mis-linked executables if that proves desirable. Under normal
  40. * circumstances, as_prepare_load and as_complete_load probably don't
  41. * need to do anything.
  42. *
  43. * If you wanted to support memory-mapped executables you would need
  44. * to rearrange this to map each segment.
  45. *
  46. * To support dynamically linked executables with shared libraries
  47. * you'd need to change this to load the "ELF interpreter" (dynamic
  48. * linker). And you'd have to write a dynamic linker...
  49. */
  50. #include <types.h>
  51. #include <kern/errno.h>
  52. #include <lib.h>
  53. #include <uio.h>
  54. #include <proc.h>
  55. #include <current.h>
  56. #include <addrspace.h>
  57. #include <vnode.h>
  58. #include <elf.h>
  59. /*
  60. * Load a segment at virtual address VADDR. The segment in memory
  61. * extends from VADDR up to (but not including) VADDR+MEMSIZE. The
  62. * segment on disk is located at file offset OFFSET and has length
  63. * FILESIZE.
  64. *
  65. * FILESIZE may be less than MEMSIZE; if so the remaining portion of
  66. * the in-memory segment should be zero-filled.
  67. *
  68. * Note that uiomove will catch it if someone tries to load an
  69. * executable whose load address is in kernel space. If you should
  70. * change this code to not use uiomove, be sure to check for this case
  71. * explicitly.
  72. */
  73. static
  74. int
  75. load_segment(struct addrspace *as, struct vnode *v,
  76. off_t offset, vaddr_t vaddr,
  77. size_t memsize, size_t filesize,
  78. int is_executable)
  79. {
  80. struct iovec iov;
  81. struct uio u;
  82. int result;
  83. if (filesize > memsize) {
  84. kprintf("ELF: warning: segment filesize > segment memsize\n");
  85. filesize = memsize;
  86. }
  87. DEBUG(DB_EXEC, "ELF: Loading %lu bytes to 0x%lx\n",
  88. (unsigned long) filesize, (unsigned long) vaddr);
  89. iov.iov_ubase = (userptr_t)vaddr;
  90. iov.iov_len = memsize; // length of the memory space
  91. u.uio_iov = &iov;
  92. u.uio_iovcnt = 1;
  93. u.uio_resid = filesize; // amount to read from the file
  94. u.uio_offset = offset;
  95. u.uio_segflg = is_executable ? UIO_USERISPACE : UIO_USERSPACE;
  96. u.uio_rw = UIO_READ;
  97. u.uio_space = as;
  98. result = VOP_READ(v, &u);
  99. if (result) {
  100. return result;
  101. }
  102. if (u.uio_resid != 0) {
  103. /* short read; problem with executable? */
  104. kprintf("ELF: short read on segment - file truncated?\n");
  105. return ENOEXEC;
  106. }
  107. /*
  108. * If memsize > filesize, the remaining space should be
  109. * zero-filled. There is no need to do this explicitly,
  110. * because the VM system should provide pages that do not
  111. * contain other processes' data, i.e., are already zeroed.
  112. *
  113. * During development of your VM system, it may have bugs that
  114. * cause it to (maybe only sometimes) not provide zero-filled
  115. * pages, which can cause user programs to fail in strange
  116. * ways. Explicitly zeroing program BSS may help identify such
  117. * bugs, so the following disabled code is provided as a
  118. * diagnostic tool. Note that it must be disabled again before
  119. * you submit your code for grading.
  120. */
  121. #if 0
  122. {
  123. size_t fillamt;
  124. fillamt = memsize - filesize;
  125. if (fillamt > 0) {
  126. DEBUG(DB_EXEC, "ELF: Zero-filling %lu more bytes\n",
  127. (unsigned long) fillamt);
  128. u.uio_resid += fillamt;
  129. result = uiomovezeros(fillamt, &u);
  130. }
  131. }
  132. #endif
  133. return result;
  134. }
  135. /*
  136. * Load an ELF executable user program into the current address space.
  137. *
  138. * Returns the entry point (initial PC) for the program in ENTRYPOINT.
  139. */
  140. int
  141. load_elf(struct vnode *v, vaddr_t *entrypoint)
  142. {
  143. Elf_Ehdr eh; /* Executable header */
  144. Elf_Phdr ph; /* "Program header" = segment header */
  145. int result, i;
  146. struct iovec iov;
  147. struct uio ku;
  148. struct addrspace *as;
  149. as = curproc_getas();
  150. /*
  151. * Read the executable header from offset 0 in the file.
  152. */
  153. uio_kinit(&iov, &ku, &eh, sizeof(eh), 0, UIO_READ);
  154. result = VOP_READ(v, &ku);
  155. if (result) {
  156. return result;
  157. }
  158. if (ku.uio_resid != 0) {
  159. /* short read; problem with executable? */
  160. kprintf("ELF: short read on header - file truncated?\n");
  161. return ENOEXEC;
  162. }
  163. /*
  164. * Check to make sure it's a 32-bit ELF-version-1 executable
  165. * for our processor type. If it's not, we can't run it.
  166. *
  167. * Ignore EI_OSABI and EI_ABIVERSION - properly, we should
  168. * define our own, but that would require tinkering with the
  169. * linker to have it emit our magic numbers instead of the
  170. * default ones. (If the linker even supports these fields,
  171. * which were not in the original elf spec.)
  172. */
  173. if (eh.e_ident[EI_MAG0] != ELFMAG0 ||
  174. eh.e_ident[EI_MAG1] != ELFMAG1 ||
  175. eh.e_ident[EI_MAG2] != ELFMAG2 ||
  176. eh.e_ident[EI_MAG3] != ELFMAG3 ||
  177. eh.e_ident[EI_CLASS] != ELFCLASS32 ||
  178. eh.e_ident[EI_DATA] != ELFDATA2MSB ||
  179. eh.e_ident[EI_VERSION] != EV_CURRENT ||
  180. eh.e_version != EV_CURRENT ||
  181. eh.e_type!=ET_EXEC ||
  182. eh.e_machine!=EM_MACHINE) {
  183. return ENOEXEC;
  184. }
  185. /*
  186. * Go through the list of segments and set up the address space.
  187. *
  188. * Ordinarily there will be one code segment, one read-only
  189. * data segment, and one data/bss segment, but there might
  190. * conceivably be more. You don't need to support such files
  191. * if it's unduly awkward to do so.
  192. *
  193. * Note that the expression eh.e_phoff + i*eh.e_phentsize is
  194. * mandated by the ELF standard - we use sizeof(ph) to load,
  195. * because that's the structure we know, but the file on disk
  196. * might have a larger structure, so we must use e_phentsize
  197. * to find where the phdr starts.
  198. */
  199. for (i=0; i<eh.e_phnum; i++) {
  200. off_t offset = eh.e_phoff + i*eh.e_phentsize;
  201. uio_kinit(&iov, &ku, &ph, sizeof(ph), offset, UIO_READ);
  202. result = VOP_READ(v, &ku);
  203. if (result) {
  204. return result;
  205. }
  206. if (ku.uio_resid != 0) {
  207. /* short read; problem with executable? */
  208. kprintf("ELF: short read on phdr - file truncated?\n");
  209. return ENOEXEC;
  210. }
  211. switch (ph.p_type) {
  212. case PT_NULL: /* skip */ continue;
  213. case PT_PHDR: /* skip */ continue;
  214. case PT_MIPS_REGINFO: /* skip */ continue;
  215. case PT_LOAD: break;
  216. default:
  217. kprintf("loadelf: unknown segment type %d\n",
  218. ph.p_type);
  219. return ENOEXEC;
  220. }
  221. result = as_define_region(as,
  222. ph.p_vaddr, ph.p_memsz,
  223. ph.p_flags & PF_R,
  224. ph.p_flags & PF_W,
  225. ph.p_flags & PF_X);
  226. if (result) {
  227. return result;
  228. }
  229. }
  230. result = as_prepare_load(as);
  231. if (result) {
  232. return result;
  233. }
  234. /*
  235. * Now actually load each segment.
  236. */
  237. for (i=0; i<eh.e_phnum; i++) {
  238. off_t offset = eh.e_phoff + i*eh.e_phentsize;
  239. uio_kinit(&iov, &ku, &ph, sizeof(ph), offset, UIO_READ);
  240. result = VOP_READ(v, &ku);
  241. if (result) {
  242. return result;
  243. }
  244. if (ku.uio_resid != 0) {
  245. /* short read; problem with executable? */
  246. kprintf("ELF: short read on phdr - file truncated?\n");
  247. return ENOEXEC;
  248. }
  249. switch (ph.p_type) {
  250. case PT_NULL: /* skip */ continue;
  251. case PT_PHDR: /* skip */ continue;
  252. case PT_MIPS_REGINFO: /* skip */ continue;
  253. case PT_LOAD: break;
  254. default:
  255. kprintf("loadelf: unknown segment type %d\n",
  256. ph.p_type);
  257. return ENOEXEC;
  258. }
  259. result = load_segment(as, v, ph.p_offset, ph.p_vaddr,
  260. ph.p_memsz, ph.p_filesz,
  261. ph.p_flags & PF_X);
  262. if (result) {
  263. return result;
  264. }
  265. }
  266. result = as_complete_load(as);
  267. if (result) {
  268. return result;
  269. }
  270. *entrypoint = eh.e_entry;
  271. as->loading = false;
  272. as_activate();
  273. return 0;
  274. }