diff --git a/linker/Android.mk b/linker/Android.mk index d1773a844..2def99dad 100644 --- a/linker/Android.mk +++ b/linker/Android.mk @@ -21,7 +21,8 @@ LOCAL_LDFLAGS := -shared -Wl,--exclude-libs,ALL LOCAL_CFLAGS += -fno-stack-protector \ -Wstrict-overflow=5 \ -fvisibility=hidden \ - -Wall -Wextra -Werror + -Wall -Wextra -Werror \ + -g # We need to access Bionic private headers in the linker. LOCAL_CFLAGS += -I$(LOCAL_PATH)/../libc/ @@ -30,12 +31,16 @@ ifeq ($(TARGET_ARCH),arm) LOCAL_CFLAGS += -DANDROID_ARM_LINKER endif +ifeq ($(TARGET_ARCH),mips) + LOCAL_CFLAGS += -DANDROID_MIPS_LINKER +endif + ifeq ($(TARGET_ARCH),x86) LOCAL_CFLAGS += -DANDROID_X86_LINKER endif -ifeq ($(TARGET_ARCH),mips) - LOCAL_CFLAGS += -DANDROID_MIPS_LINKER +ifeq ($(TARGET_ARCH),x86_64) + LOCAL_CFLAGS += -DANDROID_X86_64_LINKER endif LOCAL_MODULE:= linker diff --git a/linker/arch/x86_64/begin.S b/linker/arch/x86_64/begin.S new file mode 100644 index 000000000..9ecad1aee --- /dev/null +++ b/linker/arch/x86_64/begin.S @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +ENTRY(_start) + /* Pass elfdata to __linker_init. */ + mov %rsp, %rdi + call __linker_init + + /* linker init returns (%rax) the _entry address in the main image */ + jmp *%rax +END(_start) diff --git a/linker/debugger.cpp b/linker/debugger.cpp index c9475228b..6ddd35805 100644 --- a/linker/debugger.cpp +++ b/linker/debugger.cpp @@ -176,7 +176,12 @@ static bool have_siginfo(int signum) { * Catches fatal signals so we can ask debuggerd to ptrace us before * we crash. */ +#if __LP64__ // TODO: implement 64-bit sigaction using rt_sigaction. +void debuggerd_signal_handler(int n) { + siginfo_t* info = NULL; +#else void debuggerd_signal_handler(int n, siginfo_t* info, void*) { +#endif /* * It's possible somebody cleared the SA_SIGINFO flag, which would mean * our "info" arg holds an undefined value. @@ -249,7 +254,11 @@ void debuggerd_init() { struct sigaction action; memset(&action, 0, sizeof(action)); sigemptyset(&action.sa_mask); +#if __LP64__ // TODO: implement 64-bit sigaction using rt_sigaction. + action.sa_handler = debuggerd_signal_handler; +#else action.sa_sigaction = debuggerd_signal_handler; +#endif action.sa_flags = SA_RESTART | SA_SIGINFO; // Use the alternate signal stack if available so we can catch stack overflows. diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp index b438f00f7..621bcb730 100644 --- a/linker/dlfcn.cpp +++ b/linker/dlfcn.cpp @@ -100,11 +100,10 @@ void* dlsym(void* handle, const char* symbol) { } if (sym != NULL) { - unsigned bind = ELF32_ST_BIND(sym->st_info); + unsigned bind = ELF_ST_BIND(sym->st_info); if (bind == STB_GLOBAL && sym->st_shndx != 0) { - unsigned ret = sym->st_value + found->load_bias; - return (void*) ret; + return reinterpret_cast(sym->st_value + found->load_bias); } __bionic_format_dlerror("symbol found but not global", symbol); @@ -150,13 +149,13 @@ int dlclose(void* handle) { // 0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890123456789012 3456789 #define ANDROID_LIBDL_STRTAB \ "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0android_update_LD_LIBRARY_PATH\0dl_iterate_phdr\0dl_unwind_find_exidx\0" -#elif defined(ANDROID_X86_LINKER) || defined(ANDROID_MIPS_LINKER) +#elif defined(ANDROID_MIPS_LINKER) || defined(ANDROID_X86_LINKER) || defined(ANDROID_X86_64_LINKER) // 0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667 // 0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890 #define ANDROID_LIBDL_STRTAB \ "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0android_update_LD_LIBRARY_PATH\0dl_iterate_phdr\0" #else -#error Unsupported architecture. Only ARM, MIPS, and x86 are presently supported. +#error Unsupported architecture. Only ARM, MIPS, x86, and x86_64 are presently supported. #endif // name_offset: starting index of the name in libdl_info.strtab @@ -166,23 +165,39 @@ int dlclose(void* handle) { /* st_size */ 0, \ (shndx == 0) ? 0 : (STB_GLOBAL << 4), \ /* st_other */ 0, \ - shndx } + shndx, \ + } -static Elf32_Sym gLibDlSymtab[] = { +#define ELF64_SYM_INITIALIZER(name_offset, value, shndx) \ + { name_offset, \ + (shndx == 0) ? 0 : (STB_GLOBAL << 4), \ + /* st_other */ 0, \ + shndx, \ + reinterpret_cast(reinterpret_cast(value)), \ + /* st_size */ 0, \ + } + +#if defined(__LP64__) +# define ELF_SYM_INITIALIZER ELF64_SYM_INITIALIZER +#else +# define ELF_SYM_INITIALIZER ELF32_SYM_INITIALIZER +#endif + +static Elf_Sym gLibDlSymtab[] = { // Total length of libdl_info.strtab, including trailing 0. // This is actually the STH_UNDEF entry. Technically, it's // supposed to have st_name == 0, but instead, it points to an index // in the strtab with a \0 to make iterating through the symtab easier. - ELF32_SYM_INITIALIZER(sizeof(ANDROID_LIBDL_STRTAB) - 1, NULL, 0), - ELF32_SYM_INITIALIZER( 0, &dlopen, 1), - ELF32_SYM_INITIALIZER( 7, &dlclose, 1), - ELF32_SYM_INITIALIZER(15, &dlsym, 1), - ELF32_SYM_INITIALIZER(21, &dlerror, 1), - ELF32_SYM_INITIALIZER(29, &dladdr, 1), - ELF32_SYM_INITIALIZER(36, &android_update_LD_LIBRARY_PATH, 1), - ELF32_SYM_INITIALIZER(67, &dl_iterate_phdr, 1), + ELF_SYM_INITIALIZER(sizeof(ANDROID_LIBDL_STRTAB) - 1, NULL, 0), + ELF_SYM_INITIALIZER( 0, &dlopen, 1), + ELF_SYM_INITIALIZER( 7, &dlclose, 1), + ELF_SYM_INITIALIZER(15, &dlsym, 1), + ELF_SYM_INITIALIZER(21, &dlerror, 1), + ELF_SYM_INITIALIZER(29, &dladdr, 1), + ELF_SYM_INITIALIZER(36, &android_update_LD_LIBRARY_PATH, 1), + ELF_SYM_INITIALIZER(67, &dl_iterate_phdr, 1), #if defined(ANDROID_ARM_LINKER) - ELF32_SYM_INITIALIZER(83, &dl_unwind_find_exidx, 1), + ELF_SYM_INITIALIZER(83, &dl_unwind_find_exidx, 1), #endif }; @@ -215,9 +230,18 @@ static unsigned gLibDlChains[8] = { 0, 2, 3, 4, 5, 6, 7, 0 }; soinfo libdl_info = { "libdl.so", - phdr: 0, phnum: 0, - entry: 0, base: 0, size: 0, - unused1: 0, dynamic: 0, unused2: 0, unused3: 0, + phdr: 0, + phnum: 0, + entry: 0, + base: 0, + size: 0, +#if !defined(__LP64__) + unused1: 0, +#endif + dynamic: 0, +#if !defined(__LP64__) + unused2: 0, unused3: 0, +#endif next: 0, flags: FLAG_LINKED, @@ -230,14 +254,38 @@ soinfo libdl_info = { bucket: gLibDlBuckets, chain: gLibDlChains, - plt_got: 0, plt_rel: 0, plt_rel_count: 0, rel: 0, rel_count: 0, - preinit_array: 0, preinit_array_count: 0, init_array: 0, init_array_count: 0, - fini_array: 0, fini_array_count: 0, init_func: 0, fini_func: 0, +#if defined(ANDROID_X86_64_LINKER) + plt_rela: 0, + plt_rela_count: 0, + rela: 0, + rela_count: 0, +#else + plt_got: 0, + plt_rel: 0, + plt_rel_count: 0, + rel: 0, + rel_count: 0, +#endif + + preinit_array: 0, + preinit_array_count: 0, + + init_array: 0, + init_array_count: 0, + + fini_array: 0, + fini_array_count: 0, + + init_func: 0, + fini_func: 0, #if defined(ANDROID_ARM_LINKER) - ARM_exidx: 0, ARM_exidx_count: 0, + ARM_exidx: 0, + ARM_exidx_count: 0, #elif defined(ANDROID_MIPS_LINKER) - mips_symtabno: 0, mips_local_gotno: 0, mips_gotsym: 0, + mips_symtabno: 0, + mips_local_gotno: 0, + mips_gotsym: 0, #endif ref_count: 0, diff --git a/linker/linker.cpp b/linker/linker.cpp index 983d0a0a8..d218590cf 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -404,7 +404,7 @@ _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount) soinfo *si; unsigned addr = (unsigned)pc; - for (si = solist; si != 0; si = si->next){ + for (si = solist; si != 0; si = si->next) { if ((addr >= si->base) && (addr < (si->base + si->size))) { *pcount = si->ARM_exidx_count; return (_Unwind_Ptr)si->ARM_exidx; @@ -441,23 +441,24 @@ static Elf_Sym* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) { Elf_Sym* symtab = si->symtab; const char* strtab = si->strtab; - TRACE_TYPE(LOOKUP, "SEARCH %s in %s@0x%08x %08x %zd", - name, si->name, si->base, hash, hash % si->nbucket); + TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p %x %zd", + name, si->name, reinterpret_cast(si->base), hash, hash % si->nbucket); for (unsigned n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) { Elf_Sym* s = symtab + n; if (strcmp(strtab + s->st_name, name)) continue; /* only concern ourselves with global and weak symbol definitions */ - switch(ELF32_ST_BIND(s->st_info)){ + switch (ELF_ST_BIND(s->st_info)) { case STB_GLOBAL: case STB_WEAK: if (s->st_shndx == SHN_UNDEF) { continue; } - TRACE_TYPE(LOOKUP, "FOUND %s in %s (%08x) %d", - name, si->name, s->st_value, s->st_size); + TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd", + name, si->name, reinterpret_cast(s->st_value), + static_cast(s->st_size)); return s; } } @@ -568,10 +569,11 @@ static Elf_Sym* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, soi done: if (s != NULL) { - TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = 0x%08x, " - "found in %s, base = 0x%08x, load bias = 0x%08x", - si->name, name, s->st_value, - (*lsi)->name, (*lsi)->base, (*lsi)->load_bias); + TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, " + "found in %s, base = %p, load bias = %p", + si->name, name, reinterpret_cast(s->st_value), + (*lsi)->name, reinterpret_cast((*lsi)->base), + reinterpret_cast((*lsi)->load_bias)); return s; } @@ -613,8 +615,8 @@ Elf_Sym* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start) { } if (s != NULL) { - TRACE_TYPE(LOOKUP, "%s s->st_value = 0x%08x, found->base = 0x%08x", - name, s->st_value, (*found)->base); + TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p", + name, reinterpret_cast(s->st_value), reinterpret_cast((*found)->base)); } return s; @@ -767,8 +769,8 @@ static soinfo* find_library_internal(const char* name) { // At this point we know that whatever is loaded @ base is a valid ELF // shared library whose segments are properly mapped in. - TRACE("[ init_library base=0x%08x sz=0x%08x name='%s' ]", - si->base, si->size, si->name); + TRACE("[ init_library base=%p sz=0x%08x name='%s' ]", + reinterpret_cast(si->base), si->size, si->name); if (!soinfo_link_image(si)) { munmap(reinterpret_cast(si->base), si->size); @@ -838,10 +840,124 @@ int do_dlclose(soinfo* si) { return result; } -/* TODO: don't use unsigned for addrs below. It works, but is not - * ideal. They should probably be either uint32_t, Elf_Addr, or unsigned - * long. - */ +#if defined(ANDROID_X86_64_LINKER) +static int soinfo_relocate_a(soinfo* si, Elf_Rela* rela, unsigned count, soinfo* needed[]) { + Elf_Sym* symtab = si->symtab; + const char* strtab = si->strtab; + Elf_Sym* s; + Elf_Rela* start = rela; + soinfo* lsi; + + for (size_t idx = 0; idx < count; ++idx, ++rela) { + unsigned type = ELF_R_TYPE(rela->r_info); + unsigned sym = ELF_R_SYM(rela->r_info); + Elf_Addr reloc = static_cast(rela->r_offset + si->load_bias); + Elf_Addr sym_addr = 0; + char* sym_name = NULL; + + DEBUG("Processing '%s' relocation at index %zd", si->name, idx); + if (type == 0) { // R_*_NONE + continue; + } + if (sym != 0) { + sym_name = (char *)(strtab + symtab[sym].st_name); + s = soinfo_do_lookup(si, sym_name, &lsi, needed); + if (s == NULL) { + // We only allow an undefined symbol if this is a weak reference... + s = &symtab[sym]; + if (ELF_ST_BIND(s->st_info) != STB_WEAK) { + DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, si->name); + return -1; + } + + /* IHI0044C AAELF 4.5.1.1: + + Libraries are not searched to resolve weak references. + It is not an error for a weak reference to remain unsatisfied. + + During linking, the value of an undefined weak reference is: + - Zero if the relocation type is absolute + - The address of the place if the relocation is pc-relative + - The address of nominal base address if the relocation + type is base-relative. + */ + + switch (type) { + case R_X86_64_JUMP_SLOT: + case R_X86_64_GLOB_DAT: + case R_X86_64_32: + case R_X86_64_RELATIVE: + // No need to do anything. + break; + + case R_X86_64_PC32: + sym_addr = reloc; + break; + + default: + DL_ERR("unknown weak reloc type %d @ %p (%d)", type, rela, (int) (rela - start)); + return -1; + } + } else { + // We got a definition. + sym_addr = static_cast(s->st_value + lsi->load_bias); + } + count_relocation(kRelocSymbol); + } else { + s = NULL; + } + + switch (type) { + case R_X86_64_JUMP_SLOT: + count_relocation(kRelocAbsolute); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "RELO JMP_SLOT %08zx <- %08zx %s", static_cast(reloc), + static_cast(sym_addr + rela->r_addend), sym_name); + *reinterpret_cast(reloc) = sym_addr + rela->r_addend; + break; + case R_X86_64_GLOB_DAT: + count_relocation(kRelocAbsolute); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "RELO GLOB_DAT %08zx <- %08zx %s", static_cast(reloc), + static_cast(sym_addr + rela->r_addend), sym_name); + *reinterpret_cast(reloc) = sym_addr + rela->r_addend; + break; + case R_X86_64_RELATIVE: + count_relocation(kRelocRelative); + MARK(rela->r_offset); + if (sym) { + DL_ERR("odd RELATIVE form..."); + return -1; + } + TRACE_TYPE(RELO, "RELO RELATIVE %08zx <- +%08zx", static_cast(reloc), + static_cast(si->base)); + *reinterpret_cast(reloc) = si->base + rela->r_addend; + break; + + case R_X86_64_32: + count_relocation(kRelocRelative); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast(reloc), + static_cast(sym_addr), sym_name); + *reinterpret_cast(reloc) = sym_addr + rela->r_addend; + break; + + case R_X86_64_PC32: + count_relocation(kRelocRelative); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s", + static_cast(reloc), static_cast(sym_addr - reloc), + static_cast(sym_addr), static_cast(reloc), sym_name); + *reinterpret_cast(reloc) = sym_addr + rela->r_addend - reloc; + break; + default: + DL_ERR("unknown reloc type %d @ %p (%d)", type, rela, (int) (rela - start)); + return -1; + } + } + return 0; +} +#else static int soinfo_relocate(soinfo* si, Elf_Rel* rel, unsigned count, soinfo* needed[]) { @@ -852,8 +968,9 @@ static int soinfo_relocate(soinfo* si, Elf_Rel* rel, unsigned count, soinfo* lsi; for (size_t idx = 0; idx < count; ++idx, ++rel) { - unsigned type = ELF32_R_TYPE(rel->r_info); - unsigned sym = ELF32_R_SYM(rel->r_info); + unsigned type = ELF_R_TYPE(rel->r_info); + // TODO: don't use unsigned for 'sym'. Use uint32_t or Elf_Addr instead. + unsigned sym = ELF_R_SYM(rel->r_info); Elf_Addr reloc = static_cast(rel->r_offset + si->load_bias); Elf_Addr sym_addr = 0; char* sym_name = NULL; @@ -869,7 +986,7 @@ static int soinfo_relocate(soinfo* si, Elf_Rel* rel, unsigned count, /* We only allow an undefined symbol if this is a weak reference.. */ s = &symtab[sym]; - if (ELF32_ST_BIND(s->st_info) != STB_WEAK) { + if (ELF_ST_BIND(s->st_info) != STB_WEAK) { DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, si->name); return -1; } @@ -897,7 +1014,7 @@ static int soinfo_relocate(soinfo* si, Elf_Rel* rel, unsigned count, case R_386_JMP_SLOT: case R_386_GLOB_DAT: case R_386_32: - case R_386_RELATIVE: /* Dont' care. */ + case R_386_RELATIVE: /* Don't care. */ #endif /* ANDROID_*_LINKER */ /* sym_addr was initialized to be zero above or relocation code below does not care about value of sym_addr. @@ -940,7 +1057,7 @@ static int soinfo_relocate(soinfo* si, Elf_Rel* rel, unsigned count, /* TODO: This is ugly. Split up the relocations by arch into * different files. */ - switch(type){ + switch (type) { #if defined(ANDROID_ARM_LINKER) case R_ARM_JUMP_SLOT: count_relocation(kRelocAbsolute); @@ -1005,7 +1122,8 @@ static int soinfo_relocate(soinfo* si, Elf_Rel* rel, unsigned count, DL_ERR("odd RELATIVE form..."); return -1; } - TRACE_TYPE(RELO, "RELO RELATIVE %08x <- +%08x", reloc, si->base); + TRACE_TYPE(RELO, "RELO RELATIVE %p <- +%p", + reinterpret_cast(reloc), reinterpret_cast(si->base)); *reinterpret_cast(reloc) += si->base; break; @@ -1080,6 +1198,7 @@ static int soinfo_relocate(soinfo* si, Elf_Rel* rel, unsigned count, } return 0; } +#endif #ifdef ANDROID_MIPS_LINKER static bool mips_relocate_got(soinfo* si, soinfo* needed[]) { @@ -1129,7 +1248,7 @@ static bool mips_relocate_got(soinfo* si, soinfo* needed[]) { /* We only allow an undefined symbol if this is a weak reference.. */ s = &symtab[g]; - if (ELF32_ST_BIND(s->st_info) != STB_WEAK) { + if (ELF_ST_BIND(s->st_info) != STB_WEAK) { DL_ERR("cannot locate \"%s\"...", sym_name); return false; } @@ -1307,7 +1426,7 @@ static bool soinfo_link_image(soinfo* si) { /* We can't debug anything until the linker is relocated */ if (!relocating_linker) { INFO("[ linking %s ]", si->name); - DEBUG("si->base = 0x%08x si->flags = 0x%08x", si->base, si->flags); + DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast(si->base), si->flags); } /* Extract dynamic section */ @@ -1334,8 +1453,9 @@ static bool soinfo_link_image(soinfo* si) { // Extract useful information from dynamic section. uint32_t needed_count = 0; for (Elf_Dyn* d = si->dynamic; d->d_tag != DT_NULL; ++d) { - DEBUG("d = %p, d[0](tag) = 0x%08x d[1](val) = 0x%08x", d, d->d_tag, d->d_un.d_val); - switch(d->d_tag){ + DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p", + d, reinterpret_cast(d->d_tag), reinterpret_cast(d->d_un.d_val)); + switch (d->d_tag) { case DT_HASH: si->nbucket = ((unsigned *) (base + d->d_un.d_ptr))[0]; si->nchain = ((unsigned *) (base + d->d_un.d_ptr))[1]; @@ -1348,28 +1468,34 @@ static bool soinfo_link_image(soinfo* si) { case DT_SYMTAB: si->symtab = (Elf_Sym *) (base + d->d_un.d_ptr); break; +#if !defined(ANDROID_X86_64_LINKER) case DT_PLTREL: if (d->d_un.d_val != DT_REL) { DL_ERR("unsupported DT_RELA in \"%s\"", si->name); return false; } break; +#endif case DT_JMPREL: +#if defined(ANDROID_X86_64_LINKER) + si->plt_rela = (Elf_Rela*) (base + d->d_un.d_ptr); +#else si->plt_rel = (Elf_Rel*) (base + d->d_un.d_ptr); +#endif break; case DT_PLTRELSZ: +#if defined(ANDROID_X86_64_LINKER) + si->plt_rela_count = d->d_un.d_val / sizeof(Elf_Rela); +#else si->plt_rel_count = d->d_un.d_val / sizeof(Elf_Rel); - break; - case DT_REL: - si->rel = (Elf_Rel*) (base + d->d_un.d_ptr); - break; - case DT_RELSZ: - si->rel_count = d->d_un.d_val / sizeof(Elf_Rel); +#endif break; case DT_PLTGOT: +#if !defined(ANDROID_X86_64_LINKER) /* Save this in case we decide to do lazy binding. We don't yet. */ si->plt_got = (unsigned *)(base + d->d_un.d_ptr); break; +#endif case DT_DEBUG: // Set the DT_DEBUG entry to the address of _r_debug for GDB // if the dynamic table is writable @@ -1377,9 +1503,30 @@ static bool soinfo_link_image(soinfo* si) { d->d_un.d_val = reinterpret_cast(&_r_debug); } break; +#if defined(ANDROID_X86_64_LINKER) + case DT_RELA: + si->rela = (Elf_Rela*) (base + d->d_un.d_ptr); + break; + case DT_RELASZ: + si->rela_count = d->d_un.d_val / sizeof(Elf_Rela); + break; + case DT_REL: + DL_ERR("unsupported DT_REL in \"%s\"", si->name); + return false; + case DT_RELSZ: + DL_ERR("unsupported DT_RELSZ in \"%s\"", si->name); + return false; +#else + case DT_REL: + si->rel = (Elf_Rel*) (base + d->d_un.d_ptr); + break; + case DT_RELSZ: + si->rel_count = d->d_un.d_val / sizeof(Elf_Rel); + break; case DT_RELA: DL_ERR("unsupported DT_RELA in \"%s\"", si->name); return false; +#endif case DT_INIT: si->init_func = reinterpret_cast(base + d->d_un.d_ptr); DEBUG("%s constructors (DT_INIT) found at %p", si->name, si->init_func); @@ -1466,8 +1613,8 @@ static bool soinfo_link_image(soinfo* si) { } } - DEBUG("si->base = 0x%08x, si->strtab = %p, si->symtab = %p", - si->base, si->strtab, si->symtab); + DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p", + reinterpret_cast(si->base), si->strtab, si->symtab); // Sanity checks. if (relocating_linker && needed_count != 0) { @@ -1537,6 +1684,20 @@ static bool soinfo_link_image(soinfo* si) { } } +#if defined(ANDROID_X86_64_LINKER) + if (si->plt_rela != NULL) { + DEBUG("[ relocating %s plt ]\n", si->name ); + if (soinfo_relocate_a(si, si->plt_rela, si->plt_rela_count, needed)) { + return false; + } + } + if (si->rela != NULL) { + DEBUG("[ relocating %s ]\n", si->name ); + if (soinfo_relocate_a(si, si->rela, si->rela_count, needed)) { + return false; + } + } +#else if (si->plt_rel != NULL) { DEBUG("[ relocating %s plt ]", si->name ); if (soinfo_relocate(si, si->plt_rel, si->plt_rel_count, needed)) { @@ -1549,6 +1710,7 @@ static bool soinfo_link_image(soinfo* si) { return false; } } +#endif #ifdef ANDROID_MIPS_LINKER if (!mips_relocate_got(si, needed)) { @@ -1781,7 +1943,7 @@ static Elf_Addr __linker_init_post_relocation(KernelArgumentBlock& args, Elf_Add fflush(stdout); #endif - TRACE("[ Ready to execute '%s' @ 0x%08x ]", si->name, si->entry); + TRACE("[ Ready to execute '%s' @ %p ]", si->name, reinterpret_cast(si->entry)); return si->entry; } diff --git a/linker/linker.h b/linker/linker.h index ac7b9fe19..c5202c90a 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -128,6 +128,13 @@ struct soinfo { unsigned* bucket; unsigned* chain; +#if defined(ANDROID_X86_64_LINKER) + Elf_Rela *plt_rela; + size_t plt_rela_count; + + Elf_Rela *rela; + size_t rela_count; +#else unsigned* plt_got; Elf_Rel* plt_rel; @@ -135,6 +142,7 @@ struct soinfo { Elf_Rel* rel; size_t rel_count; +#endif linker_function_t* preinit_array; size_t preinit_array_count; diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp index bf2cc19b1..5f2b2c1f6 100644 --- a/linker/linker_phdr.cpp +++ b/linker/linker_phdr.cpp @@ -163,10 +163,29 @@ bool ElfReader::VerifyElfHeader() { return false; } - if (header_.e_ident[EI_CLASS] != ELFCLASS32) { - DL_ERR("\"%s\" not 32-bit: %d", name_, header_.e_ident[EI_CLASS]); + // Try to give a clear diagnostic for ELF class mismatches, since they're + // an easy mistake to make during the 32-bit/64-bit transition period. + int elf_class = header_.e_ident[EI_CLASS]; +#if defined(__LP64__) + if (elf_class != ELFCLASS64) { + if (elf_class == ELFCLASS32) { + DL_ERR("\"%s\" is 32-bit instead of 64-bit", name_); + } else { + DL_ERR("\"%s\" has unknown ELF class: %d", name_, elf_class); + } return false; } +#else + if (elf_class != ELFCLASS32) { + if (elf_class == ELFCLASS64) { + DL_ERR("\"%s\" is 64-bit instead of 32-bit", name_); + } else { + DL_ERR("\"%s\" has unknown ELF class: %d", name_, elf_class); + } + return false; + } +#endif + if (header_.e_ident[EI_DATA] != ELFDATA2LSB) { DL_ERR("\"%s\" not little-endian: %d", name_, header_.e_ident[EI_DATA]); return false; @@ -189,6 +208,8 @@ bool ElfReader::VerifyElfHeader() { EM_MIPS #elif defined(ANDROID_X86_LINKER) EM_386 +#elif defined(ANDROID_X86_64_LINKER) + EM_X86_64 #endif ) { DL_ERR("\"%s\" has unexpected e_machine: %d", name_, header_.e_machine); @@ -291,7 +312,7 @@ bool ElfReader::ReserveAddressSpace() { int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS; void* start = mmap(addr, load_size_, PROT_NONE, mmap_flags, -1, 0); if (start == MAP_FAILED) { - DL_ERR("couldn't reserve %d bytes of address space for \"%s\"", load_size_, name_); + DL_ERR("couldn't reserve %zd bytes of address space for \"%s\"", load_size_, name_); return false; } @@ -620,6 +641,6 @@ bool ElfReader::CheckPhdr(Elf_Addr loaded) { return true; } } - DL_ERR("\"%s\" loaded phdr %x not in loadable segment", name_, loaded); + DL_ERR("\"%s\" loaded phdr %p not in loadable segment", name_, reinterpret_cast(loaded)); return false; } diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h index 28d8b39db..f774b5dad 100644 --- a/linker/linker_phdr.h +++ b/linker/linker_phdr.h @@ -46,7 +46,7 @@ class ElfReader { size_t phdr_count() { return phdr_num_; } Elf_Addr load_start() { return reinterpret_cast(load_start_); } - Elf_Addr load_size() { return load_size_; } + size_t load_size() { return load_size_; } Elf_Addr load_bias() { return load_bias_; } const Elf_Phdr* loaded_phdr() { return loaded_phdr_; } @@ -72,7 +72,7 @@ class ElfReader { // First page of reserved address space. void* load_start_; // Size in bytes of reserved address space. - Elf_Addr load_size_; + size_t load_size_; // Load bias. Elf_Addr load_bias_;