Support -z initfirst for multiple shared libraries
Commit Message
Apologies, I renamed `node' to `new_node' at the last moment and broke
the patch. It should be easy to figure out, but here's a fixed version.
----[ cut here ]----
Support -z initfirst for multiple shared libraries (run in load order).
This is particularly useful when combined with LD_PRELOAD, as it is then
possible to run constructors before any code in other libraries runs.
---
elf/dl-init.c | 9 ++++++++-
elf/dl-load.c | 19 ++++++++++++++++++-
elf/dl-support.c | 4 ++--
sysdeps/generic/ldsodefs.h | 7 +++++--
4 files changed, 33 insertions(+), 6 deletions(-)
@@ -84,7 +84,14 @@ _dl_init (struct link_map *main_map, int argc, char
**argv, char **env)
if (__glibc_unlikely (GL(dl_initfirst) != NULL))
{
- call_init (GL(dl_initfirst), argc, argv, env);
+ struct initfirst_list *initfirst;
+ for(initfirst = GL(dl_initfirst); initfirst; initfirst = initfirst->next)
+ {
+ call_init (initfirst->which, argc, argv, env);
+ }
+
+ /* We do not try to free this list, as the memory will not be reclaimed
+ by the allocator unless there were no intervening malloc()'s. */
GL(dl_initfirst) = NULL;
}
@@ -1388,7 +1388,24 @@ cannot enable executable stack as shared object
requires");
/* Remember whether this object must be initialized first. */
if (l->l_flags_1 & DF_1_INITFIRST)
- GL(dl_initfirst) = l;
+ {
+ struct initfirst_list *new_node = malloc(sizeof(*new_node));
+ struct initfirst_list *it = GL(dl_initfirst);
+ new_node->which = l;
+ new_node->next = NULL;
+
+ /* We append to the end of the linked list. Whichever library was loaded
+ first has higher initfirst priority. This means that LD_PRELOAD
+ initfirst overrides initfirst in libraries linked normally. */
+ if (!it)
+ GL(dl_initfirst) = new_node;
+ else
+ {
+ while (it->next)
+ it = it->next;
+ it->next = new_node;
+ }
+ }
/* Finally the file information. */
l->l_file_id = id;
@@ -147,8 +147,8 @@ struct r_search_path_elem *_dl_all_dirs;
/* All directories after startup. */
struct r_search_path_elem *_dl_init_all_dirs;
-/* The object to be initialized first. */
-struct link_map *_dl_initfirst;
+/* The list of objects to be initialized first. */
+struct initfirst_list *_dl_initfirst;
/* Descriptor to write debug messages to. */
int _dl_debug_fd = STDERR_FILENO;
@@ -326,8 +326,11 @@ struct rtld_global
/* Incremented whenever something may have been added to dl_loaded. */
EXTERN unsigned long long _dl_load_adds;
- /* The object to be initialized first. */
- EXTERN struct link_map *_dl_initfirst;
+ /* The list of objects to be initialized first. */
+ EXTERN struct initfirst_list {
+ struct link_map *which;
+ struct initfirst_list *next;
+ } *_dl_initfirst;
#if HP_SMALL_TIMING_AVAIL
/* Start time on CPU clock. */