git: f31acb9d5cb2 - stable/14 - rtld: add support for -z initfirst
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 10 May 2025 19:33:12 UTC
The branch stable/14 has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=f31acb9d5cb25678cb497cb28bc466442b99239f
commit f31acb9d5cb25678cb497cb28bc466442b99239f
Author: Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2025-05-03 08:14:25 +0000
Commit: Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2025-05-10 18:57:46 +0000
rtld: add support for -z initfirst
(cherry picked from commit 78aaab9f1cf359f3b7325e4369653f6b50593393)
---
libexec/rtld-elf/rtld.c | 138 +++++++++++++++++++++++++++++++++++-------------
libexec/rtld-elf/rtld.h | 1 +
2 files changed, 103 insertions(+), 36 deletions(-)
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index ba8e2aea6e7c..8a3129093e8c 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -114,8 +114,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 *);
@@ -932,8 +935,8 @@ _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)),
- preload_tail, &initlist);
+ initlist_for_loaded_obj(globallist_curr(TAILQ_FIRST(&obj_list)),
+ preload_tail, &initlist);
r_debug_state(NULL, &obj_main->linkmap); /* say hello to gdb! */
@@ -1510,6 +1513,8 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath,
obj->bind_now = true;
if (dynp->d_un.d_val & DF_STATIC_TLS)
obj->static_tls = true;
+ if (dynp->d_un.d_val & DF_1_INITFIRST)
+ obj->z_initfirst = true;
break;
#ifdef __powerpc__
@@ -2518,15 +2523,15 @@ psa_filled:
* 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);
}
/*
@@ -2539,36 +2544,97 @@ 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;
-
- /* 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) {
- objlist_push_head(&list_fini, obj);
- obj->on_fini_list = true;
- }
+ objlist_init(&iflist);
+ initlist_add_objects(obj, tail, list, &iflist);
+
+ STAILQ_FOREACH(tmp, &iflist, link) {
+ Obj_Entry *tobj = tmp->obj;
+
+ 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;
+ }
+ }
+
+ /*
+ * 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);
+
+ 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;
+ }
+ }
}
static void
@@ -3824,7 +3890,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 97187b24ce84..8d0b8bfed2ab 100644
--- a/libexec/rtld-elf/rtld.h
+++ b/libexec/rtld-elf/rtld.h
@@ -256,6 +256,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 */