Mon Jun 10 06:14:03 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
authorroland <roland>
Mon, 10 Jun 1996 20:11:11 +0000 (20:11 +0000)
committerroland <roland>
Mon, 10 Jun 1996 20:11:11 +0000 (20:11 +0000)
* 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/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-open.c

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))