Update.
authorUlrich Drepper <drepper@redhat.com>
Sat, 8 Sep 2001 16:27:08 +0000 (16:27 +0000)
committerUlrich Drepper <drepper@redhat.com>
Sat, 8 Sep 2001 16:27:08 +0000 (16:27 +0000)
2001-09-08  Ulrich Drepper  <drepper@redhat.com>

* elf/dl-close.c (_dl_close): If object has no r_list (i.e., wasn't
loaded directly) determine length if l_initfini list by iterating
over its elements.  Minor optimizations.
* elf/dl-deps.c (_dl_map_object_deps): Always add own map to l_initfini
for dependency objects.
If object was already loaded check whether any of the dependencies
is already on the relocation dependency list.  If yes, remove the
latter.  Minor optimizations.
* elf/dl-lookup.c (add_dependency): Add check for self reference of
maps here.  Search l_initfini list only if the object was loaded
directly and not only as a dependency.
(_dl_lookup_symbol): Add relocation dependency also if object
is not in global scope.  Remove test for self-reference here.
(_dl_lookup_versioned_symbol): Likewise.
* elf/dl-object (_dl_new_object): Cleanup.  Initialize dont_free
element of first name record.
* elf/loadtest.c: Add some more test to recognize early if an object
wasn't unloaded.
* elf/Makefile: Add rules to build and run reldep5.
* elf/reldep5.c: New file.
* elf/reldepmod5.c: New file.
* elf/reldepmod6.c: New file.

* elf/reldep2.c: Fix typo.

* elf/dl-object.c (_dl_new_object): Initialize l_scope and l_scope_max.

ChangeLog
elf/Makefile
elf/dl-close.c
elf/dl-deps.c
elf/dl-lookup.c
elf/dl-object.c
elf/loadtest.c
elf/reldep5.c [new file with mode: 0644]
elf/reldepmod5.c [new file with mode: 0644]
elf/reldepmod6.c [new file with mode: 0644]

index 21653dc..81ba6ca 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,8 +1,35 @@
+2001-09-08  Ulrich Drepper  <drepper@redhat.com>
+
+       * elf/dl-close.c (_dl_close): If object has no r_list (i.e., wasn't
+       loaded directly) determine length if l_initfini list by iterating
+       over its elements.  Minor optimizations.
+       * elf/dl-deps.c (_dl_map_object_deps): Always add own map to l_initfini
+       for dependency objects.
+       If object was already loaded check whether any of the dependencies
+       is already on the relocation dependency list.  If yes, remove the
+       latter.  Minor optimizations.
+       * elf/dl-lookup.c (add_dependency): Add check for self reference of
+       maps here.  Search l_initfini list only if the object was loaded
+       directly and not only as a dependency.
+       (_dl_lookup_symbol): Add relocation dependency also if object
+       is not in global scope.  Remove test for self-reference here.
+       (_dl_lookup_versioned_symbol): Likewise.
+       * elf/dl-object (_dl_new_object): Cleanup.  Initialize dont_free
+       element of first name record.
+       * elf/loadtest.c: Add some more test to recognize early if an object
+       wasn't unloaded.
+       * elf/Makefile: Add rules to build and run reldep5.
+       * elf/reldep5.c: New file.
+       * elf/reldepmod5.c: New file.
+       * elf/reldepmod6.c: New file.
+
+       * elf/reldep2.c: Fix typo.
+
 2001-09-07  Ulrich Drepper  <drepper@redhat.com>
 
        * include/link.h (struct link_map): Add l_scope_mem and l_scope_max
        elements.  Change l_scope to be a pointer only.
-       * elf/dl-object.c (_dl_new_ojbect): Initialize l_scope and l_scope_max.
+       * elf/dl-object.c (_dl_new_object): Initialize l_scope and l_scope_max.
        * elf/dl-open.c (dl_open_worker): If dependency wasn't just opened
        here add searchlist of newly open file to the dependency's scope.
        * elf/dl-close.c (_dl_close): If dependency is used otherwise remove
index 160d901..d4fc54e 100644 (file)
@@ -55,6 +55,7 @@ distribute    := $(rtld-routines:=.c) dynamic-link.h do-rel.h dl-machine.h \
                   nodlopenmod.c nodelete.c nodelmod1.c nodelmod2.c \
                   nodelmod3.c nodelmod4.c nodlopen.c dl-osinfo.h \
                   reldepmod1.c reldepmod2.c reldepmod3.c reldepmod4.c \
+                  reldepmod5.c reldepmod6.c \
                   reldep4mod1.c reldep4mod2.c reldep4mod3.c reldep4mod4.c \
                   nextmod1.c nextmod2.c pathoptobj.c tst-pathopt.sh \
                   neededobj1.c neededobj2.c neededobj3.c neededobj4.c \
@@ -106,7 +107,7 @@ tests = loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
        reldep reldep2 reldep3 reldep4 $(tests-nodelete-$(have-z-nodelete)) \
        $(tests-nodlopen-$(have-z-nodlopen)) neededtest neededtest2 \
        neededtest3 neededtest4 unload2 lateglobal initfirst global \
-       restest2 next dblload dblunload
+       restest2 next dblload dblunload reldep5
 test-srcs = tst-pathopt
 tests-vis-yes = vismain
 tests-nodelete-yes = nodelete
@@ -122,7 +123,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
                neededobj1 neededobj2 neededobj3 neededobj4 \
                neededobj5 neededobj6 firstobj globalmod1 \
                unload2mod unload2dep ltglobmod1 ltglobmod2 pathoptobj \
-               dblloadmod1 dblloadmod2 dblloadmod3
+               dblloadmod1 dblloadmod2 dblloadmod3 reldepmod5 reldepmod6
 modules-vis-yes = vismod1 vismod2 vismod3
 modules-nodelete-yes = nodelmod1 nodelmod2 nodelmod3 nodelmod4
 modules-nodlopen-yes = nodlopenmod
@@ -285,6 +286,8 @@ $(objpfx)reldep4mod1.so: $(objpfx)reldep4mod3.so
 $(objpfx)reldep4mod2.so: $(objpfx)reldep4mod4.so
 $(objpfx)dblloadmod1.so: $(objpfx)dblloadmod3.so
 $(objpfx)dblloadmod2.so: $(objpfx)dblloadmod3.so
+$(objpfx)reldepmod5.so: $(objpfx)reldepmod2.so
+$(objpfx)reldepmod6.so: $(objpfx)reldepmod2.so
 
 # filtmod1.so has a special rule
 $(filter-out $(objpfx)filtmod1.so, $(test-modules)): $(objpfx)%.so: $(objpfx)%.os
@@ -423,3 +426,6 @@ $(objpfx)dblload.out: $(objpfx)dblloadmod1.so $(objpfx)dblloadmod2.so
 
 $(objpfx)dblunload: $(libdl)
 $(objpfx)dblunload.out: $(objpfx)dblloadmod1.so $(objpfx)dblloadmod2.so
+
+$(objpfx)reldep5: $(libdl)
+$(objpfx)reldep5.out: $(objpfx)reldepmod5.so $(objpfx)reldepmod5.so
index dfc204d..31b4863 100644 (file)
@@ -48,7 +48,8 @@ _dl_close (void *_map)
   unsigned int *new_opencount;
 
   /* First see whether we can remove the object at all.  */
-  if ((map->l_flags_1 & DF_1_NODELETE) && map->l_init_called)
+  if (__builtin_expect (map->l_flags_1 & DF_1_NODELETE, 0)
+      && map->l_init_called)
     /* Nope.  Do nothing.  */
     return;
 
@@ -63,14 +64,8 @@ _dl_close (void *_map)
     {
       /* There are still references to this object.  Do nothing more.  */
       if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0))
-       {
-         char buf[20];
-
-         buf[sizeof buf - 1] = '\0';
-
-         _dl_debug_printf ("\nclosing file=%s; opencount == %u\n",
-                           map->l_name, map->l_opencount);
-       }
+       _dl_debug_printf ("\nclosing file=%s; opencount == %u\n",
+                         map->l_name, map->l_opencount);
 
       /* One decrement the object itself, not the dependencies.  */
       --map->l_opencount;
@@ -82,8 +77,15 @@ _dl_close (void *_map)
   list = map->l_initfini;
 
   /* Compute the new l_opencount values.  */
-  new_opencount = (unsigned int *) alloca (map->l_searchlist.r_nlist
-                                          * sizeof (unsigned int));
+  i = map->l_searchlist.r_nlist;
+  if (__builtin_expect (i == 0, 0))
+    /* This can happen if we handle relocation dependencies for an
+       object which wasn't loaded directly.  */
+    for (i = 1; list[i] != NULL; ++i)
+      ;
+
+  new_opencount = (unsigned int *) alloca (i * sizeof (unsigned int));
+
   for (i = 0; list[i] != NULL; ++i)
     {
       list[i]->l_idx = i;
index c4bc987..9d91d5e 100644 (file)
@@ -448,11 +448,13 @@ _dl_map_object_deps (struct link_map *map,
        {
          needed[nneeded++] = NULL;
 
-         l->l_initfini = malloc (nneeded * sizeof needed[0]);
+         l->l_initfini = (struct link_map **)
+           malloc ((nneeded + 1) * sizeof needed[0]);
          if (l->l_initfini == NULL)
            _dl_signal_error (ENOMEM, map->l_name, NULL,
                              N_("cannot allocate dependency list"));
-         memcpy (l->l_initfini, needed, nneeded * sizeof needed[0]);
+         l->l_initfini[0] = l;
+         memcpy (&l->l_initfini[1], needed, nneeded * sizeof needed[0]);
        }
 
       /* If we have no auxiliary objects just go on to the next map.  */
@@ -462,7 +464,7 @@ _dl_map_object_deps (struct link_map *map,
        while (runp != NULL && runp->done);
     }
 
-out:
+ out:
   if (errno == 0 && errno_saved != 0)
     __set_errno (errno_saved);
 
@@ -489,7 +491,7 @@ out:
 
   for (nlist = 0, runp = known; runp; runp = runp->next)
     {
-      if (trace_mode && runp->map->l_faked)
+      if (__builtin_expect (trace_mode, 0) && runp->map->l_faked)
        /* This can happen when we trace the loading.  */
        --map->l_searchlist.r_nlist;
       else
@@ -500,6 +502,30 @@ out:
       runp->map->l_reserved = 0;
     }
 
+  /* Maybe we can remove some relocation dependencies now.  */
+  assert (map->l_searchlist.r_list[0] == map);
+  for (i = 0; i < map->l_reldepsact; ++i)
+    {
+      unsigned int j;
+
+      for (j = 1; j < nlist; ++j)
+       if (map->l_searchlist.r_list[j] == map->l_reldeps[i])
+         {
+           /* A direct or transitive dependency is also on the list
+              of relocation dependencies.  Remove the latter.  */
+           --map->l_reldeps[i]->l_opencount;
+
+           for (j = i + 1; j < map->l_reldepsact; ++j)
+             map->l_reldeps[j - 1] = map->l_reldeps[j];
+
+           --map->l_reldepsact;
+
+           /* Account for the '++i' performed by the 'for'.  */
+           --i;
+           break;
+         }
+    }
+
   /* Now determine the order in which the initialization has to happen.  */
   memcpy (map->l_initfini, map->l_searchlist.r_list,
          nlist * sizeof (struct link_map *));
index 2faa9fb..26c839c 100644 (file)
@@ -79,92 +79,94 @@ internal_function
 add_dependency (struct link_map *undef_map, struct link_map *map)
 {
   struct link_map **list;
+  struct link_map *runp;
   unsigned int act;
   unsigned int i;
   int result = 0;
 
+  /* Avoid self-references.  */
+  if (undef_map == map)
+    return 0;
+
   /* Make sure nobody can unload the object while we are at it.  */
   __libc_lock_lock_recursive (_dl_load_lock);
 
   /* Determine whether UNDEF_MAP already has a reference to MAP.  First
      look in the normal dependencies.  */
-  list = undef_map->l_initfini;
-
-  for (i = 0; list[i] != NULL; ++i)
-    if (list[i] == map)
-      break;
-
-  if (__builtin_expect (list[i] == NULL, 1))
+  if (undef_map->l_searchlist.r_list != NULL)
     {
-      /* No normal dependency.  See whether we already had to add it
-        to the special list of dynamic dependencies.  */
-      list = undef_map->l_reldeps;
-      act = undef_map->l_reldepsact;
+      list = undef_map->l_initfini;
 
-      for (i = 0; i < act; ++i)
+      for (i = 0; list[i] != NULL; ++i)
        if (list[i] == map)
-         break;
+         goto out;
+    }
+
+  /* No normal dependency.  See whether we already had to add it
+     to the special list of dynamic dependencies.  */
+  list = undef_map->l_reldeps;
+  act = undef_map->l_reldepsact;
 
-      if (i == act)
+  for (i = 0; i < act; ++i)
+    if (list[i] == map)
+      goto out;
+
+  /* The object is not yet in the dependency list.  Before we add
+     it make sure just one more time the object we are about to
+     reference is still available.  There is a brief period in
+     which the object could have been removed since we found the
+     definition.  */
+  runp = _dl_loaded;
+  while (runp != NULL && runp != map)
+    runp = runp->l_next;
+
+  if (runp != NULL)
+    {
+      /* The object is still available.  Add the reference now.  */
+      if (__builtin_expect (act >= undef_map->l_reldepsmax, 0))
        {
-         /* The object is not yet in the dependency list.  Before we add
-            it make sure just one more time the object we are about to
-            reference is still available.  There is a brief period in
-            which the object could have been removed since we found the
-            definition.  */
-         struct link_map *runp = _dl_loaded;
-
-         while (runp != NULL && runp != map)
-           runp = runp->l_next;
-
-         if (runp != NULL)
-           {
-             /* The object is still available.  Add the reference now.  */
-             if (__builtin_expect (act >= undef_map->l_reldepsmax, 0))
-               {
-                 /* Allocate more memory for the dependency list.  Since
-                    this can never happen during the startup phase we can
-                    use `realloc'.  */
-                 void *newp;
-
-                 undef_map->l_reldepsmax += 5;
-                 newp = realloc (undef_map->l_reldeps,
-                                 undef_map->l_reldepsmax
-                                 * sizeof(struct link_map *));
-
-                 if (__builtin_expect (newp != NULL, 1))
-                   undef_map->l_reldeps = (struct link_map **) newp;
-                 else
-                   /* Correct the addition.  */
-                   undef_map->l_reldepsmax -= 5;
-               }
-
-             /* If we didn't manage to allocate memory for the list this
-                is no fatal mistake.  We simply increment the use counter
-                of the referenced object and don't record the dependencies.
-                This means this increment can never be reverted and the
-                object will never be unloaded.  This is semantically the
-                correct behaviour.  */
-             if (__builtin_expect (act < undef_map->l_reldepsmax, 1))
-               undef_map->l_reldeps[undef_map->l_reldepsact++] = map;
-
-             /* And increment the counter in the referenced object.  */
-             ++map->l_opencount;
-
-             /* Display information if we are debugging.  */
-             if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0))
-               _dl_debug_printf ("\
-\nfile=%s;  needed by %s (relocation dependency)\n\n",
-                                 map->l_name[0] ? map->l_name : _dl_argv[0],
-                                 undef_map->l_name[0]
-                                 ? undef_map->l_name : _dl_argv[0]);
-           }
+         /* Allocate more memory for the dependency list.  Since this
+            can never happen during the startup phase we can use
+            `realloc'.  */
+         void *newp;
+
+         undef_map->l_reldepsmax += 5;
+         newp = realloc (undef_map->l_reldeps,
+                         undef_map->l_reldepsmax
+                         * sizeof (struct link_map *));
+
+         if (__builtin_expect (newp != NULL, 1))
+           undef_map->l_reldeps = (struct link_map **) newp;
          else
-           /* Whoa, that was bad luck.  We have to search again.  */
-           result = -1;
+           /* Correct the addition.  */
+           undef_map->l_reldepsmax -= 5;
        }
+
+      /* If we didn't manage to allocate memory for the list this is
+        no fatal mistake.  We simply increment the use counter of the
+        referenced object and don't record the dependencies.  This
+        means this increment can never be reverted and the object
+        will never be unloaded.  This is semantically the correct
+        behaviour.  */
+      if (__builtin_expect (act < undef_map->l_reldepsmax, 1))
+       undef_map->l_reldeps[undef_map->l_reldepsact++] = map;
+
+      /* And increment the counter in the referenced object.  */
+      ++map->l_opencount;
+
+      /* Display information if we are debugging.  */
+      if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0))
+       _dl_debug_printf ("\
+\nfile=%s;  needed by %s (relocation dependency)\n\n",
+                         map->l_name[0] ? map->l_name : _dl_argv[0],
+                         undef_map->l_name[0]
+                         ? undef_map->l_name : _dl_argv[0]);
     }
+  else
+    /* Whoa, that was bad luck.  We have to search again.  */
+    result = -1;
 
+ out:
   /* Release the lock.  */
   __libc_lock_unlock_recursive (_dl_load_lock);
 
@@ -212,8 +214,6 @@ _dl_lookup_symbol (const char *undef_name, struct link_map *undef_map,
           we have to prevent the latter from being unloaded unless the
           UNDEF_MAP object is also unloaded.  */
        if (__builtin_expect (current_value.m->l_type == lt_loaded, 0)
-           && current_value.m->l_global
-           && undef_map != current_value.m
            /* Don't do this for explicit lookups as opposed to implicit
               runtime lookups.  */
            && ! explicit
@@ -395,8 +395,6 @@ _dl_lookup_versioned_symbol (const char *undef_name,
             we have to prevent the latter from being unloaded unless the
             UNDEF_MAP object is also unloaded.  */
          if (__builtin_expect (current_value.m->l_type == lt_loaded, 0)
-             && current_value.m->l_global
-             && undef_map != current_value.m
              /* Don't do this for explicit lookups as opposed to implicit
                 runtime lookups.  */
              && ! explicit
index 9c32c08..65e90d6 100644 (file)
@@ -37,14 +37,18 @@ _dl_new_object (char *realname, const char *libname, int type,
   struct link_map *l;
   int idx;
   size_t libname_len = strlen (libname) + 1;
-  struct link_map *new = calloc (sizeof *new, 1);
-  struct libname_list *newname = malloc (sizeof *newname + libname_len);
-  if (! new || ! newname)
+  struct link_map *new;
+  struct libname_list *newname;
+
+  new = (struct link_map *) calloc (sizeof *new, 1);
+  newname = (struct libname_list *) malloc (sizeof *newname + libname_len);
+  if (new == NULL || newname == NULL)
     return NULL;
 
   new->l_name = realname;
-  newname->name = memcpy (newname + 1, libname, libname_len);
+  newname->name = (char *) memcpy (newname + 1, libname, libname_len);
   newname->next = NULL;
+  newname->dont_free = 0;
   new->l_libname = newname;
   new->l_type = type;
   new->l_loader = loader;
index 863dc53..6b8f4bb 100644 (file)
@@ -5,6 +5,7 @@
 #include <mcheck.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 
 /* How many load/unload operations do we do.  */
@@ -139,6 +140,23 @@ main (int argc, char *argv[])
                    testobjs[index].name, testobjs[index].handle);
 
          testobjs[index].handle = NULL;
+
+         if (testobjs[0].handle == NULL
+             && testobjs[1].handle == NULL
+             && testobjs[5].handle == NULL)
+           {
+             /* In this case none of the objects above should be
+                present.  */
+             for (map = _r_debug.r_map; map != NULL; map = map->l_next)
+               if (map->l_type == lt_loaded
+                   && (strstr (map->l_name, testobjs[0].name) != NULL
+                       || strstr (map->l_name, testobjs[1].name) != NULL
+                       || strstr (map->l_name, testobjs[5].name) != NULL))
+                 {
+                   printf ("`%s' is still loaded\n", map->l_name);
+                   result = 1;
+                 }
+           }
        }
 
       if (debug)
@@ -151,8 +169,8 @@ main (int argc, char *argv[])
       {
        printf ("\nclose: %s: l_initfini = %p, l_versions = %p\n",
                testobjs[count].name,
-               ((struct link_map*)testobjs[count].handle)->l_initfini,
-               ((struct link_map*)testobjs[count].handle)->l_versions);
+               ((struct link_map *) testobjs[count].handle)->l_initfini,
+               ((struct link_map *) testobjs[count].handle)->l_versions);
 
        if (dlclose (testobjs[count].handle) != 0)
          {
diff --git a/elf/reldep5.c b/elf/reldep5.c
new file mode 100644 (file)
index 0000000..982265f
--- /dev/null
@@ -0,0 +1,71 @@
+#include <dlfcn.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+  void *h1;
+  void *h2;
+  int (*fp) (void);
+  int *vp;
+
+  mtrace ();
+
+  /* Open the two objects.  */
+  h1 = dlopen ("reldepmod5.so", RTLD_LAZY);
+  if (h1 == NULL)
+    {
+      printf ("cannot open reldepmod5.so: %s\n", dlerror ());
+      exit (1);
+    }
+  h2 = dlopen ("reldepmod6.so", RTLD_LAZY);
+  if (h2 == NULL)
+    {
+      printf ("cannot open reldepmod6.so: %s\n", dlerror ());
+      exit (1);
+    }
+
+  /* Get the address of the variable in reldepmod1.so.  */
+  fp = dlsym (h2, "bar");
+  if (fp == NULL)
+    {
+      printf ("cannot get address of \"bar\": %s\n", dlerror ());
+      exit (1);
+    }
+
+  /* Call the function.  */
+  puts ("calling fp for the first time");
+  if (fp () != 0)
+    {
+      puts ("function \"call_me\" returned wrong result");
+      exit (1);
+    }
+
+  /* Now close the first object.  It must still be around since we have
+     an implicit dependency.  */
+  if (dlclose (h1) != 0)
+    {
+      printf ("closing h1 failed: %s\n", dlerror ());
+      exit (1);
+    }
+
+  /* Calling the function must still work.  */
+  puts ("calling fp for the second time");
+  if (fp () != 0)
+    {
+      puts ("function \"call_me\" the second time returned wrong result");
+      exit (1);
+    }
+  puts ("second call suceeded as well");
+
+  /* Close the second object, we are done.  */
+  if (dlclose (h2) != 0)
+    {
+      printf ("closing h2 failed: %s\n", dlerror ());
+      exit (1);
+    }
+
+  return 0;
+}
diff --git a/elf/reldepmod5.c b/elf/reldepmod5.c
new file mode 100644 (file)
index 0000000..eae70da
--- /dev/null
@@ -0,0 +1,5 @@
+int
+foo (void)
+{
+  return 42;
+}
diff --git a/elf/reldepmod6.c b/elf/reldepmod6.c
new file mode 100644 (file)
index 0000000..95c18d4
--- /dev/null
@@ -0,0 +1,7 @@
+extern int call_me (void);
+
+int
+bar (void)
+{
+  return call_me ();
+}