summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog12
-rw-r--r--elf/Makefile11
-rw-r--r--elf/dl-open.c166
-rw-r--r--elf/lateglobal.c47
-rw-r--r--elf/ltglobmod1.c5
-rw-r--r--elf/ltglobmod2.c32
6 files changed, 195 insertions, 78 deletions
diff --git a/ChangeLog b/ChangeLog
index fb9cce5a07..c668caba4a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
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 <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;
+}
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 <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;
+}