* Makerules ($(common-objpfx)libc.so): Depend on $(elfobjdir)/ld.so.
authorRoland McGrath <roland@gnu.org>
Mon, 10 Jun 1996 20:19:39 +0000 (20:19 +0000)
committerRoland McGrath <roland@gnu.org>
Mon, 10 Jun 1996 20:19:39 +0000 (20:19 +0000)
* elf/dl-close.c: New file.
* elf/link.h: Declare _dl_close.
* elf/Makefile (routines): Add dl-close.
* elf/dlclose.c (dlclose): Use _dl_close.

* elf/Makefile ($(objpfx)librtld.so): Remove libelf from deps.

* elf/dl-runtime.c (_dl_global_scope): New variable.
(_dl_object_relocation_scope): New function.
(fixup): Use it.
* elf/rtld.c (dl_main): Use it.
* elf/dl-open.c (_dl_open): Use it.  If (MODE & RTLD_GLOBAL), set the
l_global bit and append the new map to _dl_global_scope.
* elf/link.h: Declare _dl_global_scope, _dl_global_scope_alloc,
and _dl_object_relocation_scope.

* elf/link.h (struct link_map): Add l_loader member.
Remove _dl_map_object_from_fd decl.
* elf/dl-load.c (_dl_map_object): Pass LOADER to ...
(_dl_map_object_from_fd): Take new arg LOADER and set l_loader member.
(_dl_map_object): Try DT_RPATH from all loaders up the chain.

* elf/dl-object.c (_dl_loaded): Variable removed.
(_dl_default_scope): New variable replaces it.
* elf/link.h (_dl_loaded): Remove variable decl; instead define as
macro for _dl_default_scope[2].
(_dl_default_scope): Declare it.
* sysdeps/i386/dl-machine.h (RTLD_START): Use _dl_default_scope[2]
instead of _dl_loaded.
* sysdeps/m68k/dl-machine.h (RTLD_START): Likewise.
* elf/rtld.c (dl_main): Use _dl_default_scope for symbol lookups.

* elf/dl-reloc.c (_dl_relocate_object): Remove check for _dl_rtld_map.
* elf/rtld.c (dl_main): Pass 0 for LAZY flag when re-relocating self.

* elf/link.h (struct link_map.l_type): Remove lt_interpreter.
  (struct link_map): Add new flag member l_global.

* elf/dl-reloc.c (_dl_relocate_object): Check for _dl_rtld_map
directly instead of looking for lt_interpreter.
* sysdeps/i386/dl-machine.h (elf_machine_rel): Likewise.
* elf/rtld.c (_dl_start): Don't bother setting BOOTSTRAP_MAP.l_type.
(dl_main): Set _dl_rtld_map.l_type to lt_library.

* elf/dl-deps.c (_dl_map_object_deps): Propagate MAP->l_type to
dependencies loaded, downgrading lt_executable -> lt_library.

* elf/dl-load.c (_dl_map_object_from_fd): Take new arg TYPE and set
l_type from that, translating lt_library->lt_executable based on the
file's ELF type.
(_dl_map_object): Likewise.
* elf/link.h: Update prototypes.
* elf/dl-open.c: Pass type lt_loaded.
* elf/rtld.c: Pass type lt_library.

* elf/dl-load.c (_dl_map_object_from_fd): Handle null return from
_dl_new_object.
(_dl_map_object_from_fd: lose): Unchain and free L if it's not null.
Free REALNAME, and just use NAME in error message.
* elf/dl-object.c (_dl_new_object): If malloc fails, return null
instead of calling _dl_signal_error.

* elf/dl-load.c (_dl_map_object_from_fd): Close FD before signalling
error for _dl_zerofd setup failure.

* elf/dl-object.c (_dl_startup_loaded): Variable removed.
* elf/link.h: Remove its decl.

* elf/dl-reloc.c (_dl_relocate_object): Take new SCOPE arg and pass it
through to _dl_lookup_symbol.
* elf/link.h (_dl_relocate_object): Update comment and prototype.
* elf/rtld.c (dl_main): Pass scope vector to _dl_relocate_object.

* elf/dl-lookup.c (_dl_lookup_symbol): Arg SYMBOL_SCOPE is now a
null-terminated vector of pointers, no longer a vector of exactly two.
* elf/link.h (_dl_lookup_symbol): Update comment and prototype.

* elf/dl-runtime.c (fixup): Set up scope for symbol lookup properly as
done in _dl_relocate_object.

* elf/dlopen.c: Pass "" to _dl_open when FILE is null.

17 files changed:
ChangeLog
Makerules
elf/Makefile
elf/dl-close.c [new file with mode: 0644]
elf/dl-deps.c
elf/dl-load.c
elf/dl-lookup.c
elf/dl-object.c
elf/dl-open.c
elf/dl-reloc.c
elf/dl-runtime.c
elf/dlclose.c
elf/dlopen.c
elf/link.h
elf/rtld.c
sysdeps/i386/dl-machine.h
sysdeps/m68k/dl-machine.h

index 231facf..02a9422 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,89 @@
 Mon Jun 10 06:14:03 1996  Roland McGrath  <roland@delasyd.gnu.ai.mit.edu>
 
+       * Makerules ($(common-objpfx)libc.so): Depend on $(elfobjdir)/ld.so.
+
+       * elf/dl-close.c: New file.
+       * elf/link.h: Declare _dl_close.
+       * elf/Makefile (routines): Add dl-close.
+       * elf/dlclose.c (dlclose): Use _dl_close.
+
+       * elf/Makefile ($(objpfx)librtld.so): Remove libelf from deps.
+
+       * elf/dl-runtime.c (_dl_global_scope): New variable.
+       (_dl_object_relocation_scope): New function.
+       (fixup): Use it.
+       * elf/rtld.c (dl_main): Use it.
+       * elf/dl-open.c (_dl_open): Use it.  If (MODE & RTLD_GLOBAL), set the
+       l_global bit and append the new map to _dl_global_scope.
+       * elf/link.h: Declare _dl_global_scope, _dl_global_scope_alloc,
+       and _dl_object_relocation_scope.
+
+       * elf/link.h (struct link_map): Add l_loader member.
+       Remove _dl_map_object_from_fd decl.
+       * elf/dl-load.c (_dl_map_object): Pass LOADER to ...
+       (_dl_map_object_from_fd): Take new arg LOADER and set l_loader member.
+       (_dl_map_object): Try DT_RPATH from all loaders up the chain.
+
+       * elf/dl-object.c (_dl_loaded): Variable removed.
+       (_dl_default_scope): New variable replaces it.
+       * elf/link.h (_dl_loaded): Remove variable decl; instead define as
+       macro for _dl_default_scope[2].
+       (_dl_default_scope): Declare it.
+       * sysdeps/i386/dl-machine.h (RTLD_START): Use _dl_default_scope[2]
+       instead of _dl_loaded.
+       * sysdeps/m68k/dl-machine.h (RTLD_START): Likewise.
+       * elf/rtld.c (dl_main): Use _dl_default_scope for symbol lookups.
+
+       * elf/dl-reloc.c (_dl_relocate_object): Remove check for _dl_rtld_map.
+       * elf/rtld.c (dl_main): Pass 0 for LAZY flag when re-relocating self.
+
+       * elf/link.h (struct link_map.l_type): Remove lt_interpreter.
+       (struct link_map): Add new flag member l_global.
+
+       * elf/dl-reloc.c (_dl_relocate_object): Check for _dl_rtld_map
+       directly instead of looking for lt_interpreter.
+       * sysdeps/i386/dl-machine.h (elf_machine_rel): Likewise.
+       * elf/rtld.c (_dl_start): Don't bother setting BOOTSTRAP_MAP.l_type.
+       (dl_main): Set _dl_rtld_map.l_type to lt_library.
+
+       * elf/dl-deps.c (_dl_map_object_deps): Propagate MAP->l_type to
+       dependencies loaded, downgrading lt_executable -> lt_library.
+
+       * elf/dl-load.c (_dl_map_object_from_fd): Take new arg TYPE and set
+       l_type from that, translating lt_library->lt_executable based on the
+       file's ELF type.
+       (_dl_map_object): Likewise.
+       * elf/link.h: Update prototypes.
+       * elf/dl-open.c: Pass type lt_loaded.
+       * elf/rtld.c: Pass type lt_library.
+
+       * elf/dl-load.c (_dl_map_object_from_fd): Handle null return from
+       _dl_new_object.
+       (_dl_map_object_from_fd: lose): Unchain and free L if it's not null.
+       Free REALNAME, and just use NAME in error message.
+       * elf/dl-object.c (_dl_new_object): If malloc fails, return null
+       instead of calling _dl_signal_error.
+
+       * elf/dl-load.c (_dl_map_object_from_fd): Close FD before signalling
+       error for _dl_zerofd setup failure.
+
+       * elf/dl-object.c (_dl_startup_loaded): Variable removed.
+       * elf/link.h: Remove its decl.
+
+       * elf/dl-reloc.c (_dl_relocate_object): Take new SCOPE arg and pass it
+       through to _dl_lookup_symbol.
+       * elf/link.h (_dl_relocate_object): Update comment and prototype.
+       * elf/rtld.c (dl_main): Pass scope vector to _dl_relocate_object.
+
+       * elf/dl-lookup.c (_dl_lookup_symbol): Arg SYMBOL_SCOPE is now a
+       null-terminated vector of pointers, no longer a vector of exactly two.
+       * elf/link.h (_dl_lookup_symbol): Update comment and prototype.
+
+       * elf/dl-runtime.c (fixup): Set up scope for symbol lookup properly as
+       done in _dl_relocate_object.
+
+       * elf/dlopen.c: Pass "" to _dl_open when FILE is null.
+
        * elf/link.h: Include elfclass.h to define __ELF_NATIVE_CLASS.
        (ElfW, ELFW): Use it.
        * elf/Makefile (headers): Add elfclass.h.
index d74e5be..0310b00 100644 (file)
--- a/Makerules
+++ b/Makerules
@@ -496,7 +496,7 @@ LDFLAGS-c.so += -e __libc_print_version
 elfobjdir := $(firstword $(objdir) $(..)elf)
 $(common-objpfx)libc.so: $(elfobjdir)/soinit.so \
                         $(common-objpfx)libc_pic.a \
-                        $(elfobjdir)/sofini.so
+                        $(elfobjdir)/sofini.so $(elfobjdir)/ld.so
        $(build-shlib)
 
 ifdef libc.so-version
index 06aeb75..c2c8f7c 100644 (file)
@@ -21,7 +21,8 @@
 subdir         := elf
 
 headers                = elf.h elfclass.h link.h dlfcn.h
-routines       = init-first $(dl-routines) dl-open dl-symbol dl-support
+routines       = init-first $(dl-routines) \
+                 dl-open dl-close dl-symbol dl-support
 
 # The core dynamic linking functions are in libc for the static and
 # profiled libraries.
@@ -54,7 +55,7 @@ install-bin   = ldd
 # to run programs during the `make others' pass.
 lib-noranlib: $(objpfx)ld.so $(addprefix $(objpfx),$(extra-objs))
 
-ifneq (,$(filter linux%,$(config-os)))
+ifneq (,$(filter linux% linux,$(config-os)))
 extra-objs     += linux-compat.so
 install-others += $(slibdir)/ld-linux.so.1
 lib-noranlib: $(objpfx)ld-linux.so.1
@@ -75,7 +76,7 @@ $(objpfx)dl-allobjs.so: $(rtld-routines:%=$(objpfx)%.so)
 # dynamic linker shared objects below.
 $(objpfx)librtld.so: $(objpfx)dl-allobjs.so \
                     $(patsubst %,$(common-objpfx)lib%_pic.a,\
-                               elf c $(LDLIBS-c.so:-l%=%))
+                               c $(LDLIBS-c.so:-l%=%))
        $(reloc-link) '-Wl,-(' $^ -lgcc '-Wl,-)'
 
 $(objpfx)ld.so: $(objpfx)librtld.so
diff --git a/elf/dl-close.c b/elf/dl-close.c
new file mode 100644 (file)
index 0000000..69fdefa
--- /dev/null
@@ -0,0 +1,107 @@
+/* _dl_close -- Close a shared object opened by `_dl_open'.
+Copyright (C) 1996 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
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <link.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+
+#define LOSE(s) _dl_signal_error (0, map->l_name, s)
+
+void
+_dl_close (struct link_map *map)
+{
+  struct link_map **list;
+  unsigned int i;
+
+  if (map->l_opencount == 0)
+    LOSE ("shared object not open");
+
+  /* Decrement the reference count.  */
+  if (--map->l_opencount > 0 || map->l_type != lt_loaded)
+    /* There are still references to this object.  Do nothing more.  */
+    return;
+
+  list = map->l_searchlist;
+
+  /* The search list contains a counted reference to each object it
+     points to, the 0th elt being MAP itself.  Decrement the reference
+     counts on all the objects MAP depends on.  */
+  for (i = 1; i < map->l_nsearchlist; ++i)
+    --list[i]->l_opencount;
+
+  /* Clear the search list so it doesn't get freed while we are still
+     using it.  We have cached it in LIST and will free it when
+     finished.  */
+  map->l_searchlist = NULL;
+
+  /* Check each element of the search list to see if all references to
+     it are gone.  */
+  for (i = 0; i < map->l_nsearchlist; ++i)
+    {
+      struct link_map *map = list[i];
+      if (map->l_opencount == 0 && map->l_type == lt_loaded)
+       {
+         /* That was the last reference, and this was a dlopen-loaded
+            object.  We can unmap it.  */
+         const ElfW(Phdr) *ph;
+
+         if (map->l_info[DT_FINI])
+           /* Call its termination function.  */
+           (*(void (*) (void)) ((void *) map->l_addr +
+                                map->l_info[DT_FINI]->d_un.d_ptr)) ();
+
+         if (map->l_global)
+           {
+             /* This object is in the global scope list.  Remove it.  */
+             struct link_map **tail = _dl_global_scope_end;
+             do
+               --tail;
+             while (*tail != map);
+             --_dl_global_scope_end;
+             memcpy (tail, tail + 1, _dl_global_scope_end - tail);
+             _dl_global_scope_end[0] = NULL;
+             _dl_global_scope_end[1] = NULL;
+           }
+
+         /* Unmap the segments.  */
+         for (ph = map->l_phdr; ph < &map->l_phdr[map->l_phnum]; ++ph)
+           if (ph->p_type == PT_LOAD)
+             {
+               ElfW(Addr) mapstart = ph->p_vaddr & ~(ph->p_align - 1);
+               ElfW(Addr) mapend = ((ph->p_vaddr + ph->p_memsz
+                                     + ph->p_align - 1)
+                                    & ~(ph->p_align - 1));
+               __munmap ((caddr_t) mapstart, mapend - mapstart);
+             }
+
+         /* Finally, unlink the data structure and free it.  */
+         map->l_prev->l_next = map->l_next;
+         if (map->l_next)
+           map->l_next->l_prev = map->l_prev;
+         if (map->l_searchlist)
+           free (map->l_searchlist);
+         free (map);
+       }
+    }
+
+  free (list);
+}
index 7e3b259..3e49fcf 100644 (file)
@@ -62,7 +62,9 @@ _dl_map_object_deps (struct link_map *map)
              {
                /* Map in the needed object.  */
                struct link_map *dep
-                 = _dl_map_object (l, strtab + d->d_un.d_val);
+                 = _dl_map_object (l, strtab + d->d_un.d_val,
+                                   l->l_type == lt_executable ? lt_library :
+                                   l->l_type);
 
                if (dep->l_reserved)
                  /* This object is already in the search list we are
index c6acc8c..b9f4aa1 100644 (file)
@@ -63,152 +63,14 @@ int _dl_zerofd = -1;
 size_t _dl_pagesize;
 
 
-/* Try to open NAME in one of the directories in DIRPATH.
-   Return the fd, or -1.  If successful, fill in *REALNAME
-   with the malloc'd full directory name.  */
-
-static int
-open_path (const char *name, size_t namelen,
-          const char *dirpath,
-          char **realname)
-{
-  char *buf;
-  const char *p;
-  int fd;
-
-  p = dirpath;
-  if (p == NULL || *p == '\0')
-    {
-      errno = ENOENT;
-      return -1;
-    }
-
-  buf = __alloca (strlen (dirpath) + 1 + namelen);
-  do
-    {
-      size_t buflen;
-
-      dirpath = p;
-      p = strpbrk (dirpath, ":;");
-      if (p == NULL)
-       p = strchr (dirpath, '\0');
-
-      if (p == dirpath)
-       {
-         /* Two adjacent colons, or a colon at the beginning or the end of
-            the path means to search the current directory.  */
-         (void) memcpy (buf, name, namelen);
-         buflen = namelen;
-       }
-      else
-       {
-         /* Construct the pathname to try.  */
-         (void) memcpy (buf, dirpath, p - dirpath);
-         buf[p - dirpath] = '/';
-         (void) memcpy (&buf[(p - dirpath) + 1], name, namelen);
-         buflen = p - dirpath + 1 + namelen;
-       }
-
-      fd = __open (buf, O_RDONLY);
-      if (fd != -1)
-       {
-         *realname = malloc (buflen);
-         if (*realname)
-           {
-             memcpy (*realname, buf, buflen);
-             return fd;
-           }
-         else
-           {
-             /* No memory for the name, we certainly won't be able
-                to load and link it.  */
-             __close (fd);
-             return -1;
-           }
-       }
-      if (errno != ENOENT && errno != EACCES)
-       /* The file exists and is readable, but something went wrong.  */
-       return -1;
-    }
-  while (*p++ != '\0');
-
-  return -1;
-}
-
-/* Map in the shared object file NAME.  */
-
-struct link_map *
-_dl_map_object (struct link_map *loader, const char *name)
-{
-  int fd;
-  char *realname;
-  struct link_map *l;
-
-  /* Look for this name among those already loaded.  */
-  for (l = _dl_loaded; l; l = l->l_next)
-    if (! strcmp (name, l->l_libname))
-      {
-       /* The object is already loaded.
-          Just bump its reference count and return it.  */
-       ++l->l_opencount;
-       return l;
-      }
-
-  if (strchr (name, '/') == NULL)
-    {
-      /* Search for NAME in several places.  */
-
-      size_t namelen = strlen (name) + 1;
-
-      inline void trypath (const char *dirpath)
-       {
-         fd = open_path (name, namelen, dirpath, &realname);
-       }
-
-      fd = -1;
-      if (loader && loader->l_info[DT_RPATH])
-       trypath ((const char *) (loader->l_addr +
-                                loader->l_info[DT_STRTAB]->d_un.d_ptr +
-                                loader->l_info[DT_RPATH]->d_un.d_val));
-      if (fd == -1 && ! _dl_secure)
-       trypath (getenv ("LD_LIBRARY_PATH"));
-      if (fd == -1)
-       {
-         extern const char *_dl_rpath; /* Set in rtld.c. */
-         trypath (_dl_rpath);
-       }
-    }
-  else
-    {
-      fd = __open (name, O_RDONLY);
-      if (fd != -1)
-       {
-         size_t len = strlen (name) + 1;
-         realname = malloc (len);
-         if (realname)
-           memcpy (realname, name, len);
-         else
-           {
-             __close (fd);
-             fd = -1;
-           }
-       }
-    }
-
-  if (fd == -1)
-    _dl_signal_error (errno, name, "cannot open shared object file");
-
-  return _dl_map_object_from_fd (name, fd, realname);
-}
-
-
 /* Map in the shared object NAME, actually located in REALNAME, and already
    opened on FD.  */
 
 struct link_map *
-_dl_map_object_from_fd (const char *name, int fd, char *realname)
+_dl_map_object_from_fd (const char *name, int fd, char *realname,
+                       struct link_map *loader, int l_type)
 {
-  struct link_map *l = NULL;
+  struct link_map *l;
   void *file_mapping = NULL;
   size_t mapping_size = 0;
 
@@ -218,7 +80,17 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname)
       (void) __close (fd);
       if (file_mapping)
        __munmap (file_mapping, mapping_size);
-      _dl_signal_error (code, l ? l->l_name : name, msg);
+      if (l)
+       {
+         /* Remove the stillborn object from the list and free it.  */
+         if (l->l_prev)
+           l->l_prev->l_next = l->l_next;
+         if (l->l_next)
+           l->l_next->l_prev = l->l_prev;
+         free (l);
+       }
+      free (realname);
+      _dl_signal_error (code, name, msg);
     }
 
   inline caddr_t map_segment (ElfW(Addr) mapstart, size_t len,
@@ -304,17 +176,23 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname)
   if (header->e_phentsize != sizeof (ElfW(Phdr)))
     LOSE ("ELF file's phentsize not the expected size");
 
-  /* Enter the new object in the list of loaded objects.  */
-  l = _dl_new_object (realname, name, lt_loaded);
-  l->l_opencount = 1;
-
   if (_dl_zerofd == -1)
     {
       _dl_zerofd = _dl_sysdep_open_zero_fill ();
       if (_dl_zerofd == -1)
-       _dl_signal_error (errno, NULL, "cannot open zero fill device");
+       {
+         __close (fd);
+         _dl_signal_error (errno, NULL, "cannot open zero fill device");
+       }
     }
 
+  /* Enter the new object in the list of loaded objects.  */
+  l = _dl_new_object (realname, name, l_type);
+  if (! l)
+    lose (ENOMEM, "cannot create shared object descriptor");
+  l->l_opencount = 1;
+  l->l_loader = loader;
+
   /* Extract the remaining details we need from the ELF header
      and then map in the program header table.  */
   l->l_entry = header->e_entry;
@@ -464,7 +342,8 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname)
   /* We are done mapping in the file.  We no longer need the descriptor.  */
   __close (fd);
 
-  l->l_type = type == ET_EXEC ? lt_executable : lt_library;
+  if (l->l_type == lt_library && type == ET_EXEC)
+    l->l_type = lt_executable;
 
   if (l->l_ld == 0)
     {
@@ -484,3 +363,142 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname)
 
   return l;
 }
+\f
+/* Try to open NAME in one of the directories in DIRPATH.
+   Return the fd, or -1.  If successful, fill in *REALNAME
+   with the malloc'd full directory name.  */
+
+static int
+open_path (const char *name, size_t namelen,
+          const char *dirpath,
+          char **realname)
+{
+  char *buf;
+  const char *p;
+  int fd;
+
+  p = dirpath;
+  if (p == NULL || *p == '\0')
+    {
+      errno = ENOENT;
+      return -1;
+    }
+
+  buf = __alloca (strlen (dirpath) + 1 + namelen);
+  do
+    {
+      size_t buflen;
+
+      dirpath = p;
+      p = strpbrk (dirpath, ":;");
+      if (p == NULL)
+       p = strchr (dirpath, '\0');
+
+      if (p == dirpath)
+       {
+         /* Two adjacent colons, or a colon at the beginning or the end of
+            the path means to search the current directory.  */
+         (void) memcpy (buf, name, namelen);
+         buflen = namelen;
+       }
+      else
+       {
+         /* Construct the pathname to try.  */
+         (void) memcpy (buf, dirpath, p - dirpath);
+         buf[p - dirpath] = '/';
+         (void) memcpy (&buf[(p - dirpath) + 1], name, namelen);
+         buflen = p - dirpath + 1 + namelen;
+       }
+
+      fd = __open (buf, O_RDONLY);
+      if (fd != -1)
+       {
+         *realname = malloc (buflen);
+         if (*realname)
+           {
+             memcpy (*realname, buf, buflen);
+             return fd;
+           }
+         else
+           {
+             /* No memory for the name, we certainly won't be able
+                to load and link it.  */
+             __close (fd);
+             return -1;
+           }
+       }
+      if (errno != ENOENT && errno != EACCES)
+       /* The file exists and is readable, but something went wrong.  */
+       return -1;
+    }
+  while (*p++ != '\0');
+
+  return -1;
+}
+
+/* Map in the shared object file NAME.  */
+
+struct link_map *
+_dl_map_object (struct link_map *loader, const char *name, int type)
+{
+  int fd;
+  char *realname;
+  struct link_map *l;
+
+  /* Look for this name among those already loaded.  */
+  for (l = _dl_loaded; l; l = l->l_next)
+    if (! strcmp (name, l->l_libname))
+      {
+       /* The object is already loaded.
+          Just bump its reference count and return it.  */
+       ++l->l_opencount;
+       return l;
+      }
+
+  if (strchr (name, '/') == NULL)
+    {
+      /* Search for NAME in several places.  */
+
+      size_t namelen = strlen (name) + 1;
+
+      inline void trypath (const char *dirpath)
+       {
+         fd = open_path (name, namelen, dirpath, &realname);
+       }
+
+      fd = -1;
+      for (l = loader; l; l = l->l_loader)
+       if (l && l->l_info[DT_RPATH])
+         trypath ((const char *) (l->l_addr +
+                                  l->l_info[DT_STRTAB]->d_un.d_ptr +
+                                  l->l_info[DT_RPATH]->d_un.d_val));
+      if (fd == -1 && ! _dl_secure)
+       trypath (getenv ("LD_LIBRARY_PATH"));
+      if (fd == -1)
+       {
+         extern const char *_dl_rpath; /* Set in rtld.c. */
+         trypath (_dl_rpath);
+       }
+    }
+  else
+    {
+      fd = __open (name, O_RDONLY);
+      if (fd != -1)
+       {
+         size_t len = strlen (name) + 1;
+         realname = malloc (len);
+         if (realname)
+           memcpy (realname, name, len);
+         else
+           {
+             __close (fd);
+             fd = -1;
+           }
+       }
+    }
+
+  if (fd == -1)
+    _dl_signal_error (errno, name, "cannot open shared object file");
+
+  return _dl_map_object_from_fd (name, fd, realname, loader, type);
+}
index 0674253..5f1e6d0 100644 (file)
@@ -50,7 +50,7 @@ _dl_elf_hash (const char *name)
 
 ElfW(Addr)
 _dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
-                  struct link_map *symbol_scope[2],
+                  struct link_map *symbol_scope[],
                   const char *reference_name,
                   ElfW(Addr) reloc_addr,
                   int noplt)
@@ -65,69 +65,68 @@ _dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
   struct link_map **scope, *map;
 
   /* Search the relevant loaded objects for a definition.  */
-  for (scope = symbol_scope; scope < &symbol_scope[2]; ++scope)
-    if (*scope)
-      for (i = 0; i < (*scope)->l_nsearchlist; ++i)
-       {
-         const ElfW(Sym) *symtab;
-         const char *strtab;
-         ElfW(Word) symidx;
-
-         map = (*scope)->l_searchlist[i];
-
-         symtab = ((void *) map->l_addr + map->l_info[DT_SYMTAB]->d_un.d_ptr);
-         strtab = ((void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr);
-
-         /* Search the appropriate hash bucket in this object's symbol table
-            for a definition for the same symbol name.  */
-         for (symidx = map->l_buckets[hash % map->l_nbuckets];
-              symidx != STN_UNDEF;
-              symidx = map->l_chain[symidx])
-           {
-             const ElfW(Sym) *sym = &symtab[symidx];
-
-             if (sym->st_value == 0 || /* No value.  */
-                 /* Cannot resolve to the location being filled in.  */
-                 reloc_addr == map->l_addr + sym->st_value ||
-                 (noplt && sym->st_shndx == SHN_UNDEF)) /* Reject PLT.  */
-               continue;
-
-             switch (ELFW(ST_TYPE) (sym->st_info))
-               {
-               case STT_NOTYPE:
-               case STT_FUNC:
-               case STT_OBJECT:
-                 break;
-               default:
-                 /* Not a code/data definition.  */
-                 continue;
-               }
-
-             if (sym != *ref && strcmp (strtab + sym->st_name, undef_name))
-               /* Not the symbol we are looking for.  */
+  for (scope = symbol_scope; *scope; ++scope)
+    for (i = 0; i < (*scope)->l_nsearchlist; ++i)
+      {
+       const ElfW(Sym) *symtab;
+       const char *strtab;
+       ElfW(Word) symidx;
+
+       map = (*scope)->l_searchlist[i];
+
+       symtab = ((void *) map->l_addr + map->l_info[DT_SYMTAB]->d_un.d_ptr);
+       strtab = ((void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr);
+
+       /* Search the appropriate hash bucket in this object's symbol table
+          for a definition for the same symbol name.  */
+       for (symidx = map->l_buckets[hash % map->l_nbuckets];
+            symidx != STN_UNDEF;
+            symidx = map->l_chain[symidx])
+         {
+           const ElfW(Sym) *sym = &symtab[symidx];
+
+           if (sym->st_value == 0 || /* No value.  */
+               /* Cannot resolve to the location being filled in.  */
+               reloc_addr == map->l_addr + sym->st_value ||
+               (noplt && sym->st_shndx == SHN_UNDEF)) /* Reject PLT.  */
+             continue;
+
+           switch (ELFW(ST_TYPE) (sym->st_info))
+             {
+             case STT_NOTYPE:
+             case STT_FUNC:
+             case STT_OBJECT:
+               break;
+             default:
+               /* Not a code/data definition.  */
                continue;
-
-             switch (ELFW(ST_BIND) (sym->st_info))
-               {
-               case STB_GLOBAL:
-                 /* Global definition.  Just what we need.  */
-                 *ref = sym;
-                 return map->l_addr;
-               case STB_WEAK:
-                 /* Weak definition.  Use this value if we don't find
-                    another.  */
-                 if (! weak_value.s)
-                   {
-                     weak_value.s = sym;
-                     weak_value.a = map->l_addr;
-                   }
-                 break;
-               default:
-                 /* Local symbols are ignored.  */
-                 break;
-               }
-           }
-       }
+             }
+
+           if (sym != *ref && strcmp (strtab + sym->st_name, undef_name))
+             /* Not the symbol we are looking for.  */
+             continue;
+
+           switch (ELFW(ST_BIND) (sym->st_info))
+             {
+             case STB_GLOBAL:
+               /* Global definition.  Just what we need.  */
+               *ref = sym;
+               return map->l_addr;
+             case STB_WEAK:
+               /* Weak definition.  Use this value if we don't find
+                  another.  */
+               if (! weak_value.s)
+                 {
+                   weak_value.s = sym;
+                   weak_value.a = map->l_addr;
+                 }
+               break;
+             default:
+               /* Local symbols are ignored.  */
+               break;
+             }
+         }
+      }
 
   if (weak_value.s == NULL && ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
     {
index 11e9e08..851d133 100644 (file)
@@ -1,5 +1,5 @@
 /* Storage management for the chain of loaded shared objects.
-Copyright (C) 1995 Free Software Foundation, Inc.
+Copyright (C) 1995, 1996 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,11 +24,8 @@ Cambridge, MA 02139, USA.  */
 #include <errno.h>
 
 
-/* List of objects currently loaded.  */
-struct link_map *_dl_loaded;
-
-/* Tail of that list which were loaded at startup.  */
-struct link_map *_dl_startup_loaded;
+/* List of objects currently loaded is [2] of this, aka _dl_loaded.  */
+struct link_map *_dl_default_scope[5];
 
 /* Allocate a `struct link_map' for a new object being loaded,
    and enter it into the _dl_loaded list.  */
@@ -38,8 +35,7 @@ _dl_new_object (char *realname, const char *libname, int type)
 {
   struct link_map *new = malloc (sizeof *new);
   if (! new)
-    _dl_signal_error (ENOMEM, libname,
-                     "cannot allocate shared object descriptor");
+    return NULL;
 
   memset (new, 0, sizeof *new);
   new->l_name = realname;
index 221abbd..9389303 100644 (file)
@@ -19,6 +19,10 @@ Cambridge, MA 02139, USA.  */
 
 #include <link.h>
 #include <dlfcn.h>
+#include <stdlib.h>
+#include <errno.h>
+
+size_t _dl_global_scope_alloc;
 
 struct link_map *
 _dl_open (struct link_map *parent, const char *file, int mode)
@@ -26,16 +30,83 @@ _dl_open (struct link_map *parent, const char *file, int mode)
   struct link_map *new, *l;
   ElfW(Addr) init;
 
+
   /* Load the named object.  */
-  new = _dl_map_object (parent, file);
+  new = _dl_map_object (parent, file, lt_loaded);
+  if (new->l_searchlist)
+    /* It was already open.  */
+    return new;
 
   /* Load that object's dependencies.  */
   _dl_map_object_deps (new);
 
-  /* Relocate the objects loaded.  */
-  for (l = new; l; l = l->l_next)
-    if (! l->l_relocated)
-      _dl_relocate_object (l, (mode & RTLD_BINDING_MASK) == RTLD_LAZY);
+
+  /* Relocate the objects loaded.  We do this in reverse order so that copy
+     relocs of earlier objects overwrite the data written by later objects.  */
+
+  l = new;
+  while (l->l_next)
+    l = l->l_next;
+  do
+    {
+      if (! l->l_relocated)
+       {
+         _dl_relocate_object (l, _dl_object_relocation_scope (l),
+                              (mode & RTLD_BINDING_MASK) == RTLD_LAZY);
+         *_dl_global_scope_end = NULL;
+       }
+
+      l = l->l_prev;
+    } while (l != new);
+
+  new->l_global = (mode & RTLD_GLOBAL);
+  if (new->l_global)
+    {
+      /* The symbols of the new object and its dependencies are to be
+        introduced into the global scope that will be used to resolve
+        references from other dynamically-loaded objects.  */
+
+      if (_dl_global_scope_alloc == 0)
+       {
+         /* This is the first dynamic object given global scope.  */
+         _dl_global_scope_alloc = 8;
+         _dl_global_scope = malloc (8 * sizeof (struct link_map *));
+         if (! _dl_global_scope)
+           {
+             _dl_global_scope = _dl_default_scope;
+           nomem:
+             _dl_close (new);
+             _dl_signal_error (ENOMEM, file, "cannot extend global scope");
+           }
+         _dl_global_scope[2] = _dl_default_scope[2];
+         _dl_global_scope[3] = new;
+         _dl_global_scope[4] = NULL;
+         _dl_global_scope[5] = NULL;
+       }
+      else
+       {
+         if (_dl_global_scope_alloc <
+             _dl_global_scope_end - _dl_global_scope + 2)
+           {
+             /* Must extend the list.  */
+             struct link_map **new = realloc (_dl_global_scope,
+                                              _dl_global_scope_alloc * 2);
+             if (! new)
+               goto nomem;
+             _dl_global_scope_end = new + (_dl_global_scope_end -
+                                           _dl_global_scope);
+             _dl_global_scope = new;
+             _dl_global_scope_alloc *= 2;
+           }
+
+         /* Append the new object and re-terminate the list.  */
+         *_dl_global_scope_end++ = new;
+         /* We keep the list double-terminated so the last element
+            can be filled in for symbol lookups.  */
+         _dl_global_scope_end[0] = NULL;
+         _dl_global_scope_end[1] = NULL;
+       }
+    }
 
   /* Run the initializer functions of new objects.  */
   while (init = _dl_init_next (new))
index 5da8575..e6778e7 100644 (file)
@@ -26,7 +26,7 @@ Cambridge, MA 02139, USA.  */
 
 
 void
-_dl_relocate_object (struct link_map *l, int lazy)
+_dl_relocate_object (struct link_map *l, struct link_map *scope[], int lazy)
 {
   if (l->l_relocated)
     return;
@@ -52,44 +52,26 @@ _dl_relocate_object (struct link_map *l, int lazy)
     }
 
   {
-    struct link_map *scope[2];
+    /* Do the actual relocation of the object's GOT and other data.  */
 
-    const char *strtab
+    const char *strtab         /* String table object symbols.  */
       = ((void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr);
-
     ElfW(Addr) resolve (const ElfW(Sym) **ref,
                        ElfW(Addr) reloc_addr, int noplt)
       {
+       /* Look up the referenced symbol in the specified scope.  */
        return _dl_lookup_symbol (strtab + (*ref)->st_name, ref, scope,
                                  l->l_name, reloc_addr, noplt);
       }
 
-    if (l->l_info[DT_SYMBOLIC])
-      {
-       scope[0] = l;
-       scope[1] = _dl_loaded;
-      }
-    else
-      {
-       scope[0] = _dl_loaded;
-       scope[1] = l;
-      }
-
-    if (l->l_type == lt_interpreter)
-      /* We cannot be lazy when relocating the dynamic linker itself.  It
-        was previously relocated eagerly (allowing us to be running now),
-        and needs always to be fully relocated so it can run without the
-        aid of run-time fixups (because it's the one to do them), so we
-        must always re-relocate its PLT eagerly.  */
-      lazy = 0;
-
     ELF_DYNAMIC_RELOCATE (l, lazy, resolve);
   }
 
-  /* Set up the PLT so its unrelocated entries will
-     jump to _dl_runtime_resolve, which will relocate them.  */
+  /* Set up the PLT so its unrelocated entries will jump to
+     _dl_runtime_resolve (dl-runtime.c), which will relocate them.  */
   elf_machine_runtime_setup (l, lazy);
 
+  /* Mark the object so we know ths work has been done.  */
   l->l_relocated = 1;
 
   if (l->l_info[DT_TEXTREL])
@@ -114,5 +96,4 @@ _dl_relocate_object (struct link_map *l, int lazy)
                                "can't restore segment prot after reloc");
          }
     }
-
 }
index c306543..8ad2c0f 100644 (file)
@@ -20,6 +20,54 @@ Cambridge, MA 02139, USA.  */
 #include <link.h>
 #include "dynamic-link.h"
 
+
+/* The global scope we will use for symbol lookups.
+   This will be modified by _dl_open if RTLD_GLOBAL is used.  */
+struct link_map **_dl_global_scope = _dl_default_scope;
+struct link_map **_dl_global_scope_end = &_dl_default_scope[3];
+
+
+/* Hack _dl_global_scope[0] and [1] as necessary, and return a pointer into
+   _dl_global_scope that should be passed to _dl_lookup_symbol for symbol
+   references made in the object L's relocations.  */
+inline struct link_map **
+_dl_object_relocation_scope (struct link_map *l)
+{
+  if (l->l_info[DT_SYMBOLIC])
+    {
+      /* This object's global references are to be resolved first
+        in the object itself, and only secondarily in more global
+        scopes.  */
+
+      if (! l->l_searchlist)
+       /* We must construct the searchlist for this object.  */
+       _dl_map_object_deps (l);
+
+      /* The primary scope is this object itself and its
+        dependencies.  */
+      _dl_global_scope[0] = l;
+
+      /* Secondary is the dependency tree that reached L; the object
+        requested directly by the user is at the root of that tree.  */
+      while (l->l_loader)
+       l = l->l_loader;
+      _dl_global_scope[1] = l;
+
+      /* Finally, the global scope follows.  */
+
+      return _dl_global_scope;
+    }
+  else
+    {
+      /* Use first the global scope, and then the scope of the root of the
+        dependency tree that first caused this object to be loaded.  */
+      while (l->l_loader)
+       l = l->l_loader;
+      *_dl_global_scope_end = l;
+      return &_dl_global_scope[2];
+    }
+}
+\f
 /* Figure out the right type, Rel or Rela.  */
 #define elf_machine_rel 1
 #define elf_machine_rela 2
@@ -67,17 +115,21 @@ fixup (
     = (const void *) (l->l_addr + l->l_info[DT_JMPREL]->d_un.d_ptr +
                      reloc_offset);
 
+  /* Set up the scope to find symbols referenced by this object.  */
+  struct link_map **scope = _dl_object_relocation_scope (l);
+
+  /* Perform the specified relocation.  */
   ElfW(Addr) resolve (const ElfW(Sym) **ref,
                      ElfW(Addr) reloc_addr, int noplt)
     {
-      struct link_map *scope[2] = { _dl_loaded, NULL };
       return _dl_lookup_symbol (strtab + (*ref)->st_name, ref,
                                scope, l->l_name, reloc_addr, noplt);
     }
-
-  /* Perform the specified relocation.  */
   elf_machine_relplt (l, reloc, &symtab[ELFW(R_SYM) (reloc->r_info)], resolve);
 
+  *_dl_global_scope_end = NULL;
+
+  /* Return the address that was written by the relocation.  */
   return *(ElfW(Addr) *) (l->l_addr + reloc->r_offset);
 }
 
index 0d2689e..a5c8e7c 100644 (file)
@@ -19,81 +19,13 @@ Cambridge, MA 02139, USA.  */
 
 #include <link.h>
 #include <dlfcn.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-
-
-#define LOSE(s) _dl_signal_error (0, map->l_name, s)
 
 int
 dlclose (void *handle)
 {
   void doit (void)
     {
-      struct link_map *map = handle;
-      struct link_map **list;
-      unsigned int i;
-
-      if (map->l_opencount == 0)
-       LOSE ("shared object not open");
-
-      /* Decrement the reference count.  */
-      if (--map->l_opencount > 0 || map->l_type != lt_loaded)
-       /* There are still references to this object.  Do nothing more.  */
-       return;
-
-      list = map->l_searchlist;
-
-      /* The search list contains a counted reference to each object it
-        points to, the 0th elt being MAP itself.  Decrement the reference
-        counts on all the objects MAP depends on.  */
-      for (i = 1; i < map->l_nsearchlist; ++i)
-       --list[i]->l_opencount;
-
-      /* Clear the search list so it doesn't get freed while we are still
-         using it.  We have cached it in LIST and will free it when
-         finished.  */
-      map->l_searchlist = NULL;
-
-      /* Check each element of the search list to see if all references to
-         it are gone.  */
-      for (i = 0; i < map->l_nsearchlist; ++i)
-       {
-         struct link_map *map = list[i];
-         if (map->l_opencount == 0 && map->l_type == lt_loaded)
-           {
-             /* That was the last reference, and this was a dlopen-loaded
-                object.  We can unmap it.  */
-             const ElfW(Phdr) *ph;
-
-             if (map->l_info[DT_FINI])
-               /* Call its termination function.  */
-               (*(void (*) (void)) ((void *) map->l_addr +
-                                    map->l_info[DT_FINI]->d_un.d_ptr)) ();
-
-             /* Unmap the segments.  */
-             for (ph = map->l_phdr; ph < &map->l_phdr[map->l_phnum]; ++ph)
-               if (ph->p_type == PT_LOAD)
-                 {
-                   ElfW(Addr) mapstart = ph->p_vaddr & ~(ph->p_align - 1);
-                   ElfW(Addr) mapend = ((ph->p_vaddr + ph->p_memsz
-                                         + ph->p_align - 1)
-                                        & ~(ph->p_align - 1));
-                   munmap ((caddr_t) mapstart, mapend - mapstart);
-                 }
-
-             /* Finally, unlink the data structure and free it.  */
-             map->l_prev->l_next = map->l_next;
-             if (map->l_next)
-               map->l_next->l_prev = map->l_prev;
-             if (map->l_searchlist)
-               free (map->l_searchlist);
-             free (map);
-           }
-       }
-
-      free (list);
+      _dl_close (handle);
     }
 
   return _dlerror_run (doit) ? -1 : 0;
index 74ab8bb..e261fca 100644 (file)
@@ -28,7 +28,7 @@ dlopen (const char *file, int mode)
 
   void doit (void)
     {
-      new = _dl_open (_dl_loaded, file, mode);
+      new = _dl_open (_dl_loaded, file ?: "", mode);
     }
 
   return _dlerror_run (doit) ? NULL : new;
index 6d284cb..89dfa20 100644 (file)
@@ -106,6 +106,9 @@ struct link_map
     struct link_map **l_searchlist;
     unsigned int l_nsearchlist;
 
+    /* Dependent object that first caused this object to be loaded.  */
+    struct link_map *l_loader;
+
     /* Symbol hash table.  */
     ElfW(Word) l_nbuckets;
     const ElfW(Word) *l_buckets, *l_chain;
@@ -114,14 +117,14 @@ struct link_map
     enum                       /* Where this object came from.  */
       {
        lt_executable,          /* The main executable program.  */
-       lt_interpreter,         /* The interpreter: the dynamic linker.  */
        lt_library,             /* Library needed by main executable.  */
        lt_loaded,              /* Extra run-time loaded shared object.  */
       } l_type:2;
     unsigned int l_relocated:1;        /* Nonzero if object's relocations done.  */
     unsigned int l_init_called:1; /* Nonzero if DT_INIT function called.  */
     unsigned int l_init_running:1; /* Nonzero while DT_INIT function runs.  */
-    unsigned int l_reserved:3; /* Reserved for internal use.  */
+    unsigned int l_global:1;   /* Nonzero if object in _dl_global_scope.  */
+    unsigned int l_reserved:2; /* Reserved for internal use.  */
   };
 \f
 /* Internal functions of the run-time dynamic linker.
@@ -188,12 +191,7 @@ extern int _dlerror_run (void (*operate) (void));
    LOADER's DT_RPATH is used in searching for NAME.
    If the object is already opened, returns its existing map.  */
 extern struct link_map *_dl_map_object (struct link_map *loader,
-                                       const char *name);
-
-/* Similar, but file found at REALNAME and opened on FD.
-   REALNAME must malloc'd storage and is used in internal data structures.  */
-extern struct link_map *_dl_map_object_from_fd (const char *name,
-                                               int fd, char *realname);
+                                       const char *name, int type);
 
 /* Call _dl_map_object on the dependencies of MAP, and
    set up MAP->l_searchlist.  */
@@ -210,21 +208,24 @@ extern void _dl_setup_hash (struct link_map *map);
 extern struct link_map *_dl_open (struct link_map *loader,
                                  const char *name, int mode);
 
+/* Close an object previously opened by _dl_open.  */
+extern void _dl_close (struct link_map *map);
 
 
 /* Search loaded objects' symbol tables for a definition of the symbol
    referred to by UNDEF.  *SYM is the symbol table entry containing the
    reference; it is replaced with the defining symbol, and the base load
-   address of the defining object is returned.  Each of SYMBOL_SCOPE[0] and
-   SYMBOL_SCOPE[1] that is not null and their dependencies are searched to
-   resolve the name.  REFERENCE_NAME should name the object containing the
-   reference; it is used in error messages.  RELOC_ADDR is the address
-   being fixed up and the chosen symbol cannot be one with this value.  If
-   NOPLT is nonzero, then the reference must not be resolved to a PLT
-   entry.  */
+   address of the defining object is returned.  SYMBOL_SCOPE is a
+   null-terminated list of object scopes to search; each object's
+   l_searchlist (i.e. the segment of the dependency tree starting at that
+   object) is searched in turn.  REFERENCE_NAME should name the object
+   containing the reference; it is used in error messages.  RELOC_ADDR is
+   the address being fixed up and the chosen symbol cannot be one with this
+   value.  If NOPLT is nonzero, then the reference must not be resolved to
+   a PLT entry.  */
 extern ElfW(Addr) _dl_lookup_symbol (const char *undef,
                                     const ElfW(Sym) **sym,
-                                    struct link_map *symbol_scope[2],
+                                    struct link_map *symbol_scope[],
                                     const char *reference_name,
                                     ElfW(Addr) reloc_addr,
                                     int noplt);
@@ -236,11 +237,33 @@ extern ElfW(Addr) _dl_symbol_value (struct link_map *map, const char *name);
 /* Structure describing the dynamic linker itself.  */
 extern struct link_map _dl_rtld_map;
 
-/* List of objects currently loaded.  */
-extern struct link_map *_dl_loaded;
+/* The list of objects currently loaded is the third element of the
+   `_dl_default_scope' array, and the fourth element is always null.
+   This leaves two slots before it that are used when resolving
+   DT_SYMBOLIC objects' references one after it for normal references
+   (see below).  */
+#define _dl_loaded     (_dl_default_scope[2])
+extern struct link_map *_dl_default_scope[5];
+
+/* Null-terminated list of objects in the dynamic `global scope'.  The
+   list starts at [2]; i.e. &_dl_global_scope[2] is the argument
+   passed to _dl_lookup_symbol to search the global scope.  To search
+   a specific object and its dependencies in preference to the global
+   scope, fill in the [1] slot and pass its address; for two specific
+   object scopes, fill [0] and [1].  The list is double-terminated; to
+   search the global scope and then a specific object and its
+   dependencies, set *_dl_global_scope_end.  This variable initially
+   points to _dl_default_scope, and _dl_loaded is always kept in [2]
+   of this list.  A new list is malloc'd when new objects are loaded
+   with RTLD_GLOBAL.  */
+extern struct link_map **_dl_global_scope, **_dl_global_scope_end;
+extern size_t _dl_global_scope_alloc; /* Number of slots malloc'd.  */
+
+/* Hack _dl_global_scope[0] and [1] as necessary, and return a pointer into
+   _dl_global_scope that should be passed to _dl_lookup_symbol for symbol
+   references made in the object MAP's relocations.  */
+extern struct link_map **_dl_object_relocation_scope (struct link_map *map);
 
-/* Tail of that list which were loaded at startup.  */
-extern struct link_map *_dl_startup_loaded;
 
 /* Allocate a `struct link_map' for a new object being loaded,
    and enter it into the _dl_loaded list.  */
@@ -248,8 +271,11 @@ extern struct link_map *_dl_new_object (char *realname, const char *libname,
                                        int type);
 
 /* Relocate the given object (if it hasn't already been).
+   SCOPE is passed to _dl_lookup_symbol in symbol lookups.
    If LAZY is nonzero, don't relocate its PLT.  */
-extern void _dl_relocate_object (struct link_map *map, int lazy);
+extern void _dl_relocate_object (struct link_map *map,
+                                struct link_map *scope[],
+                                int lazy);
 
 /* Return the address of the next initializer function for MAP or one of
    its dependencies that has not yet been run.  When there are no more
index bc1f71b..6647727 100644 (file)
@@ -75,13 +75,6 @@ _dl_start (void *arg)
   /* Relocate ourselves so we can do normal function calls and
      data access using the global offset table.  */
 
-  /* We must initialize `l_type' to make sure it is not `lt_interpreter'.
-     That is the type to describe us, but not during bootstrapping--it
-     indicates to elf_machine_rel{,a} that we were already relocated during
-     bootstrapping, so it must anti-perform each bootstrapping relocation
-     before applying the final relocation when ld.so is linked in as
-     normal a shared library.  */
-  bootstrap_map.l_type = lt_library;
   ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0, NULL);
 
 
@@ -178,7 +171,7 @@ of this helper program; chances are you did not intend to run this program.\n",
       --_dl_argc;
       ++_dl_argv;
 
-      l = _dl_map_object (NULL, _dl_argv[0]);
+      l = _dl_map_object (NULL, _dl_argv[0], lt_library);
       phdr = l->l_phdr;
       phent = l->l_phnum;
       l->l_name = (char *) "";
@@ -188,7 +181,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.  */
-      l = _dl_new_object ((char *) "", "", lt_executable);
+      l = _dl_new_object ((char *) "", "", lt_library);
       l->l_phdr = phdr;
       l->l_phnum = phent;
       interpreter_name = 0;
@@ -245,7 +238,7 @@ of this helper program; chances are you did not intend to run this program.\n",
   /* Put the link_map for ourselves on the chain so it can be found by
      name.  */
   _dl_rtld_map.l_name = (char *) _dl_rtld_map.l_libname = interpreter_name;
-  _dl_rtld_map.l_type = lt_interpreter;
+  _dl_rtld_map.l_type = lt_library;
   while (l->l_next)
     l = l->l_next;
   l->l_next = &_dl_rtld_map;
@@ -293,9 +286,9 @@ of this helper program; chances are you did not intend to run this program.\n",
       for (i = 1; i < _dl_argc; ++i)
        {
          const ElfW(Sym) *ref = NULL;
-         struct link_map *scope[2] ={ _dl_loaded, NULL };
-         ElfW(Addr) loadbase
-           = _dl_lookup_symbol (_dl_argv[i], &ref, scope, "argument", 0, 0);
+         ElfW(Addr) loadbase = _dl_lookup_symbol (_dl_argv[i], &ref,
+                                                  &_dl_default_scope[2],
+                                                  "argument", 0, 0);
          char buf[20], *bp;
          buf[sizeof buf - 1] = '\0';
          bp = _itoa (ref->st_value, &buf[sizeof buf - 1], 16, 0);
@@ -314,35 +307,41 @@ of this helper program; chances are you did not intend to run this program.\n",
 
   lazy = !_dl_secure && *(getenv ("LD_BIND_NOW") ?: "") == '\0';
 
-  /* Now we have all the objects loaded.  Relocate them all except for
-     the dynamic linker itself.  We do this in reverse order so that
-     copy relocs of earlier objects overwrite the data written by later
-     objects.  We do not re-relocate the dynamic linker itself in this
-     loop because that could result in the GOT entries for functions we
-     call being changed, and that would break us.  It is safe to
-     relocate the dynamic linker out of order because it has no copy
-     relocs (we know that because it is self-contained).  */
-  l = _dl_loaded;
-  while (l->l_next)
-    l = l->l_next;
-  do
-    {
-      if (l != &_dl_rtld_map)
-       _dl_relocate_object (l, lazy);
-      l = l->l_prev;
-    } while (l);
-
-  /* Do any necessary cleanups for the startup OS interface code.
-     We do these now so that no calls are made after rtld re-relocation
-     which might be resolved to different functions than we expect.
-     We cannot do this before relocating the other objects because
-     _dl_relocate_object might need to call `mprotect' for DT_TEXTREL.  */
-  _dl_sysdep_start_cleanup ();
-
-  if (_dl_rtld_map.l_opencount > 0)
-    /* There was an explicit ref to the dynamic linker as a shared lib.
-       Re-relocate ourselves with user-controlled symbol definitions.  */
-    _dl_relocate_object (&_dl_rtld_map, lazy);
+  {
+    /* Now we have all the objects loaded.  Relocate them all except for
+       the dynamic linker itself.  We do this in reverse order so that copy
+       relocs of earlier objects overwrite the data written by later
+       objects.  We do not re-relocate the dynamic linker itself in this
+       loop because that could result in the GOT entries for functions we
+       call being changed, and that would break us.  It is safe to relocate
+       the dynamic linker out of order because it has no copy relocs (we
+       know that because it is self-contained).  */
+
+    l = _dl_loaded;
+    while (l->l_next)
+      l = l->l_next;
+    do
+      {
+       if (l != &_dl_rtld_map)
+         {
+           _dl_relocate_object (l, _dl_object_relocation_scope (l), lazy);
+           *_dl_global_scope_end = NULL;
+         }
+       l = l->l_prev;
+      } while (l);
+
+    /* Do any necessary cleanups for the startup OS interface code.
+       We do these now so that no calls are made after rtld re-relocation
+       which might be resolved to different functions than we expect.
+       We cannot do this before relocating the other objects because
+       _dl_relocate_object might need to call `mprotect' for DT_TEXTREL.  */
+    _dl_sysdep_start_cleanup ();
+
+    if (_dl_rtld_map.l_opencount > 0)
+      /* There was an explicit ref to the dynamic linker as a shared lib.
+        Re-relocate ourselves with user-controlled symbol definitions.  */
+      _dl_relocate_object (&_dl_rtld_map, &_dl_default_scope[2], 0);
+  }
 
   /* Tell the debugger where to find the map of loaded objects.  */
   _dl_r_debug.r_version = 1    /* R_DEBUG_VERSION XXX */;
index b52e604..bcd388f 100644 (file)
@@ -100,7 +100,7 @@ elf_machine_rel (struct link_map *map,
       *reloc_addr = sym ? (loadbase + sym->st_value) : 0;
       break;
     case R_386_32:
-      if (map->l_type == lt_interpreter)
+      if (resolve && map == &_dl_rtld_map)
        {
          /* Undo the relocation done here during bootstrapping.  Now we will
             relocate it anew, possibly using a binding found in the user
@@ -117,7 +117,7 @@ elf_machine_rel (struct link_map *map,
       *reloc_addr += sym ? (loadbase + sym->st_value) : 0;
       break;
     case R_386_RELATIVE:
-      if (map->l_type != lt_interpreter) /* Already done in dynamic linker.  */
+      if (!resolve || map != &_dl_rtld_map) /* Already done in rtld itself.  */
        *reloc_addr += map->l_addr;
       break;
     case R_386_PC32:
@@ -229,9 +229,9 @@ _dl_start_user:\n\
        leal (%esp,%eax,4), %esp\n\
        # Push back the modified argument count.\n\
        pushl %ecx\n\
-       # Push _dl_loaded as argument in _dl_init_next call below.\n\
-       movl _dl_loaded@GOT(%ebx), %eax\n\
-       movl (%eax), %esi\n\
+       # Push _dl_default_scope[2] as argument in _dl_init_next call below.\n\
+       movl _dl_default_scope@GOT(%ebx), %eax\n\
+       movl 8(%eax), %esi\n\
 0:     pushl %esi\n\
        # Call _dl_init_next to return the address of an initializer\n\
        # function to run.\n\
index 74e8874..415216b 100644 (file)
@@ -252,9 +252,9 @@ _dl_start_user:
        lea (%sp, %d0*4), %sp
        | Push back the modified argument count.
        move.l %d1, -(%sp)
-0:     | Push _dl_loaded as argument in _dl_init_next call below.
-       move.l ([_dl_loaded@GOT, %a5]), %d2
-0:     move.l %d2, -(%sp)
+0:     | Push _dl_default_scope[2] as argument in _dl_init_next call below.
+       move.l ([_dl_default_scope@GOT, %a5]), %d2
+0:     move.l (%d2, 8), -(%sp)
        | Call _dl_init_next to return the address of an initializer
        | function to run.
        bsr.l _dl_init_next@PLTPC