diff options
author | Elliott Hughes <enh@google.com> | 2013-05-09 14:19:58 -0700 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2013-05-09 15:29:54 -0700 |
commit | 8147d3c284932896ab6095232b355979b9eb33d3 (patch) | |
tree | 984cfb411636e857e4317e092b8132bcd42b2841 /linker | |
parent | ff220f70036178aa0d7dcf1cbc4825085a84441e (diff) | |
download | bionic-8147d3c284932896ab6095232b355979b9eb33d3.zip bionic-8147d3c284932896ab6095232b355979b9eb33d3.tar.gz bionic-8147d3c284932896ab6095232b355979b9eb33d3.tar.bz2 |
Don't fail to run DT_INIT and DT_INIT_ARRAY constructors if a shared library has DT_PREINIT_ARRAY constructors.
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
Change-Id: I4fd8450ecc44d8767a1cb808aeecfbfbfc77c070
Diffstat (limited to 'linker')
-rw-r--r-- | linker/linker.cpp | 62 |
1 files changed, 24 insertions, 38 deletions
diff --git a/linker/linker.cpp b/linker/linker.cpp index 3ce75f1..c97b712 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); |