summary refs log tree commit diff
path: root/elf
diff options
context:
space:
mode:
Diffstat (limited to 'elf')
-rw-r--r--elf/Makefile12
-rw-r--r--elf/dl-open.c16
-rw-r--r--elf/reldep6.c97
-rw-r--r--elf/reldep6mod0.c8
-rw-r--r--elf/reldep6mod1.c14
-rw-r--r--elf/reldep6mod2.c3
-rw-r--r--elf/reldep6mod3.c3
-rw-r--r--elf/reldep6mod4.c12
8 files changed, 160 insertions, 5 deletions
diff --git a/elf/Makefile b/elf/Makefile
index d4fc54e010..91d7e3a508 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -107,7 +107,7 @@ tests = loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
 	reldep reldep2 reldep3 reldep4 $(tests-nodelete-$(have-z-nodelete)) \
 	$(tests-nodlopen-$(have-z-nodlopen)) neededtest neededtest2 \
 	neededtest3 neededtest4 unload2 lateglobal initfirst global \
-	restest2 next dblload dblunload reldep5
+	restest2 next dblload dblunload reldep5 reldep6
 test-srcs = tst-pathopt
 tests-vis-yes = vismain
 tests-nodelete-yes = nodelete
@@ -123,7 +123,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
 		neededobj1 neededobj2 neededobj3 neededobj4 \
 		neededobj5 neededobj6 firstobj globalmod1 \
 		unload2mod unload2dep ltglobmod1 ltglobmod2 pathoptobj \
-		dblloadmod1 dblloadmod2 dblloadmod3 reldepmod5 reldepmod6
+		dblloadmod1 dblloadmod2 dblloadmod3 reldepmod5 reldepmod6 \
+	        reldep6mod0 reldep6mod1 reldep6mod2 reldep6mod3 reldep6mod4
 modules-vis-yes = vismod1 vismod2 vismod3
 modules-nodelete-yes = nodelmod1 nodelmod2 nodelmod3 nodelmod4
 modules-nodlopen-yes = nodlopenmod
@@ -288,6 +289,10 @@ $(objpfx)dblloadmod1.so: $(objpfx)dblloadmod3.so
 $(objpfx)dblloadmod2.so: $(objpfx)dblloadmod3.so
 $(objpfx)reldepmod5.so: $(objpfx)reldepmod2.so
 $(objpfx)reldepmod6.so: $(objpfx)reldepmod2.so
+$(objpfx)reldep6mod1.so: $(objpfx)reldep6mod0.so
+$(objpfx)reldep6mod2.so: $(objpfx)reldep6mod1.so
+$(objpfx)reldep6mod3.so: $(objpfx)reldep6mod2.so
+$(objpfx)reldep6mod4.so: $(objpfx)reldep6mod1.so
 
 # filtmod1.so has a special rule
 $(filter-out $(objpfx)filtmod1.so, $(test-modules)): $(objpfx)%.so: $(objpfx)%.os
@@ -429,3 +434,6 @@ $(objpfx)dblunload.out: $(objpfx)dblloadmod1.so $(objpfx)dblloadmod2.so
 
 $(objpfx)reldep5: $(libdl)
 $(objpfx)reldep5.out: $(objpfx)reldepmod5.so $(objpfx)reldepmod5.so
+
+$(objpfx)reldep6: $(libdl)
+$(objpfx)reldep6.out: $(objpfx)reldep6mod3.so $(objpfx)reldep6mod4.so
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 3f2631a98b..c061cdeb0e 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -312,10 +312,20 @@ dl_open_worker (void *a)
 
 	while (*runp != NULL)
 	  {
+	    /* This can happen if imap was just loaded, but during
+	       relocation had l_opencount bumped because of relocation
+	       dependency.  Avoid duplicates in l_scope.  */
+	    if (__builtin_expect (*runp == &new->l_searchlist, 0))
+	      break;
+
 	    ++cnt;
 	    ++runp;
 	  }
 
+	if (*runp != NULL)
+	  /* Avoid duplicates.  */
+	  continue;
+
 	if (__builtin_expect (cnt + 1 >= imap->l_scope_max, 0))
 	  {
 	    /* The 'r_scope' array is too small.  Allocate a new one
@@ -478,11 +488,11 @@ show_scope (struct link_map *new)
 
       for (cnt = 0; cnt < new->l_scope[scope_cnt]->r_nlist; ++cnt)
 	if (*new->l_scope[scope_cnt]->r_list[cnt]->l_name)
-	  _dl_printf (" %s", new->l_scope[scope_cnt]->r_list[cnt]->l_name)
+	  _dl_printf (" %s", new->l_scope[scope_cnt]->r_list[cnt]->l_name);
 	else
-	  _dl_printf (" <main>", NULL);
+	  _dl_printf (" <main>");
 
-      _dl_printf ("\n", NULL);
+      _dl_printf ("\n");
     }
 }
 #endif
diff --git a/elf/reldep6.c b/elf/reldep6.c
new file mode 100644
index 0000000000..bf80ec5773
--- /dev/null
+++ b/elf/reldep6.c
@@ -0,0 +1,97 @@
+#include <dlfcn.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef int (*fn)(void);
+#define CHUNKS 1024
+#define REPEAT 64
+
+int
+main (void)
+{
+  void *h1;
+  void *h2;
+  fn **foopp;
+  fn bar, baz;
+  int i, j;
+  int n;
+  void *allocs[REPEAT][CHUNKS];
+
+  mtrace ();
+
+  /* Open the two objects.  */
+  h1 = dlopen ("reldep6mod3.so", RTLD_LAZY);
+  if (h1 == NULL)
+    {
+      printf ("cannot open reldep6mod3.so: %s\n", dlerror ());
+      exit (1);
+    }
+
+  foopp = dlsym (h1, "foopp");
+  if (foopp == NULL)
+    {
+      printf ("cannot get address of \"foopp\": %s\n", dlerror ());
+      exit (1);
+    }
+  n = (**foopp) ();
+  if (n != 20)
+    {
+      printf ("(**foopp)() return %d, not return 20\n", n);
+      exit (1);
+    }
+
+  h2 = dlopen ("reldep6mod4.so", RTLD_LAZY);
+  if (h2 == NULL)
+    {
+      printf ("cannot open reldep6mod4.so: %s\n", dlerror ());
+      exit (1);
+    }
+
+  if (dlclose (h1) != 0)
+    {
+      printf ("closing h1 failed: %s\n", dlerror ());
+      exit (1);
+    }
+
+  /* Clobber memory.  */
+  for (i = 0; i < REPEAT; ++i)
+    for (j = 0; j < CHUNKS; ++j)
+      allocs[i][j] = calloc (1, j + 1);
+
+  bar = dlsym (h2, "bar");
+  if (bar == NULL)
+    {
+      printf ("cannot get address of \"bar\": %s\n", dlerror ());
+      exit (1);
+    }
+  if (bar () != 40)
+    {
+      printf ("bar() did not return 40\n");
+      exit (1);
+    }
+
+  baz = dlsym (h2, "baz");
+  if (baz == NULL)
+    {
+      printf ("cannot get address of \"baz\": %s\n", dlerror ());
+      exit (1);
+    }
+  if (baz () != 31)
+    {
+      printf ("baz() did not return 31\n");
+      exit (1);
+    }
+
+  for (i = 0; i < REPEAT; ++i)
+    for (j = 0; j < CHUNKS; ++j)
+      free (allocs[i][j]);
+
+  if (dlclose (h2) != 0)
+    {
+      printf ("closing h2 failed: %s\n", dlerror ());
+      exit (1);
+    }
+
+  return 0;
+}
diff --git a/elf/reldep6mod0.c b/elf/reldep6mod0.c
new file mode 100644
index 0000000000..58f3745fb4
--- /dev/null
+++ b/elf/reldep6mod0.c
@@ -0,0 +1,8 @@
+int bar (void);
+extern void free (void *);
+
+int bar (void)
+{
+  free (0);
+  return 40;
+}
diff --git a/elf/reldep6mod1.c b/elf/reldep6mod1.c
new file mode 100644
index 0000000000..037a73a198
--- /dev/null
+++ b/elf/reldep6mod1.c
@@ -0,0 +1,14 @@
+int foo (void);
+int baz (void);
+extern int weak (void);
+asm (".weak weak");
+
+int foo (void)
+{
+  return 20;
+}
+
+int baz (void)
+{
+  return weak () + 1;
+}
diff --git a/elf/reldep6mod2.c b/elf/reldep6mod2.c
new file mode 100644
index 0000000000..c2ef3f9bc0
--- /dev/null
+++ b/elf/reldep6mod2.c
@@ -0,0 +1,3 @@
+extern int foo (void);
+
+void *foop = (void *) foo;
diff --git a/elf/reldep6mod3.c b/elf/reldep6mod3.c
new file mode 100644
index 0000000000..881828ef6e
--- /dev/null
+++ b/elf/reldep6mod3.c
@@ -0,0 +1,3 @@
+extern void *foop;
+
+void **foopp = &foop;
diff --git a/elf/reldep6mod4.c b/elf/reldep6mod4.c
new file mode 100644
index 0000000000..8fa89de64b
--- /dev/null
+++ b/elf/reldep6mod4.c
@@ -0,0 +1,12 @@
+int foo (void);
+int weak (void);
+
+int foo (void)
+{
+  return 10;
+}
+
+int weak (void)
+{
+  return 30;
+}