diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h --- a/libexec/rtld-elf/rtld.h +++ b/libexec/rtld-elf/rtld.h @@ -246,6 +246,7 @@ bool z_nodeflib : 1; /* Don't search default library path */ bool z_global : 1; /* Make the object global */ bool z_pie : 1; /* Object proclaimed itself PIE executable */ + bool z_initfirst : 1; /* Proceed initializers before other objects */ bool static_tls : 1; /* Needs static TLS allocation */ bool static_tls_copied : 1; /* Needs static TLS copying */ bool ref_nodel : 1; /* Refcount increased to prevent dlclose */ diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -1564,6 +1564,8 @@ obj->z_nodeflib = true; if (dynp->d_un.d_val & DF_1_PIE) obj->z_pie = true; + if (dynp->d_un.d_val & DF_1_INITFIRST) + obj->z_initfirst = true; break; default: @@ -2570,25 +2572,55 @@ if (obj->init_scanned || obj->init_done) return; - obj->init_scanned = true; - /* Recursively process the successor objects. */ - nobj = globallist_next(obj); - if (nobj != NULL && obj != tail) - initlist_add_objects(nobj, tail, list); + if (obj->z_initfirst) { + Objlist flist; + Objlist_Entry *tmp; - /* Recursively process the needed objects. */ - if (obj->needed != NULL) - initlist_add_neededs(obj->needed, list); - if (obj->needed_filtees != NULL) - initlist_add_neededs(obj->needed_filtees, list); - if (obj->needed_aux_filtees != NULL) - initlist_add_neededs(obj->needed_aux_filtees, list); + objlist_init(&flist); + /* Recursively process the needed objects. */ + if (obj->needed != NULL) + initlist_add_neededs(obj->needed, &flist); + if (obj->needed_filtees != NULL) + initlist_add_neededs(obj->needed_filtees, &flist); + if (obj->needed_aux_filtees != NULL) + initlist_add_neededs(obj->needed_aux_filtees, &flist); + objlist_push_tail(&flist, obj); - /* Add the object to the init list. */ - objlist_push_tail(list, obj); + /* + * This might result in the same object appearing more + * than once on the init list. objlist_call_init() + * uses obj->init_scanned to avoid dup calls. + */ + STAILQ_REVERSE(&flist, Struct_Objlist_Entry, link); + STAILQ_FOREACH(tmp, &flist, link) + objlist_push_head(list, tmp->obj); - /* Add the object to the global fini list in the reverse order. */ + objlist_clear(&flist); + } else { + obj->init_scanned = true; + + /* Recursively process the successor objects. */ + nobj = globallist_next(obj); + if (nobj != NULL && obj != tail) + initlist_add_objects(nobj, tail, list); + + /* Recursively process the needed objects. */ + if (obj->needed != NULL) + initlist_add_neededs(obj->needed, list); + if (obj->needed_filtees != NULL) + initlist_add_neededs(obj->needed_filtees, list); + if (obj->needed_aux_filtees != NULL) + initlist_add_neededs(obj->needed_aux_filtees, list); + + /* Add the object to the init list. */ + objlist_push_tail(list, obj); + } + + /* + * Add the object to the global fini list in the + * reverse order. + */ if ((obj->fini != (Elf_Addr)NULL || obj->fini_array != (Elf_Addr)NULL) && !obj->on_fini_list) {