Merge changes I3bd27087,I0c9ec550,I3a0e5e86 into eclair
* changes: bionic/linker: allow resolving of symbols from library back to executable bionic/linker: change lookup() to return soinfo, not base Revert "Revert "bionic/linker: fix symbol lookup during relocations""
This commit is contained in:
commit
fe46030cdd
@ -74,7 +74,7 @@ const char *dlerror(void)
|
|||||||
|
|
||||||
void *dlsym(void *handle, const char *symbol)
|
void *dlsym(void *handle, const char *symbol)
|
||||||
{
|
{
|
||||||
unsigned base;
|
soinfo *found;
|
||||||
Elf32_Sym *sym;
|
Elf32_Sym *sym;
|
||||||
unsigned bind;
|
unsigned bind;
|
||||||
|
|
||||||
@ -90,19 +90,19 @@ void *dlsym(void *handle, const char *symbol)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(handle == RTLD_DEFAULT) {
|
if(handle == RTLD_DEFAULT) {
|
||||||
sym = lookup(symbol, &base);
|
sym = lookup(symbol, &found);
|
||||||
} else if(handle == RTLD_NEXT) {
|
} else if(handle == RTLD_NEXT) {
|
||||||
sym = lookup(symbol, &base);
|
sym = lookup(symbol, &found);
|
||||||
} else {
|
} else {
|
||||||
sym = lookup_in_library((soinfo*) handle, symbol);
|
found = (soinfo*)handle;
|
||||||
base = ((soinfo*) handle)->base;
|
sym = lookup_in_library(found, symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(likely(sym != 0)) {
|
if(likely(sym != 0)) {
|
||||||
bind = ELF32_ST_BIND(sym->st_info);
|
bind = ELF32_ST_BIND(sym->st_info);
|
||||||
|
|
||||||
if(likely((bind == STB_GLOBAL) && (sym->st_shndx != 0))) {
|
if(likely((bind == STB_GLOBAL) && (sym->st_shndx != 0))) {
|
||||||
unsigned ret = sym->st_value + base;
|
unsigned ret = sym->st_value + found->base;
|
||||||
pthread_mutex_unlock(&dl_lock);
|
pthread_mutex_unlock(&dl_lock);
|
||||||
return (void*)ret;
|
return (void*)ret;
|
||||||
}
|
}
|
||||||
|
143
linker/linker.c
143
linker/linker.c
@ -51,6 +51,7 @@
|
|||||||
|
|
||||||
#include "ba.h"
|
#include "ba.h"
|
||||||
|
|
||||||
|
#define ALLOW_SYMBOLS_FROM_MAIN 1
|
||||||
#define SO_MAX 96
|
#define SO_MAX 96
|
||||||
|
|
||||||
/* Assume average path length of 64 and max 8 paths */
|
/* Assume average path length of 64 and max 8 paths */
|
||||||
@ -86,6 +87,15 @@ static soinfo sopool[SO_MAX];
|
|||||||
static soinfo *freelist = NULL;
|
static soinfo *freelist = NULL;
|
||||||
static soinfo *solist = &libdl_info;
|
static soinfo *solist = &libdl_info;
|
||||||
static soinfo *sonext = &libdl_info;
|
static soinfo *sonext = &libdl_info;
|
||||||
|
#if ALLOW_SYMBOLS_FROM_MAIN
|
||||||
|
static soinfo *somain; /* main process, always the one after libdl_info */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline int validate_soinfo(soinfo *si)
|
||||||
|
{
|
||||||
|
return (si >= sopool && si < sopool + SO_MAX) ||
|
||||||
|
si == &libdl_info;
|
||||||
|
}
|
||||||
|
|
||||||
static char ldpaths_buf[LDPATH_BUFSIZE];
|
static char ldpaths_buf[LDPATH_BUFSIZE];
|
||||||
static const char *ldpaths[LDPATH_MAX + 1];
|
static const char *ldpaths[LDPATH_MAX + 1];
|
||||||
@ -421,53 +431,98 @@ _do_lookup_in_so(soinfo *si, const char *name, unsigned *elf_hash)
|
|||||||
return _elf_lookup (si, *elf_hash, name);
|
return _elf_lookup (si, *elf_hash, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is used by dl_sym() */
|
|
||||||
Elf32_Sym *lookup_in_library(soinfo *si, const char *name)
|
|
||||||
{
|
|
||||||
unsigned unused = 0;
|
|
||||||
return _do_lookup_in_so(si, name, &unused);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Elf32_Sym *
|
static Elf32_Sym *
|
||||||
_do_lookup(soinfo *user_si, const char *name, unsigned *base)
|
_do_lookup(soinfo *si, const char *name, unsigned *base)
|
||||||
{
|
{
|
||||||
unsigned elf_hash = 0;
|
unsigned elf_hash = 0;
|
||||||
Elf32_Sym *s = NULL;
|
Elf32_Sym *s;
|
||||||
soinfo *si;
|
unsigned *d;
|
||||||
|
soinfo *lsi = si;
|
||||||
|
|
||||||
/* Look for symbols in the local scope first (the object who is
|
/* Look for symbols in the local scope first (the object who is
|
||||||
* searching). This happens with C++ templates on i386 for some
|
* searching). This happens with C++ templates on i386 for some
|
||||||
* reason. */
|
* reason. */
|
||||||
if (user_si) {
|
s = _do_lookup_in_so(si, name, &elf_hash);
|
||||||
s = _do_lookup_in_so(user_si, name, &elf_hash);
|
if(s != NULL)
|
||||||
if (s != NULL)
|
goto done;
|
||||||
*base = user_si->base;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(si = solist; (s == NULL) && (si != NULL); si = si->next)
|
for(d = si->dynamic; *d; d += 2) {
|
||||||
{
|
if(d[0] == DT_NEEDED){
|
||||||
if((si->flags & FLAG_ERROR) || (si == user_si))
|
lsi = (soinfo *)d[1];
|
||||||
continue;
|
if (!validate_soinfo(lsi)) {
|
||||||
s = _do_lookup_in_so(si, name, &elf_hash);
|
DL_ERR("%5d bad DT_NEEDED pointer in %s",
|
||||||
if (s != NULL) {
|
pid, si->name);
|
||||||
*base = si->base;
|
return 0;
|
||||||
break;
|
}
|
||||||
|
|
||||||
|
DEBUG("%5d %s: looking up %s in %s\n",
|
||||||
|
pid, si->name, name, lsi->name);
|
||||||
|
s = _do_lookup_in_so(lsi, name, &elf_hash);
|
||||||
|
if(s != NULL)
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s != NULL) {
|
#if ALLOW_SYMBOLS_FROM_MAIN
|
||||||
TRACE_TYPE(LOOKUP, "%5d %s s->st_value = 0x%08x, "
|
/* If we are resolving relocations while dlopen()ing a library, it's OK for
|
||||||
"si->base = 0x%08x\n", pid, name, s->st_value, si->base);
|
* the library to resolve a symbol that's defined in the executable itself,
|
||||||
|
* although this is rare and is generally a bad idea.
|
||||||
|
*/
|
||||||
|
if (somain) {
|
||||||
|
lsi = somain;
|
||||||
|
DEBUG("%5d %s: looking up %s in executable %s\n",
|
||||||
|
pid, si->name, name, lsi->name);
|
||||||
|
s = _do_lookup_in_so(lsi, name, &elf_hash);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
done:
|
||||||
|
if(s != NULL) {
|
||||||
|
TRACE_TYPE(LOOKUP, "%5d si %s sym %s s->st_value = 0x%08x, "
|
||||||
|
"found in %s, base = 0x%08x\n",
|
||||||
|
pid, si->name, name, s->st_value, lsi->name, lsi->base);
|
||||||
|
*base = lsi->base;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is used by dl_sym() */
|
/* This is used by dl_sym(). It performs symbol lookup only within the
|
||||||
Elf32_Sym *lookup(const char *name, unsigned *base)
|
specified soinfo object and not in any of its dependencies.
|
||||||
|
*/
|
||||||
|
Elf32_Sym *lookup_in_library(soinfo *si, const char *name)
|
||||||
{
|
{
|
||||||
return _do_lookup(NULL, name, base);
|
unsigned unused = 0;
|
||||||
|
return _do_lookup_in_so(si, name, &unused);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is used by dl_sym(). It performs a global symbol lookup.
|
||||||
|
*/
|
||||||
|
Elf32_Sym *lookup(const char *name, soinfo **found)
|
||||||
|
{
|
||||||
|
unsigned elf_hash = 0;
|
||||||
|
Elf32_Sym *s = NULL;
|
||||||
|
soinfo *si;
|
||||||
|
|
||||||
|
for(si = solist; (s == NULL) && (si != NULL); si = si->next)
|
||||||
|
{
|
||||||
|
if(si->flags & FLAG_ERROR)
|
||||||
|
continue;
|
||||||
|
s = _do_lookup_in_so(si, name, &elf_hash);
|
||||||
|
if (s != NULL) {
|
||||||
|
*found = si;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(s != NULL) {
|
||||||
|
TRACE_TYPE(LOOKUP, "%5d %s s->st_value = 0x%08x, "
|
||||||
|
"si->base = 0x%08x\n", pid, name, s->st_value, si->base);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@ -1116,14 +1171,16 @@ unsigned unload_library(soinfo *si)
|
|||||||
|
|
||||||
for(d = si->dynamic; *d; d += 2) {
|
for(d = si->dynamic; *d; d += 2) {
|
||||||
if(d[0] == DT_NEEDED){
|
if(d[0] == DT_NEEDED){
|
||||||
TRACE("%5d %s needs to unload %s\n", pid,
|
soinfo *lsi = (soinfo *)d[1];
|
||||||
si->name, si->strtab + d[1]);
|
d[1] = 0;
|
||||||
soinfo *lsi = find_library(si->strtab + d[1]);
|
if (validate_soinfo(lsi)) {
|
||||||
if(lsi)
|
TRACE("%5d %s needs to unload %s\n", pid,
|
||||||
|
si->name, lsi->name);
|
||||||
unload_library(lsi);
|
unload_library(lsi);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
DL_ERR("%5d could not unload '%s'",
|
DL_ERR("%5d %s: could not unload dependent library",
|
||||||
pid, si->strtab + d[1]);
|
pid, si->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1641,6 +1698,14 @@ static int link_image(soinfo *si, unsigned wr_offset)
|
|||||||
pid, si->strtab + d[1], si->name, tmp_err_buf);
|
pid, si->strtab + d[1], si->name, tmp_err_buf);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
/* Save the soinfo of the loaded DT_NEEDED library in the payload
|
||||||
|
of the DT_NEEDED entry itself, so that we can retrieve the
|
||||||
|
soinfo directly later from the dynamic segment. This is a hack,
|
||||||
|
but it allows us to map from DT_NEEDED to soinfo efficiently
|
||||||
|
later on when we resolve relocations, trying to look up a symgol
|
||||||
|
with dlsym().
|
||||||
|
*/
|
||||||
|
d[1] = (unsigned)lsi;
|
||||||
lsi->refcount++;
|
lsi->refcount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1846,6 +1911,14 @@ unsigned __linker_init(unsigned **elfdata)
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ALLOW_SYMBOLS_FROM_MAIN
|
||||||
|
/* Set somain after we've loaded all the libraries in order to prevent
|
||||||
|
* linking of symbols back to the main image, which is not set up at that
|
||||||
|
* point yet.
|
||||||
|
*/
|
||||||
|
somain = si;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if TIMING
|
#if TIMING
|
||||||
gettimeofday(&t1,NULL);
|
gettimeofday(&t1,NULL);
|
||||||
PRINT("LINKER TIME: %s: %d microseconds\n", argv[0], (int) (
|
PRINT("LINKER TIME: %s: %d microseconds\n", argv[0], (int) (
|
||||||
|
@ -203,7 +203,7 @@ extern soinfo libdl_info;
|
|||||||
soinfo *find_library(const char *name);
|
soinfo *find_library(const char *name);
|
||||||
unsigned unload_library(soinfo *si);
|
unsigned unload_library(soinfo *si);
|
||||||
Elf32_Sym *lookup_in_library(soinfo *si, const char *name);
|
Elf32_Sym *lookup_in_library(soinfo *si, const char *name);
|
||||||
Elf32_Sym *lookup(const char *name, unsigned *base);
|
Elf32_Sym *lookup(const char *name, soinfo **found);
|
||||||
const char *linker_get_error(void);
|
const char *linker_get_error(void);
|
||||||
|
|
||||||
#ifdef ANDROID_ARM_LINKER
|
#ifdef ANDROID_ARM_LINKER
|
||||||
|
Loading…
x
Reference in New Issue
Block a user