aboutsummaryrefslogtreecommitdiff
path: root/elf
diff options
context:
space:
mode:
Diffstat (limited to 'elf')
-rw-r--r--elf/Makefile28
-rw-r--r--elf/dl-close.c127
-rw-r--r--elf/dl-deps.c6
-rw-r--r--elf/dl-lookup.c27
-rw-r--r--elf/nodelete2.c16
-rw-r--r--elf/reldep6.c12
-rw-r--r--elf/reldep9.c16
-rw-r--r--elf/reldep9mod1.c23
-rw-r--r--elf/reldep9mod2.c3
-rw-r--r--elf/reldep9mod3.c1
-rw-r--r--elf/tls-macros.h32
11 files changed, 229 insertions, 62 deletions
diff --git a/elf/Makefile b/elf/Makefile
index e9090d3044..38819a3884 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -1,4 +1,4 @@
-# Copyright (C) 1995-1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+# Copyright (C) 1995-2002, 2003 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
@@ -73,7 +73,9 @@ distribute := rtld-Rules \
circlemod1.c circlemod1a.c circlemod2.c circlemod2a.c \
circlemod3.c circlemod3a.c nodlopenmod2.c \
tls-macros.h \
- reldep8mod1.c reldep8mod2.c reldep8mod3.c
+ reldep8mod1.c reldep8mod2.c reldep8mod3.c \
+ nodel2mod1.c nodel2mod2.c nodel2mod3.c \
+ reldep9mod1.c reldep9mod2.c reldep9mod3.c
include ../Makeconfig
@@ -138,9 +140,10 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
neededtest3 neededtest4 unload2 lateglobal initfirst global \
restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \
circleload1 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 tst-tls8
+# reldep9
test-srcs = tst-pathopt
tests-vis-yes = vismain
-tests-nodelete-yes = nodelete
+tests-nodelete-yes = nodelete nodelete2
tests-nodlopen-yes = nodlopen nodlopen2
endif
modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
@@ -160,12 +163,14 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
tst-tlsmod5 tst-tlsmod6 \
circlemod1 circlemod1a circlemod2 circlemod2a \
circlemod3 circlemod3a \
- reldep8mod1 reldep8mod2 reldep8mod3
+ reldep8mod1 reldep8mod2 reldep8mod3 \
+ reldep9mod1 reldep9mod2 reldep9mod3
ifeq (yes,$(have-initfini-array))
modules-names += tst-array2dep
endif
modules-vis-yes = vismod1 vismod2 vismod3
-modules-nodelete-yes = nodelmod1 nodelmod2 nodelmod3 nodelmod4
+modules-nodelete-yes = nodelmod1 nodelmod2 nodelmod3 nodelmod4 \
+ nodel2mod1 nodel2mod2 nodel2mod3
modules-nodlopen-yes = nodlopenmod nodlopenmod2
extra-objs += $(addsuffix .os,$(strip $(modules-names)))
# We need this variable to be sure the test modules get the right CPPFLAGS.
@@ -363,7 +368,13 @@ $(objpfx)reldep6mod2.so: $(objpfx)reldep6mod1.so
$(objpfx)reldep6mod3.so: $(objpfx)reldep6mod2.so
$(objpfx)reldep6mod4.so: $(objpfx)reldep6mod1.so
$(objpfx)tst-tlsmod3.so: $(objpfx)tst-tlsmod2.so
+# For tst-tls9-static, make sure the modules it dlopens have libc.so in DT_NEEDED
+$(objpfx)tst-tlsmod5.so: $(common-objpfx)libc.so
+$(objpfx)tst-tlsmod6.so: $(common-objpfx)libc.so
$(objpfx)reldep8mod3.so: $(objpfx)reldep8mod1.so $(objpfx)reldep8mod2.so
+$(objpfx)nodel2mod3.so: $(objpfx)nodel2mod1.so $(objpfx)nodel2mod2.so
+$(objpfx)reldep9mod2.so: $(objpfx)reldep9mod1.so
+$(objpfx)reldep9mod3.so: $(objpfx)reldep9mod1.so $(objpfx)reldep9mod2.so
LDFLAGS-tst-tlsmod5.so = -nostdlib
LDFLAGS-tst-tlsmod6.so = -nostdlib
@@ -531,6 +542,13 @@ $(objpfx)reldep7.out: $(objpfx)reldep7mod1.so $(objpfx)reldep7mod2.so
$(objpfx)reldep8: $(libdl)
$(objpfx)reldep8.out: $(objpfx)reldep8mod3.so
+LDFLAGS-nodel2mod2.so = -Wl,--enable-new-dtags,-z,nodelete
+$(objpfx)nodelete2: $(libdl)
+$(objpfx)nodelete2.out: $(objpfx)nodel2mod3.so
+
+$(objpfx)reldep9: $(libdl)
+$(objpfx)reldep9.out: $(objpfx)reldep9mod3.so
+
$(objpfx)tst-tls3: $(objpfx)tst-tlsmod1.so
$(objpfx)tst-tls4: $(libdl)
diff --git a/elf/dl-close.c b/elf/dl-close.c
index 7e4626e3d6..0953fab210 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -1,5 +1,5 @@
/* Close a shared object opened by `_dl_open'.
- Copyright (C) 1996-2001, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1996-2002, 2003 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
@@ -138,7 +138,7 @@ _dl_close (void *_map)
_dl_debug_printf ("\nclosing file=%s; opencount == %u\n",
map->l_name, map->l_opencount);
- /* One decrement the object itself, not the dependencies. */
+ /* Decrement the object's reference counter, not the dependencies'. */
--map->l_opencount;
__rtld_lock_unlock_recursive (GL(dl_load_lock));
@@ -165,7 +165,7 @@ _dl_close (void *_map)
}
--new_opencount[0];
for (i = 1; list[i] != NULL; ++i)
- if ((! (list[i]->l_flags_1 & DF_1_NODELETE) || ! list[i]->l_init_called)
+ if ((list[i]->l_flags_1 & DF_1_NODELETE) == 0
/* Decrement counter. */
&& --new_opencount[i] == 0)
{
@@ -185,7 +185,10 @@ _dl_close (void *_map)
{
assert (dep_list[j]->l_idx < map->l_searchlist.r_nlist);
if (--new_opencount[dep_list[j]->l_idx] == 0)
- mark_removed (dep_list[j]);
+ {
+ assert (dep_list[j]->l_type == lt_loaded);
+ mark_removed (dep_list[j]);
+ }
}
}
@@ -200,8 +203,11 @@ _dl_close (void *_map)
== remmap->l_reldeps[j]))
/* Yes, it is. */
if (--new_opencount[remmap->l_reldeps[j]->l_idx] == 0)
- /* This one is now gone, too. */
- mark_removed (remmap->l_reldeps[j]);
+ {
+ /* This one is now gone, too. */
+ assert (remmap->l_reldeps[j]->l_type == lt_loaded);
+ mark_removed (remmap->l_reldeps[j]);
+ }
}
}
}
@@ -215,57 +221,98 @@ _dl_close (void *_map)
{
struct link_map *imap = list[i];
if (new_opencount[i] == 0 && imap->l_type == lt_loaded
- && (imap->l_info[DT_FINI] || imap->l_info[DT_FINI_ARRAY])
- && (! (imap->l_flags_1 & DF_1_NODELETE) || ! imap->l_init_called)
- /* Skip any half-cooked objects that were never initialized. */
- && imap->l_init_called)
+ && (imap->l_flags_1 & DF_1_NODELETE) == 0)
{
/* When debugging print a message first. */
if (__builtin_expect (GL(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
_dl_debug_printf ("\ncalling fini: %s\n\n", imap->l_name);
- /* Call its termination function. */
- if (imap->l_info[DT_FINI_ARRAY] != NULL)
+ /* Call its termination function. Do not do it for
+ half-cooked objects. */
+ if (imap->l_init_called)
{
- ElfW(Addr) *array =
- (ElfW(Addr) *) (imap->l_addr
- + imap->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
- unsigned int sz = (imap->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
- / sizeof (ElfW(Addr)));
- unsigned int cnt;
-
- for (cnt = 0; cnt < sz; ++cnt)
- ((fini_t) (imap->l_addr + array[cnt])) ();
+ if (imap->l_info[DT_FINI_ARRAY] != NULL)
+ {
+ ElfW(Addr) *array =
+ (ElfW(Addr) *) (imap->l_addr
+ + imap->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
+ unsigned int sz = (imap->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
+ / sizeof (ElfW(Addr)));
+ unsigned int cnt;
+
+ for (cnt = 0; cnt < sz; ++cnt)
+ ((fini_t) (imap->l_addr + array[cnt])) ();
+ }
+
+ /* Next try the old-style destructor. */
+ if (imap->l_info[DT_FINI] != NULL)
+ (*(void (*) (void)) DL_DT_FINI_ADDRESS
+ (imap, ((void *) imap->l_addr
+ + imap->l_info[DT_FINI]->d_un.d_ptr))) ();
}
- /* Next try the old-style destructor. */
- if (imap->l_info[DT_FINI] != NULL)
- (*(void (*) (void)) DL_DT_FINI_ADDRESS
- (imap, (void *) imap->l_addr
- + imap->l_info[DT_FINI]->d_un.d_ptr)) ();
+ /* This object must not be used anymore. We must remove the
+ reference from the scope. */
+ unsigned int j;
+ struct link_map **searchlist = map->l_searchlist.r_list;
+ unsigned int nsearchlist = map->l_searchlist.r_nlist;
+
+#ifndef NDEBUG
+ bool found = false;
+#endif
+ for (j = 0; j < nsearchlist; ++j)
+ if (imap == searchlist[j])
+ {
+ /* This is the object to remove. Copy all the
+ following ones. */
+ while (++j < nsearchlist)
+ searchlist[j - 1] = searchlist[j];
+
+ searchlist[j - 1] = NULL;
+
+ --map->l_searchlist.r_nlist;
+
+#ifndef NDEBUG
+ found = true;
+#endif
+ break;
+ }
+ assert (found);
}
- else if (new_opencount[i] != 0 && imap->l_type == lt_loaded)
+ else if (new_opencount[i] != 0 && imap->l_type == lt_loaded
+ && imap->l_searchlist.r_list == NULL
+ && imap->l_initfini != NULL)
{
- /* The object is still used. But the object we are unloading
- right now is responsible for loading it and therefore we
- have the search list of the current object in its scope.
- Remove it. */
- struct r_scope_elem **runp = imap->l_scope;
-
- while (*runp != NULL)
- if (*runp == &map->l_searchlist)
+ /* The object is still used. But the object 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
+ the finalizers.
+
+ To do this count the number of dependencies. */
+ unsigned int cnt;
+ for (cnt = 1; imap->l_initfini[cnt] != NULL; ++cnt)
+ if (imap->l_initfini[cnt]->l_idx >= i
+ && imap->l_initfini[cnt]->l_idx < nopencount)
+ ++new_opencount[imap->l_initfini[cnt]->l_idx];
+ else
+ ++imap->l_initfini[cnt]->l_opencount;
+
+ /* We simply reuse the l_initfini list. */
+ imap->l_searchlist.r_list = &imap->l_initfini[cnt + 1];
+ imap->l_searchlist.r_nlist = cnt;
+
+ for (cnt = 0; imap->l_scope[cnt] != NULL; ++cnt)
+ if (imap->l_scope[cnt] = &map->l_searchlist)
{
- /* Copy all later elements. */
- while ((runp[0] = runp[1]) != NULL)
- ++runp;
+ imap->l_scope[cnt] = &imap->l_searchlist;
break;
}
- else
- ++runp;
}
/* Store the new l_opencount value. */
imap->l_opencount = new_opencount[i];
+
/* Just a sanity check. */
assert (imap->l_type == lt_loaded || imap->l_opencount > 0);
}
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
index 9fd2dd23ef..0a9183faee 100644
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -1,5 +1,5 @@
/* Load the dependencies of a mapped object.
- Copyright (C) 1996-2001, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1996-2001, 2002, 2003 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
@@ -455,12 +455,14 @@ _dl_map_object_deps (struct link_map *map,
needed[nneeded++] = NULL;
l->l_initfini = (struct link_map **)
- malloc ((nneeded + 1) * sizeof needed[0]);
+ malloc ((2 * nneeded + 1) * sizeof needed[0]);
if (l->l_initfini == NULL)
INTUSE(_dl_signal_error) (ENOMEM, map->l_name, NULL,
N_("cannot allocate dependency list"));
l->l_initfini[0] = l;
memcpy (&l->l_initfini[1], needed, nneeded * sizeof needed[0]);
+ memcpy (&l->l_initfini[nneeded + 1], l->l_initfini,
+ nneeded * sizeof needed[0]);
}
/* If we have no auxiliary objects just go on to the next map. */
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index 39b3a3d013..4603761383 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -1,5 +1,5 @@
/* Look up a symbol in the loaded objects.
- Copyright (C) 1995,96,97,98,99,2000,2001,2002 Free Software Foundation, Inc.
+ Copyright (C) 1995-2002, 2003 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
@@ -90,17 +90,34 @@ add_dependency (struct link_map *undef_map, struct link_map *map)
unsigned int i;
int result = 0;
- /* Avoid self-references. */
+ /* Avoid self-references and references to objects which cannot be
+ unloaded anyway. */
if (undef_map == map)
return 0;
+ /* Make sure nobody can unload the object while we are at it. */
+ __rtld_lock_lock_recursive (GL(dl_load_lock));
+
/* Don't create cross-reference between modules which are
dynamically loaded by the same dlopen() call. */
if (undef_map->l_opencount == 0 && map->l_opencount == 0)
- return 0;
+ goto out;
- /* Make sure nobody can unload the object while we are at it. */
- __rtld_lock_lock_recursive (GL(dl_load_lock));
+ /* Avoid references to objects which cannot be unloaded anyway. */
+ if (map->l_type != lt_loaded
+ || (map->l_flags_1 & DF_1_NODELETE) != 0)
+ goto out;
+
+ /* If the object with the undefined reference cannot be removed ever
+ just make sure the same is true for the object which contains the
+ definition. */
+ if (undef_map->l_type != lt_loaded
+ || (undef_map->l_flags_1 & DF_1_NODELETE) != 0)
+ {
+ ++map->l_opencount;
+ map->l_flags |= DF_1_NODELETE;
+ goto out;
+ }
/* Determine whether UNDEF_MAP already has a reference to MAP. First
look in the normal dependencies. */
diff --git a/elf/nodelete2.c b/elf/nodelete2.c
new file mode 100644
index 0000000000..b3d7e31a08
--- /dev/null
+++ b/elf/nodelete2.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+
+int
+main (void)
+{
+ void *handle = dlopen ("nodel2mod3.so", RTLD_LAZY);
+ if (handle == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit (1);
+ }
+ dlclose (handle);
+ exit (1);
+}
diff --git a/elf/reldep6.c b/elf/reldep6.c
index bf80ec5773..1eeec6c862 100644
--- a/elf/reldep6.c
+++ b/elf/reldep6.c
@@ -48,6 +48,18 @@ main (void)
exit (1);
}
+ baz = dlsym (h2, "baz");
+ if (baz == NULL)
+ {
+ printf ("cannot get address of \"baz\": %s\n", dlerror ());
+ exit (1);
+ }
+ if (baz () != 31)
+ {
+ printf ("baz() did not return 31\n");
+ exit (1);
+ }
+
if (dlclose (h1) != 0)
{
printf ("closing h1 failed: %s\n", dlerror ());
diff --git a/elf/reldep9.c b/elf/reldep9.c
new file mode 100644
index 0000000000..51c7a8bb9e
--- /dev/null
+++ b/elf/reldep9.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+
+int
+main (void)
+{
+ void *handle = dlopen ("reldep9mod3.so", RTLD_LAZY);
+ if (handle == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit (1);
+ }
+ dlclose (handle);
+ abort ();
+}
diff --git a/elf/reldep9mod1.c b/elf/reldep9mod1.c
new file mode 100644
index 0000000000..249a2bae1c
--- /dev/null
+++ b/elf/reldep9mod1.c
@@ -0,0 +1,23 @@
+#include <stdlib.h>
+void
+foo (void)
+{
+ exit (0);
+}
+
+void
+__attribute__((destructor))
+bar (void)
+{
+ static int i;
+ foo ();
+ ++i;
+}
+
+void
+__attribute__((constructor))
+destr (void)
+{
+ extern void baz (void);
+ baz ();
+}
diff --git a/elf/reldep9mod2.c b/elf/reldep9mod2.c
new file mode 100644
index 0000000000..090966e3e3
--- /dev/null
+++ b/elf/reldep9mod2.c
@@ -0,0 +1,3 @@
+void baz (void)
+{
+}
diff --git a/elf/reldep9mod3.c b/elf/reldep9mod3.c
new file mode 100644
index 0000000000..6d1a0d47b7
--- /dev/null
+++ b/elf/reldep9mod3.c
@@ -0,0 +1 @@
+int x;
diff --git a/elf/tls-macros.h b/elf/tls-macros.h
index 6b40dedf88..046a7d4c92 100644
--- a/elf/tls-macros.h
+++ b/elf/tls-macros.h
@@ -243,47 +243,59 @@ register void *__gp __asm__("$29");
# define TLS_LE(x) \
({ void *__l; \
- asm ("ld8 r2=tp\n\t" \
+ asm ("mov r2=r13\n\t" \
";;\n\t" \
- "addl %0=@tpre1(" #x "),r2\n\t" \
+ "addl %0=@tprel(" #x "),r2\n\t" \
: "=r" (__l) : : "r2" ); __l; })
# define TLS_IE(x) \
({ void *__l; \
- asm ("addl r16=@ltoff(@tprel(" #x ")),gp\n\t" \
+ asm (";;\n\t" \
+ "addl r16=@ltoff(@tprel(" #x ")),gp\n\t" \
";;\n\t" \
"ld8 r17=[r16]\n\t" \
";;\n\t" \
- "add %0=tp,r17\n\t" \
+ "add %0=r13,r17\n\t" \
: "=r" (__l) : : "r16", "r17" ); __l; })
+# define __TLS_CALL_CLOBBERS \
+ "r2", "r3", "r8", "r9", "r10", "r11", "r14", "r15", "r16", "r17", \
+ "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", \
+ "r27", "r28", "r29", "r30", "r31", \
+ "p6", "p7", "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15", \
+ "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \
+ "b6", "b7", \
+ "out0", "out1", "out2", "out3", "out4", "out5", "out6", "out7"
+
# define TLS_LD(x) \
({ void *__l; \
- asm ("mov loc0=gp\n\t" \
+ asm (";;\n\t" \
+ "mov loc0=gp\n\t" \
"addl r16=@ltoff(@dtpmod(" #x ")),gp\n\t" \
"addl out1=@dtprel(" #x "),r0\n\t" \
";;\n\t" \
"ld8 out0=[r16]\n\t" \
- "br.callrp=__tls_get_addr" \
+ "br.call.sptk.many b0=__tls_get_addr" \
";;\n\t" \
"mov gp=loc0\n\t" \
"mov %0=r8\n\t" \
- : "=r" (__l) : : "r16" , "loc0" , "out0" , "out1" , "r8" ); \
+ : "=r" (__l) : : "loc0", __TLS_CALL_CLOBBERS); \
__l; })
# define TLS_GD(x) \
({ void *__l; \
- asm ("mov loc0=gp\n\t" \
+ asm (";;\n\t" \
+ "mov loc0=gp\n\t" \
"addl r16=@ltoff(@dtpmod(" #x ")),gp\n\t" \
"addl r17=@ltoff(@dtprel(" #x ")),gp\n\t" \
";;\n\t" \
"ld8 out0=[r16]\n\t" \
"ld8 out1=[r17]\n\t" \
- "br.callrp=__tls_get_addr" \
+ "br.call.sptk.many b0=__tls_get_addr" \
";;\n\t" \
"mov gp=loc0\n\t" \
"mov %0=r8\n\t" \
- : "=r" (__l) : : "r16", "r17" , "loc0" , "out0", "out1" , "r8"); \
+ : "=r" (__l) : : "loc0", __TLS_CALL_CLOBBERS); \
__l; })
#else