summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog20
-rw-r--r--bits/dlfcn.h3
-rw-r--r--elf/Makefile14
-rw-r--r--elf/dl-deps.c2
-rw-r--r--elf/dl-load.c14
-rw-r--r--elf/dl-object.c12
-rw-r--r--elf/dl-open.c3
-rw-r--r--elf/rtld.c5
-rw-r--r--elf/tst-deep1.c36
-rw-r--r--elf/tst-deep1mod1.c14
-rw-r--r--elf/tst-deep1mod2.c16
-rw-r--r--elf/tst-deep1mod3.c17
-rw-r--r--sysdeps/generic/bits/dlfcn.h3
-rw-r--r--sysdeps/generic/ldsodefs.h3
14 files changed, 142 insertions, 20 deletions
diff --git a/ChangeLog b/ChangeLog
index aeb4726e55..11d9810f8a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2004-09-23  Ulrich Drepper  <drepper@redhat.com>
+
+	* sysdeps/generic/bits/dlfcn.h: Add RTLD_DEEPBIND.
+	* elf/dl-object.c (_dl_new_object): Add new parameter mode.  If mode
+	has RTLD_DEEPBIND set add local searchlist before global scope.
+	* sysdeps/generic/ldsodefs.h (_dl_new_object): Adjust prototype.
+	* elf/rtld.c: Adjust callers of _dl_new_object.
+	* elf/dl-load.c: Likewise.
+	(_dl_map_object_from_fd): If RTLD_DEEPBIND is used, don't do anything
+	for DF_SYMBOLIC.
+	* elf/dl-open.c (dl_open_writer): Pass RTLD_DEEPBIND flag on to
+	_dl_map_object_deps.
+	* elf/tst-deep1.c: New file.
+	* elf/tst-deep1mod1.c: New file.
+	* elf/tst-deep1mod2.c: New file.
+	* elf/tst-deep1mod3.c: New file.
+	* elf/Makefile: Add rules to build and run new tests.
+
+	* elf/dl-deps.c: Pretty printing.
+
 2004-09-23  Jakub Jelinek  <jakub@redhat.com>
 
 	* sysdeps/unix/alpha/sysdep.h (inline_syscall[0-6]): Change name
diff --git a/bits/dlfcn.h b/bits/dlfcn.h
index e96b5c17ae..67fd96a22a 100644
--- a/bits/dlfcn.h
+++ b/bits/dlfcn.h
@@ -1,5 +1,5 @@
 /* System dependent definitions for run-time dynamic loading.
-   Copyright (C) 1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc.
+   Copyright (C) 1996-2001, 2004 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
@@ -26,6 +26,7 @@
 #define RTLD_NOW	0x00002	/* Immediate function call binding.  */
 #define	RTLD_BINDING_MASK   0x3	/* Mask of binding time value.  */
 #define RTLD_NOLOAD	0x00004	/* Do not load the object.  */
+#define RTLD_DEEPBIND	0x00008	/* Use deep binding.  */
 
 /* If the following bit is set in the MODE argument to `dlopen',
    the symbols of the loaded object and its dependencies are made
diff --git a/elf/Makefile b/elf/Makefile
index ac8319bc5f..d40d3fd6a7 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -82,7 +82,8 @@ distribute	:= rtld-Rules \
 		   tst-array1.exp tst-array2.exp tst-array4.exp \
 		   tst-array2dep.c tst-piemod1.c \
 		   tst-execstack-mod.c tst-dlmodcount.c \
-		   check-textrel.c dl-sysdep.h test-dlopenrpathmod.c
+		   check-textrel.c dl-sysdep.h test-dlopenrpathmod.c \
+		   tst-deep1mod1.c tst-deep1mod2.c tst-deep1mod3.c
 
 CFLAGS-dl-runtime.c = -fexceptions -fasynchronous-unwind-tables
 CFLAGS-dl-lookup.c = -fexceptions -fasynchronous-unwind-tables
@@ -152,7 +153,8 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
 	 restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \
 	 circleload1 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 tst-tls8 \
 	 tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-align \
-	 $(tests-execstack-$(have-z-execstack)) tst-dlmodcount tst-dlopenrpath
+	 $(tests-execstack-$(have-z-execstack)) tst-dlmodcount \
+	 tst-dlopenrpath tst-deep1
 #	 reldep9
 test-srcs = tst-pathopt
 tests-vis-yes = vismain
@@ -185,7 +187,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
 		reldep8mod1 reldep8mod2 reldep8mod3 \
 		reldep9mod1 reldep9mod2 reldep9mod3 \
 		tst-alignmod $(modules-execstack-$(have-z-execstack)) \
-		tst-dlopenrpathmod
+		tst-dlopenrpathmod tst-deep1mod1 tst-deep1mod2 tst-deep1mod3
 ifeq (yes,$(have-initfini-array))
 modules-names += tst-array2dep
 endif
@@ -754,3 +756,9 @@ $(objpfx)tst-dlopenrpath: $(objpfx)tst-dlopenrpathmod.so $(libdl)
 CFLAGS-tst-dlopenrpath.c += -DPFX=\"$(objpfx)\"
 LDFLAGS-tst-dlopenrpathmod.so += -Wl,-rpath,\$$ORIGIN/test-subdir
 $(objpfx)tst-dlopenrpath.out: $(objpfx)firstobj.so
+
+$(objpfx)tst-deep1mod2.so: $(objpfx)tst-deep1mod3.so
+$(objpfx)tst-deep1: $(libdl) $(objpfx)tst-deep1mod1.so
+$(objpfx)tst-deep1.out: $(objpfx)tst-deep1mod2.so
+LDFLAGS-tst-deep1 += -rdynamic
+tst-deep1mod3.so-no-z-defs = yes
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
index b8dee8ab52..1a0fedf988 100644
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -509,7 +509,7 @@ _dl_map_object_deps (struct link_map *map,
       runp->map->l_reserved = 0;
     }
 
-  if (__builtin_expect(GLRO(dl_debug_mask) & DL_DEBUG_PRELINK, 0) != 0
+  if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK, 0) != 0
       && map == GL(dl_loaded))
     {
       /* If we are to compute conflicts, we have to build local scope
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 73112bce23..15fff3c5e1 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -881,7 +881,7 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
 #endif
 
   /* Enter the new object in the list of loaded objects.  */
-  l = _dl_new_object (realname, name, l_type, loader);
+  l = _dl_new_object (realname, name, l_type, loader, mode);
   if (__builtin_expect (! l, 0))
     {
       errstring = N_("cannot create shared object descriptor");
@@ -1355,15 +1355,12 @@ cannot enable executable stack as shared object requires");
 
   /* If this object has DT_SYMBOLIC set modify now its scope.  We don't
      have to do this for the main map.  */
-  if (__builtin_expect (l->l_info[DT_SYMBOLIC] != NULL, 0)
+  if ((mode & RTLD_DEEPBIND) == 0
+      && __builtin_expect (l->l_info[DT_SYMBOLIC] != NULL, 0)
       && &l->l_searchlist != l->l_scope[0])
     {
       /* Create an appropriate searchlist.  It contains only this map.
-
-	 XXX This is the definition of DT_SYMBOLIC in SysVr4.  The old
-	 GNU ld.so implementation had a different interpretation which
-	 is more reasonable.  We are prepared to add this possibility
-	 back as part of a GNU extension of the ELF format.  */
+	 This is the definition of DT_SYMBOLIC in SysVr4.  */
       l->l_symbolic_searchlist.r_list =
 	(struct link_map **) malloc (sizeof (struct link_map *));
 
@@ -1968,7 +1965,8 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
 
 	  /* Enter the new object in the list of loaded objects.  */
 	  if ((name_copy = local_strdup (name)) == NULL
-	      || (l = _dl_new_object (name_copy, name, type, loader)) == NULL)
+	      || (l = _dl_new_object (name_copy, name, type, loader,
+				      mode)) == NULL)
 	    _dl_signal_error (ENOMEM, name, NULL,
 			      N_("cannot create shared object descriptor"));
 	  /* Signal that this is a faked entry.  */
diff --git a/elf/dl-object.c b/elf/dl-object.c
index 52131181b3..91b1fa2187 100644
--- a/elf/dl-object.c
+++ b/elf/dl-object.c
@@ -32,7 +32,7 @@
 struct link_map *
 internal_function
 _dl_new_object (char *realname, const char *libname, int type,
-		struct link_map *loader)
+		struct link_map *loader, int mode)
 {
   struct link_map *l;
   int idx;
@@ -95,7 +95,15 @@ _dl_new_object (char *realname, const char *libname, int type,
 
   /* Insert the scope if it isn't the global scope we already added.  */
   if (idx == 0 || &loader->l_searchlist != new->l_scope[0])
-    new->l_scope[idx] = &loader->l_searchlist;
+    {
+      if ((mode & RTLD_DEEPBIND) != 0 && idx != 0)
+	{
+	  new->l_scope[1] = new->l_scope[0];
+	  idx = 0;
+	}
+
+      new->l_scope[idx] = &loader->l_searchlist;
+    }
 
   new->l_local_scope[0] = &new->l_searchlist;
 
diff --git a/elf/dl-open.c b/elf/dl-open.c
index c352722e27..c9b4a45596 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -272,7 +272,8 @@ dl_open_worker (void *a)
     }
 
   /* Load that object's dependencies.  */
-  GLRO(dl_map_object_deps) (new, NULL, 0, 0, mode & __RTLD_DLOPEN);
+  GLRO(dl_map_object_deps) (new, NULL, 0, 0,
+			    mode & (__RTLD_DLOPEN | RTLD_DEEPBIND));
 
   /* So far, so good.  Now check the versions.  */
   for (i = 0; i < new->l_searchlist.r_nlist; ++i)
diff --git a/elf/rtld.c b/elf/rtld.c
index 2daf05a6d6..1ee875a088 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -879,7 +879,7 @@ of this helper program; chances are you did not intend to run this program.\n\
     {
       /* Create a link_map for the executable itself.
 	 This will be what dlopen on "" returns.  */
-      _dl_new_object ((char *) "", "", lt_executable, NULL);
+      _dl_new_object ((char *) "", "", lt_executable, NULL, 0);
       if (GL(dl_loaded) == NULL)
 	_dl_fatal_printf ("cannot allocate memory for link map\n");
       GL(dl_loaded)->l_phdr = phdr;
@@ -1271,7 +1271,8 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
 	 better be, since it's read-only and so we couldn't relocate it).
 	 We just want our data structures to describe it as if we had just
 	 mapped and relocated it normally.  */
-      struct link_map *l = _dl_new_object ((char *) "", "", lt_library, NULL);
+      struct link_map *l = _dl_new_object ((char *) "", "", lt_library, NULL,
+					   0);
       if (__builtin_expect (l != NULL, 1))
 	{
 	  static ElfW(Dyn) dyn_temp[DL_RO_DYN_TEMP_CNT] attribute_relro;
diff --git a/elf/tst-deep1.c b/elf/tst-deep1.c
new file mode 100644
index 0000000000..5428d13de4
--- /dev/null
+++ b/elf/tst-deep1.c
@@ -0,0 +1,36 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+int
+xyzzy (void)
+{
+  printf ("%s:%s\n", __FILE__, __func__);
+  return 21;
+}
+
+int
+back (void)
+{
+  printf ("%s:%s\n", __FILE__, __func__);
+  return 1;
+}
+
+extern int foo (void);
+
+static int
+do_test (void)
+{
+  void *p = dlopen ("$ORIGIN/tst-deep1mod2.so", RTLD_LAZY|RTLD_DEEPBIND);
+
+  int (*f) (void) = dlsym (p, "bar");
+  if (f == NULL)
+    {
+      puts (dlerror ());
+      return 1;
+    }
+
+  return foo () + f ();
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/elf/tst-deep1mod1.c b/elf/tst-deep1mod1.c
new file mode 100644
index 0000000000..cc922e6ea5
--- /dev/null
+++ b/elf/tst-deep1mod1.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+int
+foo (void)
+{
+  printf ("%s:%s\n", __FILE__, __func__);
+  return 1;
+}
+
+int
+baz (void)
+{
+  printf ("%s:%s\n", __FILE__, __func__);
+  return 20;
+}
diff --git a/elf/tst-deep1mod2.c b/elf/tst-deep1mod2.c
new file mode 100644
index 0000000000..b99caf0328
--- /dev/null
+++ b/elf/tst-deep1mod2.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+extern int baz (void);
+extern int xyzzy (void);
+int
+bar (void)
+{
+  printf ("%s:%s\n", __FILE__, __func__);
+  return baz () + xyzzy ();;
+}
+
+int
+back (void)
+{
+  printf ("%s:%s\n", __FILE__, __func__);
+  return -1;
+}
diff --git a/elf/tst-deep1mod3.c b/elf/tst-deep1mod3.c
new file mode 100644
index 0000000000..eee7d5c97b
--- /dev/null
+++ b/elf/tst-deep1mod3.c
@@ -0,0 +1,17 @@
+#include <stdio.h>
+
+extern int back (void);
+
+int
+baz (void)
+{
+  printf ("%s:%s\n", __FILE__, __func__);
+  return back ();
+}
+
+int
+xyzzy (void)
+{
+  printf ("%s:%s\n", __FILE__, __func__);
+  return 0;
+}
diff --git a/sysdeps/generic/bits/dlfcn.h b/sysdeps/generic/bits/dlfcn.h
index e96b5c17ae..67fd96a22a 100644
--- a/sysdeps/generic/bits/dlfcn.h
+++ b/sysdeps/generic/bits/dlfcn.h
@@ -1,5 +1,5 @@
 /* System dependent definitions for run-time dynamic loading.
-   Copyright (C) 1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc.
+   Copyright (C) 1996-2001, 2004 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
@@ -26,6 +26,7 @@
 #define RTLD_NOW	0x00002	/* Immediate function call binding.  */
 #define	RTLD_BINDING_MASK   0x3	/* Mask of binding time value.  */
 #define RTLD_NOLOAD	0x00004	/* Do not load the object.  */
+#define RTLD_DEEPBIND	0x00008	/* Use deep binding.  */
 
 /* If the following bit is set in the MODE argument to `dlopen',
    the symbols of the loaded object and its dependencies are made
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index be3d2dd61f..2b526867ad 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -722,7 +722,8 @@ extern ElfW(Addr) _dl_symbol_value (struct link_map *map, const char *name)
 /* Allocate a `struct link_map' for a new object being loaded,
    and enter it into the _dl_main_map list.  */
 extern struct link_map *_dl_new_object (char *realname, const char *libname,
-					int type, struct link_map *loader)
+					int type, struct link_map *loader,
+					int mode)
      internal_function attribute_hidden;
 
 /* Relocate the given object (if it hasn't already been).