Merge "linker: handle R_ARM_COPY relocations in a proper way"
This commit is contained in:
commit
084be59192
3 changed files with 79 additions and 57 deletions
|
@ -236,5 +236,7 @@ soinfo libdl_info = {
|
|||
|
||||
refcount: 0,
|
||||
{ l_addr: 0, l_name: 0, l_ld: 0, l_next: 0, l_prev: 0, },
|
||||
constructors_called: 0, load_bias: 0, has_text_relocations: 0,
|
||||
constructors_called: 0, load_bias: 0,
|
||||
has_text_relocations: false,
|
||||
has_DT_SYMBOLIC: true,
|
||||
};
|
||||
|
|
|
@ -51,7 +51,6 @@
|
|||
#include "linker_format.h"
|
||||
#include "linker_phdr.h"
|
||||
|
||||
#define ALLOW_SYMBOLS_FROM_MAIN 1
|
||||
#define SO_MAX 128
|
||||
|
||||
/* Assume average path length of 64 and max 8 paths */
|
||||
|
@ -89,9 +88,7 @@ static soinfo sopool[SO_MAX];
|
|||
static soinfo *freelist = NULL;
|
||||
static soinfo *solist = &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 char ldpaths_buf[LDPATH_BUFSIZE];
|
||||
static const char *ldpaths[LDPATH_MAX + 1];
|
||||
|
@ -421,15 +418,31 @@ static unsigned elfhash(const char *_name)
|
|||
}
|
||||
|
||||
static Elf32_Sym *
|
||||
soinfo_do_lookup(soinfo *si, const char *name, Elf32_Addr *offset,
|
||||
soinfo *needed[], bool ignore_local)
|
||||
soinfo_do_lookup(soinfo *si, const char *name, soinfo **lsi,
|
||||
soinfo *needed[])
|
||||
{
|
||||
unsigned elf_hash = elfhash(name);
|
||||
Elf32_Sym *s = NULL;
|
||||
soinfo *lsi = si;
|
||||
int i;
|
||||
|
||||
if (!ignore_local) {
|
||||
if (si != NULL) {
|
||||
|
||||
/*
|
||||
* If this object was built with symbolic relocations disabled, the
|
||||
* first place to look to resolve external references is the main
|
||||
* executable.
|
||||
*/
|
||||
|
||||
if (!si->has_DT_SYMBOLIC) {
|
||||
DEBUG("%5d %s: looking up %s in executable %s\n",
|
||||
pid, si->name, name, somain->name);
|
||||
s = soinfo_elf_lookup(somain, elf_hash, name);
|
||||
if (s != NULL) {
|
||||
*lsi = somain;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* Look for symbols in the local scope (the object who is
|
||||
* searching). This happens with C++ templates on i386 for some
|
||||
* reason.
|
||||
|
@ -441,47 +454,37 @@ soinfo_do_lookup(soinfo *si, const char *name, Elf32_Addr *offset,
|
|||
* Here we return the first definition found for simplicity. */
|
||||
|
||||
s = soinfo_elf_lookup(si, elf_hash, name);
|
||||
if(s != NULL)
|
||||
if (s != NULL) {
|
||||
*lsi = si;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* Next, look for it in the preloads list */
|
||||
for(i = 0; preloads[i] != NULL; i++) {
|
||||
lsi = preloads[i];
|
||||
s = soinfo_elf_lookup(lsi, elf_hash, name);
|
||||
if(s != NULL)
|
||||
s = soinfo_elf_lookup(preloads[i], elf_hash, name);
|
||||
if(s != NULL) {
|
||||
*lsi = preloads[i];
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; needed[i] != NULL; i++) {
|
||||
lsi = needed[i];
|
||||
DEBUG("%5d %s: looking up %s in %s\n",
|
||||
pid, si->name, name, lsi->name);
|
||||
s = soinfo_elf_lookup(lsi, elf_hash, name);
|
||||
if (s != NULL)
|
||||
pid, si->name, name, needed[i]->name);
|
||||
s = soinfo_elf_lookup(needed[i], elf_hash, name);
|
||||
if (s != NULL) {
|
||||
*lsi = needed[i];
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
#if ALLOW_SYMBOLS_FROM_MAIN
|
||||
/* If we are resolving relocations while dlopen()ing a library, it's OK for
|
||||
* 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 = soinfo_elf_lookup(lsi, elf_hash, name);
|
||||
}
|
||||
#endif
|
||||
|
||||
done:
|
||||
if(s != NULL) {
|
||||
TRACE_TYPE(LOOKUP, "%5d si %s sym %s s->st_value = 0x%08x, "
|
||||
"found in %s, base = 0x%08x, load bias = 0x%08x\n",
|
||||
pid, si->name, name, s->st_value,
|
||||
lsi->name, lsi->base, lsi->load_bias);
|
||||
*offset = lsi->load_bias;
|
||||
(*lsi)->name, (*lsi)->base, (*lsi)->load_bias);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -863,13 +866,8 @@ soinfo *find_library(const char *name)
|
|||
{
|
||||
soinfo *si;
|
||||
|
||||
#if ALLOW_SYMBOLS_FROM_MAIN
|
||||
if (name == NULL)
|
||||
return somain;
|
||||
#else
|
||||
if (name == NULL)
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
si = find_loaded_library(name);
|
||||
if (si != NULL) {
|
||||
|
@ -933,8 +931,8 @@ static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count,
|
|||
Elf32_Sym *symtab = si->symtab;
|
||||
const char *strtab = si->strtab;
|
||||
Elf32_Sym *s;
|
||||
Elf32_Addr offset;
|
||||
Elf32_Rel *start = rel;
|
||||
soinfo *lsi;
|
||||
|
||||
for (size_t idx = 0; idx < count; ++idx, ++rel) {
|
||||
unsigned type = ELF32_R_TYPE(rel->r_info);
|
||||
|
@ -950,11 +948,7 @@ static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count,
|
|||
}
|
||||
if(sym != 0) {
|
||||
sym_name = (char *)(strtab + symtab[sym].st_name);
|
||||
bool ignore_local = false;
|
||||
#if defined(ANDROID_ARM_LINKER)
|
||||
ignore_local = (type == R_ARM_COPY);
|
||||
#endif
|
||||
s = soinfo_do_lookup(si, sym_name, &offset, needed, ignore_local);
|
||||
s = soinfo_do_lookup(si, sym_name, &lsi, needed);
|
||||
if(s == NULL) {
|
||||
/* We only allow an undefined symbol if this is a weak
|
||||
reference.. */
|
||||
|
@ -1020,7 +1014,7 @@ static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count,
|
|||
return -1;
|
||||
}
|
||||
#endif
|
||||
sym_addr = (unsigned)(s->st_value + offset);
|
||||
sym_addr = (unsigned)(s->st_value + lsi->load_bias);
|
||||
}
|
||||
count_relocation(kRelocSymbol);
|
||||
} else {
|
||||
|
@ -1154,10 +1148,27 @@ static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count,
|
|||
TRACE_TYPE(RELO, "%5d RELO %08x <- %d @ %08x %s\n", pid,
|
||||
reloc, s->st_size, sym_addr, sym_name);
|
||||
if (reloc == sym_addr) {
|
||||
DL_ERR("Internal linker error detected. reloc == symaddr");
|
||||
Elf32_Sym *src = soinfo_do_lookup(NULL, sym_name, &lsi, needed);
|
||||
|
||||
if (src == NULL) {
|
||||
DL_ERR("%s R_ARM_COPY relocation source cannot be resolved", si->name);
|
||||
return -1;
|
||||
}
|
||||
if (lsi->has_DT_SYMBOLIC) {
|
||||
DL_ERR("%s invalid R_ARM_COPY relocation against DT_SYMBOLIC shared "
|
||||
"library %s (built with -Bsymbolic?)", si->name, lsi->name);
|
||||
return -1;
|
||||
}
|
||||
if (s->st_size < src->st_size) {
|
||||
DL_ERR("%s R_ARM_COPY relocation size mismatch (%d < %d)",
|
||||
si->name, s->st_size, src->st_size);
|
||||
return -1;
|
||||
}
|
||||
memcpy((void*)reloc, (void*)(src->st_value + lsi->load_bias), src->st_size);
|
||||
} else {
|
||||
DL_ERR("%s R_ARM_COPY relocation target cannot be resolved", si->name);
|
||||
return -1;
|
||||
}
|
||||
memcpy((void*)reloc, (void*)sym_addr, s->st_size);
|
||||
break;
|
||||
#endif /* ANDROID_ARM_LINKER */
|
||||
|
||||
|
@ -1210,12 +1221,12 @@ static int mips_relocate_got(soinfo* si, soinfo* needed[]) {
|
|||
got = si->plt_got + local_gotno;
|
||||
for (g = gotsym; g < symtabno; g++, sym++, got++) {
|
||||
const char *sym_name;
|
||||
unsigned base;
|
||||
Elf32_Sym *s;
|
||||
soinfo *lsi;
|
||||
|
||||
/* This is an undefined reference... try to locate it */
|
||||
sym_name = si->strtab + sym->st_name;
|
||||
s = soinfo_do_lookup(si, sym_name, &base, needed, false);
|
||||
s = soinfo_do_lookup(si, sym_name, &lsi, needed);
|
||||
if (s == NULL) {
|
||||
/* We only allow an undefined symbol if this is a weak
|
||||
reference.. */
|
||||
|
@ -1231,7 +1242,7 @@ static int mips_relocate_got(soinfo* si, soinfo* needed[]) {
|
|||
* For reference see NetBSD link loader
|
||||
* http://cvsweb.netbsd.org/bsdweb.cgi/src/libexec/ld.elf_so/arch/mips/mips_reloc.c?rev=1.53&content-type=text/x-cvsweb-markup
|
||||
*/
|
||||
*got = base + s->st_value;
|
||||
*got = lsi->load_bias + s->st_value;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -1537,6 +1548,19 @@ static int soinfo_link_image(soinfo *si)
|
|||
case DT_TEXTREL:
|
||||
si->has_text_relocations = true;
|
||||
break;
|
||||
case DT_SYMBOLIC:
|
||||
si->has_DT_SYMBOLIC = true;
|
||||
break;
|
||||
#if defined(DT_FLAGS)
|
||||
case DT_FLAGS:
|
||||
if (*d & DF_TEXTREL) {
|
||||
si->has_text_relocations = true;
|
||||
}
|
||||
if (*d & DF_SYMBOLIC) {
|
||||
si->has_DT_SYMBOLIC = true;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if defined(ANDROID_MIPS_LINKER)
|
||||
case DT_NEEDED:
|
||||
case DT_STRSZ:
|
||||
|
@ -1868,6 +1892,8 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke
|
|||
parse_LD_LIBRARY_PATH(ldpath_env);
|
||||
parse_LD_PRELOAD(ldpreload_env);
|
||||
|
||||
somain = si;
|
||||
|
||||
if(soinfo_link_image(si)) {
|
||||
char errmsg[] = "CANNOT LINK EXECUTABLE\n";
|
||||
write(2, __linker_dl_err_buf, strlen(__linker_dl_err_buf));
|
||||
|
@ -1889,14 +1915,6 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke
|
|||
map->l_addr = si->base;
|
||||
soinfo_call_constructors(si);
|
||||
|
||||
#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
|
||||
gettimeofday(&t1,NULL);
|
||||
PRINT("LINKER TIME: %s: %d microseconds\n", argv[0], (int) (
|
||||
|
|
|
@ -160,7 +160,9 @@ struct soinfo {
|
|||
/* When you read a virtual address from the ELF file, add this
|
||||
* value to get the corresponding address in the process' address space */
|
||||
Elf32_Addr load_bias;
|
||||
int has_text_relocations;
|
||||
|
||||
bool has_text_relocations;
|
||||
bool has_DT_SYMBOLIC;
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue