The diff below adds support for DT_PREINIT_ARRAY, DT_INIT_ARRAY and
DT_FINI_ARRAY to our ld.so.  The idea is that these tags each point to
a list of function pointers that get executed at initialization and
termination time.  Functions listed by DT_PREINIT_ARRAY get run
immediately after ld.so has finished loading and relocating all shared
objects.  This happens only for the main executable.  DT_INIT_ARRAY
runs immediately after DT_INIT for an object, and DT_FINI_ARRAY
immediately before DT_FINI.  The functions listed by DT_FINI_ARRAY run
in reversed order.

There is a functional change here.  Our current ld.so doesn't run
DT_INIT and DT_FINI for the main executable.  The ELF standard is a
bit ambiguous about this, but Linux does run tose for the main
executable.  And Solaris allegedly does as well.  So my diff changes that.

This stuff is apparently necessary for implementing the official ARM C++ ABI.

Tested on hppa.

ok?


Index: loader.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/loader.c,v
retrieving revision 1.165
diff -u -p -r1.165 loader.c
--- loader.c    14 Aug 2016 04:30:39 -0000      1.165
+++ loader.c    17 Aug 2016 19:05:20 -0000
@@ -73,9 +73,31 @@ struct r_debug *_dl_debug_map;
 void _dl_dopreload(char *paths);
 
 /*
- * Run dtors for all objects that are eligible.
+ * Run dtors for a single object.
  */
+void
+_dl_run_dtors(elf_object_t *obj)
+{
+       if (obj->dyn.fini_array) {
+               int num = obj->dyn.fini_arraysz / sizeof(Elf_Addr);
+               int i;
+
+               DL_DEB(("doing finiarray obj %p @%p: [%s]\n",
+                   obj, obj->dyn.fini, obj->load_name));
+               for (i = num; i > 0; i--)
+                       (*obj->dyn.fini_array[i-1])();
+       }
 
+       if (obj->dyn.fini) {
+               DL_DEB(("doing dtors obj %p @%p: [%s]\n",
+                   obj, obj->dyn.fini, obj->load_name));
+               (*obj->dyn.fini)();
+       }
+}
+
+/*
+ * Run dtors for all objects that are eligible.
+ */
 void
 _dl_run_all_dtors(void)
 {
@@ -91,10 +113,10 @@ _dl_run_all_dtors(void)
 
        while (fini_complete == 0) {
                fini_complete = 1;
-               for (node = _dl_objects->next;
+               for (node = _dl_objects;
                    node != NULL;
                    node = node->next) {
-                       if ((node->dyn.fini) &&
+                       if ((node->dyn.fini || node->dyn.fini_array) &&
                            (OBJECT_REF_CNT(node) == 0) &&
                            (node->status & STAT_INIT_DONE) &&
                            ((node->status & STAT_FINI_DONE) == 0)) {
@@ -105,10 +127,10 @@ _dl_run_all_dtors(void)
                                        node->status |= STAT_FINI_READY;
                            }
                }
-               for (node = _dl_objects->next;
+               for (node = _dl_objects;
                    node != NULL;
                    node = node->next ) {
-                       if ((node->dyn.fini) &&
+                       if ((node->dyn.fini || node->dyn.fini_array) &&
                            (OBJECT_REF_CNT(node) == 0) &&
                            (node->status & STAT_INIT_DONE) &&
                            ((node->status & STAT_FINI_DONE) == 0) &&
@@ -120,18 +142,14 @@ _dl_run_all_dtors(void)
                }
 
 
-               for (node = _dl_objects->next;
+               for (node = _dl_objects;
                    node != NULL;
                    node = node->next ) {
                        if (node->status & STAT_FINI_READY) {
-                               DL_DEB(("doing dtors obj %p @%p: [%s]\n",
-                                   node, node->dyn.fini,
-                                   node->load_name));
-
                                fini_complete = 0;
                                node->status |= STAT_FINI_DONE;
                                node->status &= ~STAT_FINI_READY;
-                               (*node->dyn.fini)();
+                               _dl_run_dtors(node);
                        }
                }
 
@@ -157,11 +175,6 @@ _dl_dtors(void)
 
        DL_DEB(("doing dtors\n"));
 
-       /* main program runs its dtors itself
-        * but we want to run dtors on all it's children);
-        */
-       _dl_objects->status |= STAT_FINI_DONE;
-
        _dl_objects->opencount--;
        _dl_notify_unload_shlib(_dl_objects);
 
@@ -605,16 +618,10 @@ _dl_boot(const char **argv, char **envp,
        _dl_debug_state();
 
        /*
-        * The first object is the executable itself,
-        * it is responsible for running it's own ctors/dtors
-        * thus do NOT run the ctors for the executable, all of
-        * the shared libraries which follow.
         * Do not run init code if run from ldd.
         */
-       if (_dl_objects->next != NULL) {
-               _dl_objects->status |= STAT_INIT_DONE;
+       if (_dl_objects->next != NULL)
                _dl_call_init(_dl_objects);
-       }
 
        DL_DEB(("entry point: 0x%lx\n", dl_data[AUX_entry]));
 
@@ -692,6 +699,16 @@ _dl_rtld(elf_object_t *object)
 void
 _dl_call_init(elf_object_t *object)
 {
+       if (object->dyn.preinit_array) {
+               int num = object->dyn.preinit_arraysz / sizeof(Elf_Addr);
+               int i;
+
+               DL_DEB(("doing preinitarray obj %p @%p: [%s]\n",
+                   object, object->dyn.preinit_array, object->load_name));
+               for (i = 0; i < num; i++)
+                       (*object->dyn.preinit_array[i])();
+       }
+
        _dl_call_init_recurse(object, 1);
        _dl_call_init_recurse(object, 0);
 }
@@ -721,6 +738,16 @@ _dl_call_init_recurse(elf_object_t *obje
                DL_DEB(("doing ctors obj %p @%p: [%s]\n",
                    object, object->dyn.init, object->load_name));
                (*object->dyn.init)();
+       }
+
+       if (object->dyn.init_array) {
+               int num = object->dyn.init_arraysz / sizeof(Elf_Addr);
+               int i;
+
+               DL_DEB(("doing initarray obj %p @%p: [%s]\n",
+                   object, object->dyn.init_array, object->load_name));
+               for (i = 0; i < num; i++)
+                       (*object->dyn.init_array[i])();
        }
 
        object->status |= STAT_INIT_DONE;
Index: resolve.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/resolve.c,v
retrieving revision 1.74
diff -u -p -r1.74 resolve.c
--- resolve.c   8 Aug 2016 21:59:20 -0000       1.74
+++ resolve.c   17 Aug 2016 19:05:20 -0000
@@ -246,6 +246,7 @@ _dl_finalize_object(const char *objname,
     int phdrc, const int objtype, const long lbase, const long obase)
 {
        elf_object_t *object;
+
 #if 0
        _dl_printf("objname [%s], dynp %p, objtype %x lbase %lx, obase %lx\n",
            objname, dynp, objtype, lbase, obase);
@@ -322,6 +323,12 @@ _dl_finalize_object(const char *objname,
                object->Dyn.info[DT_FINI] += obase;
        if (object->Dyn.info[DT_JMPREL])
                object->Dyn.info[DT_JMPREL] += obase;
+       if (object->Dyn.info[DT_INIT_ARRAY])
+               object->Dyn.info[DT_INIT_ARRAY] += obase;
+       if (object->Dyn.info[DT_FINI_ARRAY])
+               object->Dyn.info[DT_FINI_ARRAY] += obase;
+       if (object->Dyn.info[DT_PREINIT_ARRAY])
+               object->Dyn.info[DT_PREINIT_ARRAY] += obase;
 
        if (object->Dyn.info[DT_HASH] != 0) {
                Elf_Word *hashtab = (Elf_Word *)object->Dyn.info[DT_HASH];
Index: resolve.h
===================================================================
RCS file: /cvs/src/libexec/ld.so/resolve.h,v
retrieving revision 1.79
diff -u -p -r1.79 resolve.h
--- resolve.h   8 Aug 2016 21:59:20 -0000       1.79
+++ resolve.h   17 Aug 2016 19:05:20 -0000
@@ -81,13 +81,23 @@ struct elf_object {
                        const char      *soname;
                        const char      *rpath;
                        Elf_Addr        symbolic;
-                       Elf_Rel *rel;
+                       Elf_Rel         *rel;
                        Elf_Addr        relsz;
                        Elf_Addr        relent;
                        Elf_Addr        pltrel;
                        Elf_Addr        debug;
                        Elf_Addr        textrel;
                        Elf_Addr        jmprel;
+                       Elf_Addr        bind_now;
+                       void            (**init_array)(void);
+                       void            (**fini_array)(void);
+                       Elf_Addr        init_arraysz;
+                       Elf_Addr        fini_arraysz;
+                       const char      *runpath;
+                       Elf_Addr        flags;
+                       Elf_Addr        encoding;
+                       void            (**preinit_array)(void);
+                       Elf_Addr        preinit_arraysz;
                } u;
        } Dyn;
 #define dyn Dyn.u

Reply via email to