about summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1999-02-19 00:00:05 +0000
committerUlrich Drepper <drepper@redhat.com>1999-02-19 00:00:05 +0000
commit61e0617ac34c4daaeb2f07f89a05c9f9353b8879 (patch)
tree8dc1f2e00b67c6661892258bf2d479e793854c54
parent1a989e004c00955e60cd315666ebd450d6fa9732 (diff)
downloadglibc-61e0617ac34c4daaeb2f07f89a05c9f9353b8879.tar.gz
glibc-61e0617ac34c4daaeb2f07f89a05c9f9353b8879.tar.xz
glibc-61e0617ac34c4daaeb2f07f89a05c9f9353b8879.zip
Update.
	* elf/link.h (link_map): Add l_dev and l_ino.
	* elf/dl-load.c (_dl_map_object_from_fd): Test dev/ino of newly
	loaded shared object with all laoded objects.  Initialize l_ino
	and l_dev in case it's new.
	* elf/rtld.c (dl_main): Explain situation is l_dev/l_ino with main
	object.
	* elf/Makefile: Compile and run new test.
	* elf/multiload.c: New file.
-rw-r--r--ChangeLog9
-rw-r--r--elf/Makefile10
-rw-r--r--elf/dl-load.c11
-rw-r--r--elf/link.h8
-rw-r--r--elf/multiload.c78
-rw-r--r--elf/rtld.c17
6 files changed, 128 insertions, 5 deletions
diff --git a/ChangeLog b/ChangeLog
index c1a00362f3..ff83c3143d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 1999-02-18  Ulrich Drepper  <drepper@cygnus.com>
 
+	* elf/link.h (link_map): Add l_dev and l_ino.
+	* elf/dl-load.c (_dl_map_object_from_fd): Test dev/ino of newly
+	loaded shared object with all laoded objects.  Initialize l_ino
+	and l_dev in case it's new.
+	* elf/rtld.c (dl_main): Explain situation is l_dev/l_ino with main
+	object.
+	* elf/Makefile: Compile and run new test.
+	* elf/multiload.c: New file.
+
 	* nss/nsswitch.h (service_user): Change name field from const char *
 	to char[0].
 	(name_database_entry): Likewise.
diff --git a/elf/Makefile b/elf/Makefile
index 1706efc510..ef5b831863 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -77,7 +77,7 @@ others		+= ldconfig
 install-rootsbin += ldconfig
 endif
 
-tests = loadtest restest1 preloadtest loadfail
+tests = loadtest restest1 preloadtest loadfail multiload
 modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
 		testobj1_1 failobj
 extra-objs += $(modules-names:=.os)
@@ -244,7 +244,13 @@ preloadtest-ENV = \
 $(objpfx)loadfail: $(libdl)
 LDFLAGS-loadfail = -rdynamic
 
-$(objpfx)loadfile.out: $(objpfx)failobj.so
+$(objpfx)loadfail.out: $(objpfx)failobj.so
+
+$(objpfx)multiload: $(libdl)
+LDFLAGS-multiload = -rdynamic
+CFLAGS-multiload.c = -DOBJDIR=\"$(objdir)/$(subdir)\"
+
+$(objpfx)multiload.out: $(objpfx)testobj1.so
 
 # muwahaha
 
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 84951ea00f..bf3e4195ad 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -602,10 +602,15 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
   int type;
   char *readbuf;
   ssize_t readlength;
+  struct stat st;
+
+  /* Get file information.  */
+  if (__fstat (fd, &st) < 0)
+    lose (errno, "cannot stat shared object");
 
   /* Look again to see if the real name matched another already loaded.  */
   for (l = _dl_loaded; l; l = l->l_next)
-    if (! strcmp (realname, l->l_name))
+    if (l->l_ino == st.st_ino && l->l_dev == st.st_dev)
       {
 	/* The object is already loaded.
 	   Just bump its reference count and return it.  */
@@ -961,6 +966,10 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
       l->l_scope[0] = &l->l_symbolic_searchlist;
     }
 
+  /* Finally the file information.  */
+  l->l_dev = st.st_dev;
+  l->l_ino = st.st_ino;
+
   return l;
 }
 
diff --git a/elf/link.h b/elf/link.h
index ecf0469b7a..4abcb49070 100644
--- a/elf/link.h
+++ b/elf/link.h
@@ -1,6 +1,6 @@
 /* Data structure for communication from the run-time dynamic linker for
    loaded ELF shared objects.
-   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1995, 1996, 1997, 1998, 1999 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
@@ -24,6 +24,7 @@
 #include <features.h>
 #include <elf.h>
 #include <dlfcn.h>
+#include <sys/types.h>
 
 /* We use this macro to refer to ELF types independent of the native wordsize.
    `ElfW(TYPE)' is used in place of `Elf32_TYPE' or `Elf64_TYPE'.  */
@@ -193,6 +194,11 @@ struct link_map
     /* A similar array, this time only with the local scope.  This is
        used occasionally.  */
     struct r_scope_elem *l_local_scope[2];
+
+    /* This information is kept to check for sure whether a shared
+       object is the same as one already loaded.  */
+    dev_t l_dev;
+    ino_t l_ino;
   };
 
 #endif /* link.h */
diff --git a/elf/multiload.c b/elf/multiload.c
new file mode 100644
index 0000000000..724c1ed562
--- /dev/null
+++ b/elf/multiload.c
@@ -0,0 +1,78 @@
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int
+main (void)
+{
+  void *a;
+  void *b;
+  void *c;
+  void *d;
+  char *wd;
+  char *base;
+  char *buf;
+
+  /* Change to the binary directory.  */
+  if (chdir (OBJDIR) != 0)
+    {
+      printf ("cannot change to `%s': %m", OBJDIR);
+      exit (EXIT_FAILURE);
+    }
+
+  wd = getcwd (NULL, 0);
+  base = basename (wd);
+  buf = alloca (strlen (wd) + strlen (base) + 5 + sizeof "testobj1.so");
+
+  printf ("loading `%s'\n", "./testobj1.so");
+  a = dlopen ("./testobj1.so", RTLD_NOW);
+  if (a == NULL)
+    {
+      printf ("cannot load `./testobj1.so': %s\n", dlerror ());
+      exit (EXIT_FAILURE);
+    }
+
+  stpcpy (stpcpy (stpcpy (buf, "../"), base), "/testobj1.so");
+  printf ("loading `%s'\n", buf);
+  b = dlopen (buf, RTLD_NOW);
+  if (b == NULL)
+    {
+      printf ("cannot load `%s': %s\n", buf, dlerror ());
+      exit (EXIT_FAILURE);
+    }
+
+  stpcpy (stpcpy (buf, wd), "/testobj1.so");
+  printf ("loading `%s'\n", buf);
+  c = dlopen (buf, RTLD_NOW);
+  if (c == NULL)
+    {
+      printf ("cannot load `%s': %s\n", buf, dlerror ());
+      exit (EXIT_FAILURE);
+    }
+
+  stpcpy (stpcpy (stpcpy (stpcpy (buf, wd), "/../"), base), "/testobj1.so");
+  printf ("loading `%s'\n", buf);
+  d = dlopen (buf, RTLD_NOW);
+  if (d == NULL)
+    {
+      printf ("cannot load `%s': %s\n", buf, dlerror ());
+      exit (EXIT_FAILURE);
+    }
+
+  if (a != b || b != c || c != d)
+    {
+      puts ("shared object loaded more than once");
+      exit (EXIT_FAILURE);
+    }
+
+  return 0;
+}
+
+int
+foo (int a)
+{
+  return a;
+}
diff --git a/elf/rtld.c b/elf/rtld.c
index df6a945105..6aa3a65fbb 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -461,7 +461,7 @@ of this helper program; chances are you did not intend to run this program.\n\
 	  HP_TIMING_NOW (start);
 	  _dl_map_object (NULL, _dl_argv[0], 0, lt_library, 0);
 	  HP_TIMING_NOW (stop);
-	  
+
 	  HP_TIMING_DIFF (load_time, start, stop);
 	}
 
@@ -486,6 +486,21 @@ of this helper program; chances are you did not intend to run this program.\n\
       _dl_loaded->l_entry = *user_entry;
       _dl_loaded->l_opencount = 1;
 
+      /* At this point we are in a bit of trouble.  We would have to
+	 fill in the values for l_dev and l_ino.  But in general we
+	 do not know where the file is.  We also do not handle AT_EXECFD
+	 even if it would be passed up.
+
+	 We leave the values here defined to 0.  This is normally no
+	 problem as the program code itself is normally no shared
+	 object and therefore cannot be loaded dynamically.  Nothing
+	 prevent the use of dynamic binaries and in these situations
+	 we might get problems.  We might not be able to find out
+	 whether the object is already loaded.  But since there is no
+	 easy way out and because the dynamic binary must also not
+	 have an SONAME we ignore this program for now.  If it becomes
+	 a problem we can force people using SONAMEs.  */
+
       /* We delay initializing the path structure until we got the dynamic
 	 information for the program.  */
     }