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 (cherry picked from commit 8147d3c284932896ab6095232b355979b9eb33d3) Change-Id: Iad8e7e3743d1a5e6bd1d44ef40b1ab3499cb64f2
This commit is contained in:
parent
262b7384e4
commit
738370d938
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user