2 * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
6 * This is a standalone program that loads and runs the dynamic linker.
7 * This program itself must be linked statically. To keep it small, it's
8 * written to avoid all dependencies on libc and standard startup code.
9 * Hence, this should be linked using -nostartfiles. It must be compiled
10 * with -fno-stack-protector to ensure the compiler won't emit code that
11 * presumes some special setup has been done.
13 * On ARM, the compiler will emit calls to some libc functions, so we
14 * cannot link with -nostdlib. The functions it does use (memset and
15 * __aeabi_* functions for integer division) are sufficiently small and
16 * self-contained in ARM's libc.a that we don't have any problem using
17 * the libc definitions though we aren't using the rest of libc or doing
18 * any of the setup it might expect.
29 * Get inline functions for system calls.
32 #define SYS_ERRNO my_errno
33 #include "third_party/lss/linux_syscall_support.h"
37 typedef uintptr_t __attribute__((may_alias)) stack_val_t;
40 * These exact magic argument strings are recognized in check_r_debug_arg
41 * and check_reserved_at_zero_arg, below. Requiring the arguments to have
42 * those Xs as a template both simplifies our argument matching code and saves
43 * us from having to reformat the whole stack to find space for a string longer
44 * than the original argument.
46 #define TEMPLATE_DIGITS "XXXXXXXXXXXXXXXX"
47 #define R_DEBUG_TEMPLATE_PREFIX "--r_debug=0x"
48 static const char kRDebugTemplate[] = R_DEBUG_TEMPLATE_PREFIX TEMPLATE_DIGITS;
49 static const size_t kRDebugPrefixLen = sizeof(R_DEBUG_TEMPLATE_PREFIX) - 1;
51 #define RESERVED_AT_ZERO_TEMPLATE_PREFIX "--reserved_at_zero=0x"
52 static const char kReservedAtZeroTemplate[] =
53 RESERVED_AT_ZERO_TEMPLATE_PREFIX TEMPLATE_DIGITS;
54 static const size_t kReservedAtZeroPrefixLen =
55 sizeof(RESERVED_AT_ZERO_TEMPLATE_PREFIX) - 1;
56 extern char RESERVE_TOP[];
58 extern char TEXT_START[];
61 * We're not using <string.h> functions here, to avoid dependencies.
62 * In the x86 libc, even "simple" functions like memset and strlen can
63 * depend on complex startup code, because in newer libc
64 * implementations they are defined using STT_GNU_IFUNC.
68 * Some GCC versions are so clever that they recognize these simple loops
69 * as having the semantics of standard library functions and replace them
70 * with calls. That defeats the whole purpose, which is to avoid requiring
71 * any C library at all. Fortunately, this optimization can be disabled
72 * for all (following) functions in the file via #pragma.
74 #if (defined(__GNUC__) && !defined(__clang__) && \
75 (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
76 # pragma GCC optimize("-fno-tree-loop-distribute-patterns")
79 static void my_bzero(void *buf, size_t n) {
85 static size_t my_strlen(const char *s) {
92 static int my_strcmp(const char *a, const char *b) {
99 return (int) (unsigned char) *a - (int) (unsigned char) *b;
104 * We're avoiding libc, so no printf. The only nontrivial thing we need
105 * is rendering numbers, which is, in fact, pretty trivial.
106 * bufsz of course must be enough to hold INT_MIN in decimal.
108 static void iov_int_string(int value, struct kernel_iovec *iov,
109 char *buf, size_t bufsz) {
110 char *p = &buf[bufsz];
111 int negative = value < 0;
116 *p = "0123456789"[value % 10];
118 } while (value != 0);
122 iov->iov_len = &buf[bufsz] - p;
125 #define STRING_IOV(string_constant, cond) \
126 { (void *) string_constant, cond ? (sizeof(string_constant) - 1) : 0 }
128 __attribute__((noreturn)) static void fail(const char *filename,
130 const char *item1, int value1,
131 const char *item2, int value2) {
134 struct kernel_iovec iov[] = {
135 STRING_IOV("bootstrap_helper: ", 1),
136 { (void *) filename, my_strlen(filename) },
138 { (void *) message, my_strlen(message) },
139 { (void *) item1, item1 == NULL ? 0 : my_strlen(item1) },
140 STRING_IOV("=", item1 != NULL),
141 { NULL, 0 }, /* iov[6] */
142 STRING_IOV(", ", item1 != NULL && item2 != NULL),
143 { (void *) item2, item2 == NULL ? 0 : my_strlen(item2) },
144 STRING_IOV("=", item2 != NULL),
145 { NULL, 0 }, /* iov[10] */
148 const int niov = sizeof(iov) / sizeof(iov[0]);
151 iov_int_string(value1, &iov[6], valbuf1, sizeof(valbuf1));
153 iov_int_string(value2, &iov[10], valbuf2, sizeof(valbuf2));
155 sys_writev(2, iov, niov);
157 while (1) *(volatile int *) 0 = 0; /* Crash. */
161 static int my_open(const char *file, int oflag) {
162 int result = sys_open(file, oflag, 0);
164 fail(file, "Cannot open ELF file! ", "errno", my_errno, NULL, 0);
168 static void my_pread(const char *file, const char *fail_message,
169 int fd, void *buf, size_t bufsz, uintptr_t pos) {
170 ssize_t result = sys_pread64(fd, buf, bufsz, pos);
172 fail(file, fail_message, "errno", my_errno, NULL, 0);
173 if ((size_t) result != bufsz)
174 fail(file, fail_message, "read count", result, NULL, 0);
177 static uintptr_t my_mmap_simple(uintptr_t address, size_t size,
178 int prot, int flags, int fd, uintptr_t pos) {
179 #if defined(__NR_mmap2)
180 void *result = sys_mmap2((void *) address, size, prot, flags, fd, pos >> 12);
182 void *result = sys_mmap((void *) address, size, prot, flags, fd, pos);
184 return (uintptr_t) result;
187 static uintptr_t my_mmap(const char *file,
188 const char *segment_type, unsigned int segnum,
189 uintptr_t address, size_t size,
190 int prot, int flags, int fd, uintptr_t pos) {
191 uintptr_t result = my_mmap_simple(address, size, prot, flags, fd, pos);
192 if ((void *) result == MAP_FAILED)
193 fail(file, "Failed to map segment! ",
194 segment_type, segnum, "errno", my_errno);
198 static void my_mprotect(const char *file, unsigned int segnum,
199 uintptr_t address, size_t size, int prot) {
200 if (sys_mprotect((void *) address, size, prot) < 0)
201 fail(file, "Failed to mprotect segment hole! ",
202 "segment", segnum, "errno", my_errno);
206 static int prot_from_phdr(const ElfW(Phdr) *phdr) {
208 if (phdr->p_flags & PF_R)
210 if (phdr->p_flags & PF_W)
212 if (phdr->p_flags & PF_X)
217 static uintptr_t round_up(uintptr_t value, uintptr_t size) {
218 return (value + size - 1) & -size;
221 static uintptr_t round_down(uintptr_t value, uintptr_t size) {
222 return value & -size;
226 * Handle the "bss" portion of a segment, where the memory size
227 * exceeds the file size and we zero-fill the difference. For any
228 * whole pages in this region, we over-map anonymous pages. For the
229 * sub-page remainder, we zero-fill bytes directly.
231 static void handle_bss(const char *file,
232 unsigned int segnum, const ElfW(Phdr) *ph,
233 ElfW(Addr) load_bias, size_t pagesize) {
234 if (ph->p_memsz > ph->p_filesz) {
235 ElfW(Addr) file_end = ph->p_vaddr + load_bias + ph->p_filesz;
236 ElfW(Addr) file_page_end = round_up(file_end, pagesize);
237 ElfW(Addr) page_end = round_up(ph->p_vaddr + load_bias +
238 ph->p_memsz, pagesize);
239 if (page_end > file_page_end)
240 my_mmap(file, "bss segment", segnum,
241 file_page_end, page_end - file_page_end,
242 prot_from_phdr(ph), MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
243 if (file_page_end > file_end && (ph->p_flags & PF_W))
244 my_bzero((void *) file_end, file_page_end - file_end);
249 * Open an ELF file and load it into memory.
251 static ElfW(Addr) load_elf_file(const char *filename,
253 ElfW(Addr) *out_phdr,
254 ElfW(Addr) *out_phnum,
255 const char **out_interp) {
256 int fd = my_open(filename, O_RDONLY);
259 my_pread(filename, "Failed to read ELF header from file! ",
260 fd, &ehdr, sizeof(ehdr), 0);
262 if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
263 ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
264 ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
265 ehdr.e_ident[EI_MAG3] != ELFMAG3 ||
266 ehdr.e_version != EV_CURRENT ||
267 ehdr.e_ehsize != sizeof(ehdr) ||
268 ehdr.e_phentsize != sizeof(ElfW(Phdr)))
269 fail(filename, "File has no valid ELF header!", NULL, 0, NULL, 0);
271 switch (ehdr.e_machine) {
272 #if defined(__i386__)
274 #elif defined(__x86_64__)
276 #elif defined(__arm__)
278 #elif defined(__mips__)
281 # error "Don't know the e_machine value for this architecture!"
285 fail(filename, "ELF file has wrong architecture! ",
286 "e_machine", ehdr.e_machine, NULL, 0);
290 ElfW(Phdr) phdr[MAX_PHNUM];
291 if (ehdr.e_phnum > sizeof(phdr) / sizeof(phdr[0]) || ehdr.e_phnum < 1)
292 fail(filename, "ELF file has unreasonable ",
293 "e_phnum", ehdr.e_phnum, NULL, 0);
295 if (ehdr.e_type != ET_DYN)
296 fail(filename, "ELF file not ET_DYN! ",
297 "e_type", ehdr.e_type, NULL, 0);
299 my_pread(filename, "Failed to read program headers from ELF file! ",
300 fd, phdr, sizeof(phdr[0]) * ehdr.e_phnum, ehdr.e_phoff);
303 while (i < ehdr.e_phnum && phdr[i].p_type != PT_LOAD)
305 if (i == ehdr.e_phnum)
306 fail(filename, "ELF file has no PT_LOAD header!",
310 * ELF requires that PT_LOAD segments be in ascending order of p_vaddr.
311 * Find the last one to calculate the whole address span of the image.
313 const ElfW(Phdr) *first_load = &phdr[i];
314 const ElfW(Phdr) *last_load = &phdr[ehdr.e_phnum - 1];
315 while (last_load > first_load && last_load->p_type != PT_LOAD)
318 size_t span = last_load->p_vaddr + last_load->p_memsz - first_load->p_vaddr;
321 * Map the first segment and reserve the space used for the rest and
322 * for holes between segments.
324 const uintptr_t mapping = my_mmap(filename, "segment", first_load - phdr,
325 round_down(first_load->p_vaddr, pagesize),
326 span, prot_from_phdr(first_load),
328 round_down(first_load->p_offset, pagesize));
330 const ElfW(Addr) load_bias = mapping - round_down(first_load->p_vaddr,
333 if (first_load->p_offset > ehdr.e_phoff ||
334 first_load->p_filesz < ehdr.e_phoff + (ehdr.e_phnum * sizeof(ElfW(Phdr))))
335 fail(filename, "First load segment of ELF file does not contain phdrs!",
338 handle_bss(filename, first_load - phdr, first_load, load_bias, pagesize);
340 ElfW(Addr) last_end = first_load->p_vaddr + load_bias + first_load->p_memsz;
343 * Map the remaining segments, and protect any holes between them.
345 const ElfW(Phdr) *ph;
346 for (ph = first_load + 1; ph <= last_load; ++ph) {
347 if (ph->p_type == PT_LOAD) {
348 ElfW(Addr) last_page_end = round_up(last_end, pagesize);
350 last_end = ph->p_vaddr + load_bias + ph->p_memsz;
351 ElfW(Addr) start = round_down(ph->p_vaddr + load_bias, pagesize);
352 ElfW(Addr) end = round_up(last_end, pagesize);
354 if (start > last_page_end)
355 my_mprotect(filename,
356 ph - phdr, last_page_end, start - last_page_end, PROT_NONE);
358 my_mmap(filename, "segment", ph - phdr,
360 prot_from_phdr(ph), MAP_PRIVATE | MAP_FIXED, fd,
361 round_down(ph->p_offset, pagesize));
363 handle_bss(filename, ph - phdr, ph, load_bias, pagesize);
367 if (out_interp != NULL) {
369 * Find the PT_INTERP header, if there is one.
371 for (i = 0; i < ehdr.e_phnum; ++i) {
372 if (phdr[i].p_type == PT_INTERP) {
374 * The PT_INTERP isn't really required to sit inside the first
375 * (or any) load segment, though it normally does. So we can
376 * easily avoid an extra read in that case.
378 if (phdr[i].p_offset >= first_load->p_offset &&
379 phdr[i].p_filesz <= first_load->p_filesz) {
380 *out_interp = (const char *) (phdr[i].p_vaddr + load_bias);
382 static char interp_buffer[PATH_MAX + 1];
383 if (phdr[i].p_filesz >= sizeof(interp_buffer)) {
384 fail(filename, "ELF file has unreasonable PT_INTERP size! ",
385 "segment", i, "p_filesz", phdr[i].p_filesz);
387 my_pread(filename, "Cannot read PT_INTERP segment contents!",
388 fd, interp_buffer, phdr[i].p_filesz, phdr[i].p_offset);
389 *out_interp = interp_buffer;
398 if (out_phdr != NULL)
399 *out_phdr = (ehdr.e_phoff - first_load->p_offset +
400 first_load->p_vaddr + load_bias);
401 if (out_phnum != NULL)
402 *out_phnum = ehdr.e_phnum;
404 return ehdr.e_entry + load_bias;
408 * Replace template digits with a fill value. This function places the
409 * bottom num_digits of the hex representation of fill into the string
410 * pointed to by start.
412 static void fill_in_template_digits(char *start, size_t num_digits,
414 while (num_digits-- > 0) {
415 start[num_digits] = "0123456789abcdef"[fill & 0xf];
419 fail("fill_in_template_digits",
420 "fill has significant digits beyond num_digits", NULL, 0, NULL, 0);
424 * GDB looks for this symbol name when it cannot find PT_DYNAMIC->DT_DEBUG.
425 * We don't have a PT_DYNAMIC, so it will find this. Now all we have to do
426 * is arrange for this space to be filled in with the dynamic linker's
427 * _r_debug contents after they're initialized. That way, attaching GDB to
428 * this process or examining its core file will find the PIE we loaded, the
429 * dynamic linker, and all the shared libraries, making debugging pleasant.
431 struct r_debug _r_debug __attribute__((nocommon, section(".r_debug")));
434 * If the argument matches the kRDebugTemplate string, then replace
435 * the 16 Xs with the hexadecimal address of our _r_debug variable.
437 static int check_r_debug_arg(char *arg) {
438 if (my_strcmp(arg, kRDebugTemplate) == 0) {
439 fill_in_template_digits(arg + kRDebugPrefixLen,
440 sizeof(TEMPLATE_DIGITS) - 1,
441 (uintptr_t) &_r_debug);
448 * If the argument matches the kReservedAtZeroTemplate string, then replace
449 * the 8 Xs with the hexadecimal representation of the amount of
450 * prereserved memory.
452 static int check_reserved_at_zero_arg(char *arg) {
453 if (my_strcmp(arg, kReservedAtZeroTemplate) == 0) {
454 fill_in_template_digits(arg + kReservedAtZeroPrefixLen,
455 sizeof(TEMPLATE_DIGITS) - 1,
456 (uintptr_t) RESERVE_TOP);
463 static void ReserveBottomPages(size_t pagesize) {
468 * Attempt to protect low memory from zero to the code start address.
470 * It is normal for mmap() calls to fail with EPERM if the indicated
471 * page is less than vm.mmap_min_addr (see /proc/sys/vm/mmap_min_addr),
472 * or with EACCES under SELinux if less than CONFIG_LSM_MMAP_MIN_ADDR
473 * (64k). Sometimes, mmap() calls may fail with EINVAL if the
474 * starting address is 0. Hence, we adaptively move the bottom of the
475 * region up a page at a time until we succeed in getting a reservation.
478 page_addr < (uintptr_t) TEXT_START;
479 page_addr += pagesize) {
480 mmap_rval = my_mmap_simple(page_addr,
481 (uintptr_t) TEXT_START - page_addr,
483 MAP_PRIVATE | MAP_FIXED |
484 MAP_ANONYMOUS | MAP_NORESERVE,
486 if (page_addr == mmap_rval) {
487 /* Success; the pages are now protected. */
489 } else if (MAP_FAILED == (void *) mmap_rval &&
490 (EPERM == my_errno || EACCES == my_errno ||
491 (EINVAL == my_errno && 0 == page_addr))) {
493 * Normal; this is an invalid page for this process and
494 * doesn't need to be protected. Continue with next page.
497 fail("ReserveBottomPages", "NULL pointer guard page ",
498 "errno", my_errno, NULL, 0);
505 * This is the main loading code. It's called with the starting stack pointer.
506 * This points to a sequence of pointer-size words:
508 * [1..argc] argv[0..argc-1]
510 * [2+argc..] envp[0..]
515 * It returns the dynamic linker's runtime entry point address, where
516 * we should jump to. This is called by the machine-dependent _start
517 * code (below). On return, it restores the original stack pointer
518 * and jumps to this entry point.
520 * argv[0] is the uninteresting name of this bootstrap program. argv[1] is
521 * the real program file name we'll open, and also the argv[0] for that
522 * program. We need to modify argc, move argv[1..] back to the argv[0..]
523 * position, and also examine and modify the auxiliary vector on the stack.
525 ElfW(Addr) do_load(stack_val_t *stack) {
530 * First find the end of the auxiliary vector.
533 char **argv = (char **) &stack[1];
534 const char *program = argv[1];
535 char **envp = &argv[argc + 1];
539 ElfW(auxv_t) *auxv = (ElfW(auxv_t) *) (ep + 1);
540 ElfW(auxv_t) *av = auxv;
541 while (av->a_type != AT_NULL)
543 size_t stack_words = (stack_val_t *) (av + 1) - &stack[1];
546 fail("Usage", "PROGRAM ARGS...", NULL, 0, NULL, 0);
549 * Now move everything back to eat our original argv[0]. When we've done
550 * that, envp and auxv will start one word back from where they were.
554 auxv = (ElfW(auxv_t) *) ep;
556 for (i = 1; i < stack_words; ++i)
557 stack[i] = stack[i + 1];
560 * If an argument is the kRDebugTemplate or kReservedAtZeroTemplate
561 * string, then we'll modify that argument string in place to specify
562 * the address of our _r_debug structure (for kRDebugTemplate) or the
563 * amount of prereserved address space (for kReservedAtZeroTemplate).
564 * We expect that the arguments matching the templates are the first
565 * arguments provided.
567 for (argn = 1; argn < argc; ++argn) {
568 if (!check_r_debug_arg(argv[argn]) &&
569 !check_reserved_at_zero_arg(argv[argn]))
574 * Record the auxv entries that are specific to the file loaded.
575 * The incoming entries point to our own static executable.
577 ElfW(auxv_t) *av_entry = NULL;
578 ElfW(auxv_t) *av_phdr = NULL;
579 ElfW(auxv_t) *av_phnum = NULL;
583 av_entry == NULL || av_phdr == NULL || av_phnum == NULL || pagesize == 0;
585 switch (av->a_type) {
588 "Failed to find AT_ENTRY, AT_PHDR, AT_PHNUM, or AT_PAGESZ!",
596 pagesize = av->a_un.a_val;
607 ReserveBottomPages(pagesize);
609 /* Load the program and point the auxv elements at its phdrs and entry. */
610 const char *interp = NULL;
611 av_entry->a_un.a_val = load_elf_file(program,
613 &av_phdr->a_un.a_val,
614 &av_phnum->a_un.a_val,
617 ElfW(Addr) entry = av_entry->a_un.a_val;
619 if (interp != NULL) {
621 * There was a PT_INTERP, so we have a dynamic linker to load.
623 entry = load_elf_file(interp, pagesize, NULL, NULL, NULL);
630 * We have to define the actual entry point code (_start) in assembly for
631 * each machine. The kernel startup protocol is not compatible with the
632 * normal C function calling convention. Here, we call do_load (above)
633 * using the normal C convention as per the ABI, with the starting stack
634 * pointer as its argument; restore the original starting stack; and
635 * finally, jump to the dynamic linker's entry point address.
637 #if defined(__i386__)
638 asm(".pushsection \".text\",\"ax\",@progbits\n"
640 ".type _start,@function\n"
643 "movl %esp, %ebx\n" /* Save starting SP in %ebx. */
644 "andl $-16, %esp\n" /* Align the stack as per ABI. */
645 "pushl %ebx\n" /* Argument: stack block. */
647 "movl %ebx, %esp\n" /* Restore the saved SP. */
648 "jmp *%eax\n" /* Jump to the entry point. */
651 #elif defined(__x86_64__)
652 asm(".pushsection \".text\",\"ax\",@progbits\n"
654 ".type _start,@function\n"
657 "movq %rsp, %rbx\n" /* Save starting SP in %rbx. */
658 "andq $-16, %rsp\n" /* Align the stack as per ABI. */
659 "movq %rbx, %rdi\n" /* Argument: stack block. */
661 "movq %rbx, %rsp\n" /* Restore the saved SP. */
662 "jmp *%rax\n" /* Jump to the entry point. */
665 #elif defined(__arm__)
666 asm(".pushsection \".text\",\"ax\",%progbits\n"
668 ".type _start,#function\n"
670 #if defined(__thumb2__)
676 "mov r4, sp\n" /* Save starting SP in r4. */
677 "mov r0, sp\n" /* Argument: stack block. */
679 "mov sp, r4\n" /* Restore the saved SP. */
680 "blx r0\n" /* Jump to the entry point. */
683 #elif defined(__mips__)
684 asm(".pushsection \".text\",\"ax\",@progbits\n"
686 ".type _start,@function\n"
689 "addiu $fp, $zero, 0\n"
690 "addiu $ra, $zero, 0\n"
691 "addiu $s8, $sp, 0\n" /* Save starting SP in s8. */
692 "addiu $a0, $sp, 0\n"
693 "addiu $sp, $sp, -16\n"
696 "addiu $sp, $s8, 0\n" /* Restore the saved SP. */
697 "jr $v0\n" /* Jump to the entry point. */
702 # error "Need stack-preserving _start code for this architecture!"
707 * We may bring in __aeabi_* functions from libgcc that in turn
708 * want to call raise.
711 return sys_kill(sys_getpid(), sig);