diff options
Diffstat (limited to 'elf')
-rw-r--r-- | elf/Makefile | 28 | ||||
-rw-r--r-- | elf/dl-close.c | 127 | ||||
-rw-r--r-- | elf/dl-deps.c | 6 | ||||
-rw-r--r-- | elf/dl-lookup.c | 27 | ||||
-rw-r--r-- | elf/nodelete2.c | 16 | ||||
-rw-r--r-- | elf/reldep6.c | 12 | ||||
-rw-r--r-- | elf/reldep9.c | 16 | ||||
-rw-r--r-- | elf/reldep9mod1.c | 23 | ||||
-rw-r--r-- | elf/reldep9mod2.c | 3 | ||||
-rw-r--r-- | elf/reldep9mod3.c | 1 | ||||
-rw-r--r-- | elf/tls-macros.h | 32 |
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 |