Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(135)

Side by Side Diff: chrome/nacl/nacl_helper_bootstrap_linux.c

Issue 8524015: Make nacl_helper_bootstrap load a PIE normally, not the dynamic linker directly (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: changes per review Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 /* Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be 2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file. 3 * found in the LICENSE file.
4 * 4 *
5 * This is a standalone program that loads and runs the dynamic linker. 5 * This is a standalone program that loads and runs the dynamic linker.
6 * This program itself must be linked statically. To keep it small, it's 6 * This program itself must be linked statically. To keep it small, it's
7 * written to avoid all dependencies on libc and standard startup code. 7 * written to avoid all dependencies on libc and standard startup code.
8 * Hence, this should be linked using -nostartfiles. It must be compiled 8 * Hence, this should be linked using -nostartfiles. It must be compiled
9 * with -fno-stack-protector to ensure the compiler won't emit code that 9 * with -fno-stack-protector to ensure the compiler won't emit code that
10 * presumes some special setup has been done. 10 * presumes some special setup has been done.
11 * 11 *
12 * On ARM, the compiler will emit calls to some libc functions, so we 12 * On ARM, the compiler will emit calls to some libc functions, so we
13 * cannot link with -nostdlib. The functions it does use (memset and 13 * cannot link with -nostdlib. The functions it does use (memset and
14 * __aeabi_* functions for integer division) are sufficiently small and 14 * __aeabi_* functions for integer division) are sufficiently small and
15 * self-contained in ARM's libc.a that we don't have any problem using 15 * self-contained in ARM's libc.a that we don't have any problem using
16 * the libc definitions though we aren't using the rest of libc or doing 16 * the libc definitions though we aren't using the rest of libc or doing
17 * any of the setup it might expect. 17 * any of the setup it might expect.
18 */ 18 */
19 19
20 #include <elf.h> 20 #include <elf.h>
21 #include <fcntl.h> 21 #include <fcntl.h>
22 #include <limits.h>
22 #include <link.h> 23 #include <link.h>
23 #include <stddef.h> 24 #include <stddef.h>
24 #include <stdint.h> 25 #include <stdint.h>
25 #include <sys/mman.h> 26 #include <sys/mman.h>
26 27
27 #define MAX_PHNUM 12 28 #define MAX_PHNUM 12
28 29
29 #if defined(__i386__)
30 # define DYNAMIC_LINKER "/lib/ld-linux.so.2"
31 #elif defined(__x86_64__)
32 # define DYNAMIC_LINKER "/lib64/ld-linux-x86-64.so.2"
33 #elif defined(__ARM_EABI__)
34 # define DYNAMIC_LINKER "/lib/ld-linux.so.3"
35 #else
36 # error "Don't know the dynamic linker file name for this architecture!"
37 #endif
38
39 30
40 /* 31 /*
41 * We're not using <string.h> functions here, to avoid dependencies. 32 * We're not using <string.h> functions here, to avoid dependencies.
42 * In the x86 libc, even "simple" functions like memset and strlen can 33 * In the x86 libc, even "simple" functions like memset and strlen can
43 * depend on complex startup code, because in newer libc 34 * depend on complex startup code, because in newer libc
44 * implementations they are defined using STT_GNU_IFUNC. 35 * implementations they are defined using STT_GNU_IFUNC.
45 */ 36 */
46 37
47 static void my_bzero(void *buf, size_t n) { 38 static void my_bzero(void *buf, size_t n) {
48 char *p = buf; 39 char *p = buf;
(...skipping 29 matching lines...) Expand all
78 *p = "0123456789"[value % 10]; 69 *p = "0123456789"[value % 10];
79 value /= 10; 70 value /= 10;
80 } while (value != 0); 71 } while (value != 0);
81 iov->iov_base = p; 72 iov->iov_base = p;
82 iov->iov_len = &buf[bufsz] - p; 73 iov->iov_len = &buf[bufsz] - p;
83 } 74 }
84 75
85 #define STRING_IOV(string_constant, cond) \ 76 #define STRING_IOV(string_constant, cond) \
86 { (void *) string_constant, cond ? (sizeof(string_constant) - 1) : 0 } 77 { (void *) string_constant, cond ? (sizeof(string_constant) - 1) : 0 }
87 78
88 __attribute__((noreturn)) static void fail(const char *message, 79 __attribute__((noreturn)) static void fail(const char *filename,
80 const char *message,
89 const char *item1, int value1, 81 const char *item1, int value1,
90 const char *item2, int value2) { 82 const char *item2, int value2) {
91 char valbuf1[32]; 83 char valbuf1[32];
92 char valbuf2[32]; 84 char valbuf2[32];
93 struct kernel_iovec iov[] = { 85 struct kernel_iovec iov[] = {
94 STRING_IOV("bootstrap_helper", 1), 86 STRING_IOV("bootstrap_helper: ", 1),
95 STRING_IOV(DYNAMIC_LINKER, 1), 87 { (void *) filename, my_strlen(filename) },
96 STRING_IOV(": ", 1), 88 STRING_IOV(": ", 1),
97 { (void *) message, my_strlen(message) }, 89 { (void *) message, my_strlen(message) },
98 { (void *) item1, item1 == NULL ? 0 : my_strlen(item1) }, 90 { (void *) item1, item1 == NULL ? 0 : my_strlen(item1) },
99 STRING_IOV("=", item1 != NULL), 91 STRING_IOV("=", item1 != NULL),
100 {}, 92 {},
101 STRING_IOV(", ", item1 != NULL && item2 != NULL), 93 STRING_IOV(", ", item1 != NULL && item2 != NULL),
102 { (void *) item2, item2 == NULL ? 0 : my_strlen(item2) }, 94 { (void *) item2, item2 == NULL ? 0 : my_strlen(item2) },
103 STRING_IOV("=", item2 != NULL), 95 STRING_IOV("=", item2 != NULL),
104 {}, 96 {},
105 { "\n", 1 }, 97 { "\n", 1 },
106 }; 98 };
107 const int niov = sizeof(iov) / sizeof(iov[0]); 99 const int niov = sizeof(iov) / sizeof(iov[0]);
108 100
109 if (item1 != NULL) 101 if (item1 != NULL)
110 iov_int_string(value1, &iov[6], valbuf1, sizeof(valbuf1)); 102 iov_int_string(value1, &iov[6], valbuf1, sizeof(valbuf1));
111 if (item2 != NULL) 103 if (item2 != NULL)
112 iov_int_string(value1, &iov[10], valbuf2, sizeof(valbuf2)); 104 iov_int_string(value1, &iov[10], valbuf2, sizeof(valbuf2));
113 105
114 sys_writev(2, iov, niov); 106 sys_writev(2, iov, niov);
115 sys_exit_group(2); 107 sys_exit_group(2);
116 while (1) *(volatile int *) 0 = 0; /* Crash. */ 108 while (1) *(volatile int *) 0 = 0; /* Crash. */
117 } 109 }
118 110
119 111
120 static int my_open(const char *file, int oflag) { 112 static int my_open(const char *file, int oflag) {
121 int result = sys_open(file, oflag, 0); 113 int result = sys_open(file, oflag, 0);
122 if (result < 0) 114 if (result < 0)
123 fail("Cannot open dynamic linker! ", "errno", my_errno, NULL, 0); 115 fail(file, "Cannot open ELF file! ", "errno", my_errno, NULL, 0);
124 return result; 116 return result;
125 } 117 }
126 118
127 static void my_pread(const char *fail_message, 119 static void my_pread(const char *file, const char *fail_message,
128 int fd, void *buf, size_t bufsz, uintptr_t pos) { 120 int fd, void *buf, size_t bufsz, uintptr_t pos) {
129 ssize_t result = sys_pread64(fd, buf, bufsz, pos); 121 ssize_t result = sys_pread64(fd, buf, bufsz, pos);
130 if (result < 0) 122 if (result < 0)
131 fail(fail_message, "errno", my_errno, NULL, 0); 123 fail(file, fail_message, "errno", my_errno, NULL, 0);
132 if ((size_t) result != bufsz) 124 if ((size_t) result != bufsz)
133 fail(fail_message, "read count", result, NULL, 0); 125 fail(file, fail_message, "read count", result, NULL, 0);
134 } 126 }
135 127
136 static uintptr_t my_mmap(const char *segment_type, unsigned int segnum, 128 static uintptr_t my_mmap(const char *file,
129 const char *segment_type, unsigned int segnum,
137 uintptr_t address, size_t size, 130 uintptr_t address, size_t size,
138 int prot, int flags, int fd, uintptr_t pos) { 131 int prot, int flags, int fd, uintptr_t pos) {
139 #if defined(__NR_mmap2) 132 #if defined(__NR_mmap2)
140 void *result = sys_mmap2((void *) address, size, prot, flags, fd, pos >> 12); 133 void *result = sys_mmap2((void *) address, size, prot, flags, fd, pos >> 12);
141 #else 134 #else
142 void *result = sys_mmap((void *) address, size, prot, flags, fd, pos); 135 void *result = sys_mmap((void *) address, size, prot, flags, fd, pos);
143 #endif 136 #endif
144 if (result == MAP_FAILED) 137 if (result == MAP_FAILED)
145 fail("Failed to map from dynamic linker! ", 138 fail(file, "Failed to map segment! ",
146 segment_type, segnum, "errno", my_errno); 139 segment_type, segnum, "errno", my_errno);
147 return (uintptr_t) result; 140 return (uintptr_t) result;
148 } 141 }
149 142
150 static void my_mprotect(unsigned int segnum, 143 static void my_mprotect(const char *file, unsigned int segnum,
151 uintptr_t address, size_t size, int prot) { 144 uintptr_t address, size_t size, int prot) {
152 if (sys_mprotect((void *) address, size, prot) < 0) 145 if (sys_mprotect((void *) address, size, prot) < 0)
153 fail("Failed to mprotect hole in dynamic linker! ", 146 fail(file, "Failed to mprotect segment hole! ",
154 "segment", segnum, "errno", my_errno); 147 "segment", segnum, "errno", my_errno);
155 } 148 }
156 149
157 150
158 static int prot_from_phdr(const ElfW(Phdr) *phdr) { 151 static int prot_from_phdr(const ElfW(Phdr) *phdr) {
159 int prot = 0; 152 int prot = 0;
160 if (phdr->p_flags & PF_R) 153 if (phdr->p_flags & PF_R)
161 prot |= PROT_READ; 154 prot |= PROT_READ;
162 if (phdr->p_flags & PF_W) 155 if (phdr->p_flags & PF_W)
163 prot |= PROT_WRITE; 156 prot |= PROT_WRITE;
164 if (phdr->p_flags & PF_X) 157 if (phdr->p_flags & PF_X)
165 prot |= PROT_EXEC; 158 prot |= PROT_EXEC;
166 return prot; 159 return prot;
167 } 160 }
168 161
169 static uintptr_t round_up(uintptr_t value, uintptr_t size) { 162 static uintptr_t round_up(uintptr_t value, uintptr_t size) {
170 return (value + size - 1) & -size; 163 return (value + size - 1) & -size;
171 } 164 }
172 165
173 static uintptr_t round_down(uintptr_t value, uintptr_t size) { 166 static uintptr_t round_down(uintptr_t value, uintptr_t size) {
174 return value & -size; 167 return value & -size;
175 } 168 }
176 169
177 /* 170 /*
178 * Handle the "bss" portion of a segment, where the memory size 171 * Handle the "bss" portion of a segment, where the memory size
179 * exceeds the file size and we zero-fill the difference. For any 172 * exceeds the file size and we zero-fill the difference. For any
180 * whole pages in this region, we over-map anonymous pages. For the 173 * whole pages in this region, we over-map anonymous pages. For the
181 * sub-page remainder, we zero-fill bytes directly. 174 * sub-page remainder, we zero-fill bytes directly.
182 */ 175 */
183 static void handle_bss(unsigned int segnum, const ElfW(Phdr) *ph, 176 static void handle_bss(const char *file,
177 unsigned int segnum, const ElfW(Phdr) *ph,
184 ElfW(Addr) load_bias, size_t pagesize) { 178 ElfW(Addr) load_bias, size_t pagesize) {
185 if (ph->p_memsz > ph->p_filesz) { 179 if (ph->p_memsz > ph->p_filesz) {
186 ElfW(Addr) file_end = ph->p_vaddr + load_bias + ph->p_filesz; 180 ElfW(Addr) file_end = ph->p_vaddr + load_bias + ph->p_filesz;
187 ElfW(Addr) file_page_end = round_up(file_end, pagesize); 181 ElfW(Addr) file_page_end = round_up(file_end, pagesize);
188 ElfW(Addr) page_end = round_up(ph->p_vaddr + load_bias + 182 ElfW(Addr) page_end = round_up(ph->p_vaddr + load_bias +
189 ph->p_memsz, pagesize); 183 ph->p_memsz, pagesize);
190 if (page_end > file_page_end) 184 if (page_end > file_page_end)
191 my_mmap("bss segment", segnum, 185 my_mmap(file, "bss segment", segnum,
192 file_page_end, page_end - file_page_end, 186 file_page_end, page_end - file_page_end,
193 prot_from_phdr(ph), MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0); 187 prot_from_phdr(ph), MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
194 if (file_page_end > file_end && (ph->p_flags & PF_W)) 188 if (file_page_end > file_end && (ph->p_flags & PF_W))
195 my_bzero((void *) file_end, file_page_end - file_end); 189 my_bzero((void *) file_end, file_page_end - file_end);
196 } 190 }
197 } 191 }
198 192
199 /* 193 /*
200 * This is the main loading code. It's called with the address of the 194 * Open an ELF file and load it into memory.
201 * auxiliary vector on the stack, which we need to examine and modify.
202 * It returns the dynamic linker's runtime entry point address, where
203 * we should jump to. This is called by the machine-dependent _start
204 * code (below). On return, it restores the original stack pointer
205 * and jumps to this entry point.
206 */ 195 */
207 ElfW(Addr) do_load(ElfW(auxv_t) *auxv) { 196 static ElfW(Addr) load_elf_file(const char *filename,
208 /* 197 size_t pagesize,
209 * Record the auxv entries that are specific to the file loaded. 198 ElfW(Addr) *out_phdr,
210 * The incoming entries point to our own static executable. 199 ElfW(Addr) *out_phnum,
211 */ 200 const char **out_interp) {
212 ElfW(auxv_t) *av_entry = NULL; 201 int fd = my_open(filename, O_RDONLY);
213 ElfW(auxv_t) *av_phdr = NULL;
214 ElfW(auxv_t) *av_phnum = NULL;
215 size_t pagesize = 0;
216
217 ElfW(auxv_t) *av;
218 for (av = auxv;
219 av_entry == NULL || av_phdr == NULL || av_phnum == NULL || pagesize == 0;
220 ++av) {
221 switch (av->a_type) {
222 case AT_NULL:
223 fail("Failed to find AT_ENTRY, AT_PHDR, AT_PHNUM, or AT_PAGESZ!",
224 NULL, 0, NULL, 0);
225 /*NOTREACHED*/
226 break;
227 case AT_ENTRY:
228 av_entry = av;
229 break;
230 case AT_PAGESZ:
231 pagesize = av->a_un.a_val;
232 break;
233 case AT_PHDR:
234 av_phdr = av;
235 break;
236 case AT_PHNUM:
237 av_phnum = av;
238 break;
239 }
240 }
241
242 int fd = my_open(DYNAMIC_LINKER, O_RDONLY);
243 202
244 ElfW(Ehdr) ehdr; 203 ElfW(Ehdr) ehdr;
245 my_pread("Failed to read ELF header from dynamic linker! ", 204 my_pread(filename, "Failed to read ELF header from file! ",
246 fd, &ehdr, sizeof(ehdr), 0); 205 fd, &ehdr, sizeof(ehdr), 0);
247 206
248 if (ehdr.e_ident[EI_MAG0] != ELFMAG0 || 207 if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
249 ehdr.e_ident[EI_MAG1] != ELFMAG1 || 208 ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
250 ehdr.e_ident[EI_MAG2] != ELFMAG2 || 209 ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
251 ehdr.e_ident[EI_MAG3] != ELFMAG3 || 210 ehdr.e_ident[EI_MAG3] != ELFMAG3 ||
252 ehdr.e_version != EV_CURRENT || 211 ehdr.e_version != EV_CURRENT ||
253 ehdr.e_ehsize != sizeof(ehdr) || 212 ehdr.e_ehsize != sizeof(ehdr) ||
254 ehdr.e_phentsize != sizeof(ElfW(Phdr))) 213 ehdr.e_phentsize != sizeof(ElfW(Phdr)))
255 fail("Dynamic linker has no valid ELF header!", NULL, 0, NULL, 0); 214 fail(filename, "File has no valid ELF header!", NULL, 0, NULL, 0);
256 215
257 switch (ehdr.e_machine) { 216 switch (ehdr.e_machine) {
258 #if defined(__i386__) 217 #if defined(__i386__)
259 case EM_386: 218 case EM_386:
260 #elif defined(__x86_64__) 219 #elif defined(__x86_64__)
261 case EM_X86_64: 220 case EM_X86_64:
262 #elif defined(__arm__) 221 #elif defined(__arm__)
263 case EM_ARM: 222 case EM_ARM:
264 #else 223 #else
265 # error "Don't know the e_machine value for this architecture!" 224 # error "Don't know the e_machine value for this architecture!"
266 #endif 225 #endif
267 break; 226 break;
268 default: 227 default:
269 fail("Dynamic linker has wrong architecture! ", 228 fail(filename, "ELF file has wrong architecture! ",
270 "e_machine", ehdr.e_machine, NULL, 0); 229 "e_machine", ehdr.e_machine, NULL, 0);
271 break; 230 break;
272 } 231 }
273 232
274 ElfW(Phdr) phdr[MAX_PHNUM]; 233 ElfW(Phdr) phdr[MAX_PHNUM];
275 if (ehdr.e_phnum > sizeof(phdr) / sizeof(phdr[0]) || ehdr.e_phnum < 1) 234 if (ehdr.e_phnum > sizeof(phdr) / sizeof(phdr[0]) || ehdr.e_phnum < 1)
276 fail("Dynamic linker has unreasonable ", 235 fail(filename, "ELF file has unreasonable ",
277 "e_phnum", ehdr.e_phnum, NULL, 0); 236 "e_phnum", ehdr.e_phnum, NULL, 0);
278 237
279 if (ehdr.e_type != ET_DYN) 238 if (ehdr.e_type != ET_DYN)
280 fail("Dynamic linker not ET_DYN! ", 239 fail(filename, "ELF file not ET_DYN! ",
281 "e_type", ehdr.e_type, NULL, 0); 240 "e_type", ehdr.e_type, NULL, 0);
282 241
283 my_pread("Failed to read program headers from dynamic linker! ", 242 my_pread(filename, "Failed to read program headers from ELF file! ",
284 fd, phdr, sizeof(phdr[0]) * ehdr.e_phnum, ehdr.e_phoff); 243 fd, phdr, sizeof(phdr[0]) * ehdr.e_phnum, ehdr.e_phoff);
285 244
286 size_t i = 0; 245 size_t i = 0;
287 while (i < ehdr.e_phnum && phdr[i].p_type != PT_LOAD) 246 while (i < ehdr.e_phnum && phdr[i].p_type != PT_LOAD)
288 ++i; 247 ++i;
289 if (i == ehdr.e_phnum) 248 if (i == ehdr.e_phnum)
290 fail("Dynamic linker has no PT_LOAD header!", 249 fail(filename, "ELF file has no PT_LOAD header!",
291 NULL, 0, NULL, 0); 250 NULL, 0, NULL, 0);
292 251
293 /* 252 /*
294 * ELF requires that PT_LOAD segments be in ascending order of p_vaddr. 253 * ELF requires that PT_LOAD segments be in ascending order of p_vaddr.
295 * Find the last one to calculate the whole address span of the image. 254 * Find the last one to calculate the whole address span of the image.
296 */ 255 */
297 const ElfW(Phdr) *first_load = &phdr[i]; 256 const ElfW(Phdr) *first_load = &phdr[i];
298 const ElfW(Phdr) *last_load = &phdr[ehdr.e_phnum - 1]; 257 const ElfW(Phdr) *last_load = &phdr[ehdr.e_phnum - 1];
299 while (last_load > first_load && last_load->p_type != PT_LOAD) 258 while (last_load > first_load && last_load->p_type != PT_LOAD)
300 --last_load; 259 --last_load;
301 260
302 size_t span = last_load->p_vaddr + last_load->p_memsz - first_load->p_vaddr; 261 size_t span = last_load->p_vaddr + last_load->p_memsz - first_load->p_vaddr;
303 262
304 /* 263 /*
305 * Map the first segment and reserve the space used for the rest and 264 * Map the first segment and reserve the space used for the rest and
306 * for holes between segments. 265 * for holes between segments.
307 */ 266 */
308 const uintptr_t mapping = my_mmap("segment", first_load - phdr, 267 const uintptr_t mapping = my_mmap(filename, "segment", first_load - phdr,
309 round_down(first_load->p_vaddr, pagesize), 268 round_down(first_load->p_vaddr, pagesize),
310 span, prot_from_phdr(first_load), 269 span, prot_from_phdr(first_load),
311 MAP_PRIVATE, fd, 270 MAP_PRIVATE, fd,
312 round_down(first_load->p_offset, pagesize)); 271 round_down(first_load->p_offset, pagesize));
313 272
314 const ElfW(Addr) load_bias = mapping - round_down(first_load->p_vaddr, 273 const ElfW(Addr) load_bias = mapping - round_down(first_load->p_vaddr,
315 pagesize); 274 pagesize);
316 275
317 if (first_load->p_offset > ehdr.e_phoff || 276 if (first_load->p_offset > ehdr.e_phoff ||
318 first_load->p_filesz < ehdr.e_phoff + (ehdr.e_phnum * sizeof(ElfW(Phdr)))) 277 first_load->p_filesz < ehdr.e_phoff + (ehdr.e_phnum * sizeof(ElfW(Phdr))))
319 fail("First load segment of dynamic linker does not contain phdrs!", 278 fail(filename, "First load segment of ELF file does not contain phdrs!",
320 NULL, 0, NULL, 0); 279 NULL, 0, NULL, 0);
321 280
322 /* Point the auxv elements at the dynamic linker's phdrs and entry. */ 281 handle_bss(filename, first_load - phdr, first_load, load_bias, pagesize);
323 av_phdr->a_un.a_val = (ehdr.e_phoff - first_load->p_offset +
324 first_load->p_vaddr + load_bias);
325 av_phnum->a_un.a_val = ehdr.e_phnum;
326 av_entry->a_un.a_val = ehdr.e_entry + load_bias;
327
328 handle_bss(first_load - phdr, first_load, load_bias, pagesize);
329 282
330 ElfW(Addr) last_end = first_load->p_vaddr + load_bias + first_load->p_memsz; 283 ElfW(Addr) last_end = first_load->p_vaddr + load_bias + first_load->p_memsz;
331 284
332 /* 285 /*
333 * Map the remaining segments, and protect any holes between them. 286 * Map the remaining segments, and protect any holes between them.
334 */ 287 */
335 const ElfW(Phdr) *ph; 288 const ElfW(Phdr) *ph;
336 for (ph = first_load + 1; ph <= last_load; ++ph) { 289 for (ph = first_load + 1; ph <= last_load; ++ph) {
337 if (ph->p_type == PT_LOAD) { 290 if (ph->p_type == PT_LOAD) {
338 ElfW(Addr) last_page_end = round_up(last_end, pagesize); 291 ElfW(Addr) last_page_end = round_up(last_end, pagesize);
339 292
340 last_end = ph->p_vaddr + load_bias + ph->p_memsz; 293 last_end = ph->p_vaddr + load_bias + ph->p_memsz;
341 ElfW(Addr) start = round_down(ph->p_vaddr + load_bias, pagesize); 294 ElfW(Addr) start = round_down(ph->p_vaddr + load_bias, pagesize);
342 ElfW(Addr) end = round_up(last_end, pagesize); 295 ElfW(Addr) end = round_up(last_end, pagesize);
343 296
344 if (start > last_page_end) 297 if (start > last_page_end)
345 my_mprotect(ph - phdr, last_page_end, start - last_page_end, PROT_NONE); 298 my_mprotect(filename,
346 299 ph - phdr, last_page_end, start - last_page_end, PROT_NONE);
347 my_mmap("segment", ph - phdr, 300
301 my_mmap(filename, "segment", ph - phdr,
348 start, end - start, 302 start, end - start,
349 prot_from_phdr(ph), MAP_PRIVATE | MAP_FIXED, fd, 303 prot_from_phdr(ph), MAP_PRIVATE | MAP_FIXED, fd,
350 round_down(ph->p_offset, pagesize)); 304 round_down(ph->p_offset, pagesize));
351 305
352 handle_bss(ph - phdr, ph, load_bias, pagesize); 306 handle_bss(filename, ph - phdr, ph, load_bias, pagesize);
353 } 307 }
354 } 308 }
355 309
310 if (out_interp != NULL) {
311 /*
312 * Find the PT_INTERP header, if there is one.
313 */
314 for (i = 0; i < ehdr.e_phnum; ++i) {
315 if (phdr[i].p_type == PT_INTERP) {
316 /*
317 * The PT_INTERP isn't really required to sit inside the first
318 * (or any) load segment, though it normally does. So we can
319 * easily avoid an extra read in that case.
320 */
321 if (phdr[i].p_offset >= first_load->p_offset &&
322 phdr[i].p_filesz <= first_load->p_filesz) {
323 *out_interp = (const char *) (phdr[i].p_vaddr + load_bias);
324 } else {
325 static char interp_buffer[PATH_MAX + 1];
326 if (phdr[i].p_filesz >= sizeof(interp_buffer)) {
327 fail(filename, "ELF file has unreasonable PT_INTERP size! ",
328 "segment", i, "p_filesz", phdr[i].p_filesz);
329 }
330 my_pread(filename, "Cannot read PT_INTERP segment contents!",
331 fd, interp_buffer, phdr[i].p_filesz, phdr[i].p_offset);
332 *out_interp = interp_buffer;
333 }
334 break;
335 }
336 }
337 }
338
356 sys_close(fd); 339 sys_close(fd);
357 340
341 if (out_phdr != NULL)
342 *out_phdr = (ehdr.e_phoff - first_load->p_offset +
343 first_load->p_vaddr + load_bias);
344 if (out_phnum != NULL)
345 *out_phnum = ehdr.e_phnum;
346
358 return ehdr.e_entry + load_bias; 347 return ehdr.e_entry + load_bias;
359 } 348 }
360 349
361 /* 350 /*
362 * We have to define the actual entry point code (_start) in assembly 351 * This is the main loading code. It's called with the starting stack pointer.
363 * for each machine. The kernel startup protocol is not compatible 352 * This points to a sequence of pointer-size words:
364 * with the normal C function calling convention. Here, we calculate 353 * [0] argc
365 * the address of the auxiliary vector on the stack; call do_load 354 * [1..argc] argv[0..argc-1]
366 * (above) using the normal C convention as per the ABI; restore the 355 * [1+argc] NULL
367 * original starting stack; and finally, jump to the dynamic linker's 356 * [2+argc..] envp[0..]
368 * entry point address. 357 * NULL
358 * auxv[0].a_type
359 * auxv[1].a_un.a_val
360 * ...
361 * It returns the dynamic linker's runtime entry point address, where
362 * we should jump to. This is called by the machine-dependent _start
363 * code (below). On return, it restores the original stack pointer
364 * and jumps to this entry point.
365 *
366 * argv[0] is the uninteresting name of this bootstrap program. argv[1] is
367 * the real program file name we'll open, and also the argv[0] for that
368 * program. We need to modify argc, move argv[1..] back to the argv[0..]
369 * position, and also examine and modify the auxiliary vector on the stack.
370 */
371 ElfW(Addr) do_load(uintptr_t *stack) {
372 size_t i;
373
374 /*
375 * First find the end of the auxiliary vector.
376 */
377 int argc = stack[0];
378 char **argv = (char **) &stack[1];
379 const char *program = argv[1];
380 char **envp = &argv[argc + 1];
381 char **ep = envp;
382 while (*ep != NULL)
383 ++ep;
384 ElfW(auxv_t) *auxv = (ElfW(auxv_t) *) (ep + 1);
385 ElfW(auxv_t) *av = auxv;
386 while (av->a_type != AT_NULL)
387 ++av;
388 size_t stack_words = (uintptr_t *) (av + 1) - &stack[1];
389
390 if (argc < 2)
391 fail("Usage", "PROGRAM ARGS...", NULL, 0, NULL, 0);
392
393 /*
394 * Now move everything back to eat our original argv[0]. When we've done
395 * that, envp and auxv will start one word back from where they were.
396 */
397 --argc;
398 --envp;
399 auxv = (ElfW(auxv_t) *) ep;
400 stack[0] = argc;
401 for (i = 1; i < stack_words; ++i)
402 stack[i] = stack[i + 1];
403
404 /*
405 * Record the auxv entries that are specific to the file loaded.
406 * The incoming entries point to our own static executable.
407 */
408 ElfW(auxv_t) *av_entry = NULL;
409 ElfW(auxv_t) *av_phdr = NULL;
410 ElfW(auxv_t) *av_phnum = NULL;
411 size_t pagesize = 0;
412
413 for (av = auxv;
414 av_entry == NULL || av_phdr == NULL || av_phnum == NULL || pagesize == 0;
415 ++av) {
416 switch (av->a_type) {
417 case AT_NULL:
418 fail("startup",
419 "Failed to find AT_ENTRY, AT_PHDR, AT_PHNUM, or AT_PAGESZ!",
420 NULL, 0, NULL, 0);
421 /*NOTREACHED*/
422 break;
423 case AT_ENTRY:
424 av_entry = av;
425 break;
426 case AT_PAGESZ:
427 pagesize = av->a_un.a_val;
428 break;
429 case AT_PHDR:
430 av_phdr = av;
431 break;
432 case AT_PHNUM:
433 av_phnum = av;
434 break;
435 }
436 }
437
438 /* Load the program and point the auxv elements at its phdrs and entry. */
439 const char *interp = NULL;
440 av_entry->a_un.a_val = load_elf_file(program,
441 pagesize,
442 &av_phdr->a_un.a_val,
443 &av_phnum->a_un.a_val,
444 &interp);
445
446 ElfW(Addr) entry = av_entry->a_un.a_val;
447
448 if (interp != NULL) {
449 /*
450 * There was a PT_INTERP, so we have a dynamic linker to load.
451 */
452 entry = load_elf_file(interp, pagesize, NULL, NULL, NULL);
453 }
454
455 return entry;
456 }
457
458 /*
459 * We have to define the actual entry point code (_start) in assembly for
460 * each machine. The kernel startup protocol is not compatible with the
461 * normal C function calling convention. Here, we call do_load (above)
462 * using the normal C convention as per the ABI, with the starting stack
463 * pointer as its argument; restore the original starting stack; and
464 * finally, jump to the dynamic linker's entry point address.
369 */ 465 */
370 #if defined(__i386__) 466 #if defined(__i386__)
371 asm(".globl _start\n" 467 asm(".pushsection \".text\",\"ax\",@progbits\n"
468 ".globl _start\n"
372 ".type _start,@function\n" 469 ".type _start,@function\n"
373 "_start:\n" 470 "_start:\n"
374 "xorl %ebp, %ebp\n" 471 "xorl %ebp, %ebp\n"
375 "movl %esp, %ebx\n" /* Save starting SP in %ebx. */ 472 "movl %esp, %ebx\n" /* Save starting SP in %ebx. */
376 "andl $-16, %esp\n" /* Align the stack as per ABI. */ 473 "andl $-16, %esp\n" /* Align the stack as per ABI. */
377 "movl (%ebx), %eax\n" /* argc */ 474 "pushl %ebx\n" /* Argument: stack block. */
378 "leal 8(%ebx,%eax,4), %ecx\n" /* envp */
379 /* Find the envp element that is NULL, and auxv is past there. */
380 "0: addl $4, %ecx\n"
381 "cmpl $0, -4(%ecx)\n"
382 "jne 0b\n"
383 "pushl %ecx\n" /* Argument: auxv. */
384 "call do_load\n" 475 "call do_load\n"
385 "movl %ebx, %esp\n" /* Restore the saved SP. */ 476 "movl %ebx, %esp\n" /* Restore the saved SP. */
386 "jmp *%eax\n" /* Jump to the entry point. */ 477 "jmp *%eax\n" /* Jump to the entry point. */
478 ".popsection"
387 ); 479 );
388 #elif defined(__x86_64__) 480 #elif defined(__x86_64__)
389 asm(".globl _start\n" 481 asm(".pushsection \".text\",\"ax\",@progbits\n"
482 ".globl _start\n"
390 ".type _start,@function\n" 483 ".type _start,@function\n"
391 "_start:\n" 484 "_start:\n"
392 "xorq %rbp, %rbp\n" 485 "xorq %rbp, %rbp\n"
393 "movq %rsp, %rbx\n" /* Save starting SP in %rbx. */ 486 "movq %rsp, %rbx\n" /* Save starting SP in %rbx. */
394 "andq $-16, %rsp\n" /* Align the stack as per ABI. */ 487 "andq $-16, %rsp\n" /* Align the stack as per ABI. */
395 "movq (%rbx), %rax\n" /* argc */ 488 "movq %rbx, %rdi\n" /* Argument: stack block. */
396 "leaq 16(%rbx,%rax,8), %rdi\n" /* envp */ 489 "call do_load\n"
397 /* Find the envp element that is NULL, and auxv is past there. */
398 "0: addq $8, %rdi\n"
399 "cmpq $0, -8(%rdi)\n"
400 "jne 0b\n"
401 "call do_load\n" /* Argument already in %rdi: auxv */
402 "movq %rbx, %rsp\n" /* Restore the saved SP. */ 490 "movq %rbx, %rsp\n" /* Restore the saved SP. */
403 "jmp *%rax\n" /* Jump to the entry point. */ 491 "jmp *%rax\n" /* Jump to the entry point. */
492 ".popsection"
404 ); 493 );
405 #elif defined(__arm__) 494 #elif defined(__arm__)
406 asm(".globl _start\n" 495 asm(".pushsection \".text\",\"ax\",%progbits\n"
496 ".globl _start\n"
407 ".type _start,#function\n" 497 ".type _start,#function\n"
408 "_start:\n" 498 "_start:\n"
409 #if defined(__thumb2__) 499 #if defined(__thumb2__)
410 ".thumb\n" 500 ".thumb\n"
411 ".syntax unified\n" 501 ".syntax unified\n"
412 #endif 502 #endif
413 "mov fp, #0\n" 503 "mov fp, #0\n"
414 "mov lr, #0\n" 504 "mov lr, #0\n"
415 "mov r4, sp\n" /* Save starting SP in r4. */ 505 "mov r4, sp\n" /* Save starting SP in r4. */
416 "ldr r1, [r4]\n" /* argc */ 506 "mov r0, sp\n" /* Argument: stack block. */
417 "add r1, r1, #2\n"
418 "add r0, r4, r1, asl #2\n" /* envp */
419 /* Find the envp element that is NULL, and auxv is past there. */
420 "0: ldr r1, [r0], #4\n"
421 "cmp r1, #0\n"
422 "bne 0b\n"
423 "bl do_load\n" 507 "bl do_load\n"
424 "mov sp, r4\n" /* Restore the saved SP. */ 508 "mov sp, r4\n" /* Restore the saved SP. */
425 "blx r0\n" /* Jump to the entry point. */ 509 "blx r0\n" /* Jump to the entry point. */
510 ".popsection"
426 ); 511 );
427 #else 512 #else
428 # error "Need stack-preserving _start code for this architecture!" 513 # error "Need stack-preserving _start code for this architecture!"
429 #endif 514 #endif
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698