am 084be591: Merge "linker: handle R_ARM_COPY relocations in a proper way"
* commit '084be591923d3d509cea0a0f4b11b073e362d730': linker: handle R_ARM_COPY relocations in a proper way
This commit is contained in:
commit
3cd7a1653a
@ -236,5 +236,7 @@ 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, 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_format.h"
|
||||||
#include "linker_phdr.h"
|
#include "linker_phdr.h"
|
||||||
|
|
||||||
#define ALLOW_SYMBOLS_FROM_MAIN 1
|
|
||||||
#define SO_MAX 128
|
#define SO_MAX 128
|
||||||
|
|
||||||
/* Assume average path length of 64 and max 8 paths */
|
/* 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 *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 */
|
static soinfo *somain; /* main process, always the one after libdl_info */
|
||||||
#endif
|
|
||||||
|
|
||||||
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,15 +418,31 @@ static unsigned elfhash(const char *_name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Elf32_Sym *
|
static Elf32_Sym *
|
||||||
soinfo_do_lookup(soinfo *si, const char *name, Elf32_Addr *offset,
|
soinfo_do_lookup(soinfo *si, const char *name, soinfo **lsi,
|
||||||
soinfo *needed[], bool ignore_local)
|
soinfo *needed[])
|
||||||
{
|
{
|
||||||
unsigned elf_hash = elfhash(name);
|
unsigned elf_hash = elfhash(name);
|
||||||
Elf32_Sym *s = NULL;
|
Elf32_Sym *s = NULL;
|
||||||
soinfo *lsi = si;
|
|
||||||
int i;
|
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
|
/* Look for symbols in the local scope (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.
|
||||||
@ -441,47 +454,37 @@ soinfo_do_lookup(soinfo *si, const char *name, Elf32_Addr *offset,
|
|||||||
* Here we return the first definition found for simplicity. */
|
* Here we return the first definition found for simplicity. */
|
||||||
|
|
||||||
s = soinfo_elf_lookup(si, elf_hash, name);
|
s = soinfo_elf_lookup(si, elf_hash, name);
|
||||||
if(s != NULL)
|
if (s != NULL) {
|
||||||
|
*lsi = si;
|
||||||
goto done;
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Next, look for it in the preloads list */
|
/* Next, look for it in the preloads list */
|
||||||
for(i = 0; preloads[i] != NULL; i++) {
|
for(i = 0; preloads[i] != NULL; i++) {
|
||||||
lsi = preloads[i];
|
s = soinfo_elf_lookup(preloads[i], elf_hash, name);
|
||||||
s = soinfo_elf_lookup(lsi, elf_hash, name);
|
if(s != NULL) {
|
||||||
if(s != NULL)
|
*lsi = preloads[i];
|
||||||
goto done;
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 0; needed[i] != NULL; i++) {
|
for(i = 0; needed[i] != NULL; i++) {
|
||||||
lsi = needed[i];
|
|
||||||
DEBUG("%5d %s: looking up %s in %s\n",
|
DEBUG("%5d %s: looking up %s in %s\n",
|
||||||
pid, si->name, name, lsi->name);
|
pid, si->name, name, needed[i]->name);
|
||||||
s = soinfo_elf_lookup(lsi, elf_hash, name);
|
s = soinfo_elf_lookup(needed[i], elf_hash, name);
|
||||||
if (s != NULL)
|
if (s != NULL) {
|
||||||
|
*lsi = needed[i];
|
||||||
goto done;
|
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:
|
done:
|
||||||
if(s != NULL) {
|
if(s != NULL) {
|
||||||
TRACE_TYPE(LOOKUP, "%5d si %s sym %s s->st_value = 0x%08x, "
|
TRACE_TYPE(LOOKUP, "%5d si %s sym %s s->st_value = 0x%08x, "
|
||||||
"found in %s, base = 0x%08x, load bias = 0x%08x\n",
|
"found in %s, base = 0x%08x, load bias = 0x%08x\n",
|
||||||
pid, si->name, name, s->st_value,
|
pid, si->name, name, s->st_value,
|
||||||
lsi->name, lsi->base, lsi->load_bias);
|
(*lsi)->name, (*lsi)->base, (*lsi)->load_bias);
|
||||||
*offset = lsi->load_bias;
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -863,13 +866,8 @@ soinfo *find_library(const char *name)
|
|||||||
{
|
{
|
||||||
soinfo *si;
|
soinfo *si;
|
||||||
|
|
||||||
#if ALLOW_SYMBOLS_FROM_MAIN
|
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
return somain;
|
return somain;
|
||||||
#else
|
|
||||||
if (name == NULL)
|
|
||||||
return NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
si = find_loaded_library(name);
|
si = find_loaded_library(name);
|
||||||
if (si != NULL) {
|
if (si != NULL) {
|
||||||
@ -933,8 +931,8 @@ static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count,
|
|||||||
Elf32_Sym *symtab = si->symtab;
|
Elf32_Sym *symtab = si->symtab;
|
||||||
const char *strtab = si->strtab;
|
const char *strtab = si->strtab;
|
||||||
Elf32_Sym *s;
|
Elf32_Sym *s;
|
||||||
Elf32_Addr offset;
|
|
||||||
Elf32_Rel *start = rel;
|
Elf32_Rel *start = rel;
|
||||||
|
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);
|
||||||
@ -950,11 +948,7 @@ static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count,
|
|||||||
}
|
}
|
||||||
if(sym != 0) {
|
if(sym != 0) {
|
||||||
sym_name = (char *)(strtab + symtab[sym].st_name);
|
sym_name = (char *)(strtab + symtab[sym].st_name);
|
||||||
bool ignore_local = false;
|
s = soinfo_do_lookup(si, sym_name, &lsi, needed);
|
||||||
#if defined(ANDROID_ARM_LINKER)
|
|
||||||
ignore_local = (type == R_ARM_COPY);
|
|
||||||
#endif
|
|
||||||
s = soinfo_do_lookup(si, sym_name, &offset, needed, ignore_local);
|
|
||||||
if(s == NULL) {
|
if(s == NULL) {
|
||||||
/* We only allow an undefined symbol if this is a weak
|
/* We only allow an undefined symbol if this is a weak
|
||||||
reference.. */
|
reference.. */
|
||||||
@ -1020,7 +1014,7 @@ static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
sym_addr = (unsigned)(s->st_value + offset);
|
sym_addr = (unsigned)(s->st_value + lsi->load_bias);
|
||||||
}
|
}
|
||||||
count_relocation(kRelocSymbol);
|
count_relocation(kRelocSymbol);
|
||||||
} else {
|
} 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,
|
TRACE_TYPE(RELO, "%5d RELO %08x <- %d @ %08x %s\n", pid,
|
||||||
reloc, s->st_size, sym_addr, sym_name);
|
reloc, s->st_size, sym_addr, sym_name);
|
||||||
if (reloc == sym_addr) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
memcpy((void*)reloc, (void*)sym_addr, s->st_size);
|
|
||||||
break;
|
break;
|
||||||
#endif /* ANDROID_ARM_LINKER */
|
#endif /* ANDROID_ARM_LINKER */
|
||||||
|
|
||||||
@ -1210,12 +1221,12 @@ static int mips_relocate_got(soinfo* si, soinfo* needed[]) {
|
|||||||
got = si->plt_got + local_gotno;
|
got = si->plt_got + local_gotno;
|
||||||
for (g = gotsym; g < symtabno; g++, sym++, got++) {
|
for (g = gotsym; g < symtabno; g++, sym++, got++) {
|
||||||
const char *sym_name;
|
const char *sym_name;
|
||||||
unsigned base;
|
|
||||||
Elf32_Sym *s;
|
Elf32_Sym *s;
|
||||||
|
soinfo *lsi;
|
||||||
|
|
||||||
/* This is an undefined reference... try to locate it */
|
/* This is an undefined reference... try to locate it */
|
||||||
sym_name = si->strtab + sym->st_name;
|
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) {
|
if (s == NULL) {
|
||||||
/* We only allow an undefined symbol if this is a weak
|
/* We only allow an undefined symbol if this is a weak
|
||||||
reference.. */
|
reference.. */
|
||||||
@ -1231,7 +1242,7 @@ static int mips_relocate_got(soinfo* si, soinfo* needed[]) {
|
|||||||
* For reference see NetBSD link loader
|
* 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
|
* 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;
|
return 0;
|
||||||
@ -1537,6 +1548,19 @@ static int soinfo_link_image(soinfo *si)
|
|||||||
case DT_TEXTREL:
|
case DT_TEXTREL:
|
||||||
si->has_text_relocations = true;
|
si->has_text_relocations = true;
|
||||||
break;
|
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)
|
#if defined(ANDROID_MIPS_LINKER)
|
||||||
case DT_NEEDED:
|
case DT_NEEDED:
|
||||||
case DT_STRSZ:
|
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_LIBRARY_PATH(ldpath_env);
|
||||||
parse_LD_PRELOAD(ldpreload_env);
|
parse_LD_PRELOAD(ldpreload_env);
|
||||||
|
|
||||||
|
somain = si;
|
||||||
|
|
||||||
if(soinfo_link_image(si)) {
|
if(soinfo_link_image(si)) {
|
||||||
char errmsg[] = "CANNOT LINK EXECUTABLE\n";
|
char errmsg[] = "CANNOT LINK EXECUTABLE\n";
|
||||||
write(2, __linker_dl_err_buf, strlen(__linker_dl_err_buf));
|
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;
|
map->l_addr = si->base;
|
||||||
soinfo_call_constructors(si);
|
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
|
#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) (
|
||||||
|
@ -160,7 +160,9 @@ 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;
|
Elf32_Addr load_bias;
|
||||||
int has_text_relocations;
|
|
||||||
|
bool has_text_relocations;
|
||||||
|
bool has_DT_SYMBOLIC;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user