11dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*
21dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * All rights reserved.
41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Redistribution and use in source and binary forms, with or without
61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * modification, are permitted provided that the following conditions
71dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * are met:
81dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *  * Redistributions of source code must retain the above copyright
91dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *  * Redistributions in binary form must reproduce the above copyright
111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    notice, this list of conditions and the following disclaimer in
121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    the documentation and/or other materials provided with the
131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    distribution.
141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * SUCH DAMAGE.
271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*
291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * libc_init_static.c
301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
31b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner * The program startup function __libc_init() defined here is
32b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner * used for static executables only (i.e. those that don't depend
33b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner * on shared libraries). It is called from arch-$ARCH/bionic/crtbegin_static.S
34b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner * which is directly invoked by the kernel when the program is launched.
351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
36b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner * The 'structors' parameter contains pointers to various initializer
37b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner * arrays that must be run before the program's 'main' routine is launched.
381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes#include <elf.h>
4142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes#include <errno.h>
421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stddef.h>
4342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes#include <stdint.h>
441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdio.h>
451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdlib.h>
4642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes#include <sys/auxv.h>
4742b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes#include <sys/mman.h>
4842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes
493a654b1e04d4275ae315cfe1b196998acf10052cDavid 'Digit' Turner#include "atexit.h"
5042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes#include "bionic_tls.h"
5142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes#include "KernelArgumentBlock.h"
521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "libc_init_common.h"
5342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes#include "pthread_internal.h"
54ac3de8d080745e62c77fdf03e3923726d0a6b50dNick Kralevich
55ac3de8d080745e62c77fdf03e3923726d0a6b50dNick Kralevich// Returns the address of the page containing address 'x'.
56ac3de8d080745e62c77fdf03e3923726d0a6b50dNick Kralevich#define PAGE_START(x)  ((x) & PAGE_MASK)
57ac3de8d080745e62c77fdf03e3923726d0a6b50dNick Kralevich
58ac3de8d080745e62c77fdf03e3923726d0a6b50dNick Kralevich// Returns the address of the next page after address 'x', unless 'x' is
59ac3de8d080745e62c77fdf03e3923726d0a6b50dNick Kralevich// itself at the start of a page.
60ac3de8d080745e62c77fdf03e3923726d0a6b50dNick Kralevich#define PAGE_END(x)    PAGE_START((x) + (PAGE_SIZE-1))
613a654b1e04d4275ae315cfe1b196998acf10052cDavid 'Digit' Turner
6242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughesstatic void call_array(void(**list)()) {
6342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  // First element is -1, list is null-terminated
6442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  while (*++list) {
6542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes    (*list)();
6642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  }
67b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner}
68b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner
692c5153b043b44e9935a334ae9b2d5a4bc5258b40Nick Kralevichstatic void apply_gnu_relro() {
7042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  Elf32_Phdr* phdr_start = reinterpret_cast<Elf32_Phdr*>(getauxval(AT_PHDR));
7142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  unsigned long int phdr_ct = getauxval(AT_PHNUM);
72ac3de8d080745e62c77fdf03e3923726d0a6b50dNick Kralevich
7342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  for (Elf32_Phdr* phdr = phdr_start; phdr < (phdr_start + phdr_ct); phdr++) {
7442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes    if (phdr->p_type != PT_GNU_RELRO) {
7542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes      continue;
76ac3de8d080745e62c77fdf03e3923726d0a6b50dNick Kralevich    }
77ac3de8d080745e62c77fdf03e3923726d0a6b50dNick Kralevich
7842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes    Elf32_Addr seg_page_start = PAGE_START(phdr->p_vaddr);
7942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes    Elf32_Addr seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz);
80b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner
8142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes    // Check return value here? What do we do if we fail?
8242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes    mprotect(reinterpret_cast<void*>(seg_page_start), seg_page_end - seg_page_start, PROT_READ);
8342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  }
8442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes}
85b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner
8642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes__noreturn void __libc_init(void* raw_args,
8742b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes                            void (*onexit)(void),
8842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes                            int (*slingshot)(int, char**, char**),
8942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes                            structors_array_t const * const structors) {
9042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  KernelArgumentBlock args(raw_args);
91d3920b3a996b358e48232f417aa0a1e44a60f155Elliott Hughes  __libc_init_tls(args);
9242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  __libc_init_common(args);
93b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner
9442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  apply_gnu_relro();
95b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner
9642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  // Several Linux ABIs don't pass the onexit pointer, and the ones that
9742b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  // do never use it.  Therefore, we ignore it.
98b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner
9942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  call_array(structors->preinit_array);
10042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  call_array(structors->init_array);
101b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner
10242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  // The executable may have its own destructors listed in its .fini_array
10342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  // so we need to ensure that these are called when the program exits
10442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  // normally.
10542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  if (structors->fini_array != NULL) {
10642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes    __cxa_atexit(__libc_fini,structors->fini_array,NULL);
10742b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  }
1081df986c21ee52c6756846b4a5e45cb316f772112David 'Digit' Turner
10942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  exit(slingshot(args.argc, args.argv, args.envp));
1101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
111