Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/libexec/ld.elf_so Add .init_array/.fini_array support (condi...



details:   https://anonhg.NetBSD.org/src/rev/aa8833abc32c
branches:  trunk
changeset: 781009:aa8833abc32c
user:      matt <matt%NetBSD.org@localhost>
date:      Wed Aug 15 03:46:06 2012 +0000

description:
Add .init_array/.fini_array support (conditionalized on HAVE_INITFINI_ARRAY).

diffstat:

 libexec/ld.elf_so/arch/arm/Makefile.inc |    5 +-
 libexec/ld.elf_so/headers.c             |   26 ++++-
 libexec/ld.elf_so/rtld.c                |  164 +++++++++++++++++++------------
 libexec/ld.elf_so/rtld.h                |   15 ++-
 libexec/ld.elf_so/symbol.c              |    6 +-
 5 files changed, 140 insertions(+), 76 deletions(-)

diffs (truncated from 376 to 300 lines):

diff -r 1d06ac4ca23a -r aa8833abc32c libexec/ld.elf_so/arch/arm/Makefile.inc
--- a/libexec/ld.elf_so/arch/arm/Makefile.inc   Wed Aug 15 01:03:16 2012 +0000
+++ b/libexec/ld.elf_so/arch/arm/Makefile.inc   Wed Aug 15 03:46:06 2012 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: Makefile.inc,v 1.11 2005/06/04 16:17:17 lukem Exp $
+#      $NetBSD: Makefile.inc,v 1.12 2012/08/15 03:46:07 matt Exp $
 
 SRCS+=         rtld_start.S mdreloc.c
 
@@ -6,5 +6,8 @@
 CPPFLAGS+=     -fpic
 
 CPPFLAGS+=     -DELFSIZE=32
+.if ${MACHINE_ARCH} == "earm" || ${MACHINE_ARCH} == "earmeb"
+CPPFLAGS+=     -DHAVE_INITFINI_ARRAY
+.endif
 
 LDFLAGS+=      -Wl,-e,_rtld_start
diff -r 1d06ac4ca23a -r aa8833abc32c libexec/ld.elf_so/headers.c
--- a/libexec/ld.elf_so/headers.c       Wed Aug 15 01:03:16 2012 +0000
+++ b/libexec/ld.elf_so/headers.c       Wed Aug 15 03:46:06 2012 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: headers.c,v 1.42 2012/07/22 09:16:35 martin Exp $       */
+/*     $NetBSD: headers.c,v 1.43 2012/08/15 03:46:06 matt Exp $         */
 
 /*
  * Copyright 1996 John D. Polstra.
@@ -40,7 +40,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: headers.c,v 1.42 2012/07/22 09:16:35 martin Exp $");
+__RCSID("$NetBSD: headers.c,v 1.43 2012/08/15 03:46:06 matt Exp $");
 #endif /* not lint */
 
 #include <err.h>
@@ -227,10 +227,32 @@
                        init = dynp->d_un.d_ptr;
                        break;
 
+#ifdef HAVE_INITFINI_ARRAY
+               case DT_INIT_ARRAY:
+                       obj->init_array =
+                           (fptr_t *)(obj->relocbase + dynp->d_un.d_ptr);
+                       break;
+
+               case DT_INIT_ARRAYSZ:
+                       obj->init_arraysz = dynp->d_un.d_val / sizeof(fptr_t);
+                       break;
+#endif
+
                case DT_FINI:
                        fini = dynp->d_un.d_ptr;
                        break;
 
+#ifdef HAVE_INITFINI_ARRAY
+               case DT_FINI_ARRAY:
+                       obj->fini_array =
+                           (fptr_t *)(obj->relocbase + dynp->d_un.d_ptr);
+                       break;
+
+               case DT_FINI_ARRAYSZ:
+                       obj->fini_arraysz = dynp->d_un.d_val / sizeof(fptr_t); 
+                       break;
+#endif
+
                /*
                 * Don't process DT_DEBUG on MIPS as the dynamic section
                 * is mapped read-only. DT_MIPS_RLD_MAP is used instead.
diff -r 1d06ac4ca23a -r aa8833abc32c libexec/ld.elf_so/rtld.c
--- a/libexec/ld.elf_so/rtld.c  Wed Aug 15 01:03:16 2012 +0000
+++ b/libexec/ld.elf_so/rtld.c  Wed Aug 15 03:46:06 2012 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: rtld.c,v 1.157 2012/03/13 21:00:31 joerg Exp $  */
+/*     $NetBSD: rtld.c,v 1.158 2012/08/15 03:46:06 matt Exp $   */
 
 /*
  * Copyright 1996 John D. Polstra.
@@ -40,7 +40,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: rtld.c,v 1.157 2012/03/13 21:00:31 joerg Exp $");
+__RCSID("$NetBSD: rtld.c,v 1.158 2012/08/15 03:46:06 matt Exp $");
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -135,13 +135,50 @@
 static void _rtld_unref_dag(Obj_Entry *);
 static Obj_Entry *_rtld_obj_from_addr(const void *);
 
+static inline void
+_rtld_call_initfini_function(fptr_t func, sigset_t *mask)
+{
+       _rtld_exclusive_exit(mask);
+       (*func)();
+       _rtld_exclusive_enter(mask);
+}
+
+static void
+_rtld_call_fini_function(Obj_Entry *obj, sigset_t *mask, u_int cur_objgen)
+{
+       if (obj->fini_arraysz == 0 && (obj->fini == NULL || obj->fini_called)) {
+                       return;
+       }
+       if (obj->fini != NULL && !obj->fini_called) {
+               dbg (("calling fini function %s at %p%s", obj->path,
+                   (void *)obj->fini,
+                   obj->z_initfirst ? " (DF_1_INITFIRST)" : ""));
+               obj->fini_called = 1; 
+               _rtld_call_initfini_function(obj->fini, mask);
+       }
+#ifdef HAVE_INITFINI_ARRAY
+       /*
+        * Now process the fini_array if it exists.  Simply go from
+        * start to end.  We need to make restartable so just advance
+        * the array pointer and decrement the size each time through
+        * the loop.
+        */
+       while (obj->fini_arraysz > 0 && _rtld_objgen == cur_objgen) {
+               fptr_t fini = *obj->fini_array++;
+               obj->fini_arraysz--;
+               dbg (("calling fini array function %s at %p%s", obj->path,
+                   (void *)fini,
+                   obj->z_initfirst ? " (DF_1_INITFIRST)" : ""));
+               _rtld_call_initfini_function(fini, mask);
+       }
+#endif /* HAVE_INITFINI_ARRAY */
+}
+
 static void
 _rtld_call_fini_functions(sigset_t *mask, int force)
 {
        Objlist_Entry *elm;
        Objlist finilist;
-       Obj_Entry *obj;
-       void (*fini)(void);
        u_int cur_objgen;
 
        dbg(("_rtld_call_fini_functions(%d)", force));
@@ -153,49 +190,33 @@
 
        /* First pass: objects _not_ marked with DF_1_INITFIRST. */
        SIMPLEQ_FOREACH(elm, &finilist, link) {
-               obj = elm->obj;
-               if (obj->refcount > 0 && !force) {
-                       continue;
-               }
-               if (obj->fini == NULL || obj->fini_called || obj->z_initfirst) {
-                       continue;
+               Obj_Entry * const obj = elm->obj;
+               if (!obj->z_initfirst) {
+                       if (obj->refcount > 0 && !force) {
+                               continue;
+                       }
+                       /*
+                        * XXX This can race against a concurrent dlclose().
+                        * XXX In that case, the object could be unmapped before
+                        * XXX the fini() call or the fini_array has completed.
+                        */
+                       _rtld_call_fini_function(obj, mask, cur_objgen);
+                       if (_rtld_objgen != cur_objgen) {
+                               dbg(("restarting fini iteration"));
+                               _rtld_objlist_clear(&finilist);
+                               goto restart;
                }
-               dbg (("calling fini function %s at %p",  obj->path,
-                   (void *)obj->fini));
-               obj->fini_called = 1;
-               /*
-                * XXX This can race against a concurrent dlclose().
-                * XXX In that case, the object could be unmapped before
-                * XXX the fini() call is done.
-                */
-               fini = obj->fini;
-               _rtld_exclusive_exit(mask);
-               (*fini)();
-               _rtld_exclusive_enter(mask);
-               if (_rtld_objgen != cur_objgen) {
-                       dbg(("restarting fini iteration"));
-                       _rtld_objlist_clear(&finilist);
-                       goto restart;
                }
        }
 
        /* Second pass: objects marked with DF_1_INITFIRST. */
        SIMPLEQ_FOREACH(elm, &finilist, link) {
-               obj = elm->obj;
+               Obj_Entry * const obj = elm->obj;
                if (obj->refcount > 0 && !force) {
                        continue;
                }
-               if (obj->fini == NULL || obj->fini_called) {
-                       continue;
-               }
-               dbg (("calling fini function %s at %p (DF_1_INITFIRST)",
-                   obj->path, (void *)obj->fini));
-               obj->fini_called = 1;
                /* XXX See above for the race condition here */
-               fini = obj->fini;
-               _rtld_exclusive_exit(mask);
-               (*fini)();
-               _rtld_exclusive_enter(mask);
+               _rtld_call_fini_function(obj, mask, cur_objgen);
                if (_rtld_objgen != cur_objgen) {
                        dbg(("restarting fini iteration"));
                        _rtld_objlist_clear(&finilist);
@@ -207,12 +228,42 @@
 }
 
 static void
+_rtld_call_init_function(Obj_Entry *obj, sigset_t *mask, u_int cur_objgen)
+{
+       if (obj->init_arraysz == 0 && (obj->init_called || obj->init == NULL)) {
+               return;
+       }
+       if (!obj->init_called && obj->init != NULL) {
+               dbg (("calling init function %s at %p%s",
+                   obj->path, (void *)obj->init,
+                   obj->z_initfirst ? " (DF_1_INITFIRST)" : ""));
+               obj->init_called = 1;
+               _rtld_call_initfini_function(obj->init, mask);
+       }
+
+#ifdef HAVE_INITFINI_ARRAY
+       /*
+        * Now process the init_array if it exists.  Simply go from
+        * start to end.  We need to make restartable so just advance
+        * the array pointer and decrement the size each time through
+        * the loop.
+        */
+       while (obj->init_arraysz > 0 && _rtld_objgen == cur_objgen) {
+               fptr_t init = *obj->init_array++;
+               obj->init_arraysz--;
+               dbg (("calling init_array function %s at %p%s",
+                   obj->path, (void *)init,
+                   obj->z_initfirst ? " (DF_1_INITFIRST)" : ""));
+               _rtld_call_initfini_function(init, mask);
+       }
+#endif /* HAVE_INITFINI_ARRAY */
+}
+
+static void
 _rtld_call_init_functions(sigset_t *mask)
 {
        Objlist_Entry *elm;
        Objlist initlist;
-       Obj_Entry *obj;
-       void (*init)(void);
        u_int cur_objgen;
 
        dbg(("_rtld_call_init_functions()"));
@@ -224,37 +275,20 @@
 
        /* First pass: objects marked with DF_1_INITFIRST. */
        SIMPLEQ_FOREACH(elm, &initlist, link) {
-               obj = elm->obj;
-               if (obj->init == NULL || obj->init_called || !obj->z_initfirst) {
-                       continue;
-               }
-               dbg (("calling init function %s at %p (DF_1_INITFIRST)",
-                   obj->path, (void *)obj->init));
-               obj->init_called = 1;
-               init = obj->init;
-               _rtld_exclusive_exit(mask);
-               (*init)();
-               _rtld_exclusive_enter(mask);
-               if (_rtld_objgen != cur_objgen) {
-                       dbg(("restarting init iteration"));
-                       _rtld_objlist_clear(&initlist);
-                       goto restart;
+               Obj_Entry * const obj = elm->obj;
+               if (obj->z_initfirst) {
+                       _rtld_call_init_function(obj, mask, cur_objgen);
+                       if (_rtld_objgen != cur_objgen) {
+                               dbg(("restarting init iteration"));
+                               _rtld_objlist_clear(&initlist);
+                               goto restart;
+                       }
                }
        }
 
        /* Second pass: all other objects. */
        SIMPLEQ_FOREACH(elm, &initlist, link) {
-               obj = elm->obj;
-               if (obj->init == NULL || obj->init_called) {
-                       continue;
-               }
-               dbg (("calling init function %s at %p",  obj->path,
-                   (void *)obj->init));
-               obj->init_called = 1;
-               init = obj->init;
-               _rtld_exclusive_exit(mask);
-               (*init)();
-               _rtld_exclusive_enter(mask);
+               _rtld_call_init_function(elm->obj, mask, cur_objgen);
                if (_rtld_objgen != cur_objgen) {
                        dbg(("restarting init iteration"));
                        _rtld_objlist_clear(&initlist);
diff -r 1d06ac4ca23a -r aa8833abc32c libexec/ld.elf_so/rtld.h



Home | Main Index | Thread Index | Old Index