summaryrefslogtreecommitdiff
path: root/elf
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2005-04-27 11:31:41 +0000
committerJakub Jelinek <jakub@redhat.com>2005-04-27 11:31:41 +0000
commit35278cc7d7fe81e01bb092e76b775c169e7e85f6 (patch)
tree6ec42ab959998df5c0182183807ee2b9efc4cc91 /elf
parent536db0d3b5efac042be3bf1d6f99f9c418f76255 (diff)
Updated to fedora-glibc-20050427T1043
Diffstat (limited to 'elf')
-rw-r--r--elf/Makefile12
-rw-r--r--elf/dl-close.c55
-rw-r--r--elf/rtld-Rules11
-rw-r--r--elf/unload6.c30
-rw-r--r--elf/unload6mod1.c16
-rw-r--r--elf/unload6mod2.c23
-rw-r--r--elf/unload6mod3.c23
7 files changed, 152 insertions, 18 deletions
diff --git a/elf/Makefile b/elf/Makefile
index c034b2ba6e..d988baca3b 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -86,7 +86,7 @@ distribute := rtld-Rules \
tst-deep1mod1.c tst-deep1mod2.c tst-deep1mod3.c \
unload3mod1.c unload3mod2.c unload3mod3.c unload3mod4.c \
unload4mod1.c unload4mod2.c unload4mod3.c unload4mod4.c \
- tst-auditmod1.c \
+ unload6mod1.c unload6mod2.c unload6mod3.c tst-auditmod1.c \
order2mod1.c order2mod2.c order2mod3.c order2mod4.c
CFLAGS-dl-runtime.c = -fexceptions -fasynchronous-unwind-tables
@@ -162,7 +162,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-tls15 tst-align \
tst-align2 $(tests-execstack-$(have-z-execstack)) tst-dlmodcount \
tst-dlopenrpath tst-deep1 tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
- unload3 unload4 unload5 tst-audit1 tst-global1 order2
+ unload3 unload4 unload5 unload6 tst-audit1 tst-global1 order2
# reldep9
test-srcs = tst-pathopt
tests-vis-yes = vismain
@@ -201,6 +201,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
tst-dlmopen1mod tst-auditmod1 \
unload3mod1 unload3mod2 unload3mod3 unload3mod4 \
unload4mod1 unload4mod2 unload4mod3 unload4mod4 \
+ unload6mod1 unload6mod2 unload6mod3 \
order2mod1 order2mod2 order2mod3 order2mod4
ifeq (yes,$(have-initfini-array))
modules-names += tst-array2dep
@@ -438,6 +439,9 @@ $(objpfx)unload3mod2.so: $(objpfx)unload3mod3.so
$(objpfx)unload3mod3.so: $(objpfx)unload3mod4.so
$(objpfx)unload4mod1.so: $(objpfx)unload4mod2.so $(objpfx)unload4mod3.so
$(objpfx)unload4mod2.so: $(objpfx)unload4mod4.so $(objpfx)unload4mod3.so
+$(objpfx)unload6mod1.so: $(libdl)
+$(objpfx)unload6mod2.so: $(libdl)
+$(objpfx)unload6mod3.so: $(libdl)
LDFLAGS-tst-tlsmod5.so = -nostdlib
LDFLAGS-tst-tlsmod6.so = -nostdlib
@@ -710,6 +714,10 @@ $(objpfx)unload5: $(libdl)
$(objpfx)unload5.out: $(objpfx)unload3mod1.so $(objpfx)unload3mod2.so \
$(objpfx)unload3mod3.so $(objpfx)unload3mod4.so
+$(objpfx)unload6: $(libdl)
+$(objpfx)unload6.out: $(objpfx)unload6mod1.so $(objpfx)unload6mod2.so \
+ $(objpfx)unload6mod3.so
+
ifdef libdl
$(objpfx)tst-tls9-static: $(common-objpfx)dlfcn/libdl.a
$(objpfx)tst-tls9-static.out: $(objpfx)tst-tlsmod5.so $(objpfx)tst-tlsmod6.so
diff --git a/elf/dl-close.c b/elf/dl-close.c
index cd4fa7cfbe..754dd678fe 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -20,6 +20,7 @@
#include <assert.h>
#include <dlfcn.h>
#include <libintl.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -105,10 +106,6 @@ _dl_close (void *_map)
struct link_map *map = _map;
Lmid_t ns = map->l_ns;
unsigned int i;
-#ifdef USE_TLS
- bool any_tls = false;
-#endif
-
/* First see whether we can remove the object at all. */
if (__builtin_expect (map->l_flags_1 & DF_1_NODELETE, 0)
&& map->l_init_called)
@@ -124,9 +121,17 @@ _dl_close (void *_map)
/* One less direct use. */
--map->l_direct_opencount;
- /* Decrement the reference count. */
- if (map->l_direct_opencount > 1 || map->l_type != lt_loaded)
+ /* If _dl_close is called recursively (some destructor call dlclose),
+ just record that the parent _dl_close will need to do garbage collection
+ again and return. */
+ static enum { not_pending, pending, rerun } dl_close_state;
+
+ if (map->l_direct_opencount > 0 || map->l_type != lt_loaded
+ || dl_close_state != not_pending)
{
+ if (map->l_direct_opencount == 0 && map->l_type == lt_loaded)
+ dl_close_state = rerun;
+
/* There are still references to this object. Do nothing more. */
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
_dl_debug_printf ("\nclosing file=%s; direct_opencount=%u\n",
@@ -136,12 +141,18 @@ _dl_close (void *_map)
return;
}
+ retry:
+ dl_close_state = pending;
+
+#ifdef USE_TLS
+ bool any_tls = false;
+#endif
const unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded;
char used[nloaded];
char done[nloaded];
struct link_map *maps[nloaded];
- /* Run over the list and assign indeces to the link maps and enter
+ /* Run over the list and assign indexes to the link maps and enter
them into the MAPS array. */
int idx = 0;
for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next)
@@ -302,7 +313,7 @@ _dl_close (void *_map)
if (imap->l_searchlist.r_list == NULL
&& imap->l_initfini != NULL)
{
- /* The object is still used. But the object we are
+ /* The object is still used. But one of the objects we are
unloading right now is responsible for loading it. If
the current object does not have it's own scope yet we
have to create one. This has to be done before running
@@ -318,15 +329,27 @@ _dl_close (void *_map)
imap->l_searchlist.r_nlist = cnt;
for (cnt = 0; imap->l_scope[cnt] != NULL; ++cnt)
- if (imap->l_scope[cnt] == &map->l_searchlist)
+ /* This relies on l_scope[] entries being always set either
+ to its own l_symbolic_searchlist address, or some other map's
+ l_searchlist address. */
+ if (imap->l_scope[cnt] != &imap->l_symbolic_searchlist)
{
- imap->l_scope[cnt] = &imap->l_searchlist;
- break;
+ struct link_map *tmap;
+
+ tmap = (struct link_map *) ((char *) imap->l_scope[cnt]
+ - offsetof (struct link_map,
+ l_searchlist));
+ assert (tmap->l_ns == ns);
+ if (tmap->l_idx != -1)
+ {
+ imap->l_scope[cnt] = &imap->l_searchlist;
+ break;
+ }
}
}
/* The loader is gone, so mark the object as not having one.
- Note: l_idx == -1 -> object will be removed. */
+ Note: l_idx != -1 -> object will be removed. */
if (imap->l_loader != NULL && imap->l_loader->l_idx != -1)
imap->l_loader = NULL;
@@ -583,8 +606,12 @@ _dl_close (void *_map)
r->r_state = RT_CONSISTENT;
_dl_debug_state ();
- /* Release the lock. */
+ /* Recheck if we need to retry, release the lock. */
out:
+ if (dl_close_state == rerun)
+ goto retry;
+
+ dl_close_state = not_pending;
__rtld_lock_unlock_recursive (GL(dl_load_lock));
}
@@ -654,7 +681,7 @@ libc_freeres_fn (free_mem)
free_slotinfo (&GL(dl_tls_dtv_slotinfo_list));
else
# endif
- /* The first element of the list does not have to be deallocated.
+ /* The first element of the list does not have to be deallocated.
It was allocated in the dynamic linker (i.e., with a different
malloc), and in the static library it's in .bss space. */
free_slotinfo (&GL(dl_tls_dtv_slotinfo_list)->next);
diff --git a/elf/rtld-Rules b/elf/rtld-Rules
index ac96f728d9..61143b180c 100644
--- a/elf/rtld-Rules
+++ b/elf/rtld-Rules
@@ -1,6 +1,6 @@
# Subroutine makefile for compiling libc modules linked into dynamic linker.
-# Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+# Copyright (C) 2002, 2003, 2005 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
@@ -28,7 +28,14 @@
rtld-all:
# When run from the elf/Makefile to build rtld-libc.a, $(subdir) is elf.
-ifeq ($(subdir),elf)
+ifneq ($(subdir),elf)
+ifndef rtld-modules
+error rtld-modules not set
+endif
+endif
+
+ifndef rtld-modules
+# Running to build rtld-libc.a, driving runs of $(rtld-subdir-make), below.
ifndef rtld-subdirs
error This makefile is a subroutine of elf/Makefile not to be used directly
diff --git a/elf/unload6.c b/elf/unload6.c
new file mode 100644
index 0000000000..1efc7eb841
--- /dev/null
+++ b/elf/unload6.c
@@ -0,0 +1,30 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+int
+main (void)
+{
+ void *h = dlopen ("unload6mod1.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ puts ("dlopen unload6mod1.so failed");
+ return 1;
+ }
+
+ int (*fn) (int);
+ fn = dlsym (h, "foo");
+ if (fn == NULL)
+ {
+ puts ("dlsym failed");
+ return 1;
+ }
+
+ int val = fn (16);
+ if (val != 24)
+ {
+ printf ("foo returned %d != 24\n", val);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/elf/unload6mod1.c b/elf/unload6mod1.c
new file mode 100644
index 0000000000..24f2e5a19a
--- /dev/null
+++ b/elf/unload6mod1.c
@@ -0,0 +1,16 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+int
+foo (int i)
+{
+ void *h = dlopen ("unload6mod2.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ puts ("dlopen unload6mod2.so failed");
+ return 1;
+ }
+
+ dlclose (h);
+ return i + 8;
+}
diff --git a/elf/unload6mod2.c b/elf/unload6mod2.c
new file mode 100644
index 0000000000..980efa4b0e
--- /dev/null
+++ b/elf/unload6mod2.c
@@ -0,0 +1,23 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static void *h;
+
+static void __attribute__((constructor))
+mod2init (void)
+{
+ h = dlopen ("unload6mod3.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ puts ("dlopen unload6mod3.so failed");
+ fflush (stdout);
+ _exit (1);
+ }
+}
+
+static void __attribute__((destructor))
+mod2fini (void)
+{
+ dlclose (h);
+}
diff --git a/elf/unload6mod3.c b/elf/unload6mod3.c
new file mode 100644
index 0000000000..7b29e1d626
--- /dev/null
+++ b/elf/unload6mod3.c
@@ -0,0 +1,23 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static void *h;
+
+static void __attribute__((constructor))
+mod3init (void)
+{
+ h = dlopen ("unload6mod1.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ puts ("dlopen unload6mod1.so failed");
+ fflush (stdout);
+ _exit (1);
+ }
+}
+
+static void __attribute__((destructor))
+mod3fini (void)
+{
+ dlclose (h);
+}