* commit '4b5a0e1ad76d76d6a8793f61e3c0902ea4628ce7': Remove 32-bit assumptions from the ELF code.
This commit is contained in:
commit
58413fe735
@ -35,7 +35,7 @@
|
|||||||
extern void* __executable_start;
|
extern void* __executable_start;
|
||||||
|
|
||||||
int dl_iterate_phdr(int (*cb)(struct dl_phdr_info* info, size_t size, void* data), void* data) {
|
int dl_iterate_phdr(int (*cb)(struct dl_phdr_info* info, size_t size, void* data), void* data) {
|
||||||
Elf32_Ehdr* ehdr = (Elf32_Ehdr*) &__executable_start;
|
Elf_Ehdr* ehdr = (Elf_Ehdr*) &__executable_start;
|
||||||
|
|
||||||
// TODO: again, copied from linker.c. Find a better home for this later.
|
// TODO: again, copied from linker.c. Find a better home for this later.
|
||||||
if (ehdr->e_ident[EI_MAG0] != ELFMAG0) return -1;
|
if (ehdr->e_ident[EI_MAG0] != ELFMAG0) return -1;
|
||||||
@ -51,7 +51,7 @@ int dl_iterate_phdr(int (*cb)(struct dl_phdr_info* info, size_t size, void* data
|
|||||||
struct dl_phdr_info exe_info;
|
struct dl_phdr_info exe_info;
|
||||||
exe_info.dlpi_addr = 0;
|
exe_info.dlpi_addr = 0;
|
||||||
exe_info.dlpi_name = NULL;
|
exe_info.dlpi_name = NULL;
|
||||||
exe_info.dlpi_phdr = (Elf32_Phdr*) ((unsigned long) ehdr + ehdr->e_phoff);
|
exe_info.dlpi_phdr = (Elf_Phdr*) ((unsigned long) ehdr + ehdr->e_phoff);
|
||||||
exe_info.dlpi_phnum = ehdr->e_phnum;
|
exe_info.dlpi_phnum = ehdr->e_phnum;
|
||||||
|
|
||||||
#ifdef AT_SYSINFO_EHDR
|
#ifdef AT_SYSINFO_EHDR
|
||||||
@ -62,15 +62,15 @@ int dl_iterate_phdr(int (*cb)(struct dl_phdr_info* info, size_t size, void* data
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try the VDSO if that didn't work.
|
// Try the VDSO if that didn't work.
|
||||||
Elf32_Ehdr* ehdr_vdso = (Elf32_Ehdr*) getauxval(AT_SYSINFO_EHDR);
|
Elf_Ehdr* ehdr_vdso = (Elf_Ehdr*) getauxval(AT_SYSINFO_EHDR);
|
||||||
struct dl_phdr_info vdso_info;
|
struct dl_phdr_info vdso_info;
|
||||||
vdso_info.dlpi_addr = 0;
|
vdso_info.dlpi_addr = 0;
|
||||||
vdso_info.dlpi_name = NULL;
|
vdso_info.dlpi_name = NULL;
|
||||||
vdso_info.dlpi_phdr = (Elf32_Phdr*) ((char*) ehdr_vdso + ehdr_vdso->e_phoff);
|
vdso_info.dlpi_phdr = (Elf_Phdr*) ((char*) ehdr_vdso + ehdr_vdso->e_phoff);
|
||||||
vdso_info.dlpi_phnum = ehdr_vdso->e_phnum;
|
vdso_info.dlpi_phnum = ehdr_vdso->e_phnum;
|
||||||
for (size_t i = 0; i < vdso_info.dlpi_phnum; ++i) {
|
for (size_t i = 0; i < vdso_info.dlpi_phnum; ++i) {
|
||||||
if (vdso_info.dlpi_phdr[i].p_type == PT_LOAD) {
|
if (vdso_info.dlpi_phdr[i].p_type == PT_LOAD) {
|
||||||
vdso_info.dlpi_addr = (Elf32_Addr) ehdr_vdso - vdso_info.dlpi_phdr[i].p_vaddr;
|
vdso_info.dlpi_addr = (Elf_Addr) ehdr_vdso - vdso_info.dlpi_phdr[i].p_vaddr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,10 +32,10 @@
|
|||||||
#include <private/bionic_auxv.h>
|
#include <private/bionic_auxv.h>
|
||||||
#include <elf.h>
|
#include <elf.h>
|
||||||
|
|
||||||
__LIBC_HIDDEN__ Elf32_auxv_t* __libc_auxv = NULL;
|
__LIBC_HIDDEN__ Elf_auxv_t* __libc_auxv = NULL;
|
||||||
|
|
||||||
extern "C" unsigned long int getauxval(unsigned long int type) {
|
extern "C" unsigned long int getauxval(unsigned long int type) {
|
||||||
for (Elf32_auxv_t* v = __libc_auxv; v->a_type != AT_NULL; ++v) {
|
for (Elf_auxv_t* v = __libc_auxv; v->a_type != AT_NULL; ++v) {
|
||||||
if (v->a_type == type) {
|
if (v->a_type == type) {
|
||||||
return v->a_un.a_val;
|
return v->a_un.a_val;
|
||||||
}
|
}
|
||||||
|
@ -67,16 +67,16 @@ static void call_array(void(**list)()) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void apply_gnu_relro() {
|
static void apply_gnu_relro() {
|
||||||
Elf32_Phdr* phdr_start = reinterpret_cast<Elf32_Phdr*>(getauxval(AT_PHDR));
|
Elf_Phdr* phdr_start = reinterpret_cast<Elf_Phdr*>(getauxval(AT_PHDR));
|
||||||
unsigned long int phdr_ct = getauxval(AT_PHNUM);
|
unsigned long int phdr_ct = getauxval(AT_PHNUM);
|
||||||
|
|
||||||
for (Elf32_Phdr* phdr = phdr_start; phdr < (phdr_start + phdr_ct); phdr++) {
|
for (Elf_Phdr* phdr = phdr_start; phdr < (phdr_start + phdr_ct); phdr++) {
|
||||||
if (phdr->p_type != PT_GNU_RELRO) {
|
if (phdr->p_type != PT_GNU_RELRO) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Elf32_Addr seg_page_start = PAGE_START(phdr->p_vaddr);
|
Elf_Addr seg_page_start = PAGE_START(phdr->p_vaddr);
|
||||||
Elf32_Addr seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz);
|
Elf_Addr seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz);
|
||||||
|
|
||||||
// Check return value here? What do we do if we fail?
|
// Check return value here? What do we do if we fail?
|
||||||
mprotect(reinterpret_cast<void*>(seg_page_start), seg_page_end - seg_page_start, PROT_READ);
|
mprotect(reinterpret_cast<void*>(seg_page_start), seg_page_end - seg_page_start, PROT_READ);
|
||||||
|
@ -46,5 +46,10 @@ typedef struct {
|
|||||||
} a_un;
|
} a_un;
|
||||||
} Elf64_auxv_t;
|
} Elf64_auxv_t;
|
||||||
|
|
||||||
#endif /* _ELF_H */
|
#ifdef __LP64__
|
||||||
|
# define Elf_auxv_t Elf64_auxv_t
|
||||||
|
#else
|
||||||
|
# define Elf_auxv_t Elf32_auxv_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _ELF_H */
|
||||||
|
@ -33,8 +33,7 @@
|
|||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
/* bionic is currently only 32-bit. */
|
#define ElfW(type) Elf_##type
|
||||||
#define ElfW(type) Elf32_##type
|
|
||||||
|
|
||||||
struct dl_phdr_info {
|
struct dl_phdr_info {
|
||||||
ElfW(Addr) dlpi_addr;
|
ElfW(Addr) dlpi_addr;
|
||||||
|
@ -30,7 +30,7 @@ struct abort_msg_t;
|
|||||||
class KernelArgumentBlock {
|
class KernelArgumentBlock {
|
||||||
public:
|
public:
|
||||||
KernelArgumentBlock(void* raw_args) {
|
KernelArgumentBlock(void* raw_args) {
|
||||||
uint32_t* args = reinterpret_cast<uint32_t*>(raw_args);
|
uintptr_t* args = reinterpret_cast<uintptr_t*>(raw_args);
|
||||||
argc = static_cast<int>(*args);
|
argc = static_cast<int>(*args);
|
||||||
argv = reinterpret_cast<char**>(args + 1);
|
argv = reinterpret_cast<char**>(args + 1);
|
||||||
envp = argv + argc + 1;
|
envp = argv + argc + 1;
|
||||||
@ -43,14 +43,14 @@ class KernelArgumentBlock {
|
|||||||
}
|
}
|
||||||
++p; // Skip second NULL;
|
++p; // Skip second NULL;
|
||||||
|
|
||||||
auxv = reinterpret_cast<Elf32_auxv_t*>(p);
|
auxv = reinterpret_cast<Elf_auxv_t*>(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Similar to ::getauxval but doesn't require the libc global variables to be set up,
|
// Similar to ::getauxval but doesn't require the libc global variables to be set up,
|
||||||
// so it's safe to call this really early on. This function also lets you distinguish
|
// so it's safe to call this really early on. This function also lets you distinguish
|
||||||
// between the inability to find the given type and its value just happening to be 0.
|
// between the inability to find the given type and its value just happening to be 0.
|
||||||
unsigned long getauxval(unsigned long type, bool* found_match = NULL) {
|
unsigned long getauxval(unsigned long type, bool* found_match = NULL) {
|
||||||
for (Elf32_auxv_t* v = auxv; v->a_type != AT_NULL; ++v) {
|
for (Elf_auxv_t* v = auxv; v->a_type != AT_NULL; ++v) {
|
||||||
if (v->a_type == type) {
|
if (v->a_type == type) {
|
||||||
if (found_match != NULL) {
|
if (found_match != NULL) {
|
||||||
*found_match = true;
|
*found_match = true;
|
||||||
@ -67,7 +67,7 @@ class KernelArgumentBlock {
|
|||||||
int argc;
|
int argc;
|
||||||
char** argv;
|
char** argv;
|
||||||
char** envp;
|
char** envp;
|
||||||
Elf32_auxv_t* auxv;
|
Elf_auxv_t* auxv;
|
||||||
|
|
||||||
abort_msg_t** abort_message_ptr;
|
abort_msg_t** abort_message_ptr;
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
extern Elf32_auxv_t* __libc_auxv;
|
extern Elf_auxv_t* __libc_auxv;
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
|
@ -137,9 +137,9 @@ static void log_signal_summary(int signum, const siginfo_t* info) {
|
|||||||
// "info" will be NULL if the siginfo_t information was not available.
|
// "info" will be NULL if the siginfo_t information was not available.
|
||||||
if (info != NULL) {
|
if (info != NULL) {
|
||||||
__libc_format_log(ANDROID_LOG_FATAL, "libc",
|
__libc_format_log(ANDROID_LOG_FATAL, "libc",
|
||||||
"Fatal signal %d (%s) at 0x%08x (code=%d), thread %d (%s)",
|
"Fatal signal %d (%s) at %p (code=%d), thread %d (%s)",
|
||||||
signum, signal_name, reinterpret_cast<uintptr_t>(info->si_addr),
|
signum, signal_name, info->si_addr, info->si_code,
|
||||||
info->si_code, gettid(), thread_name);
|
gettid(), thread_name);
|
||||||
} else {
|
} else {
|
||||||
__libc_format_log(ANDROID_LOG_FATAL, "libc",
|
__libc_format_log(ANDROID_LOG_FATAL, "libc",
|
||||||
"Fatal signal %d (%s), thread %d (%s)",
|
"Fatal signal %d (%s), thread %d (%s)",
|
||||||
|
@ -83,7 +83,7 @@ void* dlsym(void* handle, const char* symbol) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
soinfo* found = NULL;
|
soinfo* found = NULL;
|
||||||
Elf32_Sym* sym = NULL;
|
Elf_Sym* sym = NULL;
|
||||||
if (handle == RTLD_DEFAULT) {
|
if (handle == RTLD_DEFAULT) {
|
||||||
sym = dlsym_linear_lookup(symbol, &found, NULL);
|
sym = dlsym_linear_lookup(symbol, &found, NULL);
|
||||||
} else if (handle == RTLD_NEXT) {
|
} else if (handle == RTLD_NEXT) {
|
||||||
@ -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 = dladdr_find_symbol(si, addr);
|
Elf_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);
|
||||||
|
@ -437,15 +437,15 @@ dl_iterate_phdr(int (*cb)(dl_phdr_info *info, size_t size, void *data),
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Elf32_Sym* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) {
|
static Elf_Sym* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) {
|
||||||
Elf32_Sym* symtab = si->symtab;
|
Elf_Sym* symtab = si->symtab;
|
||||||
const char* strtab = si->strtab;
|
const char* strtab = si->strtab;
|
||||||
|
|
||||||
TRACE_TYPE(LOOKUP, "SEARCH %s in %s@0x%08x %08x %d",
|
TRACE_TYPE(LOOKUP, "SEARCH %s in %s@0x%08x %08x %zd",
|
||||||
name, si->name, si->base, hash, hash % si->nbucket);
|
name, si->name, si->base, hash, hash % si->nbucket);
|
||||||
|
|
||||||
for (unsigned n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) {
|
for (unsigned n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) {
|
||||||
Elf32_Sym* s = symtab + n;
|
Elf_Sym* 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 */
|
||||||
@ -478,9 +478,9 @@ static unsigned elfhash(const char* _name) {
|
|||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Elf32_Sym* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, soinfo* needed[]) {
|
static Elf_Sym* 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;
|
Elf_Sym* s = NULL;
|
||||||
|
|
||||||
if (si != NULL && somain != NULL) {
|
if (si != NULL && somain != NULL) {
|
||||||
|
|
||||||
@ -587,8 +587,7 @@ done:
|
|||||||
Binary Interface) where in Chapter 5 it discuss resolving "Shared
|
Binary Interface) where in Chapter 5 it discuss resolving "Shared
|
||||||
Object Dependencies" in breadth first search order.
|
Object Dependencies" in breadth first search order.
|
||||||
*/
|
*/
|
||||||
Elf32_Sym* dlsym_handle_lookup(soinfo* si, const char* name)
|
Elf_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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -597,14 +596,14 @@ Elf32_Sym* dlsym_handle_lookup(soinfo* si, const char* name)
|
|||||||
beginning of the global solist. Otherwise the search starts at the
|
beginning of the global solist. Otherwise the search starts at the
|
||||||
specified soinfo (for RTLD_NEXT).
|
specified soinfo (for RTLD_NEXT).
|
||||||
*/
|
*/
|
||||||
Elf32_Sym* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start) {
|
Elf_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) {
|
||||||
start = solist;
|
start = solist;
|
||||||
}
|
}
|
||||||
|
|
||||||
Elf32_Sym* s = NULL;
|
Elf_Sym* s = NULL;
|
||||||
for (soinfo* si = start; (s == NULL) && (si != NULL); si = si->next) {
|
for (soinfo* si = start; (s == NULL) && (si != NULL); si = si->next) {
|
||||||
s = soinfo_elf_lookup(si, elf_hash, name);
|
s = soinfo_elf_lookup(si, elf_hash, name);
|
||||||
if (s != NULL) {
|
if (s != NULL) {
|
||||||
@ -622,7 +621,7 @@ Elf32_Sym* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start)
|
|||||||
}
|
}
|
||||||
|
|
||||||
soinfo* find_containing_library(const void* p) {
|
soinfo* find_containing_library(const void* p) {
|
||||||
Elf32_Addr address = reinterpret_cast<Elf32_Addr>(p);
|
Elf_Addr address = reinterpret_cast<Elf_Addr>(p);
|
||||||
for (soinfo* si = solist; si != NULL; si = si->next) {
|
for (soinfo* si = solist; si != NULL; si = si->next) {
|
||||||
if (address >= si->base && address - si->base < si->size) {
|
if (address >= si->base && address - si->base < si->size) {
|
||||||
return si;
|
return si;
|
||||||
@ -631,13 +630,13 @@ soinfo* find_containing_library(const void* p) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Elf32_Sym* dladdr_find_symbol(soinfo* si, const void* addr) {
|
Elf_Sym* dladdr_find_symbol(soinfo* si, const void* addr) {
|
||||||
Elf32_Addr soaddr = reinterpret_cast<Elf32_Addr>(addr) - si->base;
|
Elf_Addr soaddr = reinterpret_cast<Elf_Addr>(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 (size_t i = 0; i < si->nchain; ++i) {
|
for (size_t i = 0; i < si->nchain; ++i) {
|
||||||
Elf32_Sym* sym = &si->symtab[i];
|
Elf_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) {
|
||||||
@ -651,7 +650,7 @@ Elf32_Sym* dladdr_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;
|
Elf_Sym* s = si->symtab;
|
||||||
for (unsigned n = 0; n < si->nchain; n++) {
|
for (unsigned n = 0; n < si->nchain; n++) {
|
||||||
TRACE("%04d> %08x: %02x %04x %08x %08x %s", n, s,
|
TRACE("%04d> %08x: %02x %04x %08x %08x %s", 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,
|
||||||
@ -793,7 +792,7 @@ static int soinfo_unload(soinfo* si) {
|
|||||||
TRACE("unloading '%s'", si->name);
|
TRACE("unloading '%s'", si->name);
|
||||||
si->CallDestructors();
|
si->CallDestructors();
|
||||||
|
|
||||||
for (Elf32_Dyn* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
|
for (Elf_Dyn* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
|
||||||
if (d->d_tag == DT_NEEDED) {
|
if (d->d_tag == DT_NEEDED) {
|
||||||
const char* library_name = si->strtab + d->d_un.d_val;
|
const char* library_name = si->strtab + d->d_un.d_val;
|
||||||
TRACE("%s needs to unload %s", si->name, library_name);
|
TRACE("%s needs to unload %s", si->name, library_name);
|
||||||
@ -807,7 +806,7 @@ static int soinfo_unload(soinfo* si) {
|
|||||||
si->ref_count = 0;
|
si->ref_count = 0;
|
||||||
} else {
|
} else {
|
||||||
si->ref_count--;
|
si->ref_count--;
|
||||||
TRACE("not unloading '%s', decrementing ref_count to %d", si->name, si->ref_count);
|
TRACE("not unloading '%s', decrementing ref_count to %zd", si->name, si->ref_count);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -840,26 +839,26 @@ int do_dlclose(soinfo* si) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: don't use unsigned for addrs below. It works, but is not
|
/* TODO: don't use unsigned for addrs below. It works, but is not
|
||||||
* ideal. They should probably be either uint32_t, Elf32_Addr, or unsigned
|
* ideal. They should probably be either uint32_t, Elf_Addr, or unsigned
|
||||||
* long.
|
* long.
|
||||||
*/
|
*/
|
||||||
static int soinfo_relocate(soinfo* si, Elf32_Rel* rel, unsigned count,
|
static int soinfo_relocate(soinfo* si, Elf_Rel* rel, unsigned count,
|
||||||
soinfo* needed[])
|
soinfo* needed[])
|
||||||
{
|
{
|
||||||
Elf32_Sym* symtab = si->symtab;
|
Elf_Sym* symtab = si->symtab;
|
||||||
const char* strtab = si->strtab;
|
const char* strtab = si->strtab;
|
||||||
Elf32_Sym* s;
|
Elf_Sym* s;
|
||||||
Elf32_Rel* start = rel;
|
Elf_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);
|
||||||
Elf32_Addr reloc = static_cast<Elf32_Addr>(rel->r_offset + si->load_bias);
|
Elf_Addr reloc = static_cast<Elf_Addr>(rel->r_offset + si->load_bias);
|
||||||
Elf32_Addr sym_addr = 0;
|
Elf_Addr sym_addr = 0;
|
||||||
char* sym_name = NULL;
|
char* sym_name = NULL;
|
||||||
|
|
||||||
DEBUG("Processing '%s' relocation at index %d", si->name, idx);
|
DEBUG("Processing '%s' relocation at index %zd", si->name, idx);
|
||||||
if (type == 0) { // R_*_NONE
|
if (type == 0) { // R_*_NONE
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -931,7 +930,7 @@ static int soinfo_relocate(soinfo* si, Elf32_Rel* rel, unsigned count,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
sym_addr = static_cast<Elf32_Addr>(s->st_value + lsi->load_bias);
|
sym_addr = static_cast<Elf_Addr>(s->st_value + lsi->load_bias);
|
||||||
}
|
}
|
||||||
count_relocation(kRelocSymbol);
|
count_relocation(kRelocSymbol);
|
||||||
} else {
|
} else {
|
||||||
@ -947,39 +946,39 @@ static int soinfo_relocate(soinfo* si, Elf32_Rel* rel, unsigned count,
|
|||||||
count_relocation(kRelocAbsolute);
|
count_relocation(kRelocAbsolute);
|
||||||
MARK(rel->r_offset);
|
MARK(rel->r_offset);
|
||||||
TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name);
|
TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name);
|
||||||
*reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr;
|
*reinterpret_cast<Elf_Addr*>(reloc) = sym_addr;
|
||||||
break;
|
break;
|
||||||
case R_ARM_GLOB_DAT:
|
case R_ARM_GLOB_DAT:
|
||||||
count_relocation(kRelocAbsolute);
|
count_relocation(kRelocAbsolute);
|
||||||
MARK(rel->r_offset);
|
MARK(rel->r_offset);
|
||||||
TRACE_TYPE(RELO, "RELO GLOB_DAT %08x <- %08x %s", reloc, sym_addr, sym_name);
|
TRACE_TYPE(RELO, "RELO GLOB_DAT %08x <- %08x %s", reloc, sym_addr, sym_name);
|
||||||
*reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr;
|
*reinterpret_cast<Elf_Addr*>(reloc) = sym_addr;
|
||||||
break;
|
break;
|
||||||
case R_ARM_ABS32:
|
case R_ARM_ABS32:
|
||||||
count_relocation(kRelocAbsolute);
|
count_relocation(kRelocAbsolute);
|
||||||
MARK(rel->r_offset);
|
MARK(rel->r_offset);
|
||||||
TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
|
TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
|
||||||
*reinterpret_cast<Elf32_Addr*>(reloc) += sym_addr;
|
*reinterpret_cast<Elf_Addr*>(reloc) += sym_addr;
|
||||||
break;
|
break;
|
||||||
case R_ARM_REL32:
|
case R_ARM_REL32:
|
||||||
count_relocation(kRelocRelative);
|
count_relocation(kRelocRelative);
|
||||||
MARK(rel->r_offset);
|
MARK(rel->r_offset);
|
||||||
TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
|
TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
|
||||||
reloc, sym_addr, rel->r_offset, sym_name);
|
reloc, sym_addr, rel->r_offset, sym_name);
|
||||||
*reinterpret_cast<Elf32_Addr*>(reloc) += sym_addr - rel->r_offset;
|
*reinterpret_cast<Elf_Addr*>(reloc) += sym_addr - rel->r_offset;
|
||||||
break;
|
break;
|
||||||
#elif defined(ANDROID_X86_LINKER)
|
#elif defined(ANDROID_X86_LINKER)
|
||||||
case R_386_JMP_SLOT:
|
case R_386_JMP_SLOT:
|
||||||
count_relocation(kRelocAbsolute);
|
count_relocation(kRelocAbsolute);
|
||||||
MARK(rel->r_offset);
|
MARK(rel->r_offset);
|
||||||
TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name);
|
TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name);
|
||||||
*reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr;
|
*reinterpret_cast<Elf_Addr*>(reloc) = sym_addr;
|
||||||
break;
|
break;
|
||||||
case R_386_GLOB_DAT:
|
case R_386_GLOB_DAT:
|
||||||
count_relocation(kRelocAbsolute);
|
count_relocation(kRelocAbsolute);
|
||||||
MARK(rel->r_offset);
|
MARK(rel->r_offset);
|
||||||
TRACE_TYPE(RELO, "RELO GLOB_DAT %08x <- %08x %s", reloc, sym_addr, sym_name);
|
TRACE_TYPE(RELO, "RELO GLOB_DAT %08x <- %08x %s", reloc, sym_addr, sym_name);
|
||||||
*reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr;
|
*reinterpret_cast<Elf_Addr*>(reloc) = sym_addr;
|
||||||
break;
|
break;
|
||||||
#elif defined(ANDROID_MIPS_LINKER)
|
#elif defined(ANDROID_MIPS_LINKER)
|
||||||
case R_MIPS_REL32:
|
case R_MIPS_REL32:
|
||||||
@ -988,9 +987,9 @@ static int soinfo_relocate(soinfo* si, Elf32_Rel* rel, unsigned count,
|
|||||||
TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x %s",
|
TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x %s",
|
||||||
reloc, sym_addr, (sym_name) ? sym_name : "*SECTIONHDR*");
|
reloc, sym_addr, (sym_name) ? sym_name : "*SECTIONHDR*");
|
||||||
if (s) {
|
if (s) {
|
||||||
*reinterpret_cast<Elf32_Addr*>(reloc) += sym_addr;
|
*reinterpret_cast<Elf_Addr*>(reloc) += sym_addr;
|
||||||
} else {
|
} else {
|
||||||
*reinterpret_cast<Elf32_Addr*>(reloc) += si->base;
|
*reinterpret_cast<Elf_Addr*>(reloc) += si->base;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif /* ANDROID_*_LINKER */
|
#endif /* ANDROID_*_LINKER */
|
||||||
@ -1007,7 +1006,7 @@ static int soinfo_relocate(soinfo* si, Elf32_Rel* rel, unsigned count,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
TRACE_TYPE(RELO, "RELO RELATIVE %08x <- +%08x", reloc, si->base);
|
TRACE_TYPE(RELO, "RELO RELATIVE %08x <- +%08x", reloc, si->base);
|
||||||
*reinterpret_cast<Elf32_Addr*>(reloc) += si->base;
|
*reinterpret_cast<Elf_Addr*>(reloc) += si->base;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#if defined(ANDROID_X86_LINKER)
|
#if defined(ANDROID_X86_LINKER)
|
||||||
@ -1016,7 +1015,7 @@ static int soinfo_relocate(soinfo* si, Elf32_Rel* rel, unsigned count,
|
|||||||
MARK(rel->r_offset);
|
MARK(rel->r_offset);
|
||||||
|
|
||||||
TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
|
TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
|
||||||
*reinterpret_cast<Elf32_Addr*>(reloc) += sym_addr;
|
*reinterpret_cast<Elf_Addr*>(reloc) += sym_addr;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R_386_PC32:
|
case R_386_PC32:
|
||||||
@ -1024,7 +1023,7 @@ static int soinfo_relocate(soinfo* si, Elf32_Rel* rel, unsigned count,
|
|||||||
MARK(rel->r_offset);
|
MARK(rel->r_offset);
|
||||||
TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
|
TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
|
||||||
reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
|
reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
|
||||||
*reinterpret_cast<Elf32_Addr*>(reloc) += (sym_addr - reloc);
|
*reinterpret_cast<Elf_Addr*>(reloc) += (sym_addr - reloc);
|
||||||
break;
|
break;
|
||||||
#endif /* ANDROID_X86_LINKER */
|
#endif /* ANDROID_X86_LINKER */
|
||||||
|
|
||||||
@ -1049,7 +1048,7 @@ static int soinfo_relocate(soinfo* si, Elf32_Rel* rel, unsigned count,
|
|||||||
MARK(rel->r_offset);
|
MARK(rel->r_offset);
|
||||||
TRACE_TYPE(RELO, "RELO %08x <- %d @ %08x %s", reloc, s->st_size, sym_addr, sym_name);
|
TRACE_TYPE(RELO, "RELO %08x <- %d @ %08x %s", reloc, s->st_size, sym_addr, sym_name);
|
||||||
if (reloc == sym_addr) {
|
if (reloc == sym_addr) {
|
||||||
Elf32_Sym *src = soinfo_do_lookup(NULL, sym_name, &lsi, needed);
|
Elf_Sym *src = soinfo_do_lookup(NULL, sym_name, &lsi, needed);
|
||||||
|
|
||||||
if (src == NULL) {
|
if (src == NULL) {
|
||||||
DL_ERR("%s R_ARM_COPY relocation source cannot be resolved", si->name);
|
DL_ERR("%s R_ARM_COPY relocation source cannot be resolved", si->name);
|
||||||
@ -1091,7 +1090,7 @@ static bool mips_relocate_got(soinfo* si, soinfo* needed[]) {
|
|||||||
unsigned local_gotno = si->mips_local_gotno;
|
unsigned local_gotno = si->mips_local_gotno;
|
||||||
unsigned gotsym = si->mips_gotsym;
|
unsigned gotsym = si->mips_gotsym;
|
||||||
unsigned symtabno = si->mips_symtabno;
|
unsigned symtabno = si->mips_symtabno;
|
||||||
Elf32_Sym* symtab = si->symtab;
|
Elf_Sym* symtab = si->symtab;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* got[0] is address of lazy resolver function
|
* got[0] is address of lazy resolver function
|
||||||
@ -1116,11 +1115,11 @@ static bool mips_relocate_got(soinfo* si, soinfo* needed[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Now for the global GOT entries */
|
/* Now for the global GOT entries */
|
||||||
Elf32_Sym* sym = symtab + gotsym;
|
Elf_Sym* sym = symtab + gotsym;
|
||||||
got = si->plt_got + local_gotno;
|
got = si->plt_got + local_gotno;
|
||||||
for (size_t g = gotsym; g < symtabno; g++, sym++, got++) {
|
for (size_t g = gotsym; g < symtabno; g++, sym++, got++) {
|
||||||
const char* sym_name;
|
const char* sym_name;
|
||||||
Elf32_Sym* s;
|
Elf_Sym* s;
|
||||||
soinfo* lsi;
|
soinfo* lsi;
|
||||||
|
|
||||||
/* This is an undefined reference... try to locate it */
|
/* This is an undefined reference... try to locate it */
|
||||||
@ -1153,7 +1152,7 @@ void soinfo::CallArray(const char* array_name UNUSED, linker_function_t* functio
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("[ Calling %s (size %d) @ %p for '%s' ]", array_name, count, functions, name);
|
TRACE("[ Calling %s (size %zd) @ %p for '%s' ]", array_name, count, functions, name);
|
||||||
|
|
||||||
int begin = reverse ? (count - 1) : 0;
|
int begin = reverse ? (count - 1) : 0;
|
||||||
int end = reverse ? -1 : count;
|
int end = reverse ? -1 : count;
|
||||||
@ -1206,12 +1205,12 @@ void soinfo::CallConstructors() {
|
|||||||
|
|
||||||
if ((flags & FLAG_EXE) == 0 && preinit_array != NULL) {
|
if ((flags & FLAG_EXE) == 0 && preinit_array != NULL) {
|
||||||
// The GNU dynamic linker silently ignores these, but we warn the developer.
|
// The GNU dynamic linker silently ignores these, but we warn the developer.
|
||||||
PRINT("\"%s\": ignoring %d-entry DT_PREINIT_ARRAY in shared library!",
|
PRINT("\"%s\": ignoring %zd-entry DT_PREINIT_ARRAY in shared library!",
|
||||||
name, preinit_array_count);
|
name, preinit_array_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dynamic != NULL) {
|
if (dynamic != NULL) {
|
||||||
for (Elf32_Dyn* d = dynamic; d->d_tag != DT_NULL; ++d) {
|
for (Elf_Dyn* d = dynamic; d->d_tag != DT_NULL; ++d) {
|
||||||
if (d->d_tag == DT_NEEDED) {
|
if (d->d_tag == DT_NEEDED) {
|
||||||
const char* library_name = strtab + d->d_un.d_val;
|
const char* library_name = strtab + d->d_un.d_val;
|
||||||
TRACE("\"%s\": calling constructors in DT_NEEDED \"%s\"", name, library_name);
|
TRACE("\"%s\": calling constructors in DT_NEEDED \"%s\"", name, library_name);
|
||||||
@ -1300,8 +1299,8 @@ static int nullify_closed_stdio() {
|
|||||||
|
|
||||||
static bool soinfo_link_image(soinfo* si) {
|
static bool soinfo_link_image(soinfo* si) {
|
||||||
/* "base" might wrap around UINT32_MAX. */
|
/* "base" might wrap around UINT32_MAX. */
|
||||||
Elf32_Addr base = si->load_bias;
|
Elf_Addr base = si->load_bias;
|
||||||
const Elf32_Phdr *phdr = si->phdr;
|
const Elf_Phdr *phdr = si->phdr;
|
||||||
int phnum = si->phnum;
|
int phnum = si->phnum;
|
||||||
bool relocating_linker = (si->flags & FLAG_LINKER) != 0;
|
bool relocating_linker = (si->flags & FLAG_LINKER) != 0;
|
||||||
|
|
||||||
@ -1313,7 +1312,7 @@ static bool soinfo_link_image(soinfo* si) {
|
|||||||
|
|
||||||
/* Extract dynamic section */
|
/* Extract dynamic section */
|
||||||
size_t dynamic_count;
|
size_t dynamic_count;
|
||||||
Elf32_Word dynamic_flags;
|
Elf_Word dynamic_flags;
|
||||||
phdr_table_get_dynamic_section(phdr, phnum, base, &si->dynamic,
|
phdr_table_get_dynamic_section(phdr, phnum, base, &si->dynamic,
|
||||||
&dynamic_count, &dynamic_flags);
|
&dynamic_count, &dynamic_flags);
|
||||||
if (si->dynamic == NULL) {
|
if (si->dynamic == NULL) {
|
||||||
@ -1334,7 +1333,7 @@ static bool soinfo_link_image(soinfo* si) {
|
|||||||
|
|
||||||
// Extract useful information from dynamic section.
|
// Extract useful information from dynamic section.
|
||||||
uint32_t needed_count = 0;
|
uint32_t needed_count = 0;
|
||||||
for (Elf32_Dyn* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
|
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);
|
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){
|
switch(d->d_tag){
|
||||||
case DT_HASH:
|
case DT_HASH:
|
||||||
@ -1347,7 +1346,7 @@ static bool soinfo_link_image(soinfo* si) {
|
|||||||
si->strtab = (const char *) (base + d->d_un.d_ptr);
|
si->strtab = (const char *) (base + d->d_un.d_ptr);
|
||||||
break;
|
break;
|
||||||
case DT_SYMTAB:
|
case DT_SYMTAB:
|
||||||
si->symtab = (Elf32_Sym *) (base + d->d_un.d_ptr);
|
si->symtab = (Elf_Sym *) (base + d->d_un.d_ptr);
|
||||||
break;
|
break;
|
||||||
case DT_PLTREL:
|
case DT_PLTREL:
|
||||||
if (d->d_un.d_val != DT_REL) {
|
if (d->d_un.d_val != DT_REL) {
|
||||||
@ -1356,16 +1355,16 @@ static bool soinfo_link_image(soinfo* si) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DT_JMPREL:
|
case DT_JMPREL:
|
||||||
si->plt_rel = (Elf32_Rel*) (base + d->d_un.d_ptr);
|
si->plt_rel = (Elf_Rel*) (base + d->d_un.d_ptr);
|
||||||
break;
|
break;
|
||||||
case DT_PLTRELSZ:
|
case DT_PLTRELSZ:
|
||||||
si->plt_rel_count = d->d_un.d_val / sizeof(Elf32_Rel);
|
si->plt_rel_count = d->d_un.d_val / sizeof(Elf_Rel);
|
||||||
break;
|
break;
|
||||||
case DT_REL:
|
case DT_REL:
|
||||||
si->rel = (Elf32_Rel*) (base + d->d_un.d_ptr);
|
si->rel = (Elf_Rel*) (base + d->d_un.d_ptr);
|
||||||
break;
|
break;
|
||||||
case DT_RELSZ:
|
case DT_RELSZ:
|
||||||
si->rel_count = d->d_un.d_val / sizeof(Elf32_Rel);
|
si->rel_count = d->d_un.d_val / sizeof(Elf_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. */
|
||||||
@ -1375,7 +1374,7 @@ static bool soinfo_link_image(soinfo* si) {
|
|||||||
// 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->d_un.d_val = (int) &_r_debug;
|
d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DT_RELA:
|
case DT_RELA:
|
||||||
@ -1394,21 +1393,21 @@ static bool soinfo_link_image(soinfo* si) {
|
|||||||
DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", si->name, si->init_array);
|
DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", si->name, si->init_array);
|
||||||
break;
|
break;
|
||||||
case DT_INIT_ARRAYSZ:
|
case DT_INIT_ARRAYSZ:
|
||||||
si->init_array_count = ((unsigned)d->d_un.d_val) / sizeof(Elf32_Addr);
|
si->init_array_count = ((unsigned)d->d_un.d_val) / sizeof(Elf_Addr);
|
||||||
break;
|
break;
|
||||||
case DT_FINI_ARRAY:
|
case DT_FINI_ARRAY:
|
||||||
si->fini_array = reinterpret_cast<linker_function_t*>(base + d->d_un.d_ptr);
|
si->fini_array = reinterpret_cast<linker_function_t*>(base + d->d_un.d_ptr);
|
||||||
DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", si->name, si->fini_array);
|
DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", si->name, si->fini_array);
|
||||||
break;
|
break;
|
||||||
case DT_FINI_ARRAYSZ:
|
case DT_FINI_ARRAYSZ:
|
||||||
si->fini_array_count = ((unsigned)d->d_un.d_val) / sizeof(Elf32_Addr);
|
si->fini_array_count = ((unsigned)d->d_un.d_val) / sizeof(Elf_Addr);
|
||||||
break;
|
break;
|
||||||
case DT_PREINIT_ARRAY:
|
case DT_PREINIT_ARRAY:
|
||||||
si->preinit_array = reinterpret_cast<linker_function_t*>(base + d->d_un.d_ptr);
|
si->preinit_array = reinterpret_cast<linker_function_t*>(base + d->d_un.d_ptr);
|
||||||
DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", si->name, si->preinit_array);
|
DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", si->name, si->preinit_array);
|
||||||
break;
|
break;
|
||||||
case DT_PREINIT_ARRAYSZ:
|
case DT_PREINIT_ARRAYSZ:
|
||||||
si->preinit_array_count = ((unsigned)d->d_un.d_val) / sizeof(Elf32_Addr);
|
si->preinit_array_count = ((unsigned)d->d_un.d_val) / sizeof(Elf_Addr);
|
||||||
break;
|
break;
|
||||||
case DT_TEXTREL:
|
case DT_TEXTREL:
|
||||||
si->has_text_relocations = true;
|
si->has_text_relocations = true;
|
||||||
@ -1507,7 +1506,7 @@ static bool soinfo_link_image(soinfo* si) {
|
|||||||
soinfo** needed = (soinfo**) alloca((1 + needed_count) * sizeof(soinfo*));
|
soinfo** needed = (soinfo**) alloca((1 + needed_count) * sizeof(soinfo*));
|
||||||
soinfo** pneeded = needed;
|
soinfo** pneeded = needed;
|
||||||
|
|
||||||
for (Elf32_Dyn* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
|
for (Elf_Dyn* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
|
||||||
if (d->d_tag == DT_NEEDED) {
|
if (d->d_tag == DT_NEEDED) {
|
||||||
const char* library_name = si->strtab + d->d_un.d_val;
|
const char* library_name = si->strtab + d->d_un.d_val;
|
||||||
DEBUG("%s needs %s", si->name, library_name);
|
DEBUG("%s needs %s", si->name, library_name);
|
||||||
@ -1588,15 +1587,15 @@ static bool soinfo_link_image(soinfo* si) {
|
|||||||
*/
|
*/
|
||||||
static void add_vdso(KernelArgumentBlock& args UNUSED) {
|
static void add_vdso(KernelArgumentBlock& args UNUSED) {
|
||||||
#ifdef AT_SYSINFO_EHDR
|
#ifdef AT_SYSINFO_EHDR
|
||||||
Elf32_Ehdr* ehdr_vdso = reinterpret_cast<Elf32_Ehdr*>(args.getauxval(AT_SYSINFO_EHDR));
|
Elf_Ehdr* ehdr_vdso = reinterpret_cast<Elf_Ehdr*>(args.getauxval(AT_SYSINFO_EHDR));
|
||||||
|
|
||||||
soinfo* si = soinfo_alloc("[vdso]");
|
soinfo* si = soinfo_alloc("[vdso]");
|
||||||
si->phdr = reinterpret_cast<Elf32_Phdr*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff);
|
si->phdr = reinterpret_cast<Elf_Phdr*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff);
|
||||||
si->phnum = ehdr_vdso->e_phnum;
|
si->phnum = ehdr_vdso->e_phnum;
|
||||||
si->link_map.l_name = si->name;
|
si->link_map.l_name = si->name;
|
||||||
for (size_t i = 0; i < si->phnum; ++i) {
|
for (size_t i = 0; i < si->phnum; ++i) {
|
||||||
if (si->phdr[i].p_type == PT_LOAD) {
|
if (si->phdr[i].p_type == PT_LOAD) {
|
||||||
si->link_map.l_addr = reinterpret_cast<Elf32_Addr>(ehdr_vdso) - si->phdr[i].p_vaddr;
|
si->link_map.l_addr = reinterpret_cast<Elf_Addr>(ehdr_vdso) - si->phdr[i].p_vaddr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1608,7 +1607,7 @@ static void add_vdso(KernelArgumentBlock& args UNUSED) {
|
|||||||
* fixed it's own GOT. It is safe to make references to externs
|
* fixed it's own GOT. It is safe to make references to externs
|
||||||
* and other non-local data at this point.
|
* and other non-local data at this point.
|
||||||
*/
|
*/
|
||||||
static Elf32_Addr __linker_init_post_relocation(KernelArgumentBlock& args, Elf32_Addr linker_base) {
|
static Elf_Addr __linker_init_post_relocation(KernelArgumentBlock& args, Elf_Addr linker_base) {
|
||||||
/* NOTE: we store the args pointer on a special location
|
/* NOTE: we store the args pointer on a special location
|
||||||
* of the temporary TLS area in order to pass it to
|
* of the temporary TLS area in order to pass it to
|
||||||
* the C Library's runtime initializer.
|
* the C Library's runtime initializer.
|
||||||
@ -1688,15 +1687,15 @@ static Elf32_Addr __linker_init_post_relocation(KernelArgumentBlock& args, Elf32
|
|||||||
* warning: .dynamic section for "/system/bin/linker" is not at the
|
* warning: .dynamic section for "/system/bin/linker" is not at the
|
||||||
* expected address (wrong library or version mismatch?)
|
* expected address (wrong library or version mismatch?)
|
||||||
*/
|
*/
|
||||||
Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *) linker_base;
|
Elf_Ehdr *elf_hdr = (Elf_Ehdr *) linker_base;
|
||||||
Elf32_Phdr *phdr = (Elf32_Phdr*)((unsigned char*) linker_base + elf_hdr->e_phoff);
|
Elf_Phdr *phdr = (Elf_Phdr*)((unsigned char*) linker_base + elf_hdr->e_phoff);
|
||||||
phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base,
|
phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base,
|
||||||
&linker_soinfo.dynamic, NULL, NULL);
|
&linker_soinfo.dynamic, NULL, NULL);
|
||||||
insert_soinfo_into_debug_map(&linker_soinfo);
|
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<Elf_Phdr*>(args.getauxval(AT_PHDR));
|
||||||
si->phnum = args.getauxval(AT_PHNUM);
|
si->phnum = args.getauxval(AT_PHNUM);
|
||||||
si->entry = args.getauxval(AT_ENTRY);
|
si->entry = args.getauxval(AT_ENTRY);
|
||||||
|
|
||||||
@ -1709,8 +1708,8 @@ static Elf32_Addr __linker_init_post_relocation(KernelArgumentBlock& args, Elf32
|
|||||||
si->load_bias = 0;
|
si->load_bias = 0;
|
||||||
for (size_t i = 0; i < si->phnum; ++i) {
|
for (size_t i = 0; i < si->phnum; ++i) {
|
||||||
if (si->phdr[i].p_type == PT_PHDR) {
|
if (si->phdr[i].p_type == PT_PHDR) {
|
||||||
si->load_bias = reinterpret_cast<Elf32_Addr>(si->phdr) - si->phdr[i].p_vaddr;
|
si->load_bias = reinterpret_cast<Elf_Addr>(si->phdr) - si->phdr[i].p_vaddr;
|
||||||
si->base = reinterpret_cast<Elf32_Addr>(si->phdr) - si->phdr[i].p_offset;
|
si->base = reinterpret_cast<Elf_Addr>(si->phdr) - si->phdr[i].p_offset;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1796,14 +1795,14 @@ static Elf32_Addr __linker_init_post_relocation(KernelArgumentBlock& args, Elf32
|
|||||||
* load bias, i.e. add the value of any p_vaddr in the file to get
|
* load bias, i.e. add the value of any p_vaddr in the file to get
|
||||||
* the corresponding address in memory.
|
* the corresponding address in memory.
|
||||||
*/
|
*/
|
||||||
static Elf32_Addr get_elf_exec_load_bias(const Elf32_Ehdr* elf) {
|
static Elf_Addr get_elf_exec_load_bias(const Elf_Ehdr* elf) {
|
||||||
Elf32_Addr offset = elf->e_phoff;
|
Elf_Addr offset = elf->e_phoff;
|
||||||
const Elf32_Phdr* phdr_table = (const Elf32_Phdr*)((char*)elf + offset);
|
const Elf_Phdr* phdr_table = (const Elf_Phdr*)((char*)elf + offset);
|
||||||
const Elf32_Phdr* phdr_end = phdr_table + elf->e_phnum;
|
const Elf_Phdr* phdr_end = phdr_table + elf->e_phnum;
|
||||||
|
|
||||||
for (const Elf32_Phdr* phdr = phdr_table; phdr < phdr_end; phdr++) {
|
for (const Elf_Phdr* phdr = phdr_table; phdr < phdr_end; phdr++) {
|
||||||
if (phdr->p_type == PT_LOAD) {
|
if (phdr->p_type == PT_LOAD) {
|
||||||
return reinterpret_cast<Elf32_Addr>(elf) + phdr->p_offset - phdr->p_vaddr;
|
return reinterpret_cast<Elf_Addr>(elf) + phdr->p_offset - phdr->p_vaddr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -1818,13 +1817,13 @@ static Elf32_Addr get_elf_exec_load_bias(const Elf32_Ehdr* elf) {
|
|||||||
* relocations, any attempt to reference an extern variable, extern
|
* relocations, any attempt to reference an extern variable, extern
|
||||||
* function, or other GOT reference will generate a segfault.
|
* function, or other GOT reference will generate a segfault.
|
||||||
*/
|
*/
|
||||||
extern "C" Elf32_Addr __linker_init(void* raw_args) {
|
extern "C" Elf_Addr __linker_init(void* raw_args) {
|
||||||
KernelArgumentBlock args(raw_args);
|
KernelArgumentBlock args(raw_args);
|
||||||
|
|
||||||
Elf32_Addr linker_addr = args.getauxval(AT_BASE);
|
Elf_Addr linker_addr = args.getauxval(AT_BASE);
|
||||||
|
|
||||||
Elf32_Ehdr* elf_hdr = (Elf32_Ehdr*) linker_addr;
|
Elf_Ehdr* elf_hdr = reinterpret_cast<Elf_Ehdr*>(linker_addr);
|
||||||
Elf32_Phdr* phdr = (Elf32_Phdr*)((unsigned char*) linker_addr + elf_hdr->e_phoff);
|
Elf_Phdr* phdr = (Elf_Phdr*)((unsigned char*) linker_addr + elf_hdr->e_phoff);
|
||||||
|
|
||||||
soinfo linker_so;
|
soinfo linker_so;
|
||||||
memset(&linker_so, 0, sizeof(soinfo));
|
memset(&linker_so, 0, sizeof(soinfo));
|
||||||
@ -1850,7 +1849,7 @@ extern "C" Elf32_Addr __linker_init(void* raw_args) {
|
|||||||
// We have successfully fixed our own relocations. It's safe to run
|
// We have successfully fixed our own relocations. It's safe to run
|
||||||
// the main part of the linker now.
|
// the main part of the linker now.
|
||||||
args.abort_message_ptr = &gAbortMessage;
|
args.abort_message_ptr = &gAbortMessage;
|
||||||
Elf32_Addr start_address = __linker_init_post_relocation(args, linker_addr);
|
Elf_Addr start_address = __linker_init_post_relocation(args, linker_addr);
|
||||||
|
|
||||||
set_soinfo_pool_protection(PROT_READ);
|
set_soinfo_pool_protection(PROT_READ);
|
||||||
|
|
||||||
|
@ -100,24 +100,28 @@ typedef void (*linker_function_t)();
|
|||||||
struct soinfo {
|
struct soinfo {
|
||||||
public:
|
public:
|
||||||
char name[SOINFO_NAME_LEN];
|
char name[SOINFO_NAME_LEN];
|
||||||
const Elf32_Phdr* phdr;
|
const Elf_Phdr* phdr;
|
||||||
size_t phnum;
|
size_t phnum;
|
||||||
Elf32_Addr entry;
|
Elf_Addr entry;
|
||||||
Elf32_Addr base;
|
Elf_Addr base;
|
||||||
unsigned size;
|
unsigned size;
|
||||||
|
|
||||||
|
#ifndef __LP64__
|
||||||
uint32_t unused1; // DO NOT USE, maintained for compatibility.
|
uint32_t unused1; // DO NOT USE, maintained for compatibility.
|
||||||
|
#endif
|
||||||
|
|
||||||
Elf32_Dyn* dynamic;
|
Elf_Dyn* dynamic;
|
||||||
|
|
||||||
|
#ifndef __LP64__
|
||||||
uint32_t unused2; // DO NOT USE, maintained for compatibility
|
uint32_t unused2; // DO NOT USE, maintained for compatibility
|
||||||
uint32_t unused3; // DO NOT USE, maintained for compatibility
|
uint32_t unused3; // DO NOT USE, maintained for compatibility
|
||||||
|
#endif
|
||||||
|
|
||||||
soinfo* next;
|
soinfo* next;
|
||||||
unsigned flags;
|
unsigned flags;
|
||||||
|
|
||||||
const char* strtab;
|
const char* strtab;
|
||||||
Elf32_Sym* symtab;
|
Elf_Sym* symtab;
|
||||||
|
|
||||||
size_t nbucket;
|
size_t nbucket;
|
||||||
size_t nchain;
|
size_t nchain;
|
||||||
@ -126,10 +130,10 @@ struct soinfo {
|
|||||||
|
|
||||||
unsigned* plt_got;
|
unsigned* plt_got;
|
||||||
|
|
||||||
Elf32_Rel* plt_rel;
|
Elf_Rel* plt_rel;
|
||||||
size_t plt_rel_count;
|
size_t plt_rel_count;
|
||||||
|
|
||||||
Elf32_Rel* rel;
|
Elf_Rel* rel;
|
||||||
size_t rel_count;
|
size_t rel_count;
|
||||||
|
|
||||||
linker_function_t* preinit_array;
|
linker_function_t* preinit_array;
|
||||||
@ -160,7 +164,7 @@ struct soinfo {
|
|||||||
|
|
||||||
// When you read a virtual address from the ELF file, add this
|
// When you read a virtual address from the ELF file, add this
|
||||||
// value to get the corresponding address in the process' address space.
|
// value to get the corresponding address in the process' address space.
|
||||||
Elf32_Addr load_bias;
|
Elf_Addr load_bias;
|
||||||
|
|
||||||
bool has_text_relocations;
|
bool has_text_relocations;
|
||||||
bool has_DT_SYMBOLIC;
|
bool has_DT_SYMBOLIC;
|
||||||
@ -188,11 +192,11 @@ 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* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start);
|
Elf_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);
|
||||||
|
|
||||||
Elf32_Sym* dladdr_find_symbol(soinfo* si, const void* addr);
|
Elf_Sym* dladdr_find_symbol(soinfo* si, const void* addr);
|
||||||
Elf32_Sym* dlsym_handle_lookup(soinfo* si, const char* name);
|
Elf_Sym* dlsym_handle_lookup(soinfo* si, const char* name);
|
||||||
|
|
||||||
void debuggerd_init();
|
void debuggerd_init();
|
||||||
extern "C" abort_msg_t* gAbortMessage;
|
extern "C" abort_msg_t* gAbortMessage;
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
p_vaddr -> segment's virtual address
|
p_vaddr -> segment's virtual address
|
||||||
p_flags -> segment flags (e.g. readable, writable, executable)
|
p_flags -> segment flags (e.g. readable, writable, executable)
|
||||||
|
|
||||||
We will ignore the p_paddr and p_align fields of Elf32_Phdr for now.
|
We will ignore the p_paddr and p_align fields of Elf_Phdr for now.
|
||||||
|
|
||||||
The loadable segments can be seen as a list of [p_vaddr ... p_vaddr+p_memsz)
|
The loadable segments can be seen as a list of [p_vaddr ... p_vaddr+p_memsz)
|
||||||
ranges of virtual addresses. A few rules apply:
|
ranges of virtual addresses. A few rules apply:
|
||||||
@ -147,8 +147,8 @@ bool ElfReader::ReadElfHeader() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (rc != sizeof(header_)) {
|
if (rc != sizeof(header_)) {
|
||||||
DL_ERR("\"%s\" is too small to be an ELF executable. Expected at least %d bytes, only found %d bytes.",
|
DL_ERR("\"%s\" is too small to be an ELF executable: only found %zd bytes", name_,
|
||||||
name_, sizeof(header_), rc);
|
static_cast<size_t>(rc));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -205,14 +205,14 @@ bool ElfReader::ReadProgramHeader() {
|
|||||||
|
|
||||||
// Like the kernel, we only accept program header tables that
|
// Like the kernel, we only accept program header tables that
|
||||||
// are smaller than 64KiB.
|
// are smaller than 64KiB.
|
||||||
if (phdr_num_ < 1 || phdr_num_ > 65536/sizeof(Elf32_Phdr)) {
|
if (phdr_num_ < 1 || phdr_num_ > 65536/sizeof(Elf_Phdr)) {
|
||||||
DL_ERR("\"%s\" has invalid e_phnum: %d", name_, phdr_num_);
|
DL_ERR("\"%s\" has invalid e_phnum: %zd", name_, phdr_num_);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Elf32_Addr page_min = PAGE_START(header_.e_phoff);
|
Elf_Addr page_min = PAGE_START(header_.e_phoff);
|
||||||
Elf32_Addr page_max = PAGE_END(header_.e_phoff + (phdr_num_ * sizeof(Elf32_Phdr)));
|
Elf_Addr page_max = PAGE_END(header_.e_phoff + (phdr_num_ * sizeof(Elf_Phdr)));
|
||||||
Elf32_Addr page_offset = PAGE_OFFSET(header_.e_phoff);
|
Elf_Addr page_offset = PAGE_OFFSET(header_.e_phoff);
|
||||||
|
|
||||||
phdr_size_ = page_max - page_min;
|
phdr_size_ = page_max - page_min;
|
||||||
|
|
||||||
@ -223,7 +223,7 @@ bool ElfReader::ReadProgramHeader() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
phdr_mmap_ = mmap_result;
|
phdr_mmap_ = mmap_result;
|
||||||
phdr_table_ = reinterpret_cast<Elf32_Phdr*>(reinterpret_cast<char*>(mmap_result) + page_offset);
|
phdr_table_ = reinterpret_cast<Elf_Phdr*>(reinterpret_cast<char*>(mmap_result) + page_offset);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,17 +237,15 @@ bool ElfReader::ReadProgramHeader() {
|
|||||||
* set to the minimum and maximum addresses of pages to be reserved,
|
* set to the minimum and maximum addresses of pages to be reserved,
|
||||||
* or 0 if there is nothing to load.
|
* or 0 if there is nothing to load.
|
||||||
*/
|
*/
|
||||||
size_t phdr_table_get_load_size(const Elf32_Phdr* phdr_table,
|
size_t phdr_table_get_load_size(const Elf_Phdr* phdr_table, size_t phdr_count,
|
||||||
size_t phdr_count,
|
Elf_Addr* out_min_vaddr,
|
||||||
Elf32_Addr* out_min_vaddr,
|
Elf_Addr* out_max_vaddr) {
|
||||||
Elf32_Addr* out_max_vaddr)
|
Elf_Addr min_vaddr = 0xFFFFFFFFU;
|
||||||
{
|
Elf_Addr max_vaddr = 0x00000000U;
|
||||||
Elf32_Addr min_vaddr = 0xFFFFFFFFU;
|
|
||||||
Elf32_Addr max_vaddr = 0x00000000U;
|
|
||||||
|
|
||||||
bool found_pt_load = false;
|
bool found_pt_load = false;
|
||||||
for (size_t i = 0; i < phdr_count; ++i) {
|
for (size_t i = 0; i < phdr_count; ++i) {
|
||||||
const Elf32_Phdr* phdr = &phdr_table[i];
|
const Elf_Phdr* phdr = &phdr_table[i];
|
||||||
|
|
||||||
if (phdr->p_type != PT_LOAD) {
|
if (phdr->p_type != PT_LOAD) {
|
||||||
continue;
|
continue;
|
||||||
@ -282,7 +280,7 @@ size_t phdr_table_get_load_size(const Elf32_Phdr* phdr_table,
|
|||||||
// segments of a program header table. This is done by creating a
|
// segments of a program header table. This is done by creating a
|
||||||
// private anonymous mmap() with PROT_NONE.
|
// private anonymous mmap() with PROT_NONE.
|
||||||
bool ElfReader::ReserveAddressSpace() {
|
bool ElfReader::ReserveAddressSpace() {
|
||||||
Elf32_Addr min_vaddr;
|
Elf_Addr min_vaddr;
|
||||||
load_size_ = phdr_table_get_load_size(phdr_table_, phdr_num_, &min_vaddr);
|
load_size_ = phdr_table_get_load_size(phdr_table_, phdr_num_, &min_vaddr);
|
||||||
if (load_size_ == 0) {
|
if (load_size_ == 0) {
|
||||||
DL_ERR("\"%s\" has no loadable segments", name_);
|
DL_ERR("\"%s\" has no loadable segments", name_);
|
||||||
@ -308,27 +306,27 @@ bool ElfReader::ReserveAddressSpace() {
|
|||||||
// TODO: assert assumption.
|
// TODO: assert assumption.
|
||||||
bool ElfReader::LoadSegments() {
|
bool ElfReader::LoadSegments() {
|
||||||
for (size_t i = 0; i < phdr_num_; ++i) {
|
for (size_t i = 0; i < phdr_num_; ++i) {
|
||||||
const Elf32_Phdr* phdr = &phdr_table_[i];
|
const Elf_Phdr* phdr = &phdr_table_[i];
|
||||||
|
|
||||||
if (phdr->p_type != PT_LOAD) {
|
if (phdr->p_type != PT_LOAD) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Segment addresses in memory.
|
// Segment addresses in memory.
|
||||||
Elf32_Addr seg_start = phdr->p_vaddr + load_bias_;
|
Elf_Addr seg_start = phdr->p_vaddr + load_bias_;
|
||||||
Elf32_Addr seg_end = seg_start + phdr->p_memsz;
|
Elf_Addr seg_end = seg_start + phdr->p_memsz;
|
||||||
|
|
||||||
Elf32_Addr seg_page_start = PAGE_START(seg_start);
|
Elf_Addr seg_page_start = PAGE_START(seg_start);
|
||||||
Elf32_Addr seg_page_end = PAGE_END(seg_end);
|
Elf_Addr seg_page_end = PAGE_END(seg_end);
|
||||||
|
|
||||||
Elf32_Addr seg_file_end = seg_start + phdr->p_filesz;
|
Elf_Addr seg_file_end = seg_start + phdr->p_filesz;
|
||||||
|
|
||||||
// File offsets.
|
// File offsets.
|
||||||
Elf32_Addr file_start = phdr->p_offset;
|
Elf_Addr file_start = phdr->p_offset;
|
||||||
Elf32_Addr file_end = file_start + phdr->p_filesz;
|
Elf_Addr file_end = file_start + phdr->p_filesz;
|
||||||
|
|
||||||
Elf32_Addr file_page_start = PAGE_START(file_start);
|
Elf_Addr file_page_start = PAGE_START(file_start);
|
||||||
Elf32_Addr file_length = file_end - file_page_start;
|
Elf_Addr file_length = file_end - file_page_start;
|
||||||
|
|
||||||
if (file_length != 0) {
|
if (file_length != 0) {
|
||||||
void* seg_addr = mmap((void*)seg_page_start,
|
void* seg_addr = mmap((void*)seg_page_start,
|
||||||
@ -338,7 +336,7 @@ bool ElfReader::LoadSegments() {
|
|||||||
fd_,
|
fd_,
|
||||||
file_page_start);
|
file_page_start);
|
||||||
if (seg_addr == MAP_FAILED) {
|
if (seg_addr == MAP_FAILED) {
|
||||||
DL_ERR("couldn't map \"%s\" segment %d: %s", name_, i, strerror(errno));
|
DL_ERR("couldn't map \"%s\" segment %zd: %s", name_, i, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -375,21 +373,17 @@ bool ElfReader::LoadSegments() {
|
|||||||
* with optional extra flags (i.e. really PROT_WRITE). Used by
|
* with optional extra flags (i.e. really PROT_WRITE). Used by
|
||||||
* phdr_table_protect_segments and phdr_table_unprotect_segments.
|
* phdr_table_protect_segments and phdr_table_unprotect_segments.
|
||||||
*/
|
*/
|
||||||
static int
|
static int _phdr_table_set_load_prot(const Elf_Phdr* phdr_table, size_t phdr_count,
|
||||||
_phdr_table_set_load_prot(const Elf32_Phdr* phdr_table,
|
Elf_Addr load_bias, int extra_prot_flags) {
|
||||||
int phdr_count,
|
const Elf_Phdr* phdr = phdr_table;
|
||||||
Elf32_Addr load_bias,
|
const Elf_Phdr* phdr_limit = phdr + phdr_count;
|
||||||
int extra_prot_flags)
|
|
||||||
{
|
|
||||||
const Elf32_Phdr* phdr = phdr_table;
|
|
||||||
const Elf32_Phdr* phdr_limit = phdr + phdr_count;
|
|
||||||
|
|
||||||
for (; phdr < phdr_limit; phdr++) {
|
for (; phdr < phdr_limit; phdr++) {
|
||||||
if (phdr->p_type != PT_LOAD || (phdr->p_flags & PF_W) != 0)
|
if (phdr->p_type != PT_LOAD || (phdr->p_flags & PF_W) != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Elf32_Addr seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
|
Elf_Addr seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
|
||||||
Elf32_Addr seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
|
Elf_Addr seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
|
||||||
|
|
||||||
int ret = mprotect((void*)seg_page_start,
|
int ret = mprotect((void*)seg_page_start,
|
||||||
seg_page_end - seg_page_start,
|
seg_page_end - seg_page_start,
|
||||||
@ -412,13 +406,8 @@ _phdr_table_set_load_prot(const Elf32_Phdr* phdr_table,
|
|||||||
* Return:
|
* Return:
|
||||||
* 0 on error, -1 on failure (error code in errno).
|
* 0 on error, -1 on failure (error code in errno).
|
||||||
*/
|
*/
|
||||||
int
|
int phdr_table_protect_segments(const Elf_Phdr* phdr_table, size_t phdr_count, Elf_Addr load_bias) {
|
||||||
phdr_table_protect_segments(const Elf32_Phdr* phdr_table,
|
return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, 0);
|
||||||
int phdr_count,
|
|
||||||
Elf32_Addr load_bias)
|
|
||||||
{
|
|
||||||
return _phdr_table_set_load_prot(phdr_table, phdr_count,
|
|
||||||
load_bias, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Change the protection of all loaded segments in memory to writable.
|
/* Change the protection of all loaded segments in memory to writable.
|
||||||
@ -437,26 +426,17 @@ phdr_table_protect_segments(const Elf32_Phdr* phdr_table,
|
|||||||
* Return:
|
* Return:
|
||||||
* 0 on error, -1 on failure (error code in errno).
|
* 0 on error, -1 on failure (error code in errno).
|
||||||
*/
|
*/
|
||||||
int
|
int phdr_table_unprotect_segments(const Elf_Phdr* phdr_table, size_t phdr_count, Elf_Addr load_bias) {
|
||||||
phdr_table_unprotect_segments(const Elf32_Phdr* phdr_table,
|
return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, PROT_WRITE);
|
||||||
int phdr_count,
|
|
||||||
Elf32_Addr load_bias)
|
|
||||||
{
|
|
||||||
return _phdr_table_set_load_prot(phdr_table, phdr_count,
|
|
||||||
load_bias, PROT_WRITE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Used internally by phdr_table_protect_gnu_relro and
|
/* Used internally by phdr_table_protect_gnu_relro and
|
||||||
* phdr_table_unprotect_gnu_relro.
|
* phdr_table_unprotect_gnu_relro.
|
||||||
*/
|
*/
|
||||||
static int
|
static int _phdr_table_set_gnu_relro_prot(const Elf_Phdr* phdr_table, size_t phdr_count,
|
||||||
_phdr_table_set_gnu_relro_prot(const Elf32_Phdr* phdr_table,
|
Elf_Addr load_bias, int prot_flags) {
|
||||||
int phdr_count,
|
const Elf_Phdr* phdr = phdr_table;
|
||||||
Elf32_Addr load_bias,
|
const Elf_Phdr* phdr_limit = phdr + phdr_count;
|
||||||
int prot_flags)
|
|
||||||
{
|
|
||||||
const Elf32_Phdr* phdr = phdr_table;
|
|
||||||
const Elf32_Phdr* phdr_limit = phdr + phdr_count;
|
|
||||||
|
|
||||||
for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
|
for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
|
||||||
if (phdr->p_type != PT_GNU_RELRO)
|
if (phdr->p_type != PT_GNU_RELRO)
|
||||||
@ -479,8 +459,8 @@ _phdr_table_set_gnu_relro_prot(const Elf32_Phdr* phdr_table,
|
|||||||
* linker must only emit a PT_GNU_RELRO segment if it ensures
|
* linker must only emit a PT_GNU_RELRO segment if it ensures
|
||||||
* that it starts on a page boundary.
|
* that it starts on a page boundary.
|
||||||
*/
|
*/
|
||||||
Elf32_Addr seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
|
Elf_Addr seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
|
||||||
Elf32_Addr seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
|
Elf_Addr seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
|
||||||
|
|
||||||
int ret = mprotect((void*)seg_page_start,
|
int ret = mprotect((void*)seg_page_start,
|
||||||
seg_page_end - seg_page_start,
|
seg_page_end - seg_page_start,
|
||||||
@ -508,15 +488,8 @@ _phdr_table_set_gnu_relro_prot(const Elf32_Phdr* phdr_table,
|
|||||||
* Return:
|
* Return:
|
||||||
* 0 on error, -1 on failure (error code in errno).
|
* 0 on error, -1 on failure (error code in errno).
|
||||||
*/
|
*/
|
||||||
int
|
int phdr_table_protect_gnu_relro(const Elf_Phdr* phdr_table, size_t phdr_count, Elf_Addr load_bias) {
|
||||||
phdr_table_protect_gnu_relro(const Elf32_Phdr* phdr_table,
|
return _phdr_table_set_gnu_relro_prot(phdr_table, phdr_count, load_bias, PROT_READ);
|
||||||
int phdr_count,
|
|
||||||
Elf32_Addr load_bias)
|
|
||||||
{
|
|
||||||
return _phdr_table_set_gnu_relro_prot(phdr_table,
|
|
||||||
phdr_count,
|
|
||||||
load_bias,
|
|
||||||
PROT_READ);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ANDROID_ARM_LINKER
|
#ifdef ANDROID_ARM_LINKER
|
||||||
@ -538,21 +511,17 @@ phdr_table_protect_gnu_relro(const Elf32_Phdr* phdr_table,
|
|||||||
* Return:
|
* Return:
|
||||||
* 0 on error, -1 on failure (_no_ error code in errno)
|
* 0 on error, -1 on failure (_no_ error code in errno)
|
||||||
*/
|
*/
|
||||||
int
|
int phdr_table_get_arm_exidx(const Elf_Phdr* phdr_table, size_t phdr_count,
|
||||||
phdr_table_get_arm_exidx(const Elf32_Phdr* phdr_table,
|
Elf_Addr load_bias,
|
||||||
int phdr_count,
|
Elf_Addr** arm_exidx, unsigned* arm_exidx_count) {
|
||||||
Elf32_Addr load_bias,
|
const Elf_Phdr* phdr = phdr_table;
|
||||||
Elf32_Addr** arm_exidx,
|
const Elf_Phdr* phdr_limit = phdr + phdr_count;
|
||||||
unsigned* arm_exidx_count)
|
|
||||||
{
|
|
||||||
const Elf32_Phdr* phdr = phdr_table;
|
|
||||||
const Elf32_Phdr* phdr_limit = phdr + phdr_count;
|
|
||||||
|
|
||||||
for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
|
for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
|
||||||
if (phdr->p_type != PT_ARM_EXIDX)
|
if (phdr->p_type != PT_ARM_EXIDX)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
*arm_exidx = (Elf32_Addr*)(load_bias + phdr->p_vaddr);
|
*arm_exidx = (Elf_Addr*)(load_bias + phdr->p_vaddr);
|
||||||
*arm_exidx_count = (unsigned)(phdr->p_memsz / 8);
|
*arm_exidx_count = (unsigned)(phdr->p_memsz / 8);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -576,23 +545,18 @@ phdr_table_get_arm_exidx(const Elf32_Phdr* phdr_table,
|
|||||||
* Return:
|
* Return:
|
||||||
* void
|
* void
|
||||||
*/
|
*/
|
||||||
void
|
void phdr_table_get_dynamic_section(const Elf_Phdr* phdr_table, size_t phdr_count,
|
||||||
phdr_table_get_dynamic_section(const Elf32_Phdr* phdr_table,
|
Elf_Addr load_bias,
|
||||||
int phdr_count,
|
Elf_Dyn** dynamic, size_t* dynamic_count, Elf_Word* dynamic_flags) {
|
||||||
Elf32_Addr load_bias,
|
const Elf_Phdr* phdr = phdr_table;
|
||||||
Elf32_Dyn** dynamic,
|
const Elf_Phdr* phdr_limit = phdr + phdr_count;
|
||||||
size_t* dynamic_count,
|
|
||||||
Elf32_Word* dynamic_flags)
|
|
||||||
{
|
|
||||||
const Elf32_Phdr* phdr = phdr_table;
|
|
||||||
const Elf32_Phdr* phdr_limit = phdr + phdr_count;
|
|
||||||
|
|
||||||
for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
|
for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
|
||||||
if (phdr->p_type != PT_DYNAMIC) {
|
if (phdr->p_type != PT_DYNAMIC) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
*dynamic = reinterpret_cast<Elf32_Dyn*>(load_bias + phdr->p_vaddr);
|
*dynamic = reinterpret_cast<Elf_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);
|
||||||
}
|
}
|
||||||
@ -611,10 +575,10 @@ phdr_table_get_dynamic_section(const Elf32_Phdr* phdr_table,
|
|||||||
// segments in memory. This is in contrast with 'phdr_table_' which
|
// segments in memory. This is in contrast with 'phdr_table_' which
|
||||||
// is temporary and will be released before the library is relocated.
|
// is temporary and will be released before the library is relocated.
|
||||||
bool ElfReader::FindPhdr() {
|
bool ElfReader::FindPhdr() {
|
||||||
const Elf32_Phdr* phdr_limit = phdr_table_ + phdr_num_;
|
const Elf_Phdr* phdr_limit = phdr_table_ + phdr_num_;
|
||||||
|
|
||||||
// If there is a PT_PHDR, use it directly.
|
// If there is a PT_PHDR, use it directly.
|
||||||
for (const Elf32_Phdr* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
|
for (const Elf_Phdr* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
|
||||||
if (phdr->p_type == PT_PHDR) {
|
if (phdr->p_type == PT_PHDR) {
|
||||||
return CheckPhdr(load_bias_ + phdr->p_vaddr);
|
return CheckPhdr(load_bias_ + phdr->p_vaddr);
|
||||||
}
|
}
|
||||||
@ -623,13 +587,13 @@ bool ElfReader::FindPhdr() {
|
|||||||
// Otherwise, check the first loadable segment. If its file offset
|
// Otherwise, check the first loadable segment. If its file offset
|
||||||
// is 0, it starts with the ELF header, and we can trivially find the
|
// is 0, it starts with the ELF header, and we can trivially find the
|
||||||
// loaded program header from it.
|
// loaded program header from it.
|
||||||
for (const Elf32_Phdr* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
|
for (const Elf_Phdr* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
|
||||||
if (phdr->p_type == PT_LOAD) {
|
if (phdr->p_type == PT_LOAD) {
|
||||||
if (phdr->p_offset == 0) {
|
if (phdr->p_offset == 0) {
|
||||||
Elf32_Addr elf_addr = load_bias_ + phdr->p_vaddr;
|
Elf_Addr elf_addr = load_bias_ + phdr->p_vaddr;
|
||||||
const Elf32_Ehdr* ehdr = (const Elf32_Ehdr*)(void*)elf_addr;
|
const Elf_Ehdr* ehdr = (const Elf_Ehdr*)(void*)elf_addr;
|
||||||
Elf32_Addr offset = ehdr->e_phoff;
|
Elf_Addr offset = ehdr->e_phoff;
|
||||||
return CheckPhdr((Elf32_Addr)ehdr + offset);
|
return CheckPhdr((Elf_Addr)ehdr + offset);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -642,17 +606,17 @@ bool ElfReader::FindPhdr() {
|
|||||||
// Ensures that our program header is actually within a loadable
|
// Ensures that our program header is actually within a loadable
|
||||||
// segment. This should help catch badly-formed ELF files that
|
// segment. This should help catch badly-formed ELF files that
|
||||||
// would cause the linker to crash later when trying to access it.
|
// would cause the linker to crash later when trying to access it.
|
||||||
bool ElfReader::CheckPhdr(Elf32_Addr loaded) {
|
bool ElfReader::CheckPhdr(Elf_Addr loaded) {
|
||||||
const Elf32_Phdr* phdr_limit = phdr_table_ + phdr_num_;
|
const Elf_Phdr* phdr_limit = phdr_table_ + phdr_num_;
|
||||||
Elf32_Addr loaded_end = loaded + (phdr_num_ * sizeof(Elf32_Phdr));
|
Elf_Addr loaded_end = loaded + (phdr_num_ * sizeof(Elf_Phdr));
|
||||||
for (Elf32_Phdr* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
|
for (Elf_Phdr* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
|
||||||
if (phdr->p_type != PT_LOAD) {
|
if (phdr->p_type != PT_LOAD) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Elf32_Addr seg_start = phdr->p_vaddr + load_bias_;
|
Elf_Addr seg_start = phdr->p_vaddr + load_bias_;
|
||||||
Elf32_Addr seg_end = phdr->p_filesz + seg_start;
|
Elf_Addr seg_end = phdr->p_filesz + seg_start;
|
||||||
if (seg_start <= loaded && loaded_end <= seg_end) {
|
if (seg_start <= loaded && loaded_end <= seg_end) {
|
||||||
loaded_phdr_ = reinterpret_cast<const Elf32_Phdr*>(loaded);
|
loaded_phdr_ = reinterpret_cast<const Elf_Phdr*>(loaded);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,10 +45,10 @@ class ElfReader {
|
|||||||
bool Load();
|
bool Load();
|
||||||
|
|
||||||
size_t phdr_count() { return phdr_num_; }
|
size_t phdr_count() { return phdr_num_; }
|
||||||
Elf32_Addr load_start() { return reinterpret_cast<Elf32_Addr>(load_start_); }
|
Elf_Addr load_start() { return reinterpret_cast<Elf_Addr>(load_start_); }
|
||||||
Elf32_Addr load_size() { return load_size_; }
|
Elf_Addr load_size() { return load_size_; }
|
||||||
Elf32_Addr load_bias() { return load_bias_; }
|
Elf_Addr load_bias() { return load_bias_; }
|
||||||
const Elf32_Phdr* loaded_phdr() { return loaded_phdr_; }
|
const Elf_Phdr* loaded_phdr() { return loaded_phdr_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool ReadElfHeader();
|
bool ReadElfHeader();
|
||||||
@ -57,66 +57,46 @@ class ElfReader {
|
|||||||
bool ReserveAddressSpace();
|
bool ReserveAddressSpace();
|
||||||
bool LoadSegments();
|
bool LoadSegments();
|
||||||
bool FindPhdr();
|
bool FindPhdr();
|
||||||
bool CheckPhdr(Elf32_Addr);
|
bool CheckPhdr(Elf_Addr);
|
||||||
|
|
||||||
const char* name_;
|
const char* name_;
|
||||||
int fd_;
|
int fd_;
|
||||||
|
|
||||||
Elf32_Ehdr header_;
|
Elf_Ehdr header_;
|
||||||
size_t phdr_num_;
|
size_t phdr_num_;
|
||||||
|
|
||||||
void* phdr_mmap_;
|
void* phdr_mmap_;
|
||||||
Elf32_Phdr* phdr_table_;
|
Elf_Phdr* phdr_table_;
|
||||||
Elf32_Addr phdr_size_;
|
Elf_Addr phdr_size_;
|
||||||
|
|
||||||
// First page of reserved address space.
|
// First page of reserved address space.
|
||||||
void* load_start_;
|
void* load_start_;
|
||||||
// Size in bytes of reserved address space.
|
// Size in bytes of reserved address space.
|
||||||
Elf32_Addr load_size_;
|
Elf_Addr load_size_;
|
||||||
// Load bias.
|
// Load bias.
|
||||||
Elf32_Addr load_bias_;
|
Elf_Addr load_bias_;
|
||||||
|
|
||||||
// Loaded phdr.
|
// Loaded phdr.
|
||||||
const Elf32_Phdr* loaded_phdr_;
|
const Elf_Phdr* loaded_phdr_;
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t
|
size_t phdr_table_get_load_size(const Elf_Phdr* phdr_table, size_t phdr_count,
|
||||||
phdr_table_get_load_size(const Elf32_Phdr* phdr_table,
|
Elf_Addr* min_vaddr = NULL, Elf_Addr* max_vaddr = NULL);
|
||||||
size_t phdr_count,
|
|
||||||
Elf32_Addr* min_vaddr = NULL,
|
|
||||||
Elf32_Addr* max_vaddr = NULL);
|
|
||||||
|
|
||||||
int
|
int phdr_table_protect_segments(const Elf_Phdr* phdr_table, size_t phdr_count, Elf_Addr load_bias);
|
||||||
phdr_table_protect_segments(const Elf32_Phdr* phdr_table,
|
|
||||||
int phdr_count,
|
|
||||||
Elf32_Addr load_bias);
|
|
||||||
|
|
||||||
int
|
int phdr_table_unprotect_segments(const Elf_Phdr* phdr_table, size_t phdr_count, Elf_Addr load_bias);
|
||||||
phdr_table_unprotect_segments(const Elf32_Phdr* phdr_table,
|
|
||||||
int phdr_count,
|
|
||||||
Elf32_Addr load_bias);
|
|
||||||
|
|
||||||
int
|
int phdr_table_protect_gnu_relro(const Elf_Phdr* phdr_table, size_t phdr_count, Elf_Addr load_bias);
|
||||||
phdr_table_protect_gnu_relro(const Elf32_Phdr* phdr_table,
|
|
||||||
int phdr_count,
|
|
||||||
Elf32_Addr load_bias);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef ANDROID_ARM_LINKER
|
#ifdef ANDROID_ARM_LINKER
|
||||||
int
|
int phdr_table_get_arm_exidx(const Elf_Phdr* phdr_table, size_t phdr_count, Elf_Addr load_bias,
|
||||||
phdr_table_get_arm_exidx(const Elf32_Phdr* phdr_table,
|
Elf_Addr** arm_exidx, unsigned* arm_exidix_count);
|
||||||
int phdr_count,
|
|
||||||
Elf32_Addr load_bias,
|
|
||||||
Elf32_Addr** arm_exidx,
|
|
||||||
unsigned* arm_exidix_count);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void
|
void phdr_table_get_dynamic_section(const Elf_Phdr* phdr_table, size_t phdr_count,
|
||||||
phdr_table_get_dynamic_section(const Elf32_Phdr* phdr_table,
|
Elf_Addr load_bias,
|
||||||
int phdr_count,
|
Elf_Dyn** dynamic, size_t* dynamic_count, Elf_Word* dynamic_flags);
|
||||||
Elf32_Addr load_bias,
|
|
||||||
Elf32_Dyn** dynamic,
|
|
||||||
size_t* dynamic_count,
|
|
||||||
Elf32_Word* dynamic_flags);
|
|
||||||
|
|
||||||
#endif /* LINKER_PHDR_H */
|
#endif /* LINKER_PHDR_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user