diff --git a/ChangeLog b/ChangeLog index fb9cce5a07..c668caba4a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2000-10-21 Ulrich Drepper + + * 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 * include/link.h (struct link_map): Add l_soname_added bitfield. diff --git a/elf/Makefile b/elf/Makefile index 033b0dcce9..06ff79d30a 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -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 diff --git a/elf/dl-open.c b/elf/dl-open.c index a618ca0470..5c078d9be8 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -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")); - 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 */ - } + /* Move the object in the global namespace. */ + if (add_to_global (new) != 0) + /* It failed. */ + return; /* Mark the object as not deletable if the RTLD_NODELETE flags was passed. */ diff --git a/elf/lateglobal.c b/elf/lateglobal.c new file mode 100644 index 0000000000..2f6c2692a6 --- /dev/null +++ b/elf/lateglobal.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include + +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; +} diff --git a/elf/ltglobmod1.c b/elf/ltglobmod1.c new file mode 100644 index 0000000000..46e74ee2fb --- /dev/null +++ b/elf/ltglobmod1.c @@ -0,0 +1,5 @@ +int +bar (void) +{ + return 42; +} diff --git a/elf/ltglobmod2.c b/elf/ltglobmod2.c new file mode 100644 index 0000000000..bc1cd27c40 --- /dev/null +++ b/elf/ltglobmod2.c @@ -0,0 +1,32 @@ +#include +#include +#include + +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; +}