am d30116cf
: Merge "Keep the dynamic linker\'s soinfo pools mostly read-only."
* commit 'd30116cf4a590e7bea3b73fa49bb27502a920819': Keep the dynamic linker's soinfo pools mostly read-only.
This commit is contained in:
commit
6db8f5bb75
@ -32,7 +32,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdbool.h>
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -57,13 +57,11 @@ const char* dlerror() {
|
|||||||
|
|
||||||
void* dlopen(const char* filename, int flag) {
|
void* dlopen(const char* filename, int flag) {
|
||||||
ScopedPthreadMutexLocker locker(&gDlMutex);
|
ScopedPthreadMutexLocker locker(&gDlMutex);
|
||||||
soinfo* result = find_library(filename);
|
soinfo* result = do_dlopen(filename);
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
__bionic_format_dlerror("dlopen failed", linker_get_error());
|
__bionic_format_dlerror("dlopen failed", linker_get_error());
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
soinfo_call_constructors(result);
|
|
||||||
result->refcount++;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +137,7 @@ int dladdr(const void* addr, Dl_info* info) {
|
|||||||
|
|
||||||
int dlclose(void* handle) {
|
int dlclose(void* handle) {
|
||||||
ScopedPthreadMutexLocker locker(&gDlMutex);
|
ScopedPthreadMutexLocker locker(&gDlMutex);
|
||||||
return soinfo_unload((soinfo*) handle);
|
return do_dlclose(reinterpret_cast<soinfo*>(handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(ANDROID_ARM_LINKER)
|
#if defined(ANDROID_ARM_LINKER)
|
||||||
@ -236,7 +234,8 @@ soinfo libdl_info = {
|
|||||||
|
|
||||||
refcount: 0,
|
refcount: 0,
|
||||||
{ l_addr: 0, l_name: 0, l_ld: 0, l_next: 0, l_prev: 0, },
|
{ l_addr: 0, l_name: 0, l_ld: 0, l_next: 0, l_prev: 0, },
|
||||||
constructors_called: 0, load_bias: 0,
|
constructors_called: false,
|
||||||
|
load_bias: 0,
|
||||||
has_text_relocations: false,
|
has_text_relocations: false,
|
||||||
has_DT_SYMBOLIC: true,
|
has_DT_SYMBOLIC: true,
|
||||||
};
|
};
|
||||||
|
@ -31,7 +31,6 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <linux/auxvec.h>
|
#include <linux/auxvec.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -74,7 +73,6 @@
|
|||||||
* and NOEXEC
|
* and NOEXEC
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
static bool soinfo_link_image(soinfo* si);
|
static bool soinfo_link_image(soinfo* si);
|
||||||
|
|
||||||
// We can't use malloc(3) in the dynamic linker. We use a linked list of anonymous
|
// We can't use malloc(3) in the dynamic linker. We use a linked list of anonymous
|
||||||
@ -293,6 +291,14 @@ static bool ensure_free_list_non_empty() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void set_soinfo_pool_protection(int protection) {
|
||||||
|
for (soinfo_pool_t* p = gSoInfoPools; p != NULL; p = p->next) {
|
||||||
|
if (mprotect(p, sizeof(*p), protection) == -1) {
|
||||||
|
abort(); // Can't happen.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static soinfo* soinfo_alloc(const char* name) {
|
static soinfo* soinfo_alloc(const char* name) {
|
||||||
if (strlen(name) >= SOINFO_NAME_LEN) {
|
if (strlen(name) >= SOINFO_NAME_LEN) {
|
||||||
DL_ERR("library name \"%s\" too long", name);
|
DL_ERR("library name \"%s\" too long", name);
|
||||||
@ -833,20 +839,18 @@ static soinfo* load_library(const char* name) {
|
|||||||
return si.release();
|
return si.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
static soinfo *
|
static soinfo* init_library(soinfo* si) {
|
||||||
init_library(soinfo *si)
|
// At this point we know that whatever is loaded @ base is a valid ELF
|
||||||
{
|
// shared library whose segments are properly mapped in.
|
||||||
/* At this point we know that whatever is loaded @ base is a valid ELF
|
TRACE("[ %5d init_library base=0x%08x sz=0x%08x name='%s') ]\n",
|
||||||
* shared library whose segments are properly mapped in. */
|
pid, si->base, si->size, si->name);
|
||||||
TRACE("[ %5d init_library base=0x%08x sz=0x%08x name='%s') ]\n",
|
|
||||||
pid, si->base, si->size, si->name);
|
|
||||||
|
|
||||||
if (!soinfo_link_image(si)) {
|
if (!soinfo_link_image(si)) {
|
||||||
munmap((void *)si->base, si->size);
|
munmap((void *)si->base, si->size);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return si;
|
return si;
|
||||||
}
|
}
|
||||||
|
|
||||||
static soinfo *find_loaded_library(const char *name)
|
static soinfo *find_loaded_library(const char *name)
|
||||||
@ -868,63 +872,86 @@ static soinfo *find_loaded_library(const char *name)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
soinfo *find_library(const char *name)
|
static soinfo* find_library_internal(const char* name) {
|
||||||
{
|
if (name == NULL) {
|
||||||
soinfo *si;
|
return somain;
|
||||||
|
}
|
||||||
|
|
||||||
if (name == NULL)
|
soinfo* si = find_loaded_library(name);
|
||||||
return somain;
|
if (si != NULL) {
|
||||||
|
if (si->flags & FLAG_ERROR) {
|
||||||
si = find_loaded_library(name);
|
DL_ERR("\"%s\" failed to load previously", name);
|
||||||
if (si != NULL) {
|
return NULL;
|
||||||
if(si->flags & FLAG_ERROR) {
|
|
||||||
DL_ERR("\"%s\" failed to load previously", name);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if(si->flags & FLAG_LINKED) return si;
|
|
||||||
DL_ERR("OOPS: recursive link to \"%s\"", si->name);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
if (si->flags & FLAG_LINKED) {
|
||||||
|
return si;
|
||||||
|
}
|
||||||
|
DL_ERR("OOPS: recursive link to \"%s\"", si->name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
TRACE("[ %5d '%s' has not been loaded yet. Locating...]\n", pid, name);
|
TRACE("[ %5d '%s' has not been loaded yet. Locating...]\n", pid, name);
|
||||||
si = load_library(name);
|
si = load_library(name);
|
||||||
if (si == NULL)
|
if (si != NULL) {
|
||||||
return NULL;
|
si = init_library(si);
|
||||||
return init_library(si);
|
}
|
||||||
|
|
||||||
|
return si;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void call_destructors(soinfo *si);
|
static soinfo* find_library(const char* name) {
|
||||||
|
soinfo* si = find_library_internal(name);
|
||||||
|
if (si != NULL) {
|
||||||
|
si->refcount++;
|
||||||
|
}
|
||||||
|
return si;
|
||||||
|
}
|
||||||
|
|
||||||
int soinfo_unload(soinfo* si) {
|
static int soinfo_unload(soinfo* si) {
|
||||||
if (si->refcount == 1) {
|
if (si->refcount == 1) {
|
||||||
TRACE("%5d unloading '%s'\n", pid, si->name);
|
TRACE("%5d unloading '%s'\n", pid, si->name);
|
||||||
call_destructors(si);
|
si->CallDestructors();
|
||||||
|
|
||||||
for (unsigned* d = si->dynamic; *d; d += 2) {
|
for (unsigned* d = si->dynamic; *d; d += 2) {
|
||||||
if(d[0] == DT_NEEDED){
|
if (d[0] == DT_NEEDED) {
|
||||||
soinfo *lsi = find_loaded_library(si->strtab + d[1]);
|
soinfo* lsi = find_loaded_library(si->strtab + d[1]);
|
||||||
if (lsi) {
|
if (lsi != NULL) {
|
||||||
TRACE("%5d %s needs to unload %s\n", pid,
|
TRACE("%5d %s needs to unload %s\n", pid, si->name, lsi->name);
|
||||||
si->name, lsi->name);
|
soinfo_unload(lsi);
|
||||||
soinfo_unload(lsi);
|
} else {
|
||||||
} else {
|
// TODO: should we return -1 in this case?
|
||||||
// TODO: should we return -1 in this case?
|
DL_ERR("\"%s\": could not unload dependent library", si->name);
|
||||||
DL_ERR("\"%s\": could not unload dependent library",
|
|
||||||
si->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
munmap((char *)si->base, si->size);
|
|
||||||
notify_gdb_of_unload(si);
|
|
||||||
soinfo_free(si);
|
|
||||||
si->refcount = 0;
|
|
||||||
} else {
|
|
||||||
si->refcount--;
|
|
||||||
PRINT("%5d not unloading '%s', decrementing refcount to %d\n",
|
|
||||||
pid, si->name, si->refcount);
|
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
munmap(reinterpret_cast<void*>(si->base), si->size);
|
||||||
|
notify_gdb_of_unload(si);
|
||||||
|
soinfo_free(si);
|
||||||
|
si->refcount = 0;
|
||||||
|
} else {
|
||||||
|
si->refcount--;
|
||||||
|
PRINT("%5d not unloading '%s', decrementing refcount to %d\n",
|
||||||
|
pid, si->name, si->refcount);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
soinfo* do_dlopen(const char* name) {
|
||||||
|
set_soinfo_pool_protection(PROT_READ | PROT_WRITE);
|
||||||
|
soinfo* si = find_library(name);
|
||||||
|
if (si != NULL) {
|
||||||
|
si->CallConstructors();
|
||||||
|
}
|
||||||
|
set_soinfo_pool_protection(PROT_READ);
|
||||||
|
return si;
|
||||||
|
}
|
||||||
|
|
||||||
|
int do_dlclose(soinfo* si) {
|
||||||
|
set_soinfo_pool_protection(PROT_READ | PROT_WRITE);
|
||||||
|
int result = soinfo_unload(si);
|
||||||
|
set_soinfo_pool_protection(PROT_READ);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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
|
||||||
@ -1270,106 +1297,89 @@ static int mips_relocate_got(soinfo* si, soinfo* needed[]) {
|
|||||||
*
|
*
|
||||||
* DT_FINI_ARRAY must be parsed in reverse order.
|
* DT_FINI_ARRAY must be parsed in reverse order.
|
||||||
*/
|
*/
|
||||||
|
void soinfo::CallArray(const char* array_name UNUSED, unsigned* array, int count, bool reverse) {
|
||||||
|
if (array == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
static void call_array(unsigned *ctor, int count, int reverse)
|
int step = 1;
|
||||||
{
|
if (reverse) {
|
||||||
int n, inc = 1;
|
array += (count-1);
|
||||||
|
step = -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (reverse) {
|
TRACE("[ %5d Calling %s @ %p [%d] for '%s' ]\n", pid, array_name, array, count, name);
|
||||||
ctor += (count-1);
|
|
||||||
inc = -1;
|
for (int n = count; n > 0; n--) {
|
||||||
|
TRACE("[ %5d Looking at %s[%d] *%p == 0x%08x ]\n", pid, array_name, n, array, *array);
|
||||||
|
void (*func)() = (void (*)()) *array;
|
||||||
|
array += step;
|
||||||
|
if (((int) func == 0) || ((int) func == -1)) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
TRACE("[ %5d Calling func @ %p ]\n", pid, func);
|
||||||
|
func();
|
||||||
|
}
|
||||||
|
|
||||||
for(n = count; n > 0; n--) {
|
TRACE("[ %5d Done calling %s for '%s' ]\n", pid, array_name, name);
|
||||||
TRACE("[ %5d Looking at %s *0x%08x == 0x%08x ]\n", pid,
|
|
||||||
reverse ? "dtor" : "ctor",
|
|
||||||
(unsigned)ctor, (unsigned)*ctor);
|
|
||||||
void (*func)() = (void (*)()) *ctor;
|
|
||||||
ctor += inc;
|
|
||||||
if(((int) func == 0) || ((int) func == -1)) continue;
|
|
||||||
TRACE("[ %5d Calling func @ 0x%08x ]\n", pid, (unsigned)func);
|
|
||||||
func();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void soinfo_call_preinit_constructors(soinfo *si)
|
void soinfo::CallFunction(const char* function_name UNUSED, void (*function)()) {
|
||||||
{
|
if (function == NULL) {
|
||||||
TRACE("[ %5d Calling preinit_array @ 0x%08x [%d] for '%s' ]\n",
|
return;
|
||||||
pid, (unsigned)si->preinit_array, si->preinit_array_count,
|
}
|
||||||
si->name);
|
|
||||||
call_array(si->preinit_array, si->preinit_array_count, 0);
|
TRACE("[ %5d Calling %s @ %p for '%s' ]\n", pid, function_name, function, name);
|
||||||
TRACE("[ %5d Done calling preinit_array for '%s' ]\n", pid, si->name);
|
function();
|
||||||
|
TRACE("[ %5d Done calling %s for '%s' ]\n", pid, function_name, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void soinfo_call_constructors(soinfo *si)
|
void soinfo::CallPreInitConstructors() {
|
||||||
{
|
CallArray("DT_PREINIT_ARRAY", preinit_array, preinit_array_count, false);
|
||||||
if (si->constructors_called)
|
}
|
||||||
return;
|
|
||||||
|
|
||||||
// Set this before actually calling the constructors, otherwise it doesn't
|
void soinfo::CallConstructors() {
|
||||||
// protect against recursive constructor calls. One simple example of
|
if (constructors_called) {
|
||||||
// constructor recursion is the libc debug malloc, which is implemented in
|
return;
|
||||||
// libc_malloc_debug_leak.so:
|
}
|
||||||
// 1. The program depends on libc, so libc's constructor is called here.
|
|
||||||
// 2. The libc constructor calls dlopen() to load libc_malloc_debug_leak.so.
|
|
||||||
// 3. dlopen() calls soinfo_call_constructors() with the newly created
|
|
||||||
// soinfo for libc_malloc_debug_leak.so.
|
|
||||||
// 4. The debug so depends on libc, so soinfo_call_constructors() is
|
|
||||||
// called again with the libc soinfo. If it doesn't trigger the early-
|
|
||||||
// out above, the libc constructor will be called again (recursively!).
|
|
||||||
si->constructors_called = 1;
|
|
||||||
|
|
||||||
if (!(si->flags & FLAG_EXE) && si->preinit_array) {
|
// We set constructors_called before actually calling the constructors, otherwise it doesn't
|
||||||
DL_ERR("shared library \"%s\" has a preinit_array table @ 0x%08x. "
|
// protect against recursive constructor calls. One simple example of constructor recursion
|
||||||
"This is INVALID.", si->name, (unsigned) si->preinit_array);
|
// is the libc debug malloc, which is implemented in libc_malloc_debug_leak.so:
|
||||||
}
|
// 1. The program depends on libc, so libc's constructor is called here.
|
||||||
|
// 2. The libc constructor calls dlopen() to load libc_malloc_debug_leak.so.
|
||||||
|
// 3. dlopen() calls the constructors on the newly created
|
||||||
|
// soinfo for libc_malloc_debug_leak.so.
|
||||||
|
// 4. The debug .so depends on libc, so CallConstructors is
|
||||||
|
// called again with the libc soinfo. If it doesn't trigger the early-
|
||||||
|
// out above, the libc constructor will be called again (recursively!).
|
||||||
|
constructors_called = true;
|
||||||
|
|
||||||
if (si->dynamic) {
|
if (!(flags & FLAG_EXE) && preinit_array) {
|
||||||
unsigned *d;
|
DL_ERR("shared library \"%s\" has a preinit_array table @ %p", name, preinit_array);
|
||||||
for(d = si->dynamic; *d; d += 2) {
|
return;
|
||||||
if(d[0] == DT_NEEDED){
|
}
|
||||||
soinfo* lsi = find_loaded_library(si->strtab + d[1]);
|
|
||||||
if (!lsi) {
|
if (dynamic) {
|
||||||
DL_ERR("\"%s\": could not initialize dependent library",
|
for (unsigned* d = dynamic; *d; d += 2) {
|
||||||
si->name);
|
if (d[0] == DT_NEEDED) {
|
||||||
} else {
|
soinfo* lsi = find_loaded_library(strtab + d[1]);
|
||||||
soinfo_call_constructors(lsi);
|
if (lsi == NULL) {
|
||||||
}
|
DL_ERR("\"%s\": could not initialize dependent library", name);
|
||||||
}
|
} else {
|
||||||
|
lsi->CallConstructors();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (si->init_func) {
|
CallFunction("DT_INIT", init_func);
|
||||||
TRACE("[ %5d Calling init_func @ 0x%08x for '%s' ]\n", pid,
|
CallArray("DT_INIT_ARRAY", init_array, init_array_count, false);
|
||||||
(unsigned)si->init_func, si->name);
|
|
||||||
si->init_func();
|
|
||||||
TRACE("[ %5d Done calling init_func for '%s' ]\n", pid, si->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (si->init_array) {
|
|
||||||
TRACE("[ %5d Calling init_array @ 0x%08x [%d] for '%s' ]\n", pid,
|
|
||||||
(unsigned)si->init_array, si->init_array_count, si->name);
|
|
||||||
call_array(si->init_array, si->init_array_count, 0);
|
|
||||||
TRACE("[ %5d Done calling init_array for '%s' ]\n", pid, si->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void call_destructors(soinfo *si)
|
void soinfo::CallDestructors() {
|
||||||
{
|
CallArray("DT_FINI_ARRAY", fini_array, fini_array_count, true);
|
||||||
if (si->fini_array) {
|
CallFunction("DT_FINI", fini_func);
|
||||||
TRACE("[ %5d Calling fini_array @ 0x%08x [%d] for '%s' ]\n", pid,
|
|
||||||
(unsigned)si->fini_array, si->fini_array_count, si->name);
|
|
||||||
call_array(si->fini_array, si->fini_array_count, 1);
|
|
||||||
TRACE("[ %5d Done calling fini_array for '%s' ]\n", pid, si->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (si->fini_func) {
|
|
||||||
TRACE("[ %5d Calling fini_func @ 0x%08x for '%s' ]\n", pid,
|
|
||||||
(unsigned)si->fini_func, si->name);
|
|
||||||
si->fini_func();
|
|
||||||
TRACE("[ %5d Done calling fini_func for '%s' ]\n", pid, si->name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Force any of the closed stdin, stdout and stderr to be associated with
|
/* Force any of the closed stdin, stdout and stderr to be associated with
|
||||||
@ -1632,18 +1642,16 @@ 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) {
|
||||||
int i;
|
|
||||||
memset(preloads, 0, sizeof(preloads));
|
memset(preloads, 0, sizeof(preloads));
|
||||||
for(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 == 0) {
|
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",
|
||||||
gLdPreloadNames[i], si->name, tmp_err_buf);
|
gLdPreloadNames[i], si->name, tmp_err_buf);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
lsi->refcount++;
|
|
||||||
preloads[i] = lsi;
|
preloads[i] = lsi;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1652,17 +1660,16 @@ static bool soinfo_link_image(soinfo* si) {
|
|||||||
pneeded = needed = (soinfo**) alloca((1 + dynamic_count) * sizeof(soinfo*));
|
pneeded = needed = (soinfo**) alloca((1 + dynamic_count) * sizeof(soinfo*));
|
||||||
|
|
||||||
for (unsigned* d = si->dynamic; *d; d += 2) {
|
for (unsigned* d = si->dynamic; *d; d += 2) {
|
||||||
if(d[0] == DT_NEEDED){
|
if (d[0] == DT_NEEDED) {
|
||||||
DEBUG("%5d %s needs %s\n", pid, si->name, si->strtab + d[1]);
|
DEBUG("%5d %s needs %s\n", pid, si->name, si->strtab + d[1]);
|
||||||
soinfo *lsi = find_library(si->strtab + d[1]);
|
soinfo* lsi = find_library(si->strtab + d[1]);
|
||||||
if(lsi == 0) {
|
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);
|
si->strtab + d[1], si->name, tmp_err_buf);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*pneeded++ = lsi;
|
*pneeded++ = lsi;
|
||||||
lsi->refcount++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*pneeded = NULL;
|
*pneeded = NULL;
|
||||||
@ -1910,10 +1917,10 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
soinfo_call_preinit_constructors(si);
|
si->CallPreInitConstructors();
|
||||||
|
|
||||||
for (size_t i = 0; preloads[i] != NULL; ++i) {
|
for (size_t i = 0; preloads[i] != NULL; ++i) {
|
||||||
soinfo_call_constructors(preloads[i]);
|
preloads[i]->CallConstructors();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*After the link_image, the si->base is initialized.
|
/*After the link_image, the si->base is initialized.
|
||||||
@ -1922,7 +1929,7 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke
|
|||||||
*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->base;
|
map->l_addr = si->base;
|
||||||
soinfo_call_constructors(si);
|
si->CallConstructors();
|
||||||
|
|
||||||
#if TIMING
|
#if TIMING
|
||||||
gettimeofday(&t1,NULL);
|
gettimeofday(&t1,NULL);
|
||||||
@ -2056,6 +2063,8 @@ extern "C" unsigned __linker_init(unsigned **elfdata) {
|
|||||||
// the main part of the linker now.
|
// the main part of the linker now.
|
||||||
unsigned start_address = __linker_init_post_relocation(elfdata, linker_addr);
|
unsigned start_address = __linker_init_post_relocation(elfdata, linker_addr);
|
||||||
|
|
||||||
|
set_soinfo_pool_protection(PROT_READ);
|
||||||
|
|
||||||
// Return the address that the calling assembly stub should jump to.
|
// Return the address that the calling assembly stub should jump to.
|
||||||
return start_address;
|
return start_address;
|
||||||
}
|
}
|
||||||
|
157
linker/linker.h
157
linker/linker.h
@ -46,33 +46,29 @@
|
|||||||
// itself at the start of a page.
|
// itself at the start of a page.
|
||||||
#define PAGE_END(x) PAGE_START((x) + (PAGE_SIZE-1))
|
#define PAGE_END(x) PAGE_START((x) + (PAGE_SIZE-1))
|
||||||
|
|
||||||
void debugger_init();
|
// Magic shared structures that GDB knows about.
|
||||||
|
|
||||||
/* magic shared structures that GDB knows about */
|
struct link_map {
|
||||||
|
uintptr_t l_addr;
|
||||||
struct link_map
|
char * l_name;
|
||||||
{
|
uintptr_t l_ld;
|
||||||
uintptr_t l_addr;
|
struct link_map * l_next;
|
||||||
char * l_name;
|
struct link_map * l_prev;
|
||||||
uintptr_t l_ld;
|
|
||||||
struct link_map * l_next;
|
|
||||||
struct link_map * l_prev;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Values for r_debug->state
|
// Values for r_debug->state
|
||||||
enum {
|
enum {
|
||||||
RT_CONSISTENT,
|
RT_CONSISTENT,
|
||||||
RT_ADD,
|
RT_ADD,
|
||||||
RT_DELETE
|
RT_DELETE
|
||||||
};
|
};
|
||||||
|
|
||||||
struct r_debug
|
struct r_debug {
|
||||||
{
|
int32_t r_version;
|
||||||
int32_t r_version;
|
struct link_map* r_map;
|
||||||
struct link_map * r_map;
|
void (*r_brk)(void);
|
||||||
void (*r_brk)(void);
|
int32_t r_state;
|
||||||
int32_t r_state;
|
uintptr_t r_ldbase;
|
||||||
uintptr_t r_ldbase;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FLAG_LINKED 0x00000001
|
#define FLAG_LINKED 0x00000001
|
||||||
@ -83,75 +79,83 @@ struct r_debug
|
|||||||
#define SOINFO_NAME_LEN 128
|
#define SOINFO_NAME_LEN 128
|
||||||
|
|
||||||
struct soinfo {
|
struct soinfo {
|
||||||
char name[SOINFO_NAME_LEN];
|
char name[SOINFO_NAME_LEN];
|
||||||
const Elf32_Phdr *phdr;
|
const Elf32_Phdr* phdr;
|
||||||
int phnum;
|
int phnum;
|
||||||
unsigned entry;
|
unsigned entry;
|
||||||
unsigned base;
|
unsigned base;
|
||||||
unsigned size;
|
unsigned size;
|
||||||
|
|
||||||
int unused; // DO NOT USE, maintained for compatibility.
|
int unused; // DO NOT USE, maintained for compatibility.
|
||||||
|
|
||||||
unsigned *dynamic;
|
unsigned* 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
|
||||||
|
|
||||||
soinfo *next;
|
soinfo* next;
|
||||||
unsigned flags;
|
unsigned flags;
|
||||||
|
|
||||||
const char *strtab;
|
const char* strtab;
|
||||||
Elf32_Sym *symtab;
|
Elf32_Sym* symtab;
|
||||||
|
|
||||||
unsigned nbucket;
|
unsigned nbucket;
|
||||||
unsigned nchain;
|
unsigned nchain;
|
||||||
unsigned *bucket;
|
unsigned* bucket;
|
||||||
unsigned *chain;
|
unsigned* chain;
|
||||||
|
|
||||||
unsigned *plt_got;
|
unsigned* plt_got;
|
||||||
|
|
||||||
Elf32_Rel *plt_rel;
|
Elf32_Rel* plt_rel;
|
||||||
unsigned plt_rel_count;
|
unsigned plt_rel_count;
|
||||||
|
|
||||||
Elf32_Rel *rel;
|
Elf32_Rel* rel;
|
||||||
unsigned rel_count;
|
unsigned rel_count;
|
||||||
|
|
||||||
unsigned *preinit_array;
|
unsigned* preinit_array;
|
||||||
unsigned preinit_array_count;
|
unsigned preinit_array_count;
|
||||||
|
|
||||||
unsigned *init_array;
|
unsigned* init_array;
|
||||||
unsigned init_array_count;
|
unsigned init_array_count;
|
||||||
unsigned *fini_array;
|
unsigned* fini_array;
|
||||||
unsigned fini_array_count;
|
unsigned fini_array_count;
|
||||||
|
|
||||||
void (*init_func)(void);
|
void (*init_func)();
|
||||||
void (*fini_func)(void);
|
void (*fini_func)();
|
||||||
|
|
||||||
#if defined(ANDROID_ARM_LINKER)
|
#if defined(ANDROID_ARM_LINKER)
|
||||||
/* ARM EABI section used for stack unwinding. */
|
// ARM EABI section used for stack unwinding.
|
||||||
unsigned *ARM_exidx;
|
unsigned* ARM_exidx;
|
||||||
unsigned ARM_exidx_count;
|
unsigned ARM_exidx_count;
|
||||||
#elif defined(ANDROID_MIPS_LINKER)
|
#elif defined(ANDROID_MIPS_LINKER)
|
||||||
#if 0
|
#if 0
|
||||||
/* not yet */
|
// Not yet.
|
||||||
unsigned *mips_pltgot
|
unsigned* mips_pltgot
|
||||||
|
#endif
|
||||||
|
unsigned mips_symtabno;
|
||||||
|
unsigned mips_local_gotno;
|
||||||
|
unsigned mips_gotsym;
|
||||||
#endif
|
#endif
|
||||||
unsigned mips_symtabno;
|
|
||||||
unsigned mips_local_gotno;
|
|
||||||
unsigned mips_gotsym;
|
|
||||||
#endif /* ANDROID_*_LINKER */
|
|
||||||
|
|
||||||
unsigned refcount;
|
unsigned refcount;
|
||||||
struct link_map linkmap;
|
struct link_map linkmap;
|
||||||
|
|
||||||
int constructors_called;
|
bool constructors_called;
|
||||||
|
|
||||||
/* 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;
|
Elf32_Addr load_bias;
|
||||||
|
|
||||||
bool has_text_relocations;
|
bool has_text_relocations;
|
||||||
bool has_DT_SYMBOLIC;
|
bool has_DT_SYMBOLIC;
|
||||||
|
|
||||||
|
void CallConstructors();
|
||||||
|
void CallDestructors();
|
||||||
|
void CallPreInitConstructors();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void CallArray(const char* array_name, unsigned* array, int count, bool reverse);
|
||||||
|
void CallFunction(const char* function_name, void (*function)());
|
||||||
};
|
};
|
||||||
|
|
||||||
extern soinfo libdl_info;
|
extern soinfo libdl_info;
|
||||||
@ -203,16 +207,17 @@ extern soinfo libdl_info;
|
|||||||
#define DT_PREINIT_ARRAYSZ 33
|
#define DT_PREINIT_ARRAYSZ 33
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
soinfo *find_library(const char *name);
|
soinfo* do_dlopen(const char* name);
|
||||||
Elf32_Sym *lookup(const char *name, soinfo **found, soinfo *start);
|
int do_dlclose(soinfo* si);
|
||||||
soinfo *find_containing_library(const void *addr);
|
|
||||||
const char *linker_get_error(void);
|
|
||||||
|
|
||||||
int soinfo_unload(soinfo* si);
|
Elf32_Sym* lookup(const char* name, soinfo** found, soinfo* start);
|
||||||
Elf32_Sym *soinfo_find_symbol(soinfo* si, const void *addr);
|
soinfo* find_containing_library(const void* addr);
|
||||||
Elf32_Sym *soinfo_lookup(soinfo *si, const char *name);
|
const char* linker_get_error();
|
||||||
void soinfo_call_constructors(soinfo *si);
|
|
||||||
|
|
||||||
|
Elf32_Sym* soinfo_find_symbol(soinfo* si, const void* addr);
|
||||||
|
Elf32_Sym* soinfo_lookup(soinfo* si, const char* name);
|
||||||
|
|
||||||
|
void debugger_init();
|
||||||
extern "C" void notify_gdb_of_libraries();
|
extern "C" void notify_gdb_of_libraries();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user