Merge "x86_64 linker."
This commit is contained in:
commit
26933f4046
@ -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
|
||||
|
38
linker/arch/x86_64/begin.S
Normal file
38
linker/arch/x86_64/begin.S
Normal file
@ -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 <machine/asm.h>
|
||||
|
||||
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)
|
@ -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.
|
||||
|
@ -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<void*>(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<Elf64_Addr>(reinterpret_cast<void*>(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,
|
||||
|
@ -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<void*>(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<void*>(s->st_value),
|
||||
static_cast<size_t>(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<void*>(s->st_value),
|
||||
(*lsi)->name, reinterpret_cast<void*>((*lsi)->base),
|
||||
reinterpret_cast<void*>((*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<void*>(s->st_value), reinterpret_cast<void*>((*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<void*>(si->base), si->size, si->name);
|
||||
|
||||
if (!soinfo_link_image(si)) {
|
||||
munmap(reinterpret_cast<void*>(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<Elf_Addr>(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<Elf_Addr>(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<size_t>(reloc),
|
||||
static_cast<size_t>(sym_addr + rela->r_addend), sym_name);
|
||||
*reinterpret_cast<Elf_Addr*>(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<size_t>(reloc),
|
||||
static_cast<size_t>(sym_addr + rela->r_addend), sym_name);
|
||||
*reinterpret_cast<Elf_Addr*>(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<size_t>(reloc),
|
||||
static_cast<size_t>(si->base));
|
||||
*reinterpret_cast<Elf_Addr*>(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<size_t>(reloc),
|
||||
static_cast<size_t>(sym_addr), sym_name);
|
||||
*reinterpret_cast<Elf_Addr*>(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<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
|
||||
static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
|
||||
*reinterpret_cast<Elf_Addr*>(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<Elf_Addr>(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<void*>(reloc), reinterpret_cast<void*>(si->base));
|
||||
*reinterpret_cast<Elf_Addr*>(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<void*>(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<void*>(d->d_tag), reinterpret_cast<void*>(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<uintptr_t>(&_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<linker_function_t>(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<void*>(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<void*>(si->entry));
|
||||
return si->entry;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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<void*>(loaded));
|
||||
return false;
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ class ElfReader {
|
||||
|
||||
size_t phdr_count() { return phdr_num_; }
|
||||
Elf_Addr load_start() { return reinterpret_cast<Elf_Addr>(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_;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user