mirror of
git://sourceware.org/git/glibc.git
synced 2025-04-12 14:21:18 +08:00
2.3.4-2.fc3.5
This commit is contained in:
parent
792542d562
commit
67e218b53a
78
ChangeLog
78
ChangeLog
@ -1,3 +1,81 @@
|
||||
2005-03-20 Alfred M. Szmidt <ams@gnu.org>
|
||||
|
||||
* elf/dl-open.c (dl_open_worker): Fix typo.
|
||||
|
||||
2005-03-19 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* elf/dl-lookup.c (add_dependency): Always search l_initfini if
|
||||
the list exists.
|
||||
|
||||
* elf/Makefile: Add rules to build and run order2.
|
||||
* elf/order2.c: New file.
|
||||
* elf/order2mod1.c: New file.
|
||||
* elf/order2mod2.c: New file.
|
||||
* elf/order2mod3.c: New file.
|
||||
* elf/order2mod4.c: New file.
|
||||
|
||||
2005-03-19 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* elf/dl-open.c (dl_open_worker): Print exact l_direct_opencount value,
|
||||
it has been incremented before.
|
||||
|
||||
2005-03-18 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* elf/dl-fini.c (_dl_fini): Split sorting of the maps in separate
|
||||
function _dl_sort_fini.
|
||||
(_dl_sort_fini): New function.
|
||||
* sysdeps/generic/ldsodefs.h: Declare _dl_sort_fini.
|
||||
* elf/dl-close.c (_dl_close): Call _dl_sort_fini before running
|
||||
destructors to call them in the right order.
|
||||
|
||||
2005-03-18 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* include/link.h (struct link_map): Remove l_opencount. Add l_removed.
|
||||
Change type of l_idx to int.
|
||||
* elf/dl-close.c: Basically rewrite. Do not use l_opencount to
|
||||
determine whether a DSO has to be unloaded. Instead compute this
|
||||
in this function.
|
||||
* elf/dl-deps.c: No need to manipulate l_opencount anymore.
|
||||
* elf/dl-lookup.c: Likewise.
|
||||
* elf/rtld.c: Likewise
|
||||
* elf/dl-open.c: Likewise. Use l_init_called to determine whether
|
||||
object was just loaded.
|
||||
* elf/dl-fini.c: Bump l_direct_opencount instead of l_opencount.
|
||||
* elf/dl-load.c (_dl_map_object_from_fd): Do not recognize DSO which
|
||||
is about to be unloaded as a match.
|
||||
(_dl_map_object): Likewise.
|
||||
* elf/do-lookup.h (do_lookup_x): Do not look into DSO which is about
|
||||
to be unloaded.
|
||||
* elf/circleload1.c: Don't use l_opencount anymore.
|
||||
* elf/neededtest.c: Likewise.
|
||||
* elf/neededtest2.c: Likewise.
|
||||
* elf/neededtest3.c: Likewise.
|
||||
* elf/neededtest4.c: Likewise.
|
||||
* elf/unload.c: Likewise.
|
||||
* elf/unload2.c: Likewise.
|
||||
* elf/loadtest.c: Likewise.
|
||||
|
||||
* elf/rtld.c: Preloading errors are now never fatal.
|
||||
|
||||
2005-03-08 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* elf/Makefile: Add rules to build and run unload5 test.
|
||||
* elf/unload5.c: New file.
|
||||
|
||||
2005-03-08 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* elf/Makefile: Add rules to build and run unload4 test.
|
||||
* elf/unload4.c: New file.
|
||||
* elf/unload4mod1.c: New file.
|
||||
* elf/unload4mod2.c: New file.
|
||||
* elf/unload4mod3.c: New file.
|
||||
* elf/unload4mod4.c: New file.
|
||||
|
||||
2005-03-05 Roland McGrath <roland@redhat.com>
|
||||
|
||||
* elf/unload3mod4.c: Declare foo.
|
||||
* elf/testobj2.c: Include <stdio.h>.
|
||||
|
||||
2005-03-01 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
[BZ #776]
|
||||
|
32
elf/Makefile
32
elf/Makefile
@ -84,7 +84,9 @@ distribute := rtld-Rules \
|
||||
tst-execstack-mod.c tst-dlmodcount.c \
|
||||
check-textrel.c dl-sysdep.h test-dlopenrpathmod.c \
|
||||
tst-deep1mod1.c tst-deep1mod2.c tst-deep1mod3.c \
|
||||
unload3mod1.c unload3mod2.c unload3mod3.c unload3mod4.c
|
||||
unload3mod1.c unload3mod2.c unload3mod3.c unload3mod4.c \
|
||||
unload4mod1.c unload4mod2.c unload4mod3.c unload4mod4.c \
|
||||
order2mod1.c order2mod2.c order2mod3.c order2mod4.c
|
||||
|
||||
CFLAGS-dl-runtime.c = -fexceptions -fasynchronous-unwind-tables
|
||||
CFLAGS-dl-lookup.c = -fexceptions -fasynchronous-unwind-tables
|
||||
@ -156,7 +158,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
|
||||
tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-align \
|
||||
tst-align2 $(tests-execstack-$(have-z-execstack)) tst-dlmodcount \
|
||||
tst-dlopenrpath tst-deep1 tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
|
||||
unload3 tst-global1
|
||||
unload3 unload4 unload5 tst-global1 order2
|
||||
# reldep9
|
||||
test-srcs = tst-pathopt
|
||||
tests-vis-yes = vismain
|
||||
@ -192,7 +194,9 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
|
||||
$(modules-execstack-$(have-z-execstack)) \
|
||||
tst-dlopenrpathmod tst-deep1mod1 tst-deep1mod2 tst-deep1mod3 \
|
||||
tst-dlmopen1mod \
|
||||
unload3mod1 unload3mod2 unload3mod3 unload3mod4
|
||||
unload3mod1 unload3mod2 unload3mod3 unload3mod4 \
|
||||
unload4mod1 unload4mod2 unload4mod3 unload4mod4 \
|
||||
order2mod1 order2mod2 order2mod3 order2mod4
|
||||
ifeq (yes,$(have-initfini-array))
|
||||
modules-names += tst-array2dep
|
||||
endif
|
||||
@ -427,6 +431,8 @@ $(objpfx)reldep9mod3.so: $(objpfx)reldep9mod1.so $(objpfx)reldep9mod2.so
|
||||
$(objpfx)unload3mod1.so: $(objpfx)unload3mod3.so
|
||||
$(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
|
||||
|
||||
LDFLAGS-tst-tlsmod5.so = -nostdlib
|
||||
LDFLAGS-tst-tlsmod6.so = -nostdlib
|
||||
@ -467,6 +473,7 @@ circlemod3a.so-no-z-defs = yes
|
||||
reldep8mod2.so-no-z-defs = yes
|
||||
reldep9mod1.so-no-z-defs = yes
|
||||
unload3mod4.so-no-z-defs = yes
|
||||
unload4mod1.so-no-z-defs = yes
|
||||
|
||||
# filtmod1.so has a special rule
|
||||
$(filter-out $(objpfx)filtmod1.so, $(test-modules)): $(objpfx)%.so: $(objpfx)%.os
|
||||
@ -687,6 +694,13 @@ $(objpfx)unload3: $(libdl)
|
||||
$(objpfx)unload3.out: $(objpfx)unload3mod1.so $(objpfx)unload3mod2.so \
|
||||
$(objpfx)unload3mod3.so $(objpfx)unload3mod4.so
|
||||
|
||||
$(objpfx)unload4: $(libdl)
|
||||
$(objpfx)unload4.out: $(objpfx)unload4mod1.so $(objpfx)unload4mod3.so
|
||||
|
||||
$(objpfx)unload5: $(libdl)
|
||||
$(objpfx)unload5.out: $(objpfx)unload3mod1.so $(objpfx)unload3mod2.so \
|
||||
$(objpfx)unload3mod3.so $(objpfx)unload3mod4.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
|
||||
@ -793,3 +807,15 @@ $(objpfx)tst-dlmopen3.out: $(objpfx)tst-dlmopen1mod.so
|
||||
|
||||
$(objpfx)tst-global1: $(libdl)
|
||||
$(objpfx)tst-global1.out: $(objpfx)testobj6.so $(objpfx)testobj2.so
|
||||
|
||||
$(objpfx)order2: $(libdl)
|
||||
$(objpfx)order2.out: $(objpfx)order2 $(objpfx)order2mod1.so \
|
||||
$(objpfx)order2mod2.so
|
||||
$(elf-objpfx)$(rtld-installed-name) \
|
||||
--library-path $(rpath-link)$(patsubst %,:%,$(sysdep-library-path)) \
|
||||
$(objpfx)order2 > $@
|
||||
(echo "12345" | cmp $@ -) > /dev/null
|
||||
$(objpfx)order2mod1.so: $(objpfx)order2mod4.so
|
||||
$(objpfx)order2mod4.so: $(objpfx)order2mod3.so
|
||||
$(objpfx)order2mod2.so: $(objpfx)order2mod3.so
|
||||
order2mod2.so-no-z-defs = yes
|
||||
|
@ -27,7 +27,7 @@ check_loaded_objects (const char **loaded)
|
||||
for (lm = _r_debug.r_map; lm; lm = lm->l_next)
|
||||
{
|
||||
if (lm->l_name && lm->l_name[0])
|
||||
printf(" %s, count = %d\n", lm->l_name, (int) lm->l_opencount);
|
||||
printf(" %s, count = %d\n", lm->l_name, (int) lm->l_direct_opencount);
|
||||
if (lm->l_type == lt_loaded && lm->l_name)
|
||||
{
|
||||
int match = 0;
|
||||
|
360
elf/dl-close.c
360
elf/dl-close.c
@ -102,18 +102,9 @@ void
|
||||
internal_function
|
||||
_dl_close (void *_map)
|
||||
{
|
||||
struct reldep_list
|
||||
{
|
||||
struct link_map **rellist;
|
||||
unsigned int nrellist;
|
||||
unsigned int nhandled;
|
||||
struct reldep_list *next;
|
||||
bool handled[0];
|
||||
} *reldeps = NULL;
|
||||
struct link_map **list;
|
||||
struct link_map *map = _map;
|
||||
unsigned int i;
|
||||
unsigned int *new_opencount;
|
||||
Lmid_t ns = map->l_ns;
|
||||
#ifdef USE_TLS
|
||||
bool any_tls = false;
|
||||
#endif
|
||||
@ -124,162 +115,134 @@ _dl_close (void *_map)
|
||||
/* Nope. Do nothing. */
|
||||
return;
|
||||
|
||||
if (__builtin_expect (map->l_opencount, 1) == 0)
|
||||
if (__builtin_expect (map->l_direct_opencount, 1) == 0)
|
||||
GLRO(dl_signal_error) (0, map->l_name, NULL, N_("shared object not open"));
|
||||
|
||||
/* Acquire the lock. */
|
||||
__rtld_lock_lock_recursive (GL(dl_load_lock));
|
||||
|
||||
/* One less direct use. */
|
||||
assert (map->l_direct_opencount > 0);
|
||||
--map->l_direct_opencount;
|
||||
|
||||
/* Decrement the reference count. */
|
||||
if (map->l_opencount > 1 || map->l_type != lt_loaded)
|
||||
if (map->l_direct_opencount > 1 || map->l_type != lt_loaded)
|
||||
{
|
||||
/* There are still references to this object. Do nothing more. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
|
||||
GLRO(dl_debug_printf) ("\nclosing file=%s; opencount == %u\n",
|
||||
map->l_name, map->l_opencount);
|
||||
|
||||
/* Decrement the object's reference counter, not the dependencies'. */
|
||||
--map->l_opencount;
|
||||
|
||||
/* If the direct use counter reaches zero we have to decrement
|
||||
all the dependencies' usage counter. */
|
||||
if (map->l_direct_opencount == 0)
|
||||
for (i = 1; i < map->l_searchlist.r_nlist; ++i)
|
||||
--map->l_searchlist.r_list[i]->l_opencount;
|
||||
GLRO(dl_debug_printf) ("\nclosing file=%s; direct_opencount == %u\n",
|
||||
map->l_name, map->l_direct_opencount);
|
||||
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||
return;
|
||||
}
|
||||
|
||||
list = map->l_initfini;
|
||||
const unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded;
|
||||
char used[nloaded];
|
||||
char done[nloaded];
|
||||
struct link_map *maps[nloaded];
|
||||
|
||||
/* Compute the new l_opencount values. */
|
||||
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)
|
||||
;
|
||||
|
||||
unsigned int nopencount = i;
|
||||
new_opencount = (unsigned int *) alloca (i * sizeof (unsigned int));
|
||||
|
||||
for (i = 0; list[i] != NULL; ++i)
|
||||
/* Run over the list and assign indeces 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)
|
||||
{
|
||||
list[i]->l_idx = i;
|
||||
new_opencount[i] = list[i]->l_opencount;
|
||||
l->l_idx = idx;
|
||||
maps[idx] = l;
|
||||
++idx;
|
||||
}
|
||||
--new_opencount[0];
|
||||
for (i = 1; list[i] != NULL; ++i)
|
||||
if ((list[i]->l_flags_1 & DF_1_NODELETE) == 0
|
||||
/* Decrement counter. */
|
||||
&& (assert (new_opencount[i] > 0), --new_opencount[i] == 0))
|
||||
{
|
||||
void mark_removed (struct link_map *remmap)
|
||||
{
|
||||
/* Test whether this object was also loaded directly. */
|
||||
if (remmap->l_searchlist.r_list != NULL
|
||||
&& remmap->l_direct_opencount > 0)
|
||||
{
|
||||
/* In this case we have to decrement all the dependencies of
|
||||
this object. They are all in MAP's dependency list. */
|
||||
unsigned int j;
|
||||
struct link_map **dep_list = remmap->l_searchlist.r_list;
|
||||
assert (idx == nloaded);
|
||||
|
||||
for (j = 1; j < remmap->l_searchlist.r_nlist; ++j)
|
||||
if (! (dep_list[j]->l_flags_1 & DF_1_NODELETE)
|
||||
|| ! dep_list[j]->l_init_called)
|
||||
/* Prepare the bitmaps. */
|
||||
memset (used, '\0', sizeof (used));
|
||||
memset (done, '\0', sizeof (done));
|
||||
|
||||
/* Keep track of the lowest index link map we have covered already. */
|
||||
int done_index = -1;
|
||||
while (++done_index < nloaded)
|
||||
{
|
||||
struct link_map *l = maps[done_index];
|
||||
|
||||
if (done[done_index])
|
||||
/* Already handled. */
|
||||
continue;
|
||||
|
||||
/* Check whether this object is still used. */
|
||||
if (l->l_type == lt_loaded
|
||||
&& l->l_direct_opencount == 0
|
||||
&& (l->l_flags_1 & DF_1_NODELETE) == 0
|
||||
&& !used[done_index])
|
||||
continue;
|
||||
|
||||
/* We need this object and we handle it now. */
|
||||
done[done_index] = 1;
|
||||
used[done_index] = 1;
|
||||
/* Signal the object is still needed. */
|
||||
l->l_idx = -1;
|
||||
|
||||
/* Mark all dependencies as used. */
|
||||
if (l->l_initfini != NULL)
|
||||
{
|
||||
struct link_map **lp = &l->l_initfini[1];
|
||||
while (*lp != NULL)
|
||||
{
|
||||
if ((*lp)->l_idx != -1)
|
||||
{
|
||||
assert (dep_list[j]->l_idx < map->l_searchlist.r_nlist);
|
||||
assert (new_opencount[dep_list[j]->l_idx] > 0);
|
||||
if (--new_opencount[dep_list[j]->l_idx] == 0)
|
||||
assert ((*lp)->l_idx >= 0 && (*lp)->l_idx < nloaded);
|
||||
|
||||
if (!used[(*lp)->l_idx])
|
||||
{
|
||||
assert (dep_list[j]->l_type == lt_loaded);
|
||||
mark_removed (dep_list[j]);
|
||||
used[(*lp)->l_idx] = 1;
|
||||
if ((*lp)->l_idx - 1 < done_index)
|
||||
done_index = (*lp)->l_idx - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (remmap->l_reldeps != NULL)
|
||||
++lp;
|
||||
}
|
||||
}
|
||||
/* And the same for relocation dependencies. */
|
||||
if (l->l_reldeps != NULL)
|
||||
for (unsigned int j = 0; j < l->l_reldepsact; ++j)
|
||||
{
|
||||
struct link_map *jmap = l->l_reldeps[j];
|
||||
|
||||
if (jmap->l_idx != -1)
|
||||
{
|
||||
unsigned int j;
|
||||
for (j = 0; j < remmap->l_reldepsact; ++j)
|
||||
assert (jmap->l_idx >= 0 && jmap->l_idx < nloaded);
|
||||
|
||||
if (!used[jmap->l_idx])
|
||||
{
|
||||
struct link_map *depmap = remmap->l_reldeps[j];
|
||||
|
||||
/* Find out whether this object is in our list. */
|
||||
if (depmap->l_idx < nopencount
|
||||
&& list[depmap->l_idx] == depmap)
|
||||
{
|
||||
/* Yes, it is. If is has a search list, make a
|
||||
recursive call to handle this. */
|
||||
if (depmap->l_searchlist.r_list != NULL)
|
||||
{
|
||||
assert (new_opencount[depmap->l_idx] > 0);
|
||||
if (--new_opencount[depmap->l_idx] == 0)
|
||||
{
|
||||
/* This one is now gone, too. */
|
||||
assert (depmap->l_type == lt_loaded);
|
||||
mark_removed (depmap);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise we have to handle the dependency
|
||||
deallocation here. */
|
||||
unsigned int k;
|
||||
for (k = 0; depmap->l_initfini[k] != NULL; ++k)
|
||||
{
|
||||
struct link_map *rl = depmap->l_initfini[k];
|
||||
|
||||
if (rl->l_idx < nopencount
|
||||
&& list[rl->l_idx] == rl)
|
||||
{
|
||||
assert (new_opencount[rl->l_idx] > 0);
|
||||
if (--new_opencount[rl->l_idx] == 0)
|
||||
{
|
||||
/* Another module to remove. */
|
||||
assert (rl->l_type == lt_loaded);
|
||||
mark_removed (rl);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert (rl->l_opencount > 0);
|
||||
if (--rl->l_opencount == 0)
|
||||
mark_removed (rl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
used[jmap->l_idx] = 1;
|
||||
if (jmap->l_idx - 1 < done_index)
|
||||
done_index = jmap->l_idx - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mark_removed (list[i]);
|
||||
}
|
||||
assert (new_opencount[0] == 0);
|
||||
/* Sort the entries. */
|
||||
_dl_sort_fini (GL(dl_ns)[ns]._ns_loaded, maps, nloaded, used, ns);
|
||||
|
||||
/* Call all termination functions at once. */
|
||||
for (i = 0; list[i] != NULL; ++i)
|
||||
bool unload_any = false;
|
||||
unsigned int first_loaded = ~0;
|
||||
for (i = 0; i < nloaded; ++i)
|
||||
{
|
||||
struct link_map *imap = list[i];
|
||||
if (new_opencount[i] == 0 && imap->l_type == lt_loaded
|
||||
&& (imap->l_flags_1 & DF_1_NODELETE) == 0)
|
||||
{
|
||||
/* When debugging print a message first. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
|
||||
GLRO(dl_debug_printf) ("\ncalling fini: %s [%lu]\n\n",
|
||||
imap->l_name, imap->l_ns);
|
||||
struct link_map *imap = maps[i];
|
||||
|
||||
if (!used[i])
|
||||
{
|
||||
assert (imap->l_type == lt_loaded
|
||||
&& (imap->l_flags_1 & DF_1_NODELETE) == 0);
|
||||
|
||||
/* Call its termination function. Do not do it for
|
||||
half-cooked objects. */
|
||||
if (imap->l_init_called)
|
||||
{
|
||||
/* When debugging print a message first. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
|
||||
GLRO(dl_debug_printf) ("\ncalling fini: %s [%lu]\n\n",
|
||||
imap->l_name, ns);
|
||||
|
||||
if (imap->l_info[DT_FINI_ARRAY] != NULL)
|
||||
{
|
||||
ElfW(Addr) *array =
|
||||
@ -299,42 +262,60 @@ _dl_close (void *_map)
|
||||
+ 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;
|
||||
/* This object must not be used anymore. */
|
||||
imap->l_removed = 1;
|
||||
|
||||
#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];
|
||||
/* We indeed have an object to remove. */
|
||||
unload_any = true;
|
||||
|
||||
searchlist[j - 1] = NULL;
|
||||
|
||||
--map->l_searchlist.r_nlist;
|
||||
|
||||
#ifndef NDEBUG
|
||||
found = true;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
assert (found);
|
||||
/* Remember where the first dynamically loaded object is. */
|
||||
if (i < first_loaded)
|
||||
first_loaded = i;
|
||||
}
|
||||
/* Else used[i]. */
|
||||
else if (imap->l_type == lt_loaded)
|
||||
{
|
||||
if (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. 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.
|
||||
|
||||
/* Store the new l_opencount value. */
|
||||
imap->l_opencount = new_opencount[i];
|
||||
To do this count the number of dependencies. */
|
||||
unsigned int cnt;
|
||||
for (cnt = 1; imap->l_initfini[cnt] != NULL; ++cnt)
|
||||
;
|
||||
|
||||
/* Just a sanity check. */
|
||||
assert (imap->l_type == lt_loaded || imap->l_opencount > 0);
|
||||
/* 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)
|
||||
{
|
||||
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. */
|
||||
if (imap->l_loader != NULL && imap->l_loader->l_idx != -1)
|
||||
imap->l_loader = NULL;
|
||||
|
||||
/* Remember where the first dynamically loaded object is. */
|
||||
if (i < first_loaded)
|
||||
first_loaded = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there are no objects to unload, do nothing further. */
|
||||
if (!unload_any)
|
||||
goto out;
|
||||
|
||||
/* Notify the debugger we are about to remove some loaded objects. */
|
||||
_r_debug.r_state = RT_DELETE;
|
||||
GLRO(dl_debug_state) ();
|
||||
@ -347,12 +328,12 @@ _dl_close (void *_map)
|
||||
|
||||
/* Check each element of the search list to see if all references to
|
||||
it are gone. */
|
||||
for (i = 0; list[i] != NULL; ++i)
|
||||
for (i = first_loaded; i < nloaded; ++i)
|
||||
{
|
||||
struct link_map *imap = list[i];
|
||||
if (imap->l_opencount == 0 && imap->l_type == lt_loaded)
|
||||
struct link_map *imap = maps[i];
|
||||
if (!used[i])
|
||||
{
|
||||
struct libname_list *lnp;
|
||||
assert (imap->l_type == lt_loaded);
|
||||
|
||||
/* That was the last reference, and this was a dlopen-loaded
|
||||
object. We can unmap it. */
|
||||
@ -482,39 +463,13 @@ _dl_close (void *_map)
|
||||
if (imap->l_origin != (char *) -1)
|
||||
free ((char *) imap->l_origin);
|
||||
|
||||
/* If the object has relocation dependencies save this
|
||||
information for latter. */
|
||||
if (__builtin_expect (imap->l_reldeps != NULL, 0))
|
||||
{
|
||||
struct reldep_list *newrel;
|
||||
|
||||
newrel = (struct reldep_list *) alloca (sizeof (*reldeps)
|
||||
+ (imap->l_reldepsact
|
||||
* sizeof (bool)));
|
||||
newrel->rellist = imap->l_reldeps;
|
||||
newrel->nrellist = imap->l_reldepsact;
|
||||
newrel->next = reldeps;
|
||||
|
||||
newrel->nhandled = imap->l_reldepsact;
|
||||
unsigned int j;
|
||||
for (j = 0; j < imap->l_reldepsact; ++j)
|
||||
{
|
||||
/* Find out whether this object is in our list. */
|
||||
if (imap->l_reldeps[j]->l_idx < nopencount
|
||||
&& list[imap->l_reldeps[j]->l_idx] == imap->l_reldeps[j])
|
||||
/* Yes, it is. */
|
||||
newrel->handled[j] = true;
|
||||
else
|
||||
newrel->handled[j] = false;
|
||||
}
|
||||
|
||||
reldeps = newrel;
|
||||
}
|
||||
free (imap->l_reldeps);
|
||||
|
||||
/* This name always is allocated. */
|
||||
free (imap->l_name);
|
||||
/* Remove the list with all the names of the shared object. */
|
||||
lnp = imap->l_libname;
|
||||
|
||||
struct libname_list *lnp = imap->l_libname;
|
||||
do
|
||||
{
|
||||
struct libname_list *this = lnp;
|
||||
@ -525,8 +480,7 @@ _dl_close (void *_map)
|
||||
while (lnp != NULL);
|
||||
|
||||
/* Remove the searchlists. */
|
||||
if (imap != map)
|
||||
free (imap->l_initfini);
|
||||
free (imap->l_initfini);
|
||||
|
||||
/* Remove the scope array if we allocated it. */
|
||||
if (imap->l_scope != imap->l_scope_mem)
|
||||
@ -560,26 +514,8 @@ _dl_close (void *_map)
|
||||
_r_debug.r_state = RT_CONSISTENT;
|
||||
GLRO(dl_debug_state) ();
|
||||
|
||||
/* Now we can perhaps also remove the modules for which we had
|
||||
dependencies because of symbol lookup. */
|
||||
while (__builtin_expect (reldeps != NULL, 0))
|
||||
{
|
||||
while (reldeps->nrellist-- > 0)
|
||||
/* Some of the relocation dependencies might be on the
|
||||
dependency list of the object we are closing right now.
|
||||
They were already handled. Do not close them again. */
|
||||
if (reldeps->nrellist < reldeps->nhandled
|
||||
&& ! reldeps->handled[reldeps->nrellist])
|
||||
_dl_close (reldeps->rellist[reldeps->nrellist]);
|
||||
|
||||
free (reldeps->rellist);
|
||||
|
||||
reldeps = reldeps->next;
|
||||
}
|
||||
|
||||
free (list);
|
||||
|
||||
/* Release the lock. */
|
||||
out:
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||
}
|
||||
libc_hidden_def (_dl_close)
|
||||
@ -657,3 +593,7 @@ libc_freeres_fn (free_mem)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef SHARED
|
||||
#include "dl-fini.c"
|
||||
#endif
|
||||
|
@ -566,8 +566,6 @@ Filters not supported with LD_TRACE_PRELINKING"));
|
||||
{
|
||||
/* 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];
|
||||
|
||||
|
183
elf/dl-fini.c
183
elf/dl-fini.c
@ -23,10 +23,97 @@
|
||||
#include <ldsodefs.h>
|
||||
|
||||
|
||||
void
|
||||
internal_function
|
||||
_dl_sort_fini (struct link_map *l, struct link_map **maps, size_t nmaps,
|
||||
char *used, Lmid_t ns)
|
||||
{
|
||||
if (ns == LM_ID_BASE)
|
||||
/* The main executable always comes first. */
|
||||
l = l->l_next;
|
||||
|
||||
for (; l != NULL; l = l->l_next)
|
||||
/* Do not handle ld.so in secondary namespaces and object which
|
||||
are not removed. */
|
||||
if (l == l->l_real && l->l_idx != -1)
|
||||
{
|
||||
/* Find the place in the 'maps' array. */
|
||||
unsigned int j;
|
||||
for (j = ns == LM_ID_BASE ? 1 : 0; maps[j] != l; ++j)
|
||||
assert (j < nmaps);
|
||||
|
||||
/* Find all object for which the current one is a dependency
|
||||
and move the found object (if necessary) in front. */
|
||||
for (unsigned int k = j + 1; k < nmaps; ++k)
|
||||
{
|
||||
struct link_map **runp = maps[k]->l_initfini;
|
||||
if (runp != NULL)
|
||||
{
|
||||
while (*runp != NULL)
|
||||
if (*runp == l)
|
||||
{
|
||||
struct link_map *here = maps[k];
|
||||
|
||||
/* Move it now. */
|
||||
memmove (&maps[j] + 1,
|
||||
&maps[j], (k - j) * sizeof (struct link_map *));
|
||||
maps[j] = here;
|
||||
|
||||
if (used != NULL)
|
||||
{
|
||||
char here_used = used[k];
|
||||
|
||||
memmove (&used[j] + 1,
|
||||
&used[j], (k - j) * sizeof (char));
|
||||
used[j] = here_used;
|
||||
}
|
||||
|
||||
++j;
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
++runp;
|
||||
}
|
||||
|
||||
if (__builtin_expect (maps[k]->l_reldeps != NULL, 0))
|
||||
{
|
||||
unsigned int m = maps[k]->l_reldepsact;
|
||||
struct link_map **relmaps = maps[k]->l_reldeps;
|
||||
|
||||
while (m-- > 0)
|
||||
{
|
||||
if (relmaps[m] == l)
|
||||
{
|
||||
struct link_map *here = maps[k];
|
||||
|
||||
/* Move it now. */
|
||||
memmove (&maps[j] + 1,
|
||||
&maps[j],
|
||||
(k - j) * sizeof (struct link_map *));
|
||||
maps[j] = here;
|
||||
|
||||
if (used != NULL)
|
||||
{
|
||||
char here_used = used[k];
|
||||
|
||||
memmove (&used[j] + 1,
|
||||
&used[j], (k - j) * sizeof (char));
|
||||
used[j] = here_used;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined SHARED || defined IS_IN_rtld
|
||||
/* Type of the constructor functions. */
|
||||
typedef void (*fini_t) (void);
|
||||
|
||||
|
||||
void
|
||||
internal_function
|
||||
_dl_fini (void)
|
||||
@ -48,16 +135,16 @@ _dl_fini (void)
|
||||
/* We run the destructors of the main namespaces last. As for the
|
||||
other namespaces, we pick run the destructors in them in reverse
|
||||
order of the namespace ID. */
|
||||
for (Lmid_t cnt = DL_NNS - 1; cnt >= 0; --cnt)
|
||||
for (Lmid_t ns = DL_NNS - 1; ns >= 0; --ns)
|
||||
{
|
||||
/* Protect against concurrent loads and unloads. */
|
||||
__rtld_lock_lock_recursive (GL(dl_load_lock));
|
||||
|
||||
unsigned int nloaded = GL(dl_ns)[cnt]._ns_nloaded;
|
||||
unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded;
|
||||
|
||||
/* XXX Could it be (in static binaries) that there is no object
|
||||
loaded? */
|
||||
assert (cnt != LM_ID_BASE || nloaded > 0);
|
||||
assert (ns != LM_ID_BASE || nloaded > 0);
|
||||
|
||||
/* Now we can allocate an array to hold all the pointers and copy
|
||||
the pointers in. */
|
||||
@ -76,86 +163,27 @@ _dl_fini (void)
|
||||
|
||||
unsigned int i;
|
||||
struct link_map *l;
|
||||
for (l = GL(dl_ns)[cnt]._ns_loaded, i = 0; l != NULL; l = l->l_next)
|
||||
for (l = GL(dl_ns)[ns]._ns_loaded, i = 0; l != NULL; l = l->l_next)
|
||||
/* Do not handle ld.so in secondary namespaces. */
|
||||
if (l == l->l_real)
|
||||
{
|
||||
assert (i < nloaded);
|
||||
|
||||
maps[i++] = l;
|
||||
maps[i] = l;
|
||||
l->l_idx = i;
|
||||
++i;
|
||||
|
||||
/* Bump l_opencount of all objects so that they are not
|
||||
dlclose()ed from underneath us. */
|
||||
++l->l_opencount;
|
||||
/* Bump l_direct_opencount of all objects so that they are
|
||||
not dlclose()ed from underneath us. */
|
||||
++l->l_direct_opencount;
|
||||
}
|
||||
assert (cnt != LM_ID_BASE || i == nloaded);
|
||||
assert (cnt == LM_ID_BASE || i == nloaded || i == nloaded - 1);
|
||||
assert (ns != LM_ID_BASE || i == nloaded);
|
||||
assert (ns == LM_ID_BASE || i == nloaded || i == nloaded - 1);
|
||||
unsigned int nmaps = i;
|
||||
|
||||
if (nmaps != 0)
|
||||
{
|
||||
/* Now we have to do the sorting. */
|
||||
l = GL(dl_ns)[cnt]._ns_loaded;
|
||||
if (cnt == LM_ID_BASE)
|
||||
/* The main executable always comes first. */
|
||||
l = l->l_next;
|
||||
for (; l != NULL; l = l->l_next)
|
||||
/* Do not handle ld.so in secondary namespaces. */
|
||||
if (l == l->l_real)
|
||||
{
|
||||
/* Find the place in the 'maps' array. */
|
||||
unsigned int j;
|
||||
for (j = cnt == LM_ID_BASE ? 1 : 0; maps[j] != l; ++j)
|
||||
assert (j < nmaps);
|
||||
|
||||
/* Find all object for which the current one is a dependency
|
||||
and move the found object (if necessary) in front. */
|
||||
for (unsigned int k = j + 1; k < nmaps; ++k)
|
||||
{
|
||||
struct link_map **runp = maps[k]->l_initfini;
|
||||
if (runp != NULL)
|
||||
{
|
||||
while (*runp != NULL)
|
||||
if (*runp == l)
|
||||
{
|
||||
struct link_map *here = maps[k];
|
||||
|
||||
/* Move it now. */
|
||||
memmove (&maps[j] + 1,
|
||||
&maps[j],
|
||||
(k - j) * sizeof (struct link_map *));
|
||||
maps[j++] = here;
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
++runp;
|
||||
}
|
||||
|
||||
if (__builtin_expect (maps[k]->l_reldeps != NULL, 0))
|
||||
{
|
||||
unsigned int m = maps[k]->l_reldepsact;
|
||||
struct link_map **relmaps = maps[k]->l_reldeps;
|
||||
|
||||
while (m-- > 0)
|
||||
{
|
||||
if (relmaps[m] == l)
|
||||
{
|
||||
struct link_map *here = maps[k];
|
||||
|
||||
/* Move it now. */
|
||||
memmove (&maps[j] + 1,
|
||||
&maps[j],
|
||||
(k - j) * sizeof (struct link_map *));
|
||||
maps[j] = here;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Now we have to do the sorting. */
|
||||
_dl_sort_fini (GL(dl_ns)[ns]._ns_loaded, maps, nmaps, NULL, ns);
|
||||
|
||||
/* We do not rely on the linked list of loaded object anymore from
|
||||
this point on. We have our own list here (maps). The various
|
||||
@ -191,7 +219,7 @@ _dl_fini (void)
|
||||
0))
|
||||
_dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
|
||||
l->l_name[0] ? l->l_name : rtld_progname,
|
||||
cnt);
|
||||
ns);
|
||||
|
||||
/* First see whether an array is given. */
|
||||
if (l->l_info[DT_FINI_ARRAY] != NULL)
|
||||
@ -211,14 +239,17 @@ _dl_fini (void)
|
||||
}
|
||||
|
||||
/* Correct the previous increment. */
|
||||
--l->l_opencount;
|
||||
--l->l_direct_opencount;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SHARED
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS, 0))
|
||||
_dl_debug_printf ("\nruntime linker statistics:\n"
|
||||
" final number of relocations: %lu\n"
|
||||
"final number of relocations from cache: %lu\n",
|
||||
GL(dl_num_relocations),
|
||||
GL(dl_num_cache_relocations));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
@ -839,7 +839,7 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
|
||||
|
||||
/* Look again to see if the real name matched another already loaded. */
|
||||
for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
|
||||
if (l->l_ino == st.st_ino && l->l_dev == st.st_dev)
|
||||
if (l->l_removed == 0 && l->l_ino == st.st_ino && l->l_dev == st.st_dev)
|
||||
{
|
||||
/* The object is already loaded.
|
||||
Just bump its reference count and return it. */
|
||||
@ -1824,7 +1824,8 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
|
||||
/* If the requested name matches the soname of a loaded object,
|
||||
use that object. Elide this check for names that have not
|
||||
yet been opened. */
|
||||
if (__builtin_expect (l->l_faked, 0) != 0)
|
||||
if (__builtin_expect (l->l_faked, 0) != 0
|
||||
|| __builtin_expect (l->l_removed, 0) != 0)
|
||||
continue;
|
||||
if (!_dl_name_match_p (name, l))
|
||||
{
|
||||
|
@ -91,11 +91,6 @@ add_dependency (struct link_map *undef_map, struct link_map *map)
|
||||
/* 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)
|
||||
goto out;
|
||||
|
||||
/* Avoid references to objects which cannot be unloaded anyway. */
|
||||
if (map->l_type != lt_loaded
|
||||
|| (map->l_flags_1 & DF_1_NODELETE) != 0)
|
||||
@ -107,14 +102,13 @@ add_dependency (struct link_map *undef_map, struct link_map *map)
|
||||
if (undef_map->l_type != lt_loaded
|
||||
|| (undef_map->l_flags_1 & DF_1_NODELETE) != 0)
|
||||
{
|
||||
++map->l_opencount;
|
||||
map->l_flags_1 |= DF_1_NODELETE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Determine whether UNDEF_MAP already has a reference to MAP. First
|
||||
look in the normal dependencies. */
|
||||
if (undef_map->l_searchlist.r_list != NULL)
|
||||
if (undef_map->l_initfini != NULL)
|
||||
{
|
||||
list = undef_map->l_initfini;
|
||||
|
||||
@ -172,19 +166,6 @@ add_dependency (struct link_map *undef_map, struct link_map *map)
|
||||
if (__builtin_expect (act < undef_map->l_reldepsmax, 1))
|
||||
undef_map->l_reldeps[undef_map->l_reldepsact++] = map;
|
||||
|
||||
if (map->l_searchlist.r_list != NULL)
|
||||
/* And increment the counter in the referenced object. */
|
||||
++map->l_opencount;
|
||||
else
|
||||
/* We have to bump the counts for all dependencies since so far
|
||||
this object was only a normal or transitive dependency.
|
||||
Now it might be closed with _dl_close() directly. */
|
||||
for (list = map->l_initfini; *list != NULL; ++list)
|
||||
++(*list)->l_opencount;
|
||||
|
||||
/* As if it is opened through _dl_open. */
|
||||
++map->l_direct_opencount;
|
||||
|
||||
/* Display information if we are debugging. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
|
||||
_dl_debug_printf ("\
|
||||
|
247
elf/dl-open.c
247
elf/dl-open.c
@ -279,23 +279,14 @@ dl_open_worker (void *a)
|
||||
{
|
||||
/* Let the user know about the opencount. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
|
||||
GLRO(dl_debug_printf) ("opening file=%s [%lu]; opencount=%u\n\n",
|
||||
new->l_name, new->l_ns, new->l_opencount);
|
||||
GLRO(dl_debug_printf) ("opening file=%s [%lu]; direct_opencount=%u\n\n",
|
||||
new->l_name, new->l_ns, new->l_direct_opencount);
|
||||
|
||||
/* If the user requested the object to be in the global namespace
|
||||
but it is not so far, add it now. */
|
||||
if ((mode & RTLD_GLOBAL) && new->l_global == 0)
|
||||
(void) add_to_global (new);
|
||||
|
||||
if (new->l_direct_opencount == 1)
|
||||
/* This is the only direct reference. Increment all the
|
||||
dependencies' reference counter. */
|
||||
for (i = 0; i < new->l_searchlist.r_nlist; ++i)
|
||||
++new->l_searchlist.r_list[i]->l_opencount;
|
||||
else
|
||||
/* Increment just the reference counter of the object. */
|
||||
++new->l_opencount;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -373,136 +364,136 @@ dl_open_worker (void *a)
|
||||
any_tls = false;
|
||||
#endif
|
||||
|
||||
/* Increment the open count for all dependencies. If the file is
|
||||
not loaded as a dependency here add the search list of the newly
|
||||
loaded object to the scope. */
|
||||
/* If the file is not loaded now as a dependency, add the search
|
||||
list of the newly loaded object to the scope. */
|
||||
for (i = 0; i < new->l_searchlist.r_nlist; ++i)
|
||||
if (++new->l_searchlist.r_list[i]->l_opencount > 1
|
||||
&& new->l_real->l_searchlist.r_list[i]->l_type == lt_loaded)
|
||||
{
|
||||
struct link_map *imap = new->l_searchlist.r_list[i];
|
||||
struct r_scope_elem **runp = imap->l_scope;
|
||||
size_t cnt = 0;
|
||||
{
|
||||
struct link_map *imap = new->l_searchlist.r_list[i];
|
||||
|
||||
while (*runp != NULL)
|
||||
{
|
||||
/* This can happen if imap was just loaded, but during
|
||||
relocation had l_opencount bumped because of relocation
|
||||
dependency. Avoid duplicates in l_scope. */
|
||||
if (__builtin_expect (*runp == &new->l_searchlist, 0))
|
||||
break;
|
||||
/* If the initializer has been called already, the object has
|
||||
not been loaded here and now. */
|
||||
if (imap->l_init_called && imap->l_type == lt_loaded)
|
||||
{
|
||||
struct r_scope_elem **runp = imap->l_scope;
|
||||
size_t cnt = 0;
|
||||
|
||||
++cnt;
|
||||
++runp;
|
||||
}
|
||||
while (*runp != NULL)
|
||||
{
|
||||
++cnt;
|
||||
++runp;
|
||||
}
|
||||
|
||||
if (*runp != NULL)
|
||||
/* Avoid duplicates. */
|
||||
continue;
|
||||
if (*runp != NULL)
|
||||
/* Avoid duplicates. */
|
||||
continue;
|
||||
|
||||
if (__builtin_expect (cnt + 1 >= imap->l_scope_max, 0))
|
||||
{
|
||||
/* The 'r_scope' array is too small. Allocate a new one
|
||||
dynamically. */
|
||||
struct r_scope_elem **newp;
|
||||
size_t new_size = imap->l_scope_max * 2;
|
||||
if (__builtin_expect (cnt + 1 >= imap->l_scope_max, 0))
|
||||
{
|
||||
/* The 'r_scope' array is too small. Allocate a new one
|
||||
dynamically. */
|
||||
struct r_scope_elem **newp;
|
||||
size_t new_size = imap->l_scope_max * 2;
|
||||
|
||||
if (imap->l_scope == imap->l_scope_mem)
|
||||
{
|
||||
newp = (struct r_scope_elem **)
|
||||
malloc (new_size * sizeof (struct r_scope_elem *));
|
||||
if (newp == NULL)
|
||||
GLRO(dl_signal_error) (ENOMEM, "dlopen", NULL,
|
||||
N_("cannot create scope list"));
|
||||
imap->l_scope = memcpy (newp, imap->l_scope,
|
||||
cnt * sizeof (imap->l_scope[0]));
|
||||
}
|
||||
else
|
||||
{
|
||||
newp = (struct r_scope_elem **)
|
||||
realloc (imap->l_scope,
|
||||
new_size * sizeof (struct r_scope_elem *));
|
||||
if (newp == NULL)
|
||||
GLRO(dl_signal_error) (ENOMEM, "dlopen", NULL,
|
||||
N_("cannot create scope list"));
|
||||
imap->l_scope = newp;
|
||||
}
|
||||
if (imap->l_scope == imap->l_scope_mem)
|
||||
{
|
||||
newp = (struct r_scope_elem **)
|
||||
malloc (new_size * sizeof (struct r_scope_elem *));
|
||||
if (newp == NULL)
|
||||
GLRO(dl_signal_error) (ENOMEM, "dlopen", NULL,
|
||||
N_("cannot create scope list"));
|
||||
imap->l_scope = memcpy (newp, imap->l_scope,
|
||||
cnt * sizeof (imap->l_scope[0]));
|
||||
}
|
||||
else
|
||||
{
|
||||
newp = (struct r_scope_elem **)
|
||||
realloc (imap->l_scope,
|
||||
new_size * sizeof (struct r_scope_elem *));
|
||||
if (newp == NULL)
|
||||
GLRO(dl_signal_error) (ENOMEM, "dlopen", NULL,
|
||||
N_("cannot create scope list"));
|
||||
imap->l_scope = newp;
|
||||
}
|
||||
|
||||
imap->l_scope_max = new_size;
|
||||
}
|
||||
imap->l_scope_max = new_size;
|
||||
}
|
||||
|
||||
imap->l_scope[cnt++] = &new->l_searchlist;
|
||||
imap->l_scope[cnt] = NULL;
|
||||
}
|
||||
imap->l_scope[cnt++] = &new->l_searchlist;
|
||||
imap->l_scope[cnt] = NULL;
|
||||
}
|
||||
#if USE_TLS
|
||||
else if (new->l_searchlist.r_list[i]->l_opencount == 1
|
||||
/* Only if the module defines thread local data. */
|
||||
&& __builtin_expect (new->l_searchlist.r_list[i]->l_tls_blocksize
|
||||
> 0, 0))
|
||||
{
|
||||
/* Now that we know the object is loaded successfully add
|
||||
modules containing TLS data to the dtv info table. We
|
||||
might have to increase its size. */
|
||||
struct dtv_slotinfo_list *listp;
|
||||
struct dtv_slotinfo_list *prevp;
|
||||
size_t idx = new->l_searchlist.r_list[i]->l_tls_modid;
|
||||
/* Only add TLS memory if this object is loaded now and
|
||||
therefore is not yet initialized. */
|
||||
else if (! imap->l_init_called
|
||||
/* Only if the module defines thread local data. */
|
||||
&& __builtin_expect (imap->l_tls_blocksize > 0, 0))
|
||||
{
|
||||
/* Now that we know the object is loaded successfully add
|
||||
modules containing TLS data to the dtv info table. We
|
||||
might have to increase its size. */
|
||||
struct dtv_slotinfo_list *listp;
|
||||
struct dtv_slotinfo_list *prevp;
|
||||
size_t idx = imap->l_tls_modid;
|
||||
|
||||
assert (new->l_searchlist.r_list[i]->l_type == lt_loaded);
|
||||
assert (imap->l_type == lt_loaded);
|
||||
|
||||
/* Find the place in the dtv slotinfo list. */
|
||||
listp = GL(dl_tls_dtv_slotinfo_list);
|
||||
prevp = NULL; /* Needed to shut up gcc. */
|
||||
do
|
||||
{
|
||||
/* Does it fit in the array of this list element? */
|
||||
if (idx < listp->len)
|
||||
break;
|
||||
idx -= listp->len;
|
||||
prevp = listp;
|
||||
listp = listp->next;
|
||||
}
|
||||
while (listp != NULL);
|
||||
/* Find the place in the dtv slotinfo list. */
|
||||
listp = GL(dl_tls_dtv_slotinfo_list);
|
||||
prevp = NULL; /* Needed to shut up gcc. */
|
||||
do
|
||||
{
|
||||
/* Does it fit in the array of this list element? */
|
||||
if (idx < listp->len)
|
||||
break;
|
||||
idx -= listp->len;
|
||||
prevp = listp;
|
||||
listp = listp->next;
|
||||
}
|
||||
while (listp != NULL);
|
||||
|
||||
if (listp == NULL)
|
||||
{
|
||||
/* When we come here it means we have to add a new element
|
||||
to the slotinfo list. And the new module must be in
|
||||
the first slot. */
|
||||
assert (idx == 0);
|
||||
if (listp == NULL)
|
||||
{
|
||||
/* When we come here it means we have to add a new element
|
||||
to the slotinfo list. And the new module must be in
|
||||
the first slot. */
|
||||
assert (idx == 0);
|
||||
|
||||
listp = prevp->next = (struct dtv_slotinfo_list *)
|
||||
malloc (sizeof (struct dtv_slotinfo_list)
|
||||
+ TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
|
||||
if (listp == NULL)
|
||||
{
|
||||
/* We ran out of memory. We will simply fail this
|
||||
call but don't undo anything we did so far. The
|
||||
application will crash or be terminated anyway very
|
||||
soon. */
|
||||
listp = prevp->next = (struct dtv_slotinfo_list *)
|
||||
malloc (sizeof (struct dtv_slotinfo_list)
|
||||
+ TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
|
||||
if (listp == NULL)
|
||||
{
|
||||
/* We ran out of memory. We will simply fail this
|
||||
call but don't undo anything we did so far. The
|
||||
application will crash or be terminated anyway very
|
||||
soon. */
|
||||
|
||||
/* We have to do this since some entries in the dtv
|
||||
slotinfo array might already point to this
|
||||
generation. */
|
||||
++GL(dl_tls_generation);
|
||||
/* We have to do this since some entries in the dtv
|
||||
slotinfo array might already point to this
|
||||
generation. */
|
||||
++GL(dl_tls_generation);
|
||||
|
||||
GLRO(dl_signal_error) (ENOMEM, "dlopen", NULL, N_("\
|
||||
cannot create TLS data structures"));
|
||||
}
|
||||
GLRO(dl_signal_error) (ENOMEM, "dlopen", NULL, N_("\
|
||||
cannot create TLS data structures"));
|
||||
}
|
||||
|
||||
listp->len = TLS_SLOTINFO_SURPLUS;
|
||||
listp->next = NULL;
|
||||
memset (listp->slotinfo, '\0',
|
||||
TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
|
||||
}
|
||||
listp->len = TLS_SLOTINFO_SURPLUS;
|
||||
listp->next = NULL;
|
||||
memset (listp->slotinfo, '\0',
|
||||
TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
|
||||
}
|
||||
|
||||
/* Add the information into the slotinfo data structure. */
|
||||
listp->slotinfo[idx].map = new->l_searchlist.r_list[i];
|
||||
listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1;
|
||||
/* Add the information into the slotinfo data structure. */
|
||||
listp->slotinfo[idx].map = imap;
|
||||
listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1;
|
||||
|
||||
/* We have to bump the generation counter. */
|
||||
any_tls = true;
|
||||
}
|
||||
/* We have to bump the generation counter. */
|
||||
any_tls = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if USE_TLS
|
||||
/* Bump the generation number if necessary. */
|
||||
if (any_tls)
|
||||
if (__builtin_expect (++GL(dl_tls_generation) == 0, 0))
|
||||
@ -532,8 +523,8 @@ cannot create TLS data structures"));
|
||||
|
||||
/* Let the user know about the opencount. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
|
||||
GLRO(dl_debug_printf) ("opening file=%s [%lu]; opencount=%u\n\n",
|
||||
new->l_name, new->l_ns, new->l_opencount);
|
||||
GLRO(dl_debug_printf) ("opening file=%s [%lu]; direct_opencount=%u\n\n",
|
||||
new->l_name, new->l_ns, new->l_direct_opencount);
|
||||
}
|
||||
|
||||
|
||||
@ -603,14 +594,6 @@ no more namespaces available for dlmopen()"));
|
||||
state if relocation failed, for example. */
|
||||
if (args.map)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* Increment open counters for all objects since this
|
||||
sometimes has not happened yet. */
|
||||
if (args.map->l_searchlist.r_list[0]->l_opencount == 0)
|
||||
for (i = 0; i < args.map->l_searchlist.r_nlist; ++i)
|
||||
++args.map->l_searchlist.r_list[i]->l_opencount;
|
||||
|
||||
#ifdef USE_TLS
|
||||
/* Maybe some of the modules which were loaded uses TLS.
|
||||
Since it will be removed in the following _dl_close call
|
||||
|
@ -52,6 +52,10 @@ do_lookup_x (const char *undef_name, unsigned long int hash,
|
||||
if ((type_class & ELF_RTYPE_CLASS_COPY) && map->l_type == lt_executable)
|
||||
continue;
|
||||
|
||||
/* Do not look into objects which are going to be removed. */
|
||||
if (map->l_removed)
|
||||
continue;
|
||||
|
||||
/* Print some debugging info if wanted. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_SYMBOLS, 0))
|
||||
_dl_debug_printf ("symbol=%s; lookup in file=%s\n",
|
||||
|
@ -73,8 +73,8 @@ static const struct
|
||||
#define OUT \
|
||||
for (map = _r_debug.r_map; map != NULL; map = map->l_next) \
|
||||
if (map->l_type == lt_loaded) \
|
||||
printf ("name = \"%s\", opencount = %d\n", \
|
||||
map->l_name, (int) map->l_opencount); \
|
||||
printf ("name = \"%s\", direct_opencount = %d\n", \
|
||||
map->l_name, (int) map->l_direct_opencount); \
|
||||
fflush (stdout)
|
||||
|
||||
|
||||
@ -183,8 +183,8 @@ main (int argc, char *argv[])
|
||||
for (map = _r_debug.r_map; map != NULL; map = map->l_next)
|
||||
if (map->l_type == lt_loaded)
|
||||
{
|
||||
printf ("name = \"%s\", opencount = %d\n",
|
||||
map->l_name, (int) map->l_opencount);
|
||||
printf ("name = \"%s\", direct_opencount = %d\n",
|
||||
map->l_name, (int) map->l_direct_opencount);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ check_loaded_objects (const char **loaded)
|
||||
for (lm = _r_debug.r_map; lm; lm = lm->l_next)
|
||||
{
|
||||
if (lm->l_name && lm->l_name[0])
|
||||
printf(" %s, count = %d\n", lm->l_name, (int) lm->l_opencount);
|
||||
printf(" %s, count = %d\n", lm->l_name, (int) lm->l_direct_opencount);
|
||||
if (lm->l_type == lt_loaded && lm->l_name)
|
||||
{
|
||||
int match = 0;
|
||||
|
@ -27,7 +27,7 @@ check_loaded_objects (const char **loaded)
|
||||
for (lm = _r_debug.r_map; lm; lm = lm->l_next)
|
||||
{
|
||||
if (lm->l_name && lm->l_name[0])
|
||||
printf(" %s, count = %d\n", lm->l_name, (int) lm->l_opencount);
|
||||
printf(" %s, count = %d\n", lm->l_name, (int) lm->l_direct_opencount);
|
||||
if (lm->l_type == lt_loaded && lm->l_name)
|
||||
{
|
||||
int match = 0;
|
||||
|
@ -27,7 +27,7 @@ check_loaded_objects (const char **loaded)
|
||||
for (lm = _r_debug.r_map; lm; lm = lm->l_next)
|
||||
{
|
||||
if (lm->l_name && lm->l_name[0])
|
||||
printf(" %s, count = %d\n", lm->l_name, (int) lm->l_opencount);
|
||||
printf(" %s, count = %d\n", lm->l_name, (int) lm->l_direct_opencount);
|
||||
if (lm->l_type == lt_loaded && lm->l_name)
|
||||
{
|
||||
int match = 0;
|
||||
|
@ -27,7 +27,7 @@ check_loaded_objects (const char **loaded)
|
||||
for (lm = _r_debug.r_map; lm; lm = lm->l_next)
|
||||
{
|
||||
if (lm->l_name && lm->l_name[0])
|
||||
printf(" %s, count = %d\n", lm->l_name, (int) lm->l_opencount);
|
||||
printf(" %s, count = %d\n", lm->l_name, (int) lm->l_direct_opencount);
|
||||
if (lm->l_type == lt_loaded && lm->l_name)
|
||||
{
|
||||
int match = 0;
|
||||
|
46
elf/order2.c
Normal file
46
elf/order2.c
Normal file
@ -0,0 +1,46 @@
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
int call_puts;
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
call_puts = 1;
|
||||
|
||||
void *h1 = dlopen ("$ORIGIN/order2mod1.so", RTLD_LAZY | RTLD_GLOBAL);
|
||||
if (h1 == NULL)
|
||||
{
|
||||
puts ("cannot load order2mod1");
|
||||
return 1;
|
||||
}
|
||||
void *h2 = dlopen ("$ORIGIN/order2mod2.so", RTLD_LAZY);
|
||||
if (h2 == NULL)
|
||||
{
|
||||
puts ("cannot load order2mod2");
|
||||
return 1;
|
||||
}
|
||||
if (dlclose (h1) != 0)
|
||||
{
|
||||
puts ("dlclose order2mod1 failed");
|
||||
return 1;
|
||||
}
|
||||
if (dlclose (h2) != 0)
|
||||
{
|
||||
puts ("dlclose order2mod2 failed");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
|
||||
static void
|
||||
__attribute__ ((destructor))
|
||||
fini (void)
|
||||
{
|
||||
if (call_puts)
|
||||
puts ("5");
|
||||
}
|
8
elf/order2mod1.c
Normal file
8
elf/order2mod1.c
Normal file
@ -0,0 +1,8 @@
|
||||
#include <stdio.h>
|
||||
|
||||
static void
|
||||
__attribute__ ((destructor))
|
||||
fini (void)
|
||||
{
|
||||
putchar ('1');
|
||||
}
|
18
elf/order2mod2.c
Normal file
18
elf/order2mod2.c
Normal file
@ -0,0 +1,18 @@
|
||||
#include <stdio.h>
|
||||
|
||||
extern int foo (void);
|
||||
extern int bar (void);
|
||||
|
||||
void
|
||||
__attribute__ ((constructor))
|
||||
init (void)
|
||||
{
|
||||
foo () - bar ();
|
||||
}
|
||||
|
||||
static void
|
||||
__attribute__ ((destructor))
|
||||
fini (void)
|
||||
{
|
||||
putchar ('2');
|
||||
}
|
14
elf/order2mod3.c
Normal file
14
elf/order2mod3.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
bar (void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
__attribute__ ((destructor))
|
||||
fini (void)
|
||||
{
|
||||
putchar ('4');
|
||||
}
|
16
elf/order2mod4.c
Normal file
16
elf/order2mod4.c
Normal file
@ -0,0 +1,16 @@
|
||||
#include <stdio.h>
|
||||
|
||||
extern int bar (void);
|
||||
|
||||
int
|
||||
foo (void)
|
||||
{
|
||||
return 42 + bar ();
|
||||
}
|
||||
|
||||
static void
|
||||
__attribute__ ((destructor))
|
||||
fini (void)
|
||||
{
|
||||
putchar ('3');
|
||||
}
|
141
elf/rtld.c
141
elf/rtld.c
@ -270,7 +270,6 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
|
||||
#endif
|
||||
_dl_setup_hash (&GL(dl_rtld_map));
|
||||
GL(dl_rtld_map).l_real = &GL(dl_rtld_map);
|
||||
GL(dl_rtld_map).l_opencount = 1;
|
||||
GL(dl_rtld_map).l_map_start = (ElfW(Addr)) _begin;
|
||||
GL(dl_rtld_map).l_map_end = (ElfW(Addr)) _end;
|
||||
GL(dl_rtld_map).l_text_end = (ElfW(Addr)) _etext;
|
||||
@ -659,14 +658,48 @@ _dl_initial_error_catch_tsd (void)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static unsigned int
|
||||
do_preload (char *fname, struct link_map *main_map, const char *where)
|
||||
{
|
||||
const char *objname;
|
||||
const char *err_str = NULL;
|
||||
struct map_args args;
|
||||
|
||||
args.str = fname;
|
||||
args.loader = main_map;
|
||||
args.is_preloaded = 1;
|
||||
args.mode = 0;
|
||||
|
||||
unsigned int old_nloaded = GL(dl_ns)[LM_ID_BASE]._ns_nloaded;
|
||||
|
||||
(void) _dl_catch_error (&objname, &err_str, map_doit, &args);
|
||||
if (__builtin_expect (err_str != NULL, 0))
|
||||
{
|
||||
_dl_error_printf ("\
|
||||
ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
|
||||
fname, where);
|
||||
/* No need to call free, this is still before
|
||||
the libc's malloc is used. */
|
||||
}
|
||||
else if (GL(dl_ns)[LM_ID_BASE]._ns_nloaded != old_nloaded)
|
||||
/* It is no duplicate. */
|
||||
return 1;
|
||||
|
||||
/* Nothing loaded. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined SHARED && defined _LIBC_REENTRANT \
|
||||
&& defined __rtld_lock_default_lock_recursive
|
||||
static void rtld_lock_default_lock_recursive (void *lock)
|
||||
static void
|
||||
rtld_lock_default_lock_recursive (void *lock)
|
||||
{
|
||||
__rtld_lock_default_lock_recursive (lock);
|
||||
}
|
||||
|
||||
static void rtld_lock_default_unlock_recursive (void *lock)
|
||||
static void
|
||||
rtld_lock_default_unlock_recursive (void *lock)
|
||||
{
|
||||
__rtld_lock_default_unlock_recursive (lock);
|
||||
}
|
||||
@ -687,8 +720,6 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
{
|
||||
const ElfW(Phdr) *ph;
|
||||
enum mode mode;
|
||||
struct link_map **preloads;
|
||||
unsigned int npreloads;
|
||||
struct link_map *main_map;
|
||||
size_t file_size;
|
||||
char *file;
|
||||
@ -918,8 +949,6 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
main_map->l_text_end = 0;
|
||||
/* Perhaps the executable has no PT_LOAD header entries at all. */
|
||||
main_map->l_map_start = ~0;
|
||||
/* We opened the file, account for it. */
|
||||
++main_map->l_opencount;
|
||||
/* And it was opened directly. */
|
||||
++main_map->l_direct_opencount;
|
||||
|
||||
@ -1161,8 +1190,9 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
/* We have two ways to specify objects to preload: via environment
|
||||
variable and via the file /etc/ld.so.preload. The latter can also
|
||||
be used when security is enabled. */
|
||||
preloads = NULL;
|
||||
npreloads = 0;
|
||||
assert (GL(dl_rtld_map).l_next == NULL);
|
||||
struct link_map **preloads = NULL;
|
||||
unsigned int npreloads = 0;
|
||||
|
||||
if (__builtin_expect (preloadlist != NULL, 0))
|
||||
{
|
||||
@ -1181,14 +1211,7 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
if (p[0] != '\0'
|
||||
&& (__builtin_expect (! INTUSE(__libc_enable_secure), 1)
|
||||
|| strchr (p, '/') == NULL))
|
||||
{
|
||||
struct link_map *new_map = _dl_map_object (main_map, p, 1,
|
||||
lt_library, 0, 0,
|
||||
LM_ID_BASE);
|
||||
if (++new_map->l_opencount == 1)
|
||||
/* It is no duplicate. */
|
||||
++npreloads;
|
||||
}
|
||||
npreloads += do_preload (p, main_map, "LD_PRELOAD");
|
||||
|
||||
HP_TIMING_NOW (stop);
|
||||
HP_TIMING_DIFF (diff, start, stop);
|
||||
@ -1260,41 +1283,14 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
runp = file;
|
||||
while ((p = strsep (&runp, ": \t\n")) != NULL)
|
||||
if (p[0] != '\0')
|
||||
{
|
||||
const char *objname;
|
||||
const char *err_str = NULL;
|
||||
struct map_args args;
|
||||
|
||||
args.str = p;
|
||||
args.loader = main_map;
|
||||
args.is_preloaded = 1;
|
||||
args.mode = 0;
|
||||
|
||||
(void) _dl_catch_error (&objname, &err_str, map_doit,
|
||||
&args);
|
||||
if (__builtin_expect (err_str != NULL, 0))
|
||||
{
|
||||
_dl_error_printf ("\
|
||||
ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
|
||||
p, preload_file);
|
||||
/* No need to call free, this is still before
|
||||
the libc's malloc is used. */
|
||||
}
|
||||
else if (++args.map->l_opencount == 1)
|
||||
/* It is no duplicate. */
|
||||
++npreloads;
|
||||
}
|
||||
npreloads += do_preload (p, main_map, preload_file);
|
||||
}
|
||||
|
||||
if (problem != NULL)
|
||||
{
|
||||
char *p = strndupa (problem, file_size - (problem - file));
|
||||
struct link_map *new_map = _dl_map_object (main_map, p, 1,
|
||||
lt_library, 0, 0,
|
||||
LM_ID_BASE);
|
||||
if (++new_map->l_opencount == 1)
|
||||
/* It is no duplicate. */
|
||||
++npreloads;
|
||||
|
||||
npreloads += do_preload (p, main_map, preload_file);
|
||||
}
|
||||
|
||||
HP_TIMING_NOW (stop);
|
||||
@ -1348,18 +1344,9 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
|
||||
if (test_fd >= 0) /* open did no fail.. */
|
||||
__close(test_fd); /* avoid fd leaks */
|
||||
|
||||
if (can_load != 0) {
|
||||
struct link_map *new_map;
|
||||
new_map = _dl_map_object (main_map, LIB_NOVERSION,
|
||||
1, lt_library, 0, 0, LM_ID_BASE);
|
||||
if (++new_map->l_opencount == 1) {
|
||||
/* It is no duplicate. */
|
||||
++npreloads;
|
||||
/* _dl_sysdep_message(" DONE\n", NULL); */
|
||||
} else {
|
||||
/* _dl_sysdep_message(" FAILED\n", NULL); */
|
||||
}
|
||||
}
|
||||
if (can_load != 0)
|
||||
npreloads += do_preload (LIB_NOVERSION, main_map,
|
||||
"nonversioned binary");
|
||||
|
||||
HP_TIMING_NOW (stop);
|
||||
HP_TIMING_DIFF (diff, start, stop);
|
||||
@ -1367,7 +1354,7 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
|
||||
}
|
||||
#endif
|
||||
|
||||
if (__builtin_expect (npreloads, 0) != 0)
|
||||
if (__builtin_expect (GL(dl_rtld_map).l_next != NULL, 0))
|
||||
{
|
||||
/* Set up PRELOADS with a vector of the preloaded libraries. */
|
||||
struct link_map *l;
|
||||
@ -1464,14 +1451,9 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
|
||||
HP_TIMING_DIFF (diff, start, stop);
|
||||
HP_TIMING_ACCUM_NT (load_time, diff);
|
||||
|
||||
/* Mark all objects as being in the global scope and set the open
|
||||
counter. */
|
||||
/* Mark all objects as being in the global scope. */
|
||||
for (i = main_map->l_searchlist.r_nlist; i > 0; )
|
||||
{
|
||||
--i;
|
||||
main_map->l_searchlist.r_list[i]->l_global = 1;
|
||||
++main_map->l_searchlist.r_list[i]->l_opencount;
|
||||
}
|
||||
main_map->l_searchlist.r_list[--i]->l_global = 1;
|
||||
|
||||
#ifndef MAP_ANON
|
||||
/* We are done mapping things, so close the zero-fill descriptor. */
|
||||
@ -1481,18 +1463,22 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
|
||||
|
||||
/* Remove _dl_rtld_map from the chain. */
|
||||
GL(dl_rtld_map).l_prev->l_next = GL(dl_rtld_map).l_next;
|
||||
if (GL(dl_rtld_map).l_next)
|
||||
if (GL(dl_rtld_map).l_next != NULL)
|
||||
GL(dl_rtld_map).l_next->l_prev = GL(dl_rtld_map).l_prev;
|
||||
|
||||
if (__builtin_expect (GL(dl_rtld_map).l_opencount > 1, 1))
|
||||
for (i = 1; i < main_map->l_searchlist.r_nlist; ++i)
|
||||
if (main_map->l_searchlist.r_list[i] == &GL(dl_rtld_map))
|
||||
break;
|
||||
|
||||
bool rtld_multiple_ref = false;
|
||||
if (__builtin_expect (i < main_map->l_searchlist.r_nlist, 1))
|
||||
{
|
||||
/* Some DT_NEEDED entry referred to the interpreter object itself, so
|
||||
put it back in the list of visible objects. We insert it into the
|
||||
chain in symbol search order because gdb uses the chain's order as
|
||||
its symbol search order. */
|
||||
i = 1;
|
||||
while (main_map->l_searchlist.r_list[i] != &GL(dl_rtld_map))
|
||||
++i;
|
||||
rtld_multiple_ref = true;
|
||||
|
||||
GL(dl_rtld_map).l_prev = main_map->l_searchlist.r_list[i - 1];
|
||||
if (__builtin_expect (mode, normal) == normal)
|
||||
{
|
||||
@ -1726,7 +1712,7 @@ cannot allocate TLS data structures for initial thread");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If LD_WARN is set warn about undefined symbols. */
|
||||
/* If LD_WARN is set, warn about undefined symbols. */
|
||||
if (GLRO(dl_lazy) >= 0 && GLRO(dl_verbose))
|
||||
{
|
||||
/* We have to do symbol dependency testing. */
|
||||
@ -1736,7 +1722,7 @@ cannot allocate TLS data structures for initial thread");
|
||||
args.lazy = GLRO(dl_lazy);
|
||||
|
||||
l = main_map;
|
||||
while (l->l_next)
|
||||
while (l->l_next != NULL)
|
||||
l = l->l_next;
|
||||
do
|
||||
{
|
||||
@ -1747,10 +1733,11 @@ cannot allocate TLS data structures for initial thread");
|
||||
&args);
|
||||
}
|
||||
l = l->l_prev;
|
||||
} while (l);
|
||||
}
|
||||
while (l != NULL);
|
||||
|
||||
if ((GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
|
||||
&& GL(dl_rtld_map).l_opencount > 1)
|
||||
&& rtld_multiple_ref)
|
||||
_dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope,
|
||||
0, 0);
|
||||
}
|
||||
@ -2020,7 +2007,7 @@ cannot allocate TLS data structures for initial thread");
|
||||
/* We must prepare the profiling. */
|
||||
_dl_start_profile ();
|
||||
|
||||
if (GL(dl_rtld_map).l_opencount > 1)
|
||||
if (rtld_multiple_ref)
|
||||
{
|
||||
/* There was an explicit ref to the dynamic linker as a shared lib.
|
||||
Re-relocate ourselves with user-controlled symbol definitions. */
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <dlfcn.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "testobj.h"
|
||||
|
||||
|
@ -12,8 +12,8 @@
|
||||
#define OUT \
|
||||
for (map = _r_debug.r_map; map != NULL; map = map->l_next) \
|
||||
if (map->l_type == lt_loaded) \
|
||||
printf ("name = \"%s\", opencount = %d\n", \
|
||||
map->l_name, (int) map->l_opencount); \
|
||||
printf ("name = \"%s\", direct_opencount = %d\n", \
|
||||
map->l_name, (int) map->l_direct_opencount); \
|
||||
fflush (stdout)
|
||||
|
||||
typedef struct
|
||||
|
@ -9,8 +9,8 @@
|
||||
#define OUT \
|
||||
for (map = _r_debug.r_map; map != NULL; map = map->l_next) \
|
||||
if (map->l_type == lt_loaded) \
|
||||
printf ("name = \"%s\", opencount = %d\n", \
|
||||
map->l_name, (int) map->l_opencount); \
|
||||
printf ("name = \"%s\", direct_opencount = %d\n", \
|
||||
map->l_name, (int) map->l_direct_opencount); \
|
||||
fflush (stdout)
|
||||
|
||||
int
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
extern int foo (int x);
|
||||
|
||||
int
|
||||
bar (int x)
|
||||
{
|
||||
|
48
elf/unload4.c
Normal file
48
elf/unload4.c
Normal file
@ -0,0 +1,48 @@
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
#ifdef M_PERTURB
|
||||
mallopt (M_PERTURB, 0xaa);
|
||||
#endif
|
||||
|
||||
void *h;
|
||||
int (*fn) (int);
|
||||
h = dlopen ("unload4mod1.so", RTLD_LAZY);
|
||||
if (h == NULL)
|
||||
{
|
||||
puts ("1st dlopen failed");
|
||||
return 1;
|
||||
}
|
||||
fn = dlsym (h, "foo");
|
||||
if (fn == NULL)
|
||||
{
|
||||
puts ("dlsym failed");
|
||||
return 1;
|
||||
}
|
||||
int n = fn (10);
|
||||
if (n != 28)
|
||||
{
|
||||
printf ("foo (10) returned %d != 28\n", n);
|
||||
return 1;
|
||||
}
|
||||
dlclose (h);
|
||||
h = dlopen ("unload4mod3.so", RTLD_LAZY);
|
||||
fn = dlsym (h, "mod3fn2");
|
||||
if (fn == NULL)
|
||||
{
|
||||
puts ("second dlsym failed");
|
||||
return 1;
|
||||
}
|
||||
n = fn (10);
|
||||
if (n != 22)
|
||||
{
|
||||
printf ("mod3fn2 (10) returned %d != 22\n", n);
|
||||
return 1;
|
||||
}
|
||||
dlclose (h);
|
||||
return 0;
|
||||
}
|
10
elf/unload4mod1.c
Normal file
10
elf/unload4mod1.c
Normal file
@ -0,0 +1,10 @@
|
||||
#include <stdio.h>
|
||||
|
||||
extern int bar (int);
|
||||
|
||||
int
|
||||
foo (int x)
|
||||
{
|
||||
puts ("in foo");
|
||||
return bar (x / 2) + 2;
|
||||
}
|
8
elf/unload4mod2.c
Normal file
8
elf/unload4mod2.c
Normal file
@ -0,0 +1,8 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
baz (int x)
|
||||
{
|
||||
puts ("in baz");
|
||||
return x * 4;
|
||||
}
|
16
elf/unload4mod3.c
Normal file
16
elf/unload4mod3.c
Normal file
@ -0,0 +1,16 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
__attribute__((noinline))
|
||||
mod3fn1 (int x)
|
||||
{
|
||||
puts ("in mod3fn1");
|
||||
return x + 6;
|
||||
}
|
||||
|
||||
int
|
||||
mod3fn2 (int x)
|
||||
{
|
||||
puts ("in mod3fn2");
|
||||
return mod3fn1 (x / 2) * 2;
|
||||
}
|
16
elf/unload4mod4.c
Normal file
16
elf/unload4mod4.c
Normal file
@ -0,0 +1,16 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int
|
||||
__attribute__((noinline))
|
||||
baz (int x)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int
|
||||
bar (int x)
|
||||
{
|
||||
puts ("in bar");
|
||||
return baz (x + 1) + 2;
|
||||
}
|
42
elf/unload5.c
Normal file
42
elf/unload5.c
Normal file
@ -0,0 +1,42 @@
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
void *g = dlopen ("unload3mod1.so", RTLD_GLOBAL | RTLD_NOW);
|
||||
void *h = dlopen ("unload3mod2.so", RTLD_GLOBAL | RTLD_NOW);
|
||||
if (g == NULL || h == NULL)
|
||||
{
|
||||
printf ("dlopen unload3mod{1,2}.so failed: %p %p\n", g, h);
|
||||
return 1;
|
||||
}
|
||||
dlopen ("unload3mod4.so", RTLD_GLOBAL | RTLD_NOW);
|
||||
dlclose (h);
|
||||
dlclose (g);
|
||||
|
||||
g = dlopen ("unload3mod3.so", RTLD_GLOBAL | RTLD_NOW);
|
||||
h = dlopen ("unload3mod4.so", RTLD_GLOBAL | RTLD_NOW);
|
||||
if (g == NULL || h == NULL)
|
||||
{
|
||||
printf ("dlopen unload3mod{3,4}.so failed: %p %p\n", g, h);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int (*fn) (int);
|
||||
fn = dlsym (h, "bar");
|
||||
if (fn == NULL)
|
||||
{
|
||||
puts ("dlsym failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int val = fn (16);
|
||||
if (val != 24)
|
||||
{
|
||||
printf ("bar returned %d != 24\n", val);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
%define glibcrelease 2.fc3.4
|
||||
%define glibcrelease 2.fc3.5
|
||||
%define auxarches i586 i686 athlon sparcv9 alphaev6
|
||||
%define prelinkarches noarch
|
||||
%define nptlarches i386 i686 athlon x86_64 ia64 s390 s390x sparcv9 ppc ppc64
|
||||
@ -1270,6 +1270,9 @@ rm -f *.filelist*
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Sat Mar 19 2005 Jakub Jelinek <jakub@redhat.com> 2.3.4-2.fc3.5
|
||||
- better fix for the dlclose bug (#145810, #150414)
|
||||
|
||||
* Thu Mar 3 2005 Jakub Jelinek <jakub@redhat.com> 2.3.4-2.fc3.4
|
||||
- fix dlclose (#145810)
|
||||
- clear padding in gconv-modules.cache (#146614, BZ#776)
|
||||
|
@ -177,7 +177,7 @@ struct link_map
|
||||
Elf_Symndx l_nbuckets;
|
||||
const Elf_Symndx *l_buckets, *l_chain;
|
||||
|
||||
unsigned int l_opencount; /* Counter for direct and indirect usage. */
|
||||
unsigned int l_dummy_opencount; /* Used to be l_opencount, now unused. */
|
||||
unsigned int l_direct_opencount; /* Reference count for dlopen/dlclose. */
|
||||
enum /* Where this object came from. */
|
||||
{
|
||||
@ -199,6 +199,8 @@ struct link_map
|
||||
should be called on this link map
|
||||
when relocation finishes. */
|
||||
unsigned int l_used:1; /* Nonzero if the DSO is used. */
|
||||
unsigned int l_removed:1; /* Nozero if the object cannot be used anymore
|
||||
since it is removed. */
|
||||
/* Array with version names. */
|
||||
unsigned int l_nversions;
|
||||
struct r_found_version *l_versions;
|
||||
@ -255,7 +257,7 @@ struct link_map
|
||||
ElfW(Word) l_flags;
|
||||
|
||||
/* Temporarily used in `dl_close'. */
|
||||
unsigned int l_idx;
|
||||
int l_idx;
|
||||
|
||||
struct link_map_machine l_mach;
|
||||
|
||||
|
@ -783,6 +783,11 @@ extern void _dl_init (struct link_map *main_map, int argc, char **argv,
|
||||
initializer functions have completed. */
|
||||
extern void _dl_fini (void) internal_function;
|
||||
|
||||
/* Sort array MAPS according to dependencies of the contained objects. */
|
||||
extern void _dl_sort_fini (struct link_map *l, struct link_map **maps,
|
||||
size_t nmaps, char *used, Lmid_t ns)
|
||||
internal_function;
|
||||
|
||||
/* The dynamic linker calls this function before and having changing
|
||||
any shared object mappings. The `r_state' member of `struct r_debug'
|
||||
says what change is taking place. This function's address is
|
||||
|
Loading…
x
Reference in New Issue
Block a user