Sort objects before relocations
authorUlrich Drepper <drepper@gmail.com>
Fri, 27 Jan 2012 20:05:19 +0000 (15:05 -0500)
committerUlrich Drepper <drepper@gmail.com>
Fri, 27 Jan 2012 20:05:19 +0000 (15:05 -0500)
ChangeLog
Makeconfig
NEWS
elf/Makefile
elf/dl-open.c
elf/tst-relsort1.c [new file with mode: 0644]
elf/tst-relsort1mod1.c [new file with mode: 0644]
elf/tst-relsort1mod2.c [new file with mode: 0644]

index 24c9550..2efe17a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2012-01-27  Ulrich Drepper  <drepper@gmail.com>
+
+       [BZ #13618]
+       * elf/dl-open.c (dl_open_worker): Sort objects by dependency before
+       relocation.
+       * Makeconfig (libm): Define.
+       * elf/Makefile: Add rules to build and run tst-relsort1.
+       * elf/tst-relsort1.c: New file.
+       * elf/tst-relsort1mod1.c: New file.
+       * elf/tst-relsort1mod2.c: New file.
+
 2012-01-26  Joseph Myers  <joseph@codesourcery.com>
 
        * crypt/md5.h: Remove __STDC__ conditionals.
index 2db2821..68547b2 100644 (file)
@@ -900,6 +900,12 @@ else
 libdl = $(common-objpfx)dlfcn/libdl.a
 endif
 
+ifeq ($(build-shared),yes)
+libm = $(common-objpfx)math/libm.so$(libm.so-version)
+else
+libm = $(common-objpfx)math/libm.a
+endif
+
 # These are the subdirectories containing the library source.  The order
 # is more or less arbitrary.  The sorting step will take care of the
 # dependencies.
diff --git a/NEWS b/NEWS
index 42e09c1..3b502b7 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-GNU C Library NEWS -- history of user-visible changes.  2012-1-26
+GNU C Library NEWS -- history of user-visible changes.  2012-1-27
 Copyright (C) 1992-2009, 2010, 2011, 2012 Free Software Foundation, Inc.
 See the end for copying conditions.
 
@@ -10,7 +10,7 @@ Version 2.16
 * The following bugs are resolved with this release:
 
   13525, 13526, 13527, 13528, 13529, 13531, 13532, 13533, 13547, 13530,
-  13551, 13552, 13553, 13555, 13559, 13583
+  13551, 13552, 13553, 13555, 13559, 13583, 13618
 
 * ISO C11 support:
 
index 052e763..3f1772a 100644 (file)
@@ -124,7 +124,8 @@ distribute  := rtld-Rules \
                   tst-initordera1.c tst-initordera2.c tst-initorderb1.c \
                   tst-initorderb2.c tst-initordera3.c tst-initordera4.c \
                   tst-initorder.c \
-                  tst-initorder2.c
+                  tst-initorder2.c \
+                  tst-relsort1.c tst-relsort1mod1.c tst-relsort1mod2.c
 
 CFLAGS-dl-runtime.c = -fexceptions -fasynchronous-unwind-tables
 CFLAGS-dl-lookup.c = -fexceptions -fasynchronous-unwind-tables
@@ -227,7 +228,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
         tst-audit1 tst-audit2 \
         tst-stackguard1 tst-addr1 tst-thrlock \
         tst-unique1 tst-unique2 tst-unique3 tst-unique4 \
-        tst-initorder tst-initorder2
+        tst-initorder tst-initorder2 tst-relsort1
 #       reldep9
 test-srcs = tst-pathopt
 selinux-enabled := $(shell cat /selinux/enforce 2> /dev/null)
@@ -290,7 +291,9 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
                tst-initordera1 tst-initorderb1 \
                tst-initordera2 tst-initorderb2 \
                tst-initordera3 tst-initordera4 \
-               tst-initorder2a tst-initorder2b tst-initorder2c tst-initorder2d
+               tst-initorder2a tst-initorder2b tst-initorder2c \
+               tst-initorder2d \
+               tst-relsort1mod1 tst-relsort1mod2
 ifeq (yes,$(have-initfini-array))
 modules-names += tst-array2dep tst-array5dep
 endif
@@ -1195,3 +1198,9 @@ CFLAGS-tst-auditmod6b.c += $(AVX-CFLAGS)
 CFLAGS-tst-auditmod6c.c += $(AVX-CFLAGS)
 CFLAGS-tst-auditmod7b.c += $(AVX-CFLAGS)
 endif
+
+$(objpfx)tst-relsort1: $(libdl)
+$(objpfx)tst-relsort1mod1.so: $(libm) $(objpfx)tst-relsort1mod2.so
+$(objpfx)tst-relsort1mod2.so: $(libm)
+$(objpfx)tst-relsort1.out: $(objpfx)tst-relsort1mod1.so \
+                          $(objpfx)tst-relsort1mod2.so
index a0b5c50..a56bdc1 100644 (file)
@@ -1,5 +1,5 @@
 /* Load a shared object at runtime, relocate it, and run its initializer.
-   Copyright (C) 1996-2007, 2009, 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 1996-2007, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -302,45 +302,109 @@ dl_open_worker (void *a)
   if (GLRO(dl_lazy))
     reloc_mode |= mode & RTLD_LAZY;
 
-  /* Relocate the objects loaded.  We do this in reverse order so that copy
-     relocs of earlier objects overwrite the data written by later objects.  */
-
+  /* Sort the objects by dependency for the relocation process.  This
+     allows IFUNC relocations to work and it also means copy
+     relocation of dependencies are if necessary overwritten.  */
+  size_t nmaps = 0;
   struct link_map *l = new;
-  while (l->l_next)
-    l = l->l_next;
-  while (1)
+  do
+    {
+      if (! l->l_real->l_relocated)
+       ++nmaps;
+      l = l->l_next;
+    }
+  while (l != NULL);
+  struct link_map *maps[nmaps];
+  nmaps = 0;
+  l = new;
+  do
     {
       if (! l->l_real->l_relocated)
+       maps[nmaps++] = l;
+      l = l->l_next;
+    }
+  while (l != NULL);
+  if (nmaps > 1)
+    {
+      char seen[nmaps];
+      memset (seen, '\0', nmaps);
+      size_t i = 0;
+      while (1)
        {
-#ifdef SHARED
-         if (__builtin_expect (GLRO(dl_profile) != NULL, 0))
+         ++seen[i];
+         struct link_map *thisp = maps[i];
+
+         /* Find the last object in the list for which the current one is
+            a dependency and move the current object behind the object
+            with the dependency.  */
+         size_t k = nmaps - 1;
+         while (k > i)
            {
-             /* If this here is the shared object which we want to profile
-                make sure the profile is started.  We can find out whether
-                this is necessary or not by observing the `_dl_profile_map'
-                variable.  If was NULL but is not NULL afterwars we must
-                start the profiling.  */
-             struct link_map *old_profile_map = GL(dl_profile_map);
+             struct link_map **runp = maps[k]->l_initfini;
+             if (runp != NULL)
+               /* Look through the dependencies of the object.  */
+               while (*runp != NULL)
+                 if (__builtin_expect (*runp++ == thisp, 0))
+                   {
+                     /* Move the current object to the back past the last
+                        object with it as the dependency.  */
+                     memmove (&maps[i], &maps[i + 1],
+                              (k - i) * sizeof (maps[0]));
+                     maps[k] = thisp;
+
+                     if (seen[i + 1] > 1)
+                       {
+                         ++i;
+                         goto next_clear;
+                       }
+
+                     char this_seen = seen[i];
+                     memmove (&seen[i], &seen[i + 1],
+                              (k - i) * sizeof (seen[0]));
+                     seen[k] = this_seen;
+
+                     goto next;
+                   }
+
+             --k;
+           }
 
-             _dl_relocate_object (l, l->l_scope, reloc_mode | RTLD_LAZY, 1);
+         if (++i == nmaps)
+           break;
+       next_clear:
+         memset (&seen[i], 0, (nmaps - i) * sizeof (seen[0]));
+       next:;
+       }
+    }
 
-             if (old_profile_map == NULL && GL(dl_profile_map) != NULL)
-               {
-                 /* We must prepare the profiling.  */
-                 _dl_start_profile ();
+  for (size_t i = nmaps; i-- > 0; )
+    {
+      l = maps[i];
 
-                 /* Prevent unloading the object.  */
-                 GL(dl_profile_map)->l_flags_1 |= DF_1_NODELETE;
-               }
+#ifdef SHARED
+      if (__builtin_expect (GLRO(dl_profile) != NULL, 0))
+       {
+         /* If this here is the shared object which we want to profile
+            make sure the profile is started.  We can find out whether
+            this is necessary or not by observing the `_dl_profile_map'
+            variable.  If it was NULL but is not NULL afterwars we must
+            start the profiling.  */
+         struct link_map *old_profile_map = GL(dl_profile_map);
+
+         _dl_relocate_object (l, l->l_scope, reloc_mode | RTLD_LAZY, 1);
+
+         if (old_profile_map == NULL && GL(dl_profile_map) != NULL)
+           {
+             /* We must prepare the profiling.  */
+             _dl_start_profile ();
+
+             /* Prevent unloading the object.  */
+             GL(dl_profile_map)->l_flags_1 |= DF_1_NODELETE;
            }
-         else
-#endif
-           _dl_relocate_object (l, l->l_scope, reloc_mode, 0);
        }
-
-      if (l == new)
-       break;
-      l = l->l_prev;
+      else
+#endif
+       _dl_relocate_object (l, l->l_scope, reloc_mode, 0);
     }
 
   /* If the file is not loaded now as a dependency, add the search
diff --git a/elf/tst-relsort1.c b/elf/tst-relsort1.c
new file mode 100644 (file)
index 0000000..972100c
--- /dev/null
@@ -0,0 +1,19 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+
+static int
+do_test ()
+{
+  const char lib[] = "$ORIGIN/tst-relsort1mod1.so";
+  void *h = dlopen (lib, RTLD_NOW);
+  if (h == NULL)
+    {
+      puts (dlerror ());
+      return 1;
+    }
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/elf/tst-relsort1mod1.c b/elf/tst-relsort1mod1.c
new file mode 100644 (file)
index 0000000..9e4a943
--- /dev/null
@@ -0,0 +1,7 @@
+extern int foo (double);
+
+int
+bar (void)
+{
+  return foo (1.2);
+}
diff --git a/elf/tst-relsort1mod2.c b/elf/tst-relsort1mod2.c
new file mode 100644 (file)
index 0000000..a2c3e55
--- /dev/null
@@ -0,0 +1,7 @@
+#include <math.h>
+
+int
+foo (double d)
+{
+  return floor (d) != 0.0;
+}