Minor linker cleanup, primarily to use Elf32_Dyn

Change-Id: Ifa9408e9859c6f79444715bed4808b7c13fdced5
This commit is contained in:
Brian Carlstrom 2013-02-28 15:58:45 -08:00
parent d392e044c7
commit d4ee82dfa3
6 changed files with 188 additions and 176 deletions

View File

@ -174,7 +174,7 @@ static bool haveSiginfo(int signum) {
* Catches fatal signals so we can ask debuggerd to ptrace us before * Catches fatal signals so we can ask debuggerd to ptrace us before
* we crash. * we crash.
*/ */
void debugger_signal_handler(int n, siginfo_t* info, void*) { void debuggerd_signal_handler(int n, siginfo_t* info, void*) {
/* /*
* It's possible somebody cleared the SA_SIGINFO flag, which would mean * It's possible somebody cleared the SA_SIGINFO flag, which would mean
* our "info" arg holds an undefined value. * our "info" arg holds an undefined value.
@ -245,10 +245,10 @@ void debugger_signal_handler(int n, siginfo_t* info, void*) {
} }
} }
void debugger_init() { void debuggerd_init() {
struct sigaction act; struct sigaction act;
memset(&act, 0, sizeof(act)); memset(&act, 0, sizeof(act));
act.sa_sigaction = debugger_signal_handler; act.sa_sigaction = debuggerd_signal_handler;
act.sa_flags = SA_RESTART | SA_SIGINFO; act.sa_flags = SA_RESTART | SA_SIGINFO;
sigemptyset(&act.sa_mask); sigemptyset(&act.sa_mask);

View File

@ -85,18 +85,18 @@ void* dlsym(void* handle, const char* symbol) {
soinfo* found = NULL; soinfo* found = NULL;
Elf32_Sym* sym = NULL; Elf32_Sym* sym = NULL;
if (handle == RTLD_DEFAULT) { if (handle == RTLD_DEFAULT) {
sym = lookup(symbol, &found, NULL); sym = dlsym_linear_lookup(symbol, &found, NULL);
} else if (handle == RTLD_NEXT) { } else if (handle == RTLD_NEXT) {
void* ret_addr = __builtin_return_address(0); void* ret_addr = __builtin_return_address(0);
soinfo* si = find_containing_library(ret_addr); soinfo* si = find_containing_library(ret_addr);
sym = NULL; sym = NULL;
if (si && si->next) { if (si && si->next) {
sym = lookup(symbol, &found, si->next); sym = dlsym_linear_lookup(symbol, &found, si->next);
} }
} else { } else {
found = (soinfo*) handle; found = reinterpret_cast<soinfo*>(handle);
sym = soinfo_lookup(found, symbol); sym = dlsym_handle_lookup(found, symbol);
} }
if (sym != NULL) { if (sym != NULL) {
@ -131,7 +131,7 @@ int dladdr(const void* addr, Dl_info* info) {
info->dli_fbase = (void*) si->base; info->dli_fbase = (void*) si->base;
// Determine if any symbol in the library contains the specified address. // Determine if any symbol in the library contains the specified address.
Elf32_Sym *sym = soinfo_find_symbol(si, addr); Elf32_Sym *sym = dladdr_find_symbol(si, addr);
if (sym != NULL) { if (sym != NULL) {
info->dli_sname = si->strtab + sym->st_name; info->dli_sname = si->strtab + sym->st_name;
info->dli_saddr = (void*)(si->load_bias + sym->st_value); info->dli_saddr = (void*)(si->load_bias + sym->st_value);

View File

@ -87,9 +87,9 @@ struct soinfo_pool_t {
static struct soinfo_pool_t* gSoInfoPools = NULL; static struct soinfo_pool_t* gSoInfoPools = NULL;
static soinfo* gSoInfoFreeList = NULL; static soinfo* gSoInfoFreeList = NULL;
static soinfo *solist = &libdl_info; static soinfo* solist = &libdl_info;
static soinfo *sonext = &libdl_info; static soinfo* sonext = &libdl_info;
static soinfo *somain; /* main process, always the one after libdl_info */ static soinfo* somain; /* main process, always the one after libdl_info */
static const char* const gSoPaths[] = { static const char* const gSoPaths[] = {
"/vendor/lib", "/vendor/lib",
@ -103,7 +103,7 @@ static const char* gLdPaths[LDPATH_MAX + 1];
static char gLdPreloadsBuffer[LDPRELOAD_BUFSIZE]; static char gLdPreloadsBuffer[LDPRELOAD_BUFSIZE];
static const char* gLdPreloadNames[LDPRELOAD_MAX + 1]; static const char* gLdPreloadNames[LDPRELOAD_MAX + 1];
static soinfo *preloads[LDPRELOAD_MAX + 1]; static soinfo* gLdPreloads[LDPRELOAD_MAX + 1];
static int debug_verbosity; static int debug_verbosity;
@ -332,13 +332,13 @@ static void soinfo_free(soinfo* si)
TRACE("name %s: freeing soinfo @ %p\n", si->name, si); TRACE("name %s: freeing soinfo @ %p\n", si->name, si);
for(trav = solist; trav != NULL; trav = trav->next){ for (trav = solist; trav != NULL; trav = trav->next) {
if (trav == si) if (trav == si)
break; break;
prev = trav; prev = trav;
} }
if (trav == NULL) { if (trav == NULL) {
/* si was not ni solist */ /* si was not in solist */
DL_ERR("name \"%s\" is not in solist!", si->name); DL_ERR("name \"%s\" is not in solist!", si->name);
return; return;
} }
@ -347,7 +347,9 @@ static void soinfo_free(soinfo* si)
always the static libdl_info. always the static libdl_info.
*/ */
prev->next = si->next; prev->next = si->next;
if (si == sonext) sonext = prev; if (si == sonext) {
sonext = prev;
}
si->next = gSoInfoFreeList; si->next = gSoInfoFreeList;
gSoInfoFreeList = si; gSoInfoFreeList = si;
} }
@ -440,27 +442,27 @@ dl_iterate_phdr(int (*cb)(dl_phdr_info *info, size_t size, void *data),
#endif #endif
static Elf32_Sym *soinfo_elf_lookup(soinfo *si, unsigned hash, const char *name) static Elf32_Sym* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) {
{ Elf32_Sym* s;
Elf32_Sym *s; Elf32_Sym* symtab = si->symtab;
Elf32_Sym *symtab = si->symtab; const char* strtab = si->strtab;
const char *strtab = si->strtab;
unsigned n; unsigned n;
TRACE_TYPE(LOOKUP, "SEARCH %s in %s@0x%08x %08x %d\n", TRACE_TYPE(LOOKUP, "SEARCH %s in %s@0x%08x %08x %d\n",
name, si->name, si->base, hash, hash % si->nbucket); name, si->name, si->base, hash, hash % si->nbucket);
n = hash % si->nbucket; n = hash % si->nbucket;
for(n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]){ for (n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) {
s = symtab + n; s = symtab + n;
if(strcmp(strtab + s->st_name, name)) continue; if (strcmp(strtab + s->st_name, name)) continue;
/* only concern ourselves with global and weak symbol definitions */ /* only concern ourselves with global and weak symbol definitions */
switch(ELF32_ST_BIND(s->st_info)){ switch(ELF32_ST_BIND(s->st_info)){
case STB_GLOBAL: case STB_GLOBAL:
case STB_WEAK: case STB_WEAK:
if(s->st_shndx == SHN_UNDEF) if (s->st_shndx == SHN_UNDEF) {
continue; continue;
}
TRACE_TYPE(LOOKUP, "FOUND %s in %s (%08x) %d\n", TRACE_TYPE(LOOKUP, "FOUND %s in %s (%08x) %d\n",
name, si->name, s->st_value, s->st_size); name, si->name, s->st_value, s->st_size);
@ -471,9 +473,8 @@ static Elf32_Sym *soinfo_elf_lookup(soinfo *si, unsigned hash, const char *name)
return NULL; return NULL;
} }
static unsigned elfhash(const char *_name) static unsigned elfhash(const char* _name) {
{ const unsigned char* name = (const unsigned char*) _name;
const unsigned char *name = (const unsigned char *) _name;
unsigned h = 0, g; unsigned h = 0, g;
while(*name) { while(*name) {
@ -485,13 +486,9 @@ static unsigned elfhash(const char *_name)
return h; return h;
} }
static Elf32_Sym * static Elf32_Sym* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, soinfo* needed[]) {
soinfo_do_lookup(soinfo *si, const char *name, soinfo **lsi,
soinfo *needed[])
{
unsigned elf_hash = elfhash(name); unsigned elf_hash = elfhash(name);
Elf32_Sym *s = NULL; Elf32_Sym* s = NULL;
int i;
if (si != NULL && somain != NULL) { if (si != NULL && somain != NULL) {
@ -559,15 +556,15 @@ soinfo_do_lookup(soinfo *si, const char *name, soinfo **lsi,
} }
/* Next, look for it in the preloads list */ /* Next, look for it in the preloads list */
for(i = 0; preloads[i] != NULL; i++) { for (int i = 0; gLdPreloads[i] != NULL; i++) {
s = soinfo_elf_lookup(preloads[i], elf_hash, name); s = soinfo_elf_lookup(gLdPreloads[i], elf_hash, name);
if(s != NULL) { if (s != NULL) {
*lsi = preloads[i]; *lsi = gLdPreloads[i];
goto done; goto done;
} }
} }
for(i = 0; needed[i] != NULL; i++) { for (int i = 0; needed[i] != NULL; i++) {
DEBUG("%s: looking up %s in %s\n", DEBUG("%s: looking up %s in %s\n",
si->name, name, needed[i]->name); si->name, name, needed[i]->name);
s = soinfo_elf_lookup(needed[i], elf_hash, name); s = soinfo_elf_lookup(needed[i], elf_hash, name);
@ -578,7 +575,7 @@ soinfo_do_lookup(soinfo *si, const char *name, soinfo **lsi,
} }
done: done:
if(s != NULL) { if (s != NULL) {
TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = 0x%08x, " TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = 0x%08x, "
"found in %s, base = 0x%08x, load bias = 0x%08x\n", "found in %s, base = 0x%08x, load bias = 0x%08x\n",
si->name, name, s->st_value, si->name, name, s->st_value,
@ -589,17 +586,26 @@ done:
return NULL; return NULL;
} }
/* This is used by dl_sym(). It performs symbol lookup only within the /* This is used by dlsym(3). It performs symbol lookup only within the
specified soinfo object and not in any of its dependencies. specified soinfo object and not in any of its dependencies.
TODO: Only looking in the specified soinfo seems wrong. dlsym(3) says
that it should do a breadth first search through the dependency
tree. This agrees with the ELF spec (aka System V Application
Binary Interface) where in Chapter 5 it discuss resolving "Shared
Object Dependencies" in breadth first search order.
*/ */
Elf32_Sym *soinfo_lookup(soinfo *si, const char *name) Elf32_Sym* dlsym_handle_lookup(soinfo* si, const char* name)
{ {
return soinfo_elf_lookup(si, elfhash(name), name); return soinfo_elf_lookup(si, elfhash(name), name);
} }
/* This is used by dl_sym(). It performs a global symbol lookup. /* This is used by dlsym(3) to performs a global symbol lookup. If the
start value is null (for RTLD_DEFAULT), the search starts at the
beginning of the global solist. Otherwise the search starts at the
specified soinfo (for RTLD_NEXT).
*/ */
Elf32_Sym* lookup(const char* name, soinfo** found, soinfo* start) { Elf32_Sym* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start) {
unsigned elf_hash = elfhash(name); unsigned elf_hash = elfhash(name);
if (start == NULL) { if (start == NULL) {
@ -623,31 +629,25 @@ Elf32_Sym* lookup(const char* name, soinfo** found, soinfo* start) {
return s; return s;
} }
soinfo *find_containing_library(const void *addr) soinfo* find_containing_library(const void* addr) {
{ for (soinfo* si = solist; si != NULL; si = si->next) {
soinfo *si; if ((unsigned)addr >= si->base && (unsigned)addr - si->base < si->size) {
for(si = solist; si != NULL; si = si->next)
{
if((unsigned)addr >= si->base && (unsigned)addr - si->base < si->size) {
return si; return si;
} }
} }
return NULL; return NULL;
} }
Elf32_Sym *soinfo_find_symbol(soinfo* si, const void *addr) Elf32_Sym* dladdr_find_symbol(soinfo* si, const void* addr) {
{
unsigned int i; unsigned int i;
unsigned soaddr = (unsigned)addr - si->base; unsigned soaddr = (unsigned)addr - si->base;
/* Search the library's symbol table for any defined symbol which /* Search the library's symbol table for any defined symbol which
* contains this address */ * contains this address */
for(i=0; i<si->nchain; i++) { for (i=0; i<si->nchain; i++) {
Elf32_Sym *sym = &si->symtab[i]; Elf32_Sym *sym = &si->symtab[i];
if(sym->st_shndx != SHN_UNDEF && if (sym->st_shndx != SHN_UNDEF &&
soaddr >= sym->st_value && soaddr >= sym->st_value &&
soaddr < sym->st_value + sym->st_size) { soaddr < sym->st_value + sym->st_size) {
return sym; return sym;
@ -658,12 +658,10 @@ Elf32_Sym *soinfo_find_symbol(soinfo* si, const void *addr)
} }
#if 0 #if 0
static void dump(soinfo *si) static void dump(soinfo* si)
{ {
Elf32_Sym *s = si->symtab; Elf32_Sym* s = si->symtab;
unsigned n; for (unsigned n = 0; n < si->nchain; n++) {
for(n = 0; n < si->nchain; n++) {
TRACE("%04d> %08x: %02x %04x %08x %08x %s\n", n, s, TRACE("%04d> %08x: %02x %04x %08x %08x %s\n", n, s,
s->st_info, s->st_shndx, s->st_value, s->st_size, s->st_info, s->st_shndx, s->st_value, s->st_size,
si->strtab + s->st_name); si->strtab + s->st_name);
@ -890,7 +888,7 @@ static soinfo* load_library(const char* name) {
si.ptr->load_bias = load_bias; si.ptr->load_bias = load_bias;
si.ptr->flags = 0; si.ptr->flags = 0;
si.ptr->entry = 0; si.ptr->entry = 0;
si.ptr->dynamic = (unsigned *)-1; si.ptr->dynamic = NULL;
si.ptr->phnum = phdr_count; si.ptr->phnum = phdr_count;
si.ptr->phdr = phdr_table_get_loaded_phdr(phdr_table, phdr_count, load_bias); si.ptr->phdr = phdr_table_get_loaded_phdr(phdr_table, phdr_count, load_bias);
if (si.ptr->phdr == NULL) { if (si.ptr->phdr == NULL) {
@ -912,8 +910,8 @@ static soinfo *find_loaded_library(const char *name)
bname = strrchr(name, '/'); bname = strrchr(name, '/');
bname = bname ? bname + 1 : name; bname = bname ? bname + 1 : name;
for(si = solist; si != NULL; si = si->next){ for (si = solist; si != NULL; si = si->next) {
if(!strcmp(bname, si->name)) { if (!strcmp(bname, si->name)) {
return si; return si;
} }
} }
@ -967,9 +965,10 @@ static int soinfo_unload(soinfo* si) {
TRACE("unloading '%s'\n", si->name); TRACE("unloading '%s'\n", si->name);
si->CallDestructors(); si->CallDestructors();
for (unsigned* d = si->dynamic; *d; d += 2) { for (Elf32_Dyn* d = si->dynamic; d->d_tag != DT_NEEDED; ++d) {
if (d[0] == DT_NEEDED) { if (d->d_tag == DT_NEEDED) {
soinfo* lsi = find_loaded_library(si->strtab + d[1]); const char* library_name = si->strtab + d->d_un.d_val;
soinfo* lsi = find_loaded_library(library_name);
if (lsi != NULL) { if (lsi != NULL) {
TRACE("%s needs to unload %s\n", si->name, lsi->name); TRACE("%s needs to unload %s\n", si->name, lsi->name);
soinfo_unload(lsi); soinfo_unload(lsi);
@ -1022,30 +1021,30 @@ int do_dlclose(soinfo* si) {
* ideal. They should probably be either uint32_t, Elf32_Addr, or unsigned * ideal. They should probably be either uint32_t, Elf32_Addr, or unsigned
* long. * long.
*/ */
static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count, static int soinfo_relocate(soinfo* si, Elf32_Rel* rel, unsigned count,
soinfo *needed[]) soinfo* needed[])
{ {
Elf32_Sym *symtab = si->symtab; Elf32_Sym* symtab = si->symtab;
const char *strtab = si->strtab; const char* strtab = si->strtab;
Elf32_Sym *s; Elf32_Sym* s;
Elf32_Rel *start = rel; Elf32_Rel* start = rel;
soinfo *lsi; soinfo* lsi;
for (size_t idx = 0; idx < count; ++idx, ++rel) { for (size_t idx = 0; idx < count; ++idx, ++rel) {
unsigned type = ELF32_R_TYPE(rel->r_info); unsigned type = ELF32_R_TYPE(rel->r_info);
unsigned sym = ELF32_R_SYM(rel->r_info); unsigned sym = ELF32_R_SYM(rel->r_info);
unsigned reloc = (unsigned)(rel->r_offset + si->load_bias); unsigned reloc = (unsigned)(rel->r_offset + si->load_bias);
unsigned sym_addr = 0; unsigned sym_addr = 0;
char *sym_name = NULL; char* sym_name = NULL;
DEBUG("Processing '%s' relocation at index %d\n", si->name, idx); DEBUG("Processing '%s' relocation at index %d\n", si->name, idx);
if (type == 0) { // R_*_NONE if (type == 0) { // R_*_NONE
continue; continue;
} }
if(sym != 0) { if (sym != 0) {
sym_name = (char *)(strtab + symtab[sym].st_name); sym_name = (char *)(strtab + symtab[sym].st_name);
s = soinfo_do_lookup(si, sym_name, &lsi, needed); s = soinfo_do_lookup(si, sym_name, &lsi, needed);
if(s == NULL) { if (s == NULL) {
/* We only allow an undefined symbol if this is a weak /* We only allow an undefined symbol if this is a weak
reference.. */ reference.. */
s = &symtab[sym]; s = &symtab[sym];
@ -1103,7 +1102,7 @@ static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count,
} else { } else {
/* We got a definition. */ /* We got a definition. */
#if 0 #if 0
if((base == 0) && (si->base != 0)){ if ((base == 0) && (si->base != 0)) {
/* linking from libraries to main image is bad */ /* linking from libraries to main image is bad */
DL_ERR("cannot locate \"%s\"...", DL_ERR("cannot locate \"%s\"...",
strtab + symtab[sym].st_name); strtab + symtab[sym].st_name);
@ -1300,9 +1299,9 @@ static int mips_relocate_got(soinfo* si, soinfo* needed[]) {
sym = symtab + gotsym; sym = symtab + gotsym;
got = si->plt_got + local_gotno; got = si->plt_got + local_gotno;
for (g = gotsym; g < symtabno; g++, sym++, got++) { for (g = gotsym; g < symtabno; g++, sym++, got++) {
const char *sym_name; const char* sym_name;
Elf32_Sym *s; Elf32_Sym* s;
soinfo *lsi; soinfo* lsi;
/* This is an undefined reference... try to locate it */ /* This is an undefined reference... try to locate it */
sym_name = si->strtab + sym->st_name; sym_name = si->strtab + sym->st_name;
@ -1407,10 +1406,11 @@ void soinfo::CallConstructors() {
return; return;
} }
if (dynamic) { if (dynamic != NULL) {
for (unsigned* d = dynamic; *d; d += 2) { for (Elf32_Dyn* d = dynamic; d->d_tag != DT_NULL; ++d) {
if (d[0] == DT_NEEDED) { if (d->d_tag == DT_NEEDED) {
soinfo* lsi = find_loaded_library(strtab + d[1]); const char* library_name = strtab + d->d_un.d_val;
soinfo* lsi = find_loaded_library(library_name);
if (lsi == NULL) { if (lsi == NULL) {
DL_ERR("\"%s\": could not initialize dependent library", name); DL_ERR("\"%s\": could not initialize dependent library", name);
} else { } else {
@ -1495,8 +1495,7 @@ static bool soinfo_link_image(soinfo* si) {
Elf32_Addr base = si->load_bias; Elf32_Addr base = si->load_bias;
const Elf32_Phdr *phdr = si->phdr; const Elf32_Phdr *phdr = si->phdr;
int phnum = si->phnum; int phnum = si->phnum;
int relocating_linker = (si->flags & FLAG_LINKER) != 0; bool relocating_linker = (si->flags & FLAG_LINKER) != 0;
soinfo **needed, **pneeded;
/* We can't debug anything until the linker is relocated */ /* We can't debug anything until the linker is relocated */
if (!relocating_linker) { if (!relocating_linker) {
@ -1526,81 +1525,82 @@ static bool soinfo_link_image(soinfo* si) {
#endif #endif
/* extract useful information from dynamic section */ /* extract useful information from dynamic section */
for (unsigned* d = si->dynamic; *d; ++d) { uint32_t needed_count = 0;
DEBUG("d = %p, d[0] = 0x%08x d[1] = 0x%08x\n", d, d[0], d[1]); for (Elf32_Dyn* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
switch(*d++){ DEBUG("d = %p, d[0](tag) = 0x%08x d[1](val) = 0x%08x\n", d, d->d_tag, d->d_un.d_val);
switch(d->d_tag){
case DT_HASH: case DT_HASH:
si->nbucket = ((unsigned *) (base + *d))[0]; si->nbucket = ((unsigned *) (base + d->d_un.d_ptr))[0];
si->nchain = ((unsigned *) (base + *d))[1]; si->nchain = ((unsigned *) (base + d->d_un.d_ptr))[1];
si->bucket = (unsigned *) (base + *d + 8); si->bucket = (unsigned *) (base + d->d_un.d_ptr + 8);
si->chain = (unsigned *) (base + *d + 8 + si->nbucket * 4); si->chain = (unsigned *) (base + d->d_un.d_ptr + 8 + si->nbucket * 4);
break; break;
case DT_STRTAB: case DT_STRTAB:
si->strtab = (const char *) (base + *d); si->strtab = (const char *) (base + d->d_un.d_ptr);
break; break;
case DT_SYMTAB: case DT_SYMTAB:
si->symtab = (Elf32_Sym *) (base + *d); si->symtab = (Elf32_Sym *) (base + d->d_un.d_ptr);
break; break;
case DT_PLTREL: case DT_PLTREL:
if(*d != DT_REL) { if (d->d_un.d_val != DT_REL) {
DL_ERR("unsupported DT_RELA in \"%s\"", si->name); DL_ERR("unsupported DT_RELA in \"%s\"", si->name);
return false; return false;
} }
break; break;
case DT_JMPREL: case DT_JMPREL:
si->plt_rel = (Elf32_Rel*) (base + *d); si->plt_rel = (Elf32_Rel*) (base + d->d_un.d_ptr);
break; break;
case DT_PLTRELSZ: case DT_PLTRELSZ:
si->plt_rel_count = *d / 8; si->plt_rel_count = d->d_un.d_val / sizeof(Elf32_Rel);
break; break;
case DT_REL: case DT_REL:
si->rel = (Elf32_Rel*) (base + *d); si->rel = (Elf32_Rel*) (base + d->d_un.d_ptr);
break; break;
case DT_RELSZ: case DT_RELSZ:
si->rel_count = *d / 8; si->rel_count = d->d_un.d_val / sizeof(Elf32_Rel);
break; break;
case DT_PLTGOT: case DT_PLTGOT:
/* Save this in case we decide to do lazy binding. We don't yet. */ /* Save this in case we decide to do lazy binding. We don't yet. */
si->plt_got = (unsigned *)(base + *d); si->plt_got = (unsigned *)(base + d->d_un.d_ptr);
break; break;
case DT_DEBUG: case DT_DEBUG:
// Set the DT_DEBUG entry to the address of _r_debug for GDB // Set the DT_DEBUG entry to the address of _r_debug for GDB
// if the dynamic table is writable // if the dynamic table is writable
if ((dynamic_flags & PF_W) != 0) { if ((dynamic_flags & PF_W) != 0) {
*d = (int) &_r_debug; d->d_un.d_val = (int) &_r_debug;
} }
break; break;
case DT_RELA: case DT_RELA:
DL_ERR("unsupported DT_RELA in \"%s\"", si->name); DL_ERR("unsupported DT_RELA in \"%s\"", si->name);
return false; return false;
case DT_INIT: case DT_INIT:
si->init_func = (void (*)(void))(base + *d); si->init_func = (void (*)(void))(base + d->d_un.d_ptr);
DEBUG("%s constructors (init func) found at %p\n", si->name, si->init_func); DEBUG("%s constructors (init func) found at %p\n", si->name, si->init_func);
break; break;
case DT_FINI: case DT_FINI:
si->fini_func = (void (*)(void))(base + *d); si->fini_func = (void (*)(void))(base + d->d_un.d_ptr);
DEBUG("%s destructors (fini func) found at %p\n", si->name, si->fini_func); DEBUG("%s destructors (fini func) found at %p\n", si->name, si->fini_func);
break; break;
case DT_INIT_ARRAY: case DT_INIT_ARRAY:
si->init_array = (unsigned *)(base + *d); si->init_array = (unsigned *)(base + d->d_un.d_ptr);
DEBUG("%s constructors (init_array) found at %p\n", si->name, si->init_array); DEBUG("%s constructors (init_array) found at %p\n", si->name, si->init_array);
break; break;
case DT_INIT_ARRAYSZ: case DT_INIT_ARRAYSZ:
si->init_array_count = ((unsigned)*d) / sizeof(Elf32_Addr); si->init_array_count = ((unsigned)d->d_un.d_val) / sizeof(Elf32_Addr);
break; break;
case DT_FINI_ARRAY: case DT_FINI_ARRAY:
si->fini_array = (unsigned *)(base + *d); si->fini_array = (unsigned *)(base + d->d_un.d_ptr);
DEBUG("%s destructors (fini_array) found at %p\n", si->name, si->fini_array); DEBUG("%s destructors (fini_array) found at %p\n", si->name, si->fini_array);
break; break;
case DT_FINI_ARRAYSZ: case DT_FINI_ARRAYSZ:
si->fini_array_count = ((unsigned)*d) / sizeof(Elf32_Addr); si->fini_array_count = ((unsigned)d->d_un.d_val) / sizeof(Elf32_Addr);
break; break;
case DT_PREINIT_ARRAY: case DT_PREINIT_ARRAY:
si->preinit_array = (unsigned *)(base + *d); si->preinit_array = (unsigned *)(base + d->d_un.d_ptr);
DEBUG("%s constructors (preinit_array) found at %p\n", si->name, si->preinit_array); DEBUG("%s constructors (preinit_array) found at %p\n", si->name, si->preinit_array);
break; break;
case DT_PREINIT_ARRAYSZ: case DT_PREINIT_ARRAYSZ:
si->preinit_array_count = ((unsigned)*d) / sizeof(Elf32_Addr); si->preinit_array_count = ((unsigned)d->d_un.d_val) / sizeof(Elf32_Addr);
break; break;
case DT_TEXTREL: case DT_TEXTREL:
si->has_text_relocations = true; si->has_text_relocations = true;
@ -1608,18 +1608,21 @@ static bool soinfo_link_image(soinfo* si) {
case DT_SYMBOLIC: case DT_SYMBOLIC:
si->has_DT_SYMBOLIC = true; si->has_DT_SYMBOLIC = true;
break; break;
#if defined(DT_FLAGS) case DT_NEEDED:
++needed_count;
break;
#if defined DT_FLAGS
// TODO: why is DT_FLAGS not defined?
case DT_FLAGS: case DT_FLAGS:
if (*d & DF_TEXTREL) { if (d->d_un.d_val & DF_TEXTREL) {
si->has_text_relocations = true; si->has_text_relocations = true;
} }
if (*d & DF_SYMBOLIC) { if (d->d_un.d_val & DF_SYMBOLIC) {
si->has_DT_SYMBOLIC = true; si->has_DT_SYMBOLIC = true;
} }
break; break;
#endif #endif
#if defined(ANDROID_MIPS_LINKER) #if defined(ANDROID_MIPS_LINKER)
case DT_NEEDED:
case DT_STRSZ: case DT_STRSZ:
case DT_SYMENT: case DT_SYMENT:
case DT_RELENT: case DT_RELENT:
@ -1627,7 +1630,7 @@ static bool soinfo_link_image(soinfo* si) {
case DT_MIPS_RLD_MAP: case DT_MIPS_RLD_MAP:
// Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB. // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
{ {
r_debug** dp = (r_debug**) *d; r_debug** dp = (r_debug**) d->d_un.d_ptr;
*dp = &_r_debug; *dp = &_r_debug;
} }
break; break;
@ -1638,15 +1641,15 @@ static bool soinfo_link_image(soinfo* si) {
break; break;
case DT_MIPS_SYMTABNO: case DT_MIPS_SYMTABNO:
si->mips_symtabno = *d; si->mips_symtabno = d->d_un.d_val;
break; break;
case DT_MIPS_LOCAL_GOTNO: case DT_MIPS_LOCAL_GOTNO:
si->mips_local_gotno = *d; si->mips_local_gotno = d->d_un.d_val;
break; break;
case DT_MIPS_GOTSYM: case DT_MIPS_GOTSYM:
si->mips_gotsym = *d; si->mips_gotsym = d->d_un.d_val;
break; break;
default: default:
@ -1660,6 +1663,10 @@ static bool soinfo_link_image(soinfo* si) {
si->base, si->strtab, si->symtab); si->base, si->strtab, si->symtab);
// Sanity checks. // Sanity checks.
if (relocating_linker && needed_count != 0) {
DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
return false;
}
if (si->nbucket == 0) { if (si->nbucket == 0) {
DL_ERR("empty/missing DT_HASH in \"%s\" (built with --hash-style=gnu?)", si->name); DL_ERR("empty/missing DT_HASH in \"%s\" (built with --hash-style=gnu?)", si->name);
return false; return false;
@ -1675,7 +1682,7 @@ static bool soinfo_link_image(soinfo* si) {
/* if this is the main executable, then load all of the preloads now */ /* if this is the main executable, then load all of the preloads now */
if (si->flags & FLAG_EXE) { if (si->flags & FLAG_EXE) {
memset(preloads, 0, sizeof(preloads)); memset(gLdPreloads, 0, sizeof(gLdPreloads));
for (size_t i = 0; gLdPreloadNames[i] != NULL; i++) { for (size_t i = 0; gLdPreloadNames[i] != NULL; i++) {
soinfo* lsi = find_library(gLdPreloadNames[i]); soinfo* lsi = find_library(gLdPreloadNames[i]);
if (lsi == NULL) { if (lsi == NULL) {
@ -1684,21 +1691,22 @@ static bool soinfo_link_image(soinfo* si) {
gLdPreloadNames[i], si->name, tmp_err_buf); gLdPreloadNames[i], si->name, tmp_err_buf);
return false; return false;
} }
preloads[i] = lsi; gLdPreloads[i] = lsi;
} }
} }
/* dynamic_count is an upper bound for the number of needed libs */ soinfo** needed = (soinfo**) alloca((1 + needed_count) * sizeof(soinfo*));
pneeded = needed = (soinfo**) alloca((1 + dynamic_count) * sizeof(soinfo*)); soinfo** pneeded = needed;
for (unsigned* d = si->dynamic; *d; d += 2) { for (Elf32_Dyn* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
if (d[0] == DT_NEEDED) { if (d->d_tag == DT_NEEDED) {
DEBUG("%s needs %s\n", si->name, si->strtab + d[1]); const char* library_name = si->strtab + d->d_un.d_val;
soinfo* lsi = find_library(si->strtab + d[1]); DEBUG("%s needs %s\n", si->name, library_name);
soinfo* lsi = find_library(library_name);
if (lsi == NULL) { if (lsi == NULL) {
strlcpy(tmp_err_buf, linker_get_error(), sizeof(tmp_err_buf)); strlcpy(tmp_err_buf, linker_get_error(), sizeof(tmp_err_buf));
DL_ERR("could not load library \"%s\" needed by \"%s\"; caused by %s", DL_ERR("could not load library \"%s\" needed by \"%s\"; caused by %s",
si->strtab + d[1], si->name, tmp_err_buf); library_name, si->name, tmp_err_buf);
return false; return false;
} }
*pneeded++ = lsi; *pneeded++ = lsi;
@ -1719,15 +1727,15 @@ static bool soinfo_link_image(soinfo* si) {
} }
} }
if (si->plt_rel) { if (si->plt_rel != NULL) {
DEBUG("[ relocating %s plt ]\n", si->name ); DEBUG("[ relocating %s plt ]\n", si->name );
if(soinfo_relocate(si, si->plt_rel, si->plt_rel_count, needed)) { if (soinfo_relocate(si, si->plt_rel, si->plt_rel_count, needed)) {
return false; return false;
} }
} }
if (si->rel) { if (si->rel != NULL) {
DEBUG("[ relocating %s ]\n", si->name ); DEBUG("[ relocating %s ]\n", si->name );
if(soinfo_relocate(si, si->rel, si->rel_count, needed)) { if (soinfo_relocate(si, si->rel, si->rel_count, needed)) {
return false; return false;
} }
} }
@ -1791,7 +1799,7 @@ static unsigned __linker_init_post_relocation(KernelArgumentBlock& args, unsigne
// Initialize environment functions, and get to the ELF aux vectors table. // Initialize environment functions, and get to the ELF aux vectors table.
linker_env_init(args); linker_env_init(args);
debugger_init(); debuggerd_init();
// Get a few environment variables. // Get a few environment variables.
const char* LD_DEBUG = linker_env_get("LD_DEBUG"); const char* LD_DEBUG = linker_env_get("LD_DEBUG");
@ -1827,29 +1835,31 @@ static unsigned __linker_init_post_relocation(KernelArgumentBlock& args, unsigne
_r_debug.r_map = map; _r_debug.r_map = map;
r_debug_tail = map; r_debug_tail = map;
/* gdb expects the linker to be in the debug shared object list. /* gdb expects the linker to be in the debug shared object list.
* Without this, gdb has trouble locating the linker's ".text" * Without this, gdb has trouble locating the linker's ".text"
* and ".plt" sections. Gdb could also potentially use this to * and ".plt" sections. Gdb could also potentially use this to
* relocate the offset of our exported 'rtld_db_dlactivity' symbol. * relocate the offset of our exported 'rtld_db_dlactivity' symbol.
* Don't use soinfo_alloc(), because the linker shouldn't * Don't use soinfo_alloc(), because the linker shouldn't
* be on the soinfo list. * be on the soinfo list.
*/
static soinfo linker_soinfo;
strlcpy(linker_soinfo.name, "/system/bin/linker", sizeof(linker_soinfo.name));
linker_soinfo.flags = 0;
linker_soinfo.base = linker_base;
/*
* Set the dynamic field in the link map otherwise gdb will complain with
* the following:
* warning: .dynamic section for "/system/bin/linker" is not at the
* expected address (wrong library or version mismatch?)
*/ */
Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *) linker_base; {
Elf32_Phdr *phdr = (Elf32_Phdr*)((unsigned char*) linker_base + elf_hdr->e_phoff); static soinfo linker_soinfo;
phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base, strlcpy(linker_soinfo.name, "/system/bin/linker", sizeof(linker_soinfo.name));
&linker_soinfo.dynamic, NULL, NULL); linker_soinfo.flags = 0;
insert_soinfo_into_debug_map(&linker_soinfo); linker_soinfo.base = linker_base;
/*
* Set the dynamic field in the link map otherwise gdb will complain with
* the following:
* warning: .dynamic section for "/system/bin/linker" is not at the
* expected address (wrong library or version mismatch?)
*/
Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *) linker_base;
Elf32_Phdr *phdr = (Elf32_Phdr*)((unsigned char*) linker_base + elf_hdr->e_phoff);
phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base,
&linker_soinfo.dynamic, NULL, NULL);
insert_soinfo_into_debug_map(&linker_soinfo);
}
// Extract information passed from the kernel. // Extract information passed from the kernel.
si->phdr = reinterpret_cast<Elf32_Phdr*>(args.getauxval(AT_PHDR)); si->phdr = reinterpret_cast<Elf32_Phdr*>(args.getauxval(AT_PHDR));
@ -1870,7 +1880,7 @@ static unsigned __linker_init_post_relocation(KernelArgumentBlock& args, unsigne
break; break;
} }
} }
si->dynamic = (unsigned *)-1; si->dynamic = NULL;
si->refcount = 1; si->refcount = 1;
// Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid). // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid).
@ -1888,14 +1898,14 @@ static unsigned __linker_init_post_relocation(KernelArgumentBlock& args, unsigne
si->CallPreInitConstructors(); si->CallPreInitConstructors();
for (size_t i = 0; preloads[i] != NULL; ++i) { for (size_t i = 0; gLdPreloads[i] != NULL; ++i) {
preloads[i]->CallConstructors(); gLdPreloads[i]->CallConstructors();
} }
/*After the link_image, the si->load_bias is initialized. /* After the link_image, the si->load_bias is initialized.
*For so lib, the map->l_addr will be updated in notify_gdb_of_load. * For so lib, the map->l_addr will be updated in notify_gdb_of_load.
*We need to update this value for so exe here. So Unwind_Backtrace * We need to update this value for so exe here. So Unwind_Backtrace
*for some arch like x86 could work correctly within so exe. * for some arch like x86 could work correctly within so exe.
*/ */
map->l_addr = si->load_bias; map->l_addr = si->load_bias;
si->CallConstructors(); si->CallConstructors();
@ -1919,11 +1929,13 @@ static unsigned __linker_init_post_relocation(KernelArgumentBlock& args, unsigne
unsigned n; unsigned n;
unsigned i; unsigned i;
unsigned count = 0; unsigned count = 0;
for(n = 0; n < 4096; n++){ for (n = 0; n < 4096; n++) {
if(bitmask[n]){ if (bitmask[n]) {
unsigned x = bitmask[n]; unsigned x = bitmask[n];
for(i = 0; i < 8; i++){ for (i = 0; i < 8; i++) {
if(x & 1) count++; if (x & 1) {
count++;
}
x >>= 1; x >>= 1;
} }
} }
@ -1989,7 +2001,7 @@ extern "C" unsigned __linker_init(void* raw_args) {
linker_so.base = linker_addr; linker_so.base = linker_addr;
linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum); linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum);
linker_so.load_bias = get_elf_exec_load_bias(elf_hdr); linker_so.load_bias = get_elf_exec_load_bias(elf_hdr);
linker_so.dynamic = (unsigned*) -1; linker_so.dynamic = NULL;
linker_so.phdr = phdr; linker_so.phdr = phdr;
linker_so.phnum = elf_hdr->e_phnum; linker_so.phnum = elf_hdr->e_phnum;
linker_so.flags |= FLAG_LINKER; linker_so.flags |= FLAG_LINKER;

View File

@ -50,10 +50,10 @@
struct link_map { struct link_map {
uintptr_t l_addr; uintptr_t l_addr;
char * l_name; char* l_name;
uintptr_t l_ld; uintptr_t l_ld;
struct link_map * l_next; struct link_map* l_next;
struct link_map * l_prev; struct link_map* l_prev;
}; };
// Values for r_debug->state // Values for r_debug->state
@ -87,7 +87,7 @@ struct soinfo {
int unused; // DO NOT USE, maintained for compatibility. int unused; // DO NOT USE, maintained for compatibility.
unsigned* dynamic; Elf32_Dyn* dynamic;
unsigned unused2; // DO NOT USE, maintained for compatibility unsigned unused2; // DO NOT USE, maintained for compatibility
unsigned unused3; // DO NOT USE, maintained for compatibility unsigned unused3; // DO NOT USE, maintained for compatibility
@ -167,14 +167,14 @@ void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path);
soinfo* do_dlopen(const char* name, int flags); soinfo* do_dlopen(const char* name, int flags);
int do_dlclose(soinfo* si); int do_dlclose(soinfo* si);
Elf32_Sym* lookup(const char* name, soinfo** found, soinfo* start); Elf32_Sym* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start);
soinfo* find_containing_library(const void* addr); soinfo* find_containing_library(const void* addr);
const char* linker_get_error(); const char* linker_get_error();
Elf32_Sym* soinfo_find_symbol(soinfo* si, const void* addr); Elf32_Sym* dladdr_find_symbol(soinfo* si, const void* addr);
Elf32_Sym* soinfo_lookup(soinfo* si, const char* name); Elf32_Sym* dlsym_handle_lookup(soinfo* si, const char* name);
void debugger_init(); void debuggerd_init();
extern "C" void notify_gdb_of_libraries(); extern "C" void notify_gdb_of_libraries();
#endif #endif

View File

@ -550,7 +550,7 @@ void
phdr_table_get_dynamic_section(const Elf32_Phdr* phdr_table, phdr_table_get_dynamic_section(const Elf32_Phdr* phdr_table,
int phdr_count, int phdr_count,
Elf32_Addr load_bias, Elf32_Addr load_bias,
Elf32_Addr** dynamic, Elf32_Dyn** dynamic,
size_t* dynamic_count, size_t* dynamic_count,
Elf32_Word* dynamic_flags) Elf32_Word* dynamic_flags)
{ {
@ -562,7 +562,7 @@ phdr_table_get_dynamic_section(const Elf32_Phdr* phdr_table,
continue; continue;
} }
*dynamic = (Elf32_Addr*)(load_bias + phdr->p_vaddr); *dynamic = reinterpret_cast<Elf32_Dyn*>(load_bias + phdr->p_vaddr);
if (dynamic_count) { if (dynamic_count) {
*dynamic_count = (unsigned)(phdr->p_memsz / 8); *dynamic_count = (unsigned)(phdr->p_memsz / 8);
} }

View File

@ -98,7 +98,7 @@ void
phdr_table_get_dynamic_section(const Elf32_Phdr* phdr_table, phdr_table_get_dynamic_section(const Elf32_Phdr* phdr_table,
int phdr_count, int phdr_count,
Elf32_Addr load_bias, Elf32_Addr load_bias,
Elf32_Addr** dynamic, Elf32_Dyn** dynamic,
size_t* dynamic_count, size_t* dynamic_count,
Elf32_Word* dynamic_flags); Elf32_Word* dynamic_flags);