Merge "linker: handle R_ARM_COPY relocations in a proper way"
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index c77b9a3..c87d29a 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -236,5 +236,7 @@
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,
};
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 4c52f3d..9e4138e 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -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 *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 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 @@
* 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 *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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
* 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 @@
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 @@
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 @@
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) (
diff --git a/linker/linker.h b/linker/linker.h
index 54563bb..cb33602 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -160,7 +160,9 @@
/* 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;
};