Implement support for DT_INIT_ARRAY, DT_FINI_ARRAY and DT_PREINIT_ARRAY.
authorkettenis <kettenis@openbsd.org>
Tue, 23 Aug 2016 06:46:17 +0000 (06:46 +0000)
committerkettenis <kettenis@openbsd.org>
Tue, 23 Aug 2016 06:46:17 +0000 (06:46 +0000)
Don't skip DT_INIT and DT_FINI for the main executable.  This matches what
Linux and Solaris do.

ok guenther@

libexec/ld.so/loader.c
libexec/ld.so/resolve.c
libexec/ld.so/resolve.h
sys/sys/exec_elf.h

index 6fcff3d..b85db85 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: loader.c,v 1.165 2016/08/14 04:30:39 guenther Exp $ */
+/*     $OpenBSD: loader.c,v 1.166 2016/08/23 06:46:17 kettenis Exp $ */
 
 /*
  * Copyright (c) 1998 Per Fogelstrom, Opsycon AB
@@ -53,6 +53,7 @@ void _dl_debug_state(void);
 void _dl_setup_env(const char *_argv0, char **_envp);
 void _dl_dtors(void);
 void _dl_fixup_user_env(void);
+void _dl_call_preinit(elf_object_t *);
 void _dl_call_init_recurse(elf_object_t *object, int initfirst);
 
 int  _dl_pagesz;
@@ -73,9 +74,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_array, 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 +114,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 +128,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 +143,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 +176,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,14 +619,10 @@ _dl_boot(const char **argv, char **envp, const long dyn_loff, long *dl_data)
        _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;
+               _dl_call_preinit(_dl_objects);
                _dl_call_init(_dl_objects);
        }
 
@@ -689,6 +699,20 @@ _dl_rtld(elf_object_t *object)
        return (fails);
 }
 
+void
+_dl_call_preinit(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])();
+       }
+}
+
 void
 _dl_call_init(elf_object_t *object)
 {
@@ -723,6 +747,16 @@ _dl_call_init_recurse(elf_object_t *object, int initfirst)
                (*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 dc384c7..02d9683 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: resolve.c,v 1.74 2016/08/08 21:59:20 guenther Exp $ */
+/*     $OpenBSD: resolve.c,v 1.75 2016/08/23 06:46:17 kettenis Exp $ */
 
 /*
  * Copyright (c) 1998 Per Fogelstrom, Opsycon AB
@@ -246,6 +246,7 @@ _dl_finalize_object(const char *objname, Elf_Dyn *dynp, Elf_Phdr *phdrp,
     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, Elf_Dyn *dynp, Elf_Phdr *phdrp,
                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 df0469c..24dbef6 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: resolve.h,v 1.79 2016/08/08 21:59:20 guenther Exp $ */
+/*     $OpenBSD: resolve.h,v 1.80 2016/08/23 06:46:17 kettenis Exp $ */
 
 /*
  * Copyright (c) 1998 Per Fogelstrom, Opsycon AB
@@ -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
index f1c5d48..f3186e6 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: exec_elf.h,v 1.59 2016/07/14 06:03:46 guenther Exp $  */
+/*     $OpenBSD: exec_elf.h,v 1.60 2016/08/23 06:46:17 kettenis Exp $  */
 /*
  * Copyright (c) 1995, 1996 Erik Theisen.  All rights reserved.
  *
@@ -526,7 +526,7 @@ typedef struct {
 #define DF_1_CONLFAT   0x00002000
 
 /* ld.so: number of low tags that are used saved internally (0 .. DT_NUM-1) */
-#define DT_NUM         (DT_JMPREL+1)
+#define DT_NUM         (DT_PREINIT_ARRAYSZ+1)
 
 /* Standard ELF hashing function */
 unsigned int elf_hash(const unsigned char *name);