Merge "linker: handle R_ARM_COPY relocations in a proper way"

This commit is contained in:
Elliott Hughes 2012-10-30 17:10:30 -07:00 committed by Gerrit Code Review
commit 084be59192
3 changed files with 79 additions and 57 deletions

View file

@ -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,
};

View file

@ -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) (

View file

@ -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;
};