summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog29
-rw-r--r--elf/Makefile10
-rw-r--r--elf/dl-close.c24
-rw-r--r--elf/dl-deps.c34
-rw-r--r--elf/dl-lookup.c142
-rw-r--r--elf/dl-object.c12
-rw-r--r--elf/loadtest.c22
-rw-r--r--elf/reldep5.c71
-rw-r--r--elf/reldepmod5.c5
-rw-r--r--elf/reldepmod6.c7
10 files changed, 260 insertions, 96 deletions
diff --git a/ChangeLog b/ChangeLog
index 21653dc4d9..81ba6caab6 100644
--- 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
diff --git a/elf/Makefile b/elf/Makefile
index 160d901526..d4fc54e010 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -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
diff --git a/elf/dl-close.c b/elf/dl-close.c
index dfc204d478..31b4863afe 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -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;
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
index c4bc9874cc..9d91d5ef00 100644
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -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 *));
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index 2faa9fb99c..26c839caa7 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -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
diff --git a/elf/dl-object.c b/elf/dl-object.c
index 9c32c08ff2..65e90d66a0 100644
--- a/elf/dl-object.c
+++ b/elf/dl-object.c
@@ -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;
diff --git a/elf/loadtest.c b/elf/loadtest.c
index 863dc536e7..6b8f4bb7d0 100644
--- a/elf/loadtest.c
+++ b/elf/loadtest.c
@@ -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
index 0000000000..982265f251
--- /dev/null
+++ b/elf/reldep5.c
@@ -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
index 0000000000..eae70da1e2
--- /dev/null
+++ b/elf/reldepmod5.c
@@ -0,0 +1,5 @@
+int
+foo (void)
+{
+ return 42;
+}
diff --git a/elf/reldepmod6.c b/elf/reldepmod6.c
new file mode 100644
index 0000000000..95c18d4cdb
--- /dev/null
+++ b/elf/reldepmod6.c
@@ -0,0 +1,7 @@
+extern int call_me (void);
+
+int
+bar (void)
+{
+ return call_me ();
+}