aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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. */
}