Date: Tue, 6 May 2025 17:15:08 GMT From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: 78aaab9f1cf3 - main - rtld: add support for -z initfirst Message-ID: <202505061715.546HF8WB089398@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by kib: URL: https://cgit.FreeBSD.org/src/commit/?id=78aaab9f1cf359f3b7325e4369653f6b50593393 commit 78aaab9f1cf359f3b7325e4369653f6b50593393 Author: Konstantin Belousov <kib@FreeBSD.org> AuthorDate: 2025-05-03 08:14:25 +0000 Commit: Konstantin Belousov <kib@FreeBSD.org> CommitDate: 2025-05-06 17:14:56 +0000 rtld: add support for -z initfirst Internally, initfirst objects and their needed objects are put on the dedicated initlist, which is prepended to the current regular initlist at the last moment. This results in the move of the needed objects into the beginning of the initlist, which is required for the proper initialization of the dependencies. It seems that glibc moves only the initfirst object, which makes its constructors depend on not yet initialized dsos. Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D50132 --- libexec/rtld-elf/rtld.c | 127 ++++++++++++++++++++++++++++++++++++------------ libexec/rtld-elf/rtld.h | 1 + 2 files changed, 97 insertions(+), 31 deletions(-) diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 0575ce19d476..12aee444fccf 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -112,8 +112,11 @@ static void init_dag(Obj_Entry *); static void init_marker(Obj_Entry *); static void init_pagesizes(Elf_Auxinfo **aux_info); static void init_rtld(caddr_t, Elf_Auxinfo **); -static void initlist_add_neededs(Needed_Entry *, Objlist *); -static void initlist_add_objects(Obj_Entry *, Obj_Entry *, Objlist *); +static void initlist_add_neededs(Needed_Entry *, Objlist *, Objlist *); +static void initlist_add_objects(Obj_Entry *, Obj_Entry *, Objlist *, + Objlist *); +static void initlist_for_loaded_obj(Obj_Entry *obj, Obj_Entry *tail, + Objlist *list); static int initlist_objects_ifunc(Objlist *, bool, int, RtldLockState *); static void linkmap_add(Obj_Entry *); static void linkmap_delete(Obj_Entry *); @@ -952,7 +955,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) /* Make a list of init functions to call. */ objlist_init(&initlist); - initlist_add_objects(globallist_curr(TAILQ_FIRST(&obj_list)), + initlist_for_loaded_obj(globallist_curr(TAILQ_FIRST(&obj_list)), preload_tail, &initlist); r_debug_state(NULL, &obj_main->linkmap); /* say hello to gdb! */ @@ -1564,6 +1567,8 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath, 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: @@ -2543,15 +2548,15 @@ init_pagesizes(Elf_Auxinfo **aux_info) * when this function is called. */ static void -initlist_add_neededs(Needed_Entry *needed, Objlist *list) +initlist_add_neededs(Needed_Entry *needed, Objlist *list, Objlist *iflist) { /* Recursively process the successor needed objects. */ if (needed->next != NULL) - initlist_add_neededs(needed->next, list); + initlist_add_neededs(needed->next, list, iflist); /* Process the current needed object. */ if (needed->obj != NULL) - initlist_add_objects(needed->obj, needed->obj, list); + initlist_add_objects(needed->obj, needed->obj, list, iflist); } /* @@ -2564,36 +2569,96 @@ initlist_add_neededs(Needed_Entry *needed, Objlist *list) * held when this function is called. */ static void -initlist_add_objects(Obj_Entry *obj, Obj_Entry *tail, Objlist *list) +initlist_for_loaded_obj(Obj_Entry *obj, Obj_Entry *tail, Objlist *list) { - Obj_Entry *nobj; + Objlist iflist; /* initfirst objs and their needed */ + Objlist_Entry *tmp; - if (obj->init_scanned || obj->init_done) - return; - obj->init_scanned = true; + objlist_init(&iflist); + initlist_add_objects(obj, tail, list, &iflist); - /* Recursively process the successor objects. */ - nobj = globallist_next(obj); - if (nobj != NULL && obj != tail) - initlist_add_objects(nobj, tail, list); + STAILQ_FOREACH(tmp, &iflist, link) { + Obj_Entry *tobj = tmp->obj; - /* 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); + if ((tobj->fini != (Elf_Addr)NULL || + tobj->fini_array != (Elf_Addr)NULL) && + !tobj->on_fini_list) { + objlist_push_tail(&list_fini, tobj); + tobj->on_fini_list = true; + } + } - /* 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(&iflist, Struct_Objlist_Entry, link); + STAILQ_FOREACH(tmp, &iflist, link) + objlist_push_head(list, tmp->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) { - objlist_push_head(&list_fini, obj); - obj->on_fini_list = true; + objlist_clear(&iflist); +} + +static void +initlist_add_objects(Obj_Entry *obj, Obj_Entry *tail, Objlist *list, + Objlist *iflist) +{ + Obj_Entry *nobj; + + if (obj->init_done) + return; + + if (obj->z_initfirst || list == NULL) { + /* + * Ignore obj->init_scanned. The object might indeed + * already be on the init list, but due to being + * needed by an initfirst object, we must put it at + * the head of the init list. obj->init_done protects + * against double-initialization. + */ + if (obj->needed != NULL) + initlist_add_neededs(obj->needed, NULL, iflist); + if (obj->needed_filtees != NULL) + initlist_add_neededs(obj->needed_filtees, NULL, + iflist); + if (obj->needed_aux_filtees != NULL) + initlist_add_neededs(obj->needed_aux_filtees, + NULL, iflist); + objlist_push_tail(iflist, obj); + } else { + if (obj->init_scanned) + 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, iflist); + + /* Recursively process the needed objects. */ + if (obj->needed != NULL) + initlist_add_neededs(obj->needed, list, iflist); + if (obj->needed_filtees != NULL) + initlist_add_neededs(obj->needed_filtees, list, + iflist); + if (obj->needed_aux_filtees != NULL) + initlist_add_neededs(obj->needed_aux_filtees, list, + iflist); + + /* 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) { + objlist_push_head(&list_fini, obj); + obj->on_fini_list = true; + } } } @@ -3863,7 +3928,7 @@ dlopen_object(const char *name, int fd, Obj_Entry *refobj, int lo_flags, */ } else { /* Make list of init functions to call. */ - initlist_add_objects(obj, obj, &initlist); + initlist_for_loaded_obj(obj, obj, &initlist); } /* * Process all no_delete or global objects here, given diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h index 383b8db2114c..d1ea00b96627 100644 --- a/libexec/rtld-elf/rtld.h +++ b/libexec/rtld-elf/rtld.h @@ -246,6 +246,7 @@ typedef struct Struct_Obj_Entry { 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 */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202505061715.546HF8WB089398>