aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2013-05-09 14:19:58 -0700
committerElliott Hughes <enh@google.com>2013-05-09 15:53:30 -0700
commit738370d9387396922c10910edb61272e585be107 (patch)
tree9a7b02a86a5e1270c1f74340914474e2d889bf4f
parent262b7384e4e691d42070a57472ecc64cf668c480 (diff)
downloadbionic-android-4.3.1_r1.tar.gz
Don't fail to run DT_INIT and DT_INIT_ARRAY constructors if a shared library has DT_PREINIT_ARRAY constructors.android-4.3_r3.1android-4.3_r3android-4.3.1_r1jb-mr2.0.0-release
The GNU dynamic linker silently ignores a DT_PREINIT_ARRAY section in a shared library. We had ineffectual code that tried to report an error, which I tried to fix but got wrong --- my version still wouldn't report the error to the caller, but would prevent us from continuing to call constructors. Bug: 8825226 (cherry picked from commit 8147d3c284932896ab6095232b355979b9eb33d3) Change-Id: Iad8e7e3743d1a5e6bd1d44ef40b1ab3499cb64f2
-rw-r--r--linker/linker.cpp62
1 files changed, 24 insertions, 38 deletions
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 47c45eb0b..7c5165b0d 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -801,14 +801,8 @@ static int soinfo_unload(soinfo* si) {
for (Elf32_Dyn* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
if (d->d_tag == DT_NEEDED) {
const char* library_name = si->strtab + d->d_un.d_val;
- soinfo* lsi = find_loaded_library(library_name);
- if (lsi != NULL) {
- TRACE("%s needs to unload %s", si->name, lsi->name);
- soinfo_unload(lsi);
- } else {
- // TODO: should we return -1 in this case?
- DL_ERR("\"%s\": could not unload dependent library", si->name);
- }
+ TRACE("%s needs to unload %s", si->name, library_name);
+ soinfo_unload(find_loaded_library(library_name));
}
}
@@ -1161,21 +1155,6 @@ static int mips_relocate_got(soinfo* si, soinfo* needed[]) {
}
#endif
-/* Please read the "Initialization and Termination functions" functions.
- * of the linker design note in bionic/linker/README.TXT to understand
- * what the following code is doing.
- *
- * The important things to remember are:
- *
- * DT_PREINIT_ARRAY must be called first for executables, and should
- * not appear in shared libraries.
- *
- * DT_INIT should be called before DT_INIT_ARRAY if both are present
- *
- * DT_FINI should be called after DT_FINI_ARRAY if both are present
- *
- * DT_FINI_ARRAY must be parsed in reverse order.
- */
void soinfo::CallArray(const char* array_name UNUSED, linker_function_t* functions, size_t count, bool reverse) {
if (functions == NULL) {
return;
@@ -1210,6 +1189,8 @@ void soinfo::CallFunction(const char* function_name UNUSED, linker_function_t fu
}
void soinfo::CallPreInitConstructors() {
+ // DT_PREINIT_ARRAY functions are called before any other constructors for executables,
+ // but ignored in a shared library.
CallArray("DT_PREINIT_ARRAY", preinit_array, preinit_array_count, false);
}
@@ -1230,31 +1211,36 @@ void soinfo::CallConstructors() {
// out above, the libc constructor will be called again (recursively!).
constructors_called = true;
- if (!(flags & FLAG_EXE) && preinit_array) {
- DL_ERR("shared library \"%s\" has a preinit_array table @ %p", name, preinit_array);
- return;
+ if ((flags & FLAG_EXE) == 0 && preinit_array != NULL) {
+ // The GNU dynamic linker silently ignores these, but we warn the developer.
+ PRINT("\"%s\": ignoring %d-entry DT_PREINIT_ARRAY in shared library!",
+ name, preinit_array_count);
}
if (dynamic != NULL) {
for (Elf32_Dyn* d = dynamic; d->d_tag != DT_NULL; ++d) {
if (d->d_tag == DT_NEEDED) {
const char* library_name = strtab + d->d_un.d_val;
- soinfo* lsi = find_loaded_library(library_name);
- if (lsi == NULL) {
- DL_ERR("\"%s\": could not initialize dependent library", name);
- } else {
- lsi->CallConstructors();
- }
+ TRACE("\"%s\": calling constructors in DT_NEEDED \"%s\"", name, library_name);
+ find_loaded_library(library_name)->CallConstructors();
}
}
}
+ TRACE("\"%s\": calling constructors", name);
+
+ // DT_INIT should be called before DT_INIT_ARRAY if both are present.
CallFunction("DT_INIT", init_func);
CallArray("DT_INIT_ARRAY", init_array, init_array_count, false);
}
void soinfo::CallDestructors() {
+ TRACE("\"%s\": calling destructors", name);
+
+ // DT_FINI_ARRAY must be parsed in reverse order.
CallArray("DT_FINI_ARRAY", fini_array, fini_array_count, true);
+
+ // DT_FINI should be called after DT_FINI_ARRAY if both are present.
CallFunction("DT_FINI", fini_func);
}
@@ -1353,7 +1339,7 @@ static bool soinfo_link_image(soinfo* si) {
&si->ARM_exidx, &si->ARM_exidx_count);
#endif
- /* extract useful information from dynamic section */
+ // Extract useful information from dynamic section.
uint32_t needed_count = 0;
for (Elf32_Dyn* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
DEBUG("d = %p, d[0](tag) = 0x%08x d[1](val) = 0x%08x", d, d->d_tag, d->d_un.d_val);
@@ -1404,29 +1390,29 @@ static bool soinfo_link_image(soinfo* si) {
return false;
case DT_INIT:
si->init_func = reinterpret_cast<linker_function_t>(base + d->d_un.d_ptr);
- DEBUG("%s constructors (init func) found at %p", si->name, si->init_func);
+ DEBUG("%s constructors (DT_INIT) found at %p", si->name, si->init_func);
break;
case DT_FINI:
si->fini_func = reinterpret_cast<linker_function_t>(base + d->d_un.d_ptr);
- DEBUG("%s destructors (fini func) found at %p", si->name, si->fini_func);
+ DEBUG("%s destructors (DT_FINI) found at %p", si->name, si->fini_func);
break;
case DT_INIT_ARRAY:
si->init_array = reinterpret_cast<linker_function_t*>(base + d->d_un.d_ptr);
- DEBUG("%s constructors (init_array) found at %p", si->name, si->init_array);
+ DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", si->name, si->init_array);
break;
case DT_INIT_ARRAYSZ:
si->init_array_count = ((unsigned)d->d_un.d_val) / sizeof(Elf32_Addr);
break;
case DT_FINI_ARRAY:
si->fini_array = reinterpret_cast<linker_function_t*>(base + d->d_un.d_ptr);
- DEBUG("%s destructors (fini_array) found at %p", si->name, si->fini_array);
+ DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", si->name, si->fini_array);
break;
case DT_FINI_ARRAYSZ:
si->fini_array_count = ((unsigned)d->d_un.d_val) / sizeof(Elf32_Addr);
break;
case DT_PREINIT_ARRAY:
si->preinit_array = reinterpret_cast<linker_function_t*>(base + d->d_un.d_ptr);
- DEBUG("%s constructors (preinit_array) found at %p", si->name, si->preinit_array);
+ DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", si->name, si->preinit_array);
break;
case DT_PREINIT_ARRAYSZ:
si->preinit_array_count = ((unsigned)d->d_un.d_val) / sizeof(Elf32_Addr);