diff options
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | elf/Makefile | 10 | ||||
-rw-r--r-- | elf/dl-load.c | 11 | ||||
-rw-r--r-- | elf/link.h | 8 | ||||
-rw-r--r-- | elf/multiload.c | 78 | ||||
-rw-r--r-- | elf/rtld.c | 17 |
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. */ } |