OLD | NEW |
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 Loading... |
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 |
OLD | NEW |