Commit d67ee551 authored by mcgrathr@chromium.org's avatar mcgrathr@chromium.org

Revert 113074 - Use nacl_helper_bootstrap from native_client repository

These sources have been moved over to the native_client repository.
Remove them from chromium/src altogether and just make the gyp files
refer to the native_client stuff.

BUG= none
TEST= linux still builds

R=sehr@google.com,noelallen@chromium.org

Review URL: http://codereview.chromium.org/8799016

TBR=mcgrathr@chromium.org
Review URL: http://codereview.chromium.org/8811002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@113078 0039d316-1c4b-4281-b951-d872f2087c98
parent bcc42fcb
...@@ -33,7 +33,6 @@ vars = { ...@@ -33,7 +33,6 @@ vars = {
"libjingle_revision": "95", "libjingle_revision": "95",
"libphonenumber_revision": "407", "libphonenumber_revision": "407",
"libvpx_revision": "109236", "libvpx_revision": "109236",
"lss_revision": "9",
"ffmpeg_revision": "112050", "ffmpeg_revision": "112050",
"sfntly_revision": "111", "sfntly_revision": "111",
"skia_revision": "2785", "skia_revision": "2785",
...@@ -403,8 +402,7 @@ deps_os = { ...@@ -403,8 +402,7 @@ deps_os = {
"/trunk/deps/third_party/swig/linux@" + Var("swig_revision"), "/trunk/deps/third_party/swig/linux@" + Var("swig_revision"),
"src/third_party/lss": "src/third_party/lss":
((Var("googlecode_url") % "linux-syscall-support") + "/trunk/lss@" + (Var("googlecode_url") % "linux-syscall-support") + "/trunk/lss@8",
Var("lss_revision")),
"src/third_party/openssl": "src/third_party/openssl":
"/trunk/deps/third_party/openssl@105093", "/trunk/deps/third_party/openssl@105093",
......
...@@ -418,7 +418,7 @@ ...@@ -418,7 +418,7 @@
# For now, do not build nacl_helper when disable_nacl=1 # For now, do not build nacl_helper when disable_nacl=1
['disable_nacl!=1', { ['disable_nacl!=1', {
'dependencies': [ 'dependencies': [
'../native_client/src/trusted/service_runtime/linux/nacl_bootstrap.gyp:nacl_helper_bootstrap', 'nacl_helper_bootstrap',
'nacl_helper', 'nacl_helper',
], ],
}], }],
......
...@@ -187,6 +187,166 @@ ...@@ -187,6 +187,166 @@
'ldflags': ['-pie'], 'ldflags': ['-pie'],
}, },
}, },
{
'target_name': 'nacl_helper_bootstrap_munge_phdr',
'type': 'executable',
'toolsets': ['host'],
'sources': [
'nacl/nacl_helper_bootstrap_munge_phdr.c',
],
'libraries': [
'-lelf',
],
# This is an ugly kludge because gyp doesn't actually treat
# host_arch=x64 target_arch=ia32 as proper cross compilation.
# It still wants to compile the "host" program with -m32 et
# al. Though a program built that way can indeed run on the
# x86-64 host, we cannot reliably build this program on such a
# host because Ubuntu does not provide the full suite of
# x86-32 libraries in packages that can be installed on an
# x86-64 host; in particular, libelf is missing. So here we
# use the hack of eliding all the -m* flags from the
# compilation lines, getting the command close to what they
# would be if gyp were to really build properly for the host.
# TODO(bradnelson): Clean up with proper cross support.
'conditions': [
['host_arch=="x64"', {
'cflags/': [['exclude', '-m.*']],
'ldflags/': [['exclude', '-m.*']],
}],
],
},
{
'target_name': 'nacl_helper_bootstrap_lib',
'type': 'static_library',
'product_dir': '<(SHARED_INTERMEDIATE_DIR)/chrome',
'hard_depencency': 1,
'include_dirs': [
'..',
],
'sources': [
'nacl/nacl_helper_bootstrap_linux.c',
],
'cflags': [
# The tiny standalone bootstrap program is incompatible with
# -fstack-protector, which might be on by default. That switch
# requires using the standard libc startup code, which we do not.
'-fno-stack-protector',
# We don't want to compile it PIC (or its cousin PIE), because
# it goes at an absolute address anyway, and because any kind
# of PIC complicates life for the x86-32 assembly code. We
# append -fno-* flags here instead of using a 'cflags!' stanza
# to remove -f* flags, just in case some system's compiler
# defaults to using PIC for everything.
'-fno-pic', '-fno-PIC',
'-fno-pie', '-fno-PIE',
],
'cflags!': [
# TODO(glider): -fasan is deprecated.
'-fasan',
'-faddress-sanitizer',
'-w',
],
'conditions': [
['clang==1', {
'cflags': [
# Prevent llvm-opt from replacing my_bzero with a call
# to memset
'-ffreestanding',
# But make its <limits.h> still work!
'-U__STDC_HOSTED__', '-D__STDC_HOSTED__=1',
],
}],
],
},
{
'target_name': 'nacl_helper_bootstrap_raw',
'type': 'none',
'dependencies': [
'nacl_helper_bootstrap_lib',
],
'actions': [
{
'action_name': 'link_with_ld_bfd',
'variables': {
'bootstrap_lib': '<(SHARED_INTERMEDIATE_DIR)/chrome/<(STATIC_LIB_PREFIX)nacl_helper_bootstrap_lib<(STATIC_LIB_SUFFIX)',
'linker_script': 'nacl/nacl_helper_bootstrap_linux.x',
},
'inputs': [
'<(linker_script)',
'<(bootstrap_lib)',
'../tools/ld_bfd/ld',
],
'outputs': [
'<(PRODUCT_DIR)/nacl_helper_bootstrap_raw',
],
'message': 'Linking nacl_helper_bootstrap_raw',
'conditions': [
['target_arch=="x64"', {
'variables': {
'linker_emulation': 'elf_x86_64',
'bootstrap_extra_lib': '',
}
}],
['target_arch=="ia32"', {
'variables': {
'linker_emulation': 'elf_i386',
'bootstrap_extra_lib': '',
}
}],
['target_arch=="arm"', {
'variables': {
'linker_emulation': 'armelf_linux_eabi',
# ARM requires linking against libc due to ABI
# dependencies on memset.
'bootstrap_extra_lib' : "${SYSROOT}/usr/lib/libc.a",
}
}],
],
'action': ['../tools/ld_bfd/ld',
'-m', '<(linker_emulation)',
'--build-id',
# This program is (almost) entirely
# standalone. It has its own startup code, so
# no crt1.o for it. It is statically linked,
# and on x86 it does not use libc at all.
# However, on ARM it needs a few (safe) things
# from libc.
'-static',
# Link with custom linker script for special
# layout. The script uses the symbol RESERVE_TOP.
'<@(nacl_reserve_top)',
'--script=<(linker_script)',
'-o', '<@(_outputs)',
# On x86-64, the default page size with some
# linkers is 2M rather than the real Linux page
# size of 4K. A larger page size is incompatible
# with our custom linker script's special layout.
'-z', 'max-page-size=0x1000',
'--whole-archive', '<(bootstrap_lib)',
'--no-whole-archive',
'<@(bootstrap_extra_lib)',
],
}
],
},
{
'target_name': 'nacl_helper_bootstrap',
'dependencies': [
'nacl_helper_bootstrap_raw',
'nacl_helper_bootstrap_munge_phdr#host',
],
'type': 'none',
'actions': [{
'action_name': 'munge_phdr',
'inputs': ['nacl/nacl_helper_bootstrap_munge_phdr.py',
'<(PRODUCT_DIR)/nacl_helper_bootstrap_munge_phdr',
'<(PRODUCT_DIR)/nacl_helper_bootstrap_raw'],
'outputs': ['<(PRODUCT_DIR)/nacl_helper_bootstrap'],
'message': 'Munging ELF program header',
'action': ['python', '<@(_inputs)', '<@(_outputs)']
}],
},
], ],
}], }],
], ],
......
/* Copyright (c) 2011 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* This is a standalone program that loads and runs the dynamic linker.
* This program itself must be linked statically. To keep it small, it's
* written to avoid all dependencies on libc and standard startup code.
* Hence, this should be linked using -nostartfiles. It must be compiled
* with -fno-stack-protector to ensure the compiler won't emit code that
* presumes some special setup has been done.
*
* On ARM, the compiler will emit calls to some libc functions, so we
* cannot link with -nostdlib. The functions it does use (memset and
* __aeabi_* functions for integer division) are sufficiently small and
* self-contained in ARM's libc.a that we don't have any problem using
* the libc definitions though we aren't using the rest of libc or doing
* any of the setup it might expect.
*/
#include <elf.h>
#include <fcntl.h>
#include <limits.h>
#include <link.h>
#include <stddef.h>
#include <stdint.h>
#include <sys/mman.h>
#define MAX_PHNUM 12
/*
* This exact magic argument string is recognized in check_r_debug_arg, below.
* Requiring the argument to have those Xs as a template both simplifies
* our argument matching code and saves us from having to reformat the
* whole stack to find space for a string longer than the original argument.
*/
#define R_DEBUG_TEMPLATE_PREFIX "--r_debug=0x"
#define R_DEBUG_TEMPLATE_DIGITS "XXXXXXXXXXXXXXXX"
static const char kRDebugTemplate[] =
R_DEBUG_TEMPLATE_PREFIX R_DEBUG_TEMPLATE_DIGITS;
static const size_t kRDebugPrefixLen = sizeof(R_DEBUG_TEMPLATE_PREFIX) - 1;
/*
* We're not using <string.h> functions here, to avoid dependencies.
* In the x86 libc, even "simple" functions like memset and strlen can
* depend on complex startup code, because in newer libc
* implementations they are defined using STT_GNU_IFUNC.
*/
static void my_bzero(void *buf, size_t n) {
char *p = buf;
while (n-- > 0)
*p++ = 0;
}
static size_t my_strlen(const char *s) {
size_t n = 0;
while (*s++ != '\0')
++n;
return n;
}
static int my_strcmp(const char *a, const char *b) {
while (*a == *b) {
if (*a == '\0')
return 0;
++a;
++b;
}
return (int) (unsigned char) *a - (int) (unsigned char) *b;
}
/*
* Get inline functions for system calls.
*/
static int my_errno;
#define SYS_ERRNO my_errno
#include "third_party/lss/linux_syscall_support.h"
/*
* We're avoiding libc, so no printf. The only nontrivial thing we need
* is rendering numbers, which is, in fact, pretty trivial.
*/
static void iov_int_string(int value, struct kernel_iovec *iov,
char *buf, size_t bufsz) {
char *p = &buf[bufsz];
do {
--p;
*p = "0123456789"[value % 10];
value /= 10;
} while (value != 0);
iov->iov_base = p;
iov->iov_len = &buf[bufsz] - p;
}
#define STRING_IOV(string_constant, cond) \
{ (void *) string_constant, cond ? (sizeof(string_constant) - 1) : 0 }
__attribute__((noreturn)) static void fail(const char *filename,
const char *message,
const char *item1, int value1,
const char *item2, int value2) {
char valbuf1[32];
char valbuf2[32];
struct kernel_iovec iov[] = {
STRING_IOV("bootstrap_helper: ", 1),
{ (void *) filename, my_strlen(filename) },
STRING_IOV(": ", 1),
{ (void *) message, my_strlen(message) },
{ (void *) item1, item1 == NULL ? 0 : my_strlen(item1) },
STRING_IOV("=", item1 != NULL),
{},
STRING_IOV(", ", item1 != NULL && item2 != NULL),
{ (void *) item2, item2 == NULL ? 0 : my_strlen(item2) },
STRING_IOV("=", item2 != NULL),
{},
{ "\n", 1 },
};
const int niov = sizeof(iov) / sizeof(iov[0]);
if (item1 != NULL)
iov_int_string(value1, &iov[6], valbuf1, sizeof(valbuf1));
if (item2 != NULL)
iov_int_string(value1, &iov[10], valbuf2, sizeof(valbuf2));
sys_writev(2, iov, niov);
sys_exit_group(2);
while (1) *(volatile int *) 0 = 0; /* Crash. */
}
static int my_open(const char *file, int oflag) {
int result = sys_open(file, oflag, 0);
if (result < 0)
fail(file, "Cannot open ELF file! ", "errno", my_errno, NULL, 0);
return result;
}
static void my_pread(const char *file, const char *fail_message,
int fd, void *buf, size_t bufsz, uintptr_t pos) {
ssize_t result = sys_pread64(fd, buf, bufsz, pos);
if (result < 0)
fail(file, fail_message, "errno", my_errno, NULL, 0);
if ((size_t) result != bufsz)
fail(file, fail_message, "read count", result, NULL, 0);
}
static uintptr_t my_mmap(const char *file,
const char *segment_type, unsigned int segnum,
uintptr_t address, size_t size,
int prot, int flags, int fd, uintptr_t pos) {
#if defined(__NR_mmap2)
void *result = sys_mmap2((void *) address, size, prot, flags, fd, pos >> 12);
#else
void *result = sys_mmap((void *) address, size, prot, flags, fd, pos);
#endif
if (result == MAP_FAILED)
fail(file, "Failed to map segment! ",
segment_type, segnum, "errno", my_errno);
return (uintptr_t) result;
}
static void my_mprotect(const char *file, unsigned int segnum,
uintptr_t address, size_t size, int prot) {
if (sys_mprotect((void *) address, size, prot) < 0)
fail(file, "Failed to mprotect segment hole! ",
"segment", segnum, "errno", my_errno);
}
static int prot_from_phdr(const ElfW(Phdr) *phdr) {
int prot = 0;
if (phdr->p_flags & PF_R)
prot |= PROT_READ;
if (phdr->p_flags & PF_W)
prot |= PROT_WRITE;
if (phdr->p_flags & PF_X)
prot |= PROT_EXEC;
return prot;
}
static uintptr_t round_up(uintptr_t value, uintptr_t size) {
return (value + size - 1) & -size;
}
static uintptr_t round_down(uintptr_t value, uintptr_t size) {
return value & -size;
}
/*
* Handle the "bss" portion of a segment, where the memory size
* exceeds the file size and we zero-fill the difference. For any
* whole pages in this region, we over-map anonymous pages. For the
* sub-page remainder, we zero-fill bytes directly.
*/
static void handle_bss(const char *file,
unsigned int segnum, const ElfW(Phdr) *ph,
ElfW(Addr) load_bias, size_t pagesize) {
if (ph->p_memsz > ph->p_filesz) {
ElfW(Addr) file_end = ph->p_vaddr + load_bias + ph->p_filesz;
ElfW(Addr) file_page_end = round_up(file_end, pagesize);
ElfW(Addr) page_end = round_up(ph->p_vaddr + load_bias +
ph->p_memsz, pagesize);
if (page_end > file_page_end)
my_mmap(file, "bss segment", segnum,
file_page_end, page_end - file_page_end,
prot_from_phdr(ph), MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
if (file_page_end > file_end && (ph->p_flags & PF_W))
my_bzero((void *) file_end, file_page_end - file_end);
}
}
/*
* Open an ELF file and load it into memory.
*/
static ElfW(Addr) load_elf_file(const char *filename,
size_t pagesize,
ElfW(Addr) *out_phdr,
ElfW(Addr) *out_phnum,
const char **out_interp) {
int fd = my_open(filename, O_RDONLY);
ElfW(Ehdr) ehdr;
my_pread(filename, "Failed to read ELF header from file! ",
fd, &ehdr, sizeof(ehdr), 0);
if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
ehdr.e_ident[EI_MAG3] != ELFMAG3 ||
ehdr.e_version != EV_CURRENT ||
ehdr.e_ehsize != sizeof(ehdr) ||
ehdr.e_phentsize != sizeof(ElfW(Phdr)))
fail(filename, "File has no valid ELF header!", NULL, 0, NULL, 0);
switch (ehdr.e_machine) {
#if defined(__i386__)
case EM_386:
#elif defined(__x86_64__)
case EM_X86_64:
#elif defined(__arm__)
case EM_ARM:
#else
# error "Don't know the e_machine value for this architecture!"
#endif
break;
default:
fail(filename, "ELF file has wrong architecture! ",
"e_machine", ehdr.e_machine, NULL, 0);
break;
}
ElfW(Phdr) phdr[MAX_PHNUM];
if (ehdr.e_phnum > sizeof(phdr) / sizeof(phdr[0]) || ehdr.e_phnum < 1)
fail(filename, "ELF file has unreasonable ",
"e_phnum", ehdr.e_phnum, NULL, 0);
if (ehdr.e_type != ET_DYN)
fail(filename, "ELF file not ET_DYN! ",
"e_type", ehdr.e_type, NULL, 0);
my_pread(filename, "Failed to read program headers from ELF file! ",
fd, phdr, sizeof(phdr[0]) * ehdr.e_phnum, ehdr.e_phoff);
size_t i = 0;
while (i < ehdr.e_phnum && phdr[i].p_type != PT_LOAD)
++i;
if (i == ehdr.e_phnum)
fail(filename, "ELF file has no PT_LOAD header!",
NULL, 0, NULL, 0);
/*
* ELF requires that PT_LOAD segments be in ascending order of p_vaddr.
* Find the last one to calculate the whole address span of the image.
*/
const ElfW(Phdr) *first_load = &phdr[i];
const ElfW(Phdr) *last_load = &phdr[ehdr.e_phnum - 1];
while (last_load > first_load && last_load->p_type != PT_LOAD)
--last_load;
size_t span = last_load->p_vaddr + last_load->p_memsz - first_load->p_vaddr;
/*
* Map the first segment and reserve the space used for the rest and
* for holes between segments.
*/
const uintptr_t mapping = my_mmap(filename, "segment", first_load - phdr,
round_down(first_load->p_vaddr, pagesize),
span, prot_from_phdr(first_load),
MAP_PRIVATE, fd,
round_down(first_load->p_offset, pagesize));
const ElfW(Addr) load_bias = mapping - round_down(first_load->p_vaddr,
pagesize);
if (first_load->p_offset > ehdr.e_phoff ||
first_load->p_filesz < ehdr.e_phoff + (ehdr.e_phnum * sizeof(ElfW(Phdr))))
fail(filename, "First load segment of ELF file does not contain phdrs!",
NULL, 0, NULL, 0);
handle_bss(filename, first_load - phdr, first_load, load_bias, pagesize);
ElfW(Addr) last_end = first_load->p_vaddr + load_bias + first_load->p_memsz;
/*
* Map the remaining segments, and protect any holes between them.
*/
const ElfW(Phdr) *ph;
for (ph = first_load + 1; ph <= last_load; ++ph) {
if (ph->p_type == PT_LOAD) {
ElfW(Addr) last_page_end = round_up(last_end, pagesize);
last_end = ph->p_vaddr + load_bias + ph->p_memsz;
ElfW(Addr) start = round_down(ph->p_vaddr + load_bias, pagesize);
ElfW(Addr) end = round_up(last_end, pagesize);
if (start > last_page_end)
my_mprotect(filename,
ph - phdr, last_page_end, start - last_page_end, PROT_NONE);
my_mmap(filename, "segment", ph - phdr,
start, end - start,
prot_from_phdr(ph), MAP_PRIVATE | MAP_FIXED, fd,
round_down(ph->p_offset, pagesize));
handle_bss(filename, ph - phdr, ph, load_bias, pagesize);
}
}
if (out_interp != NULL) {
/*
* Find the PT_INTERP header, if there is one.
*/
for (i = 0; i < ehdr.e_phnum; ++i) {
if (phdr[i].p_type == PT_INTERP) {
/*
* The PT_INTERP isn't really required to sit inside the first
* (or any) load segment, though it normally does. So we can
* easily avoid an extra read in that case.
*/
if (phdr[i].p_offset >= first_load->p_offset &&
phdr[i].p_filesz <= first_load->p_filesz) {
*out_interp = (const char *) (phdr[i].p_vaddr + load_bias);
} else {
static char interp_buffer[PATH_MAX + 1];
if (phdr[i].p_filesz >= sizeof(interp_buffer)) {
fail(filename, "ELF file has unreasonable PT_INTERP size! ",
"segment", i, "p_filesz", phdr[i].p_filesz);
}
my_pread(filename, "Cannot read PT_INTERP segment contents!",
fd, interp_buffer, phdr[i].p_filesz, phdr[i].p_offset);
*out_interp = interp_buffer;
}
break;
}
}
}
sys_close(fd);
if (out_phdr != NULL)
*out_phdr = (ehdr.e_phoff - first_load->p_offset +
first_load->p_vaddr + load_bias);
if (out_phnum != NULL)
*out_phnum = ehdr.e_phnum;
return ehdr.e_entry + load_bias;
}
/*
* GDB looks for this symbol name when it cannot find PT_DYNAMIC->DT_DEBUG.
* We don't have a PT_DYNAMIC, so it will find this. Now all we have to do
* is arrange for this space to be filled in with the dynamic linker's
* _r_debug contents after they're initialized. That way, attaching GDB to
* this process or examining its core file will find the PIE we loaded, the
* dynamic linker, and all the shared libraries, making debugging pleasant.
*/
struct r_debug _r_debug __attribute__((nocommon, section(".r_debug")));
/*
* If the argument matches the kRDebugTemplate string, then replace
* the 16 Xs with the hexadecimal address of our _r_debug variable.
*/
static int check_r_debug_arg(char *arg) {
if (my_strcmp(arg, kRDebugTemplate) == 0) {
uintptr_t addr = (uintptr_t) &_r_debug;
size_t i = 16;
while (i-- > 0) {
arg[kRDebugPrefixLen + i] = "0123456789abcdef"[addr & 0xf];
addr >>= 4;
}
return 1;
}
return 0;
}
/*
* This is the main loading code. It's called with the starting stack pointer.
* This points to a sequence of pointer-size words:
* [0] argc
* [1..argc] argv[0..argc-1]
* [1+argc] NULL
* [2+argc..] envp[0..]
* NULL
* auxv[0].a_type
* auxv[1].a_un.a_val
* ...
* It returns the dynamic linker's runtime entry point address, where
* we should jump to. This is called by the machine-dependent _start
* code (below). On return, it restores the original stack pointer
* and jumps to this entry point.
*
* argv[0] is the uninteresting name of this bootstrap program. argv[1] is
* the real program file name we'll open, and also the argv[0] for that
* program. We need to modify argc, move argv[1..] back to the argv[0..]
* position, and also examine and modify the auxiliary vector on the stack.
*/
ElfW(Addr) do_load(uintptr_t *stack) {
size_t i;
/*
* First find the end of the auxiliary vector.
*/
int argc = stack[0];
char **argv = (char **) &stack[1];
const char *program = argv[1];
char **envp = &argv[argc + 1];
char **ep = envp;
while (*ep != NULL)
++ep;
ElfW(auxv_t) *auxv = (ElfW(auxv_t) *) (ep + 1);
ElfW(auxv_t) *av = auxv;
while (av->a_type != AT_NULL)
++av;
size_t stack_words = (uintptr_t *) (av + 1) - &stack[1];
if (argc < 2)
fail("Usage", "PROGRAM ARGS...", NULL, 0, NULL, 0);
/*
* Now move everything back to eat our original argv[0]. When we've done
* that, envp and auxv will start one word back from where they were.
*/
--argc;
--envp;
auxv = (ElfW(auxv_t) *) ep;
stack[0] = argc;
for (i = 1; i < stack_words; ++i)
stack[i] = stack[i + 1];
/*
* If one of our arguments is the kRDebugTemplate string, then
* we'll modify that argument string in place to specify the
* address of our _r_debug structure.
*/
for (i = 1; i < argc; ++i) {
if (check_r_debug_arg(argv[i]))
break;
}
/*
* Record the auxv entries that are specific to the file loaded.
* The incoming entries point to our own static executable.
*/
ElfW(auxv_t) *av_entry = NULL;
ElfW(auxv_t) *av_phdr = NULL;
ElfW(auxv_t) *av_phnum = NULL;
size_t pagesize = 0;
for (av = auxv;
av_entry == NULL || av_phdr == NULL || av_phnum == NULL || pagesize == 0;
++av) {
switch (av->a_type) {
case AT_NULL:
fail("startup",
"Failed to find AT_ENTRY, AT_PHDR, AT_PHNUM, or AT_PAGESZ!",
NULL, 0, NULL, 0);
/*NOTREACHED*/
break;
case AT_ENTRY:
av_entry = av;
break;
case AT_PAGESZ:
pagesize = av->a_un.a_val;
break;
case AT_PHDR:
av_phdr = av;
break;
case AT_PHNUM:
av_phnum = av;
break;
}
}
/* Load the program and point the auxv elements at its phdrs and entry. */
const char *interp = NULL;
av_entry->a_un.a_val = load_elf_file(program,
pagesize,
&av_phdr->a_un.a_val,
&av_phnum->a_un.a_val,
&interp);
ElfW(Addr) entry = av_entry->a_un.a_val;
if (interp != NULL) {
/*
* There was a PT_INTERP, so we have a dynamic linker to load.
*/
entry = load_elf_file(interp, pagesize, NULL, NULL, NULL);
}
return entry;
}
/*
* We have to define the actual entry point code (_start) in assembly for
* each machine. The kernel startup protocol is not compatible with the
* normal C function calling convention. Here, we call do_load (above)
* using the normal C convention as per the ABI, with the starting stack
* pointer as its argument; restore the original starting stack; and
* finally, jump to the dynamic linker's entry point address.
*/
#if defined(__i386__)
asm(".pushsection \".text\",\"ax\",@progbits\n"
".globl _start\n"
".type _start,@function\n"
"_start:\n"
"xorl %ebp, %ebp\n"
"movl %esp, %ebx\n" /* Save starting SP in %ebx. */
"andl $-16, %esp\n" /* Align the stack as per ABI. */
"pushl %ebx\n" /* Argument: stack block. */
"call do_load\n"
"movl %ebx, %esp\n" /* Restore the saved SP. */
"jmp *%eax\n" /* Jump to the entry point. */
".popsection"
);
#elif defined(__x86_64__)
asm(".pushsection \".text\",\"ax\",@progbits\n"
".globl _start\n"
".type _start,@function\n"
"_start:\n"
"xorq %rbp, %rbp\n"
"movq %rsp, %rbx\n" /* Save starting SP in %rbx. */
"andq $-16, %rsp\n" /* Align the stack as per ABI. */
"movq %rbx, %rdi\n" /* Argument: stack block. */
"call do_load\n"
"movq %rbx, %rsp\n" /* Restore the saved SP. */
"jmp *%rax\n" /* Jump to the entry point. */
".popsection"
);
#elif defined(__arm__)
asm(".pushsection \".text\",\"ax\",%progbits\n"
".globl _start\n"
".type _start,#function\n"
"_start:\n"
#if defined(__thumb2__)
".thumb\n"
".syntax unified\n"
#endif
"mov fp, #0\n"
"mov lr, #0\n"
"mov r4, sp\n" /* Save starting SP in r4. */
"mov r0, sp\n" /* Argument: stack block. */
"bl do_load\n"
"mov sp, r4\n" /* Restore the saved SP. */
"blx r0\n" /* Jump to the entry point. */
".popsection"
);
#else
# error "Need stack-preserving _start code for this architecture!"
#endif
/* Copyright (c) 2011 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* This is a custom linker script used to build nacl_helper_bootstrap.
* It has a very special layout. This script will only work with input
* that is kept extremely minimal. If there are unexpected input sections
* not named here, the result will not be correct.
*
* We need to use a standalone loader program rather than just using a
* dynamically-linked program here because its entire address space will be
* taken over for the NaCl untrusted address space. A normal program would
* cause dynamic linker data structures to point to its .dynamic section,
* which is no longer available after startup.
*
* We need this special layout (and the nacl_helper_bootstrap_munge_phdr
* step) because simply having bss space large enough to reserve the
* address space would cause the kernel loader to think we're using that
* much anonymous memory and refuse to execute the program on a machine
* with not much memory available.
*/
/*
* Set the entry point to the symbol called _start, which we define in assembly.
*/
ENTRY(_start)
/*
* This is the address where the program text starts.
* We set this as low as we think we can get away with.
* The common settings for sysctl vm.mmap_min_addr range from 4k to 64k.
*/
TEXT_START = 0x10000;
/*
* The symbol RESERVE_TOP is the top of the range we are trying to reserve.
* This is set via --defsym on the linker command line, because the correct
* value differs for each machine. It's not defined at all if we do not
* actually need any space reserved for this configuration.
*/
/*
* We specify the program headers we want explicitly, to get the layout
* exactly right and to give the "reserve" segment p_flags of zero, so
* that it gets mapped as PROT_NONE.
*/
PHDRS {
text PT_LOAD FILEHDR PHDRS;
data PT_LOAD;
reserve PT_LOAD FLAGS(0);
r_debug PT_LOAD;
note PT_NOTE;
stack PT_GNU_STACK FLAGS(6); /* RW, no E */
}
/*
* Now we lay out the sections across those segments.
*/
SECTIONS {
. = TEXT_START + SIZEOF_HEADERS;
/*
* The build ID note usually comes first.
* It's both part of the text PT_LOAD segment (like other rodata) and
* it's what the PT_NOTE header points to.
*/
.note.gnu.build-id : {
*(.note.gnu.build-id)
} :text :note
/*
* Here is the program itself.
*/
.text : {
*(.text*)
} :text
.rodata : {
*(.rodata*)
*(.eh_frame*)
}
etext = .;
/*
* Adjust the address for the data segment. We want to adjust up to
* the same address within the page on the next page up.
*/
. = (ALIGN(CONSTANT(MAXPAGESIZE)) -
((CONSTANT(MAXPAGESIZE) - .) & (CONSTANT(MAXPAGESIZE) - 1)));
. = DATA_SEGMENT_ALIGN(CONSTANT(MAXPAGESIZE), CONSTANT(COMMONPAGESIZE));
.data : {
*(.data*)
} :data
.bss : {
*(.bss*)
}
/*
* Now we move up to the next p_align increment, and place the dummy
* segment there. The linker emits this segment with the p_vaddr and
* p_memsz we want, which reserves the address space. But the linker
* gives it a p_filesz of zero. We have to edit the phdr after link
* time to give it a p_filesz matching its p_memsz. That way, the
* kernel doesn't think we are preallocating a huge amount of memory.
* It just maps it from the file, i.e. way off the end of the file,
* which is perfect for reserving the address space.
*/
. = ALIGN(CONSTANT(COMMONPAGESIZE));
RESERVE_START = .;
.reserve : {
. += DEFINED(RESERVE_TOP) ? (RESERVE_TOP - RESERVE_START) : 0;
} :reserve
/*
* This must be placed above the reserved address space, so it won't
* be clobbered by NaCl. We want this to be visible at its fixed address
* in the memory image so the debugger can make sense of things.
*/
.r_debug : {
*(.r_debug)
} :r_debug
/*
* These are empty input sections the linker generates.
* If we don't discard them, they pollute the flags in the output segment.
*/
/DISCARD/ : {
*(.iplt)
*(.rel*)
*(.igot.plt)
}
}
/* Copyright (c) 2011 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* This is a trivial program to edit an ELF file in place, making
* one crucial modification to a program header. It's invoked:
* bootstrap_phdr_hacker FILENAME SEGMENT_NUMBER
* where SEGMENT_NUMBER is the zero-origin index of the program header
* we'll touch. This is a PT_LOAD with p_filesz of zero. We change its
* p_filesz to match its p_memsz value.
*/
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <gelf.h>
#include <libelf.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv) {
if (argc != 3)
error(1, 0, "Usage: %s FILENAME SEGMENT_NUMBER", argv[0]);
const char *const file = argv[1];
const int segment = atoi(argv[2]);
int fd = open(file, O_RDWR);
if (fd < 0)
error(2, errno, "Cannot open %s for read/write", file);
if (elf_version(EV_CURRENT) == EV_NONE)
error(2, 0, "elf_version: %s", elf_errmsg(-1));
Elf *elf = elf_begin(fd, ELF_C_RDWR, NULL);
if (elf == NULL)
error(2, 0, "elf_begin: %s", elf_errmsg(-1));
if (elf_flagelf(elf, ELF_C_SET, ELF_F_LAYOUT) == 0)
error(2, 0, "elf_flagelf: %s", elf_errmsg(-1));
GElf_Phdr phdr;
GElf_Phdr *ph = gelf_getphdr(elf, segment, &phdr);
if (ph == NULL)
error(2, 0, "gelf_getphdr: %s", elf_errmsg(-1));
if (ph->p_type != PT_LOAD)
error(3, 0, "Program header %d is %u, not PT_LOAD",
segment, (unsigned int) ph->p_type);
if (ph->p_filesz != 0)
error(3, 0, "Program header %d has nonzero p_filesz", segment);
ph->p_filesz = ph->p_memsz;
if (gelf_update_phdr(elf, segment, ph) == 0)
error(2, 0, "gelf_update_phdr: %s", elf_errmsg(-1));
if (elf_flagphdr(elf, ELF_C_SET, ELF_F_DIRTY) == 0)
error(2, 0, "elf_flagphdr: %s", elf_errmsg(-1));
if (elf_update(elf, ELF_C_WRITE) < 0)
error(2, 0, "elf_update: %s", elf_errmsg(-1));
close(fd);
return 0;
}
#!/usr/bin/env python
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""This takes three command-line arguments:
MUNGE-PHDR-PROGRAM file name of program built from
nacl_helper_bootstrap_munge_phdr.c
INFILE raw linked ELF file name
OUTFILE output file name
We just run the MUNGE-PHDR-PROGRAM on a copy of INFILE.
That modifies the file in place. Then we move it to OUTFILE.
We only have this wrapper script because nacl_helper_bootstrap_munge_phdr.c
wants to modify a file in place (and it would be a much longer and more
fragile program if it created a fresh ELF output file instead).
"""
import shutil
import subprocess
import sys
def Main(argv):
if len(argv) != 4:
print 'Usage: %s MUNGE-PHDR-PROGRAM INFILE OUTFILE' % argv[0]
return 1
[prog, munger, infile, outfile] = argv
tmpfile = outfile + '.tmp'
shutil.copy(infile, tmpfile)
segment_num = '2'
subprocess.check_call([munger, tmpfile, segment_num])
shutil.move(tmpfile, outfile)
return 0
if __name__ == '__main__':
sys.exit(Main(sys.argv))
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment