/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- load_segment
- load_elf
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
31 /*
32 * Code to load an ELF-format executable into the current address space.
33 *
34 * It makes the following address space calls:
35 * - first, as_define_region once for each segment of the program;
36 * - then, as_prepare_load;
37 * - then it loads each chunk of the program;
38 * - finally, as_complete_load.
39 *
40 * This gives the VM code enough flexibility to deal with even grossly
41 * mis-linked executables if that proves desirable. Under normal
42 * circumstances, as_prepare_load and as_complete_load probably don't
43 * need to do anything.
44 *
45 * If you wanted to support memory-mapped executables you would need
46 * to rearrange this to map each segment.
47 *
48 * To support dynamically linked executables with shared libraries
49 * you'd need to change this to load the "ELF interpreter" (dynamic
50 * linker). And you'd have to write a dynamic linker...
51 */
52
53 #include <types.h>
54 #include <kern/errno.h>
55 #include <lib.h>
56 #include <uio.h>
57 #include <proc.h>
58 #include <current.h>
59 #include <addrspace.h>
60 #include <vnode.h>
61 #include <elf.h>
62
63 /*
64 * Load a segment at virtual address VADDR. The segment in memory
65 * extends from VADDR up to (but not including) VADDR+MEMSIZE. The
66 * segment on disk is located at file offset OFFSET and has length
67 * FILESIZE.
68 *
69 * FILESIZE may be less than MEMSIZE; if so the remaining portion of
70 * the in-memory segment should be zero-filled.
71 *
72 * Note that uiomove will catch it if someone tries to load an
73 * executable whose load address is in kernel space. If you should
74 * change this code to not use uiomove, be sure to check for this case
75 * explicitly.
76 */
77 static
78 int
79 load_segment(struct addrspace *as, struct vnode *v,
80 off_t offset, vaddr_t vaddr,
81 size_t memsize, size_t filesize,
82 int is_executable)
83 {
84 struct iovec iov;
85 struct uio u;
86 int result;
87
88 if (filesize > memsize) {
89 kprintf("ELF: warning: segment filesize > segment memsize\n");
90 filesize = memsize;
91 }
92
93 DEBUG(DB_EXEC, "ELF: Loading %lu bytes to 0x%lx\n",
94 (unsigned long) filesize, (unsigned long) vaddr);
95
96 iov.iov_ubase = (userptr_t)vaddr;
97 iov.iov_len = memsize; // length of the memory space
98 u.uio_iov = &iov;
99 u.uio_iovcnt = 1;
100 u.uio_resid = filesize; // amount to read from the file
101 u.uio_offset = offset;
102 u.uio_segflg = is_executable ? UIO_USERISPACE : UIO_USERSPACE;
103 u.uio_rw = UIO_READ;
104 u.uio_space = as;
105
106 result = VOP_READ(v, &u);
107 if (result) {
108 return result;
109 }
110
111 if (u.uio_resid != 0) {
112 /* short read; problem with executable? */
113 kprintf("ELF: short read on segment - file truncated?\n");
114 return ENOEXEC;
115 }
116
117 /*
118 * If memsize > filesize, the remaining space should be
119 * zero-filled. There is no need to do this explicitly,
120 * because the VM system should provide pages that do not
121 * contain other processes' data, i.e., are already zeroed.
122 *
123 * During development of your VM system, it may have bugs that
124 * cause it to (maybe only sometimes) not provide zero-filled
125 * pages, which can cause user programs to fail in strange
126 * ways. Explicitly zeroing program BSS may help identify such
127 * bugs, so the following disabled code is provided as a
128 * diagnostic tool. Note that it must be disabled again before
129 * you submit your code for grading.
130 */
131 #if 0
132 {
133 size_t fillamt;
134
135 fillamt = memsize - filesize;
136 if (fillamt > 0) {
137 DEBUG(DB_EXEC, "ELF: Zero-filling %lu more bytes\n",
138 (unsigned long) fillamt);
139 u.uio_resid += fillamt;
140 result = uiomovezeros(fillamt, &u);
141 }
142 }
143 #endif
144
145 return result;
146 }
147
148 /*
149 * Load an ELF executable user program into the current address space.
150 *
151 * Returns the entry point (initial PC) for the program in ENTRYPOINT.
152 */
153 int
154 load_elf(struct vnode *v, vaddr_t *entrypoint)
155 {
156 Elf_Ehdr eh; /* Executable header */
157 Elf_Phdr ph; /* "Program header" = segment header */
158 int result, i;
159 struct iovec iov;
160 struct uio ku;
161 struct addrspace *as;
162
163 as = curproc_getas();
164
165 /*
166 * Read the executable header from offset 0 in the file.
167 */
168
169 uio_kinit(&iov, &ku, &eh, sizeof(eh), 0, UIO_READ);
170 result = VOP_READ(v, &ku);
171 if (result) {
172 return result;
173 }
174
175 if (ku.uio_resid != 0) {
176 /* short read; problem with executable? */
177 kprintf("ELF: short read on header - file truncated?\n");
178 return ENOEXEC;
179 }
180
181 /*
182 * Check to make sure it's a 32-bit ELF-version-1 executable
183 * for our processor type. If it's not, we can't run it.
184 *
185 * Ignore EI_OSABI and EI_ABIVERSION - properly, we should
186 * define our own, but that would require tinkering with the
187 * linker to have it emit our magic numbers instead of the
188 * default ones. (If the linker even supports these fields,
189 * which were not in the original elf spec.)
190 */
191
192 if (eh.e_ident[EI_MAG0] != ELFMAG0 ||
193 eh.e_ident[EI_MAG1] != ELFMAG1 ||
194 eh.e_ident[EI_MAG2] != ELFMAG2 ||
195 eh.e_ident[EI_MAG3] != ELFMAG3 ||
196 eh.e_ident[EI_CLASS] != ELFCLASS32 ||
197 eh.e_ident[EI_DATA] != ELFDATA2MSB ||
198 eh.e_ident[EI_VERSION] != EV_CURRENT ||
199 eh.e_version != EV_CURRENT ||
200 eh.e_type!=ET_EXEC ||
201 eh.e_machine!=EM_MACHINE) {
202 return ENOEXEC;
203 }
204
205 /*
206 * Go through the list of segments and set up the address space.
207 *
208 * Ordinarily there will be one code segment, one read-only
209 * data segment, and one data/bss segment, but there might
210 * conceivably be more. You don't need to support such files
211 * if it's unduly awkward to do so.
212 *
213 * Note that the expression eh.e_phoff + i*eh.e_phentsize is
214 * mandated by the ELF standard - we use sizeof(ph) to load,
215 * because that's the structure we know, but the file on disk
216 * might have a larger structure, so we must use e_phentsize
217 * to find where the phdr starts.
218 */
219
220 for (i=0; i<eh.e_phnum; i++) {
221 off_t offset = eh.e_phoff + i*eh.e_phentsize;
222 uio_kinit(&iov, &ku, &ph, sizeof(ph), offset, UIO_READ);
223
224 result = VOP_READ(v, &ku);
225 if (result) {
226 return result;
227 }
228
229 if (ku.uio_resid != 0) {
230 /* short read; problem with executable? */
231 kprintf("ELF: short read on phdr - file truncated?\n");
232 return ENOEXEC;
233 }
234
235 switch (ph.p_type) {
236 case PT_NULL: /* skip */ continue;
237 case PT_PHDR: /* skip */ continue;
238 case PT_MIPS_REGINFO: /* skip */ continue;
239 case PT_LOAD: break;
240 default:
241 kprintf("loadelf: unknown segment type %d\n",
242 ph.p_type);
243 return ENOEXEC;
244 }
245
246 result = as_define_region(as,
247 ph.p_vaddr, ph.p_memsz,
248 ph.p_flags & PF_R,
249 ph.p_flags & PF_W,
250 ph.p_flags & PF_X);
251 if (result) {
252 return result;
253 }
254 }
255
256 result = as_prepare_load(as);
257 if (result) {
258 return result;
259 }
260
261 /*
262 * Now actually load each segment.
263 */
264
265 for (i=0; i<eh.e_phnum; i++) {
266 off_t offset = eh.e_phoff + i*eh.e_phentsize;
267 uio_kinit(&iov, &ku, &ph, sizeof(ph), offset, UIO_READ);
268
269 result = VOP_READ(v, &ku);
270 if (result) {
271 return result;
272 }
273
274 if (ku.uio_resid != 0) {
275 /* short read; problem with executable? */
276 kprintf("ELF: short read on phdr - file truncated?\n");
277 return ENOEXEC;
278 }
279
280 switch (ph.p_type) {
281 case PT_NULL: /* skip */ continue;
282 case PT_PHDR: /* skip */ continue;
283 case PT_MIPS_REGINFO: /* skip */ continue;
284 case PT_LOAD: break;
285 default:
286 kprintf("loadelf: unknown segment type %d\n",
287 ph.p_type);
288 return ENOEXEC;
289 }
290
291 result = load_segment(as, v, ph.p_offset, ph.p_vaddr,
292 ph.p_memsz, ph.p_filesz,
293 ph.p_flags & PF_X);
294 if (result) {
295 return result;
296 }
297 }
298
299 result = as_complete_load(as);
300 if (result) {
301 return result;
302 }
303
304 *entrypoint = eh.e_entry;
305
306 return 0;
307 }