2000-10-21  Ulrich Drepper  <drepper@redhat.com>

	* elf/dl-open.c (add_to_global): New function.  Split out from
	dl_open_worker.
	(dl_open_worker): Call add_to_global not only for new objects, also for
	previously loaded objects when (mode & RTLD_GLOBAL) and the object
	was not yet in the global scope.
	* elf/Makefile: Add rules to build and run lateglobal.
	* elf/lateglobal.c: New file.
	* elf/ltglobmod1.c: New file.
	* elf/ltglobmod2.c: New file.
This commit is contained in:
Ulrich Drepper 2000-10-21 07:16:18 +00:00
parent c91bc73e3e
commit d785c36692
6 changed files with 195 additions and 78 deletions

View File

@ -1,3 +1,15 @@
2000-10-21 Ulrich Drepper <drepper@redhat.com>
* elf/dl-open.c (add_to_global): New function. Split out from
dl_open_worker.
(dl_open_worker): Call add_to_global not only for new objects, also for
previously loaded objects when (mode & RTLD_GLOBAL) and the object
was not yet in the global scope.
* elf/Makefile: Add rules to build and run lateglobal.
* elf/lateglobal.c: New file.
* elf/ltglobmod1.c: New file.
* elf/ltglobmod2.c: New file.
2000-10-20 Ulrich Drepper <drepper@redhat.com>
* include/link.h (struct link_map): Add l_soname_added bitfield.

View File

@ -55,7 +55,7 @@ distribute := $(rtld-routines:=.c) dynamic-link.h do-rel.h dl-machine.h \
reldepmod1.c reldepmod2.c reldepmod3.c reldepmod4.c \
nextmod1.c nextmod2.c \
neededobj1.c neededobj2.c neededobj3.c \
unload2mod.c unload2dep.c
unload2mod.c unload2dep.c ltglobmod1.c ltglobmod2.c
include ../Makeconfig
@ -97,7 +97,7 @@ ifeq (yes,$(build-shared))
tests = loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
constload1 order $(tests-vis-$(have-protected)) noload filter unload \
reldep reldep2 reldep3 next $(tests-nodelete-$(have-z-nodelete)) \
$(tests-nodlopen-$(have-z-nodlopen)) neededtest unload2
$(tests-nodlopen-$(have-z-nodlopen)) neededtest unload2 lateglobal
tests-vis-yes = vismain
tests-nodelete-yes = nodelete
tests-nodlopen-yes = nodlopen
@ -108,7 +108,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
$(modules-nodelete-$(have-z-nodelete)) \
$(modules-nodlopen-$(have-z-nodlopen)) filtmod1 filtmod2 \
reldepmod1 reldepmod2 reldepmod3 reldepmod4 nextmod1 nextmod2 \
neededobj1 neededobj2 neededobj3 unload2mod unload2dep
neededobj1 neededobj2 neededobj3 unload2mod unload2dep \
ltglobmod1 ltglobmod2
modules-vis-yes = vismod1 vismod2 vismod3
modules-nodelete-yes = nodelmod1 nodelmod2 nodelmod3 nodelmod4
modules-nodlopen-yes = nodlopenmod
@ -255,6 +256,7 @@ $(objpfx)neededobj1.so: $(libdl)
$(objpfx)neededobj2.so: $(objpfx)neededobj1.so $(libdl)
$(objpfx)neededobj3.so: $(objpfx)neededobj1.so $(objpfx)neededobj2.so $(libdl)
$(objpfx)unload2mod.so: $(objpfx)unload2dep.so
$(objpfx)ltglobmod2.so: $(libdl)
# filtmod1.so has a special rule
$(filter-out $(objpfx)filtmod1.so, $(test-modules)): $(objpfx)%.so: $(objpfx)%.os
@ -356,3 +358,6 @@ $(objpfx)next: $(objpfx)nextmod1.so $(objpfx)nextmod2.so $(libdl)
$(objpfx)unload2: $(libdl)
$(objpfx)unload2.out: $(objpfx)unload2mod.so $(objpfx)unload2dep.so
$(objpfx)lateglobal: $(libdl)
$(objpfx)lateglobal.out: $(objpfx)ltglobmod1.so $(objpfx)ltglobmod2.so

View File

@ -80,6 +80,87 @@ struct dl_open_args
struct link_map *map;
};
static int
add_to_global (struct link_map *new)
{
struct link_map **new_global;
unsigned int to_add = 0;
unsigned int cnt;
/* Count the objects we have to put in the global scope. */
for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
if (new->l_searchlist.r_list[cnt]->l_global == 0)
++to_add;
/* The symbols of the new objects and its dependencies are to be
introduced into the global scope that will be used to resolve
references from other dynamically-loaded objects.
The global scope is the searchlist in the main link map. We
extend this list if necessary. There is one problem though:
since this structure was allocated very early (before the libc
is loaded) the memory it uses is allocated by the malloc()-stub
in the ld.so. When we come here these functions are not used
anymore. Instead the malloc() implementation of the libc is
used. But this means the block from the main map cannot be used
in an realloc() call. Therefore we allocate a completely new
array the first time we have to add something to the locale scope. */
if (_dl_global_scope_alloc == 0)
{
/* This is the first dynamic object given global scope. */
_dl_global_scope_alloc = _dl_main_searchlist->r_nlist + to_add + 8;
new_global = (struct link_map **)
malloc (_dl_global_scope_alloc * sizeof (struct link_map *));
if (new_global == NULL)
{
_dl_global_scope_alloc = 0;
nomem:
_dl_signal_error (ENOMEM, new->l_libname->name,
N_("cannot extend global scope"));
return 1;
}
/* Copy over the old entries. */
memcpy (new_global, _dl_main_searchlist->r_list,
(_dl_main_searchlist->r_nlist * sizeof (struct link_map *)));
_dl_main_searchlist->r_list = new_global;
}
else if (_dl_main_searchlist->r_nlist + to_add > _dl_global_scope_alloc)
{
/* We have to extend the existing array of link maps in the
main map. */
new_global = (struct link_map **)
realloc (_dl_main_searchlist->r_list,
((_dl_global_scope_alloc + to_add + 8)
* sizeof (struct link_map *)));
if (new_global == NULL)
goto nomem;
_dl_global_scope_alloc += to_add + 8;
_dl_main_searchlist->r_list = new_global;
}
/* Now add the new entries. */
for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
{
struct link_map *map = new->l_searchlist.r_list[cnt];
if (map->l_global == 0)
{
map->l_global = 1;
_dl_main_searchlist->r_list[_dl_main_searchlist->r_nlist] = map;
++_dl_main_searchlist->r_nlist;
}
}
/* XXX Do we have to add something to r_dupsearchlist??? --drepper */
return 0;
}
static void
dl_open_worker (void *a)
{
@ -172,6 +253,12 @@ dl_open_worker (void *a)
buf + sizeof buf - 1, 10, 0),
"\n\n", NULL);
}
/* If the user requested the object t 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);
/* It was already open. */
return;
}
@ -232,81 +319,10 @@ dl_open_worker (void *a)
/* Now we can make the new map available in the global scope. */
if (mode & RTLD_GLOBAL)
{
struct link_map **new_global;
unsigned int to_add = 0;
unsigned int cnt;
/* Count the objects we have to put in the global scope. */
for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
if (new->l_searchlist.r_list[cnt]->l_global == 0)
++to_add;
/* The symbols of the new objects and its dependencies are to be
introduced into the global scope that will be used to resolve
references from other dynamically-loaded objects.
The global scope is the searchlist in the main link map. We
extend this list if necessary. There is one problem though:
since this structure was allocated very early (before the libc
is loaded) the memory it uses is allocated by the malloc()-stub
in the ld.so. When we come here these functions are not used
anymore. Instead the malloc() implementation of the libc is
used. But this means the block from the main map cannot be used
in an realloc() call. Therefore we allocate a completely new
array the first time we have to add something to the locale scope. */
if (_dl_global_scope_alloc == 0)
{
/* This is the first dynamic object given global scope. */
_dl_global_scope_alloc = _dl_main_searchlist->r_nlist + to_add + 8;
new_global = (struct link_map **)
malloc (_dl_global_scope_alloc * sizeof (struct link_map *));
if (new_global == NULL)
{
_dl_global_scope_alloc = 0;
nomem:
_dl_signal_error (ENOMEM, new->l_libname->name,
N_("cannot extend global scope"));
/* Move the object in the global namespace. */
if (add_to_global (new) != 0)
/* It failed. */
return;
}
/* Copy over the old entries. */
memcpy (new_global, _dl_main_searchlist->r_list,
(_dl_main_searchlist->r_nlist * sizeof (struct link_map *)));
_dl_main_searchlist->r_list = new_global;
}
else if (_dl_main_searchlist->r_nlist + to_add > _dl_global_scope_alloc)
{
/* We have to extend the existing array of link maps in the
main map. */
new_global = (struct link_map **)
realloc (_dl_main_searchlist->r_list,
((_dl_global_scope_alloc + to_add + 8)
* sizeof (struct link_map *)));
if (new_global == NULL)
goto nomem;
_dl_global_scope_alloc += to_add + 8;
_dl_main_searchlist->r_list = new_global;
}
/* Now add the new entries. */
for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
{
struct link_map *map = new->l_searchlist.r_list[cnt];
if (map->l_global == 0)
{
map->l_global = 1;
_dl_main_searchlist->r_list[_dl_main_searchlist->r_nlist] = map;
++_dl_main_searchlist->r_nlist;
}
}
/* XXX Do we have to add something to r_dupsearchlist??? --drepper */
}
/* Mark the object as not deletable if the RTLD_NODELETE flags was
passed. */

47
elf/lateglobal.c Normal file
View File

@ -0,0 +1,47 @@
#include <dlfcn.h>
#include <mcheck.h>
#include <stdio.h>
#include <stdlib.h>
int
main (void)
{
void *h[2];
int fail;
int (*fp) (void);
mtrace ();
h[0] = dlopen ("ltglobmod1.so", RTLD_LAZY);
if (h == NULL)
{
printf ("%s: cannot open %s: %s",
__FUNCTION__, "ltglobmod1.so", dlerror ());
exit (EXIT_FAILURE);
}
h[1] = dlopen ("ltglobmod2.so", RTLD_LAZY);
if (h == NULL)
{
printf ("%s: cannot open %s: %s",
__FUNCTION__, "ltglobmod2.so", dlerror ());
exit (EXIT_FAILURE);
}
puts ("loaded \"ltglobmod1.so\" without RTLD_GLOBAL");
fp = dlsym (h[1], "foo");
if (fp == NULL)
{
printf ("cannot get address of `foo': %s", dlerror ());
exit (EXIT_FAILURE);
}
fail = fp ();
puts ("back in main");
dlclose (h[1]);
dlclose (h[0]);
return fail;
}

5
elf/ltglobmod1.c Normal file
View File

@ -0,0 +1,5 @@
int
bar (void)
{
return 42;
}

32
elf/ltglobmod2.c Normal file
View File

@ -0,0 +1,32 @@
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
extern int bar (void);
int
foo (void)
{
void *h;
int res;
/* Load ltglobalmod1 in the global namespace. */
h = dlopen ("ltglobmod1.so", RTLD_GLOBAL | RTLD_LAZY);
if (h == NULL)
{
printf ("%s: cannot open %s: %s",
__FUNCTION__, "ltglobmod1.so", dlerror ());
exit (EXIT_FAILURE);
}
/* Call bar. This is undefined in the DSO. */
puts ("about to call `bar'");
fflush (stdout);
res = bar ();
printf ("bar returned %d\n", res);
dlclose (h);
return res != 42;
}