summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>2006-03-01 06:18:49 +0000
committerRoland McGrath <roland@gnu.org>2006-03-01 06:18:49 +0000
commitd78efd9f369a8fc46229fc9224e10e3781eecc43 (patch)
tree2ab775602fdf94ce710efb518002de4a93bfab0e
parent0b890d59bd75cb8ab9232ab72ed8674054e11fa3 (diff)
* elf/tst-tls-dlinfo.c: New file.
* elf/Makefile (tests): Add it. ($(objpfx)tst-tls-dlinfo): Depend on $(libdl). ($(objpfx)tst-tls-dlinfo.out): Depend on $(objpfx)tst-tlsmod2.so. * dlfcn/dlfcn.h (RTLD_DI_PROFILENAME, RTLD_DI_PROFILEOUT): New enum values, reserve unsupported requested names used on Solaris. (RTLD_DI_TLS_MODID, RTLD_DI_TLS_DATA): New enum values. (RTLD_DI_MAX): Likewise. * dlfcn/dlinfo.c (dlinfo_doit): Handle RTLD_DI_TLS_MODID and RTLD_DI_TLS_DATA. * elf/dl-tls.c (_dl_tls_get_addr_soft): New function. * sysdeps/generic/ldsodefs.h: Declare it. * elf/Versions (ld: GLIBC_PRIVATE): Add it. * elf/link.h (struct dl_phdr_info): New members dlpi_tls_modid, dlpi_tls_data. * elf/dl-iteratephdr.c (__dl_iterate_phdr): Fill them in. * include/link.h: Don't copy contents from elf/link.h. Instead, #include it while #define'ing around link_map. * elf/dl-debug.c (_dl_debug_initialize): Add a cast. Add bogus extern decl to verify link_map members. * elf/loadtest.c (MAPS): New macro, cast _r_debug._r_map. (OUT, main): Use it in place of _r_debug._r_map. * elf/unload.c: Likewise. * elf/unload2.c: Likewise. * elf/neededtest.c (check_loaded_objects): Likewise. * elf/neededtest2.c (check_loaded_objects): Likewise. * elf/neededtest3.c (check_loaded_objects): Likewise. * elf/neededtest4.c (check_loaded_objects): Likewise. * elf/circleload1.c (check_loaded_objects): Likewise.
-rw-r--r--ChangeLog33
-rw-r--r--dlfcn/dlfcn.h21
-rw-r--r--dlfcn/dlinfo.c24
-rw-r--r--elf/Makefile13
-rw-r--r--elf/Versions1
-rw-r--r--elf/circleload1.c4
-rw-r--r--elf/dl-debug.c17
-rw-r--r--elf/dl-iteratephdr.c9
-rw-r--r--elf/dl-tls.c48
-rw-r--r--elf/link.h18
-rw-r--r--elf/loadtest.c8
-rw-r--r--elf/neededtest.c4
-rw-r--r--elf/neededtest2.c4
-rw-r--r--elf/neededtest3.c4
-rw-r--r--elf/neededtest4.c4
-rw-r--r--elf/tst-tls-dlinfo.c92
-rw-r--r--elf/unload.c4
-rw-r--r--elf/unload2.c4
-rw-r--r--include/link.h130
-rw-r--r--sysdeps/generic/ldsodefs.h5
20 files changed, 312 insertions, 135 deletions
diff --git a/ChangeLog b/ChangeLog
index 6ccf70ada2..b35cd50a36 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,38 @@
2006-02-28 Roland McGrath <roland@redhat.com>
+ * elf/tst-tls-dlinfo.c: New file.
+ * elf/Makefile (tests): Add it.
+ ($(objpfx)tst-tls-dlinfo): Depend on $(libdl).
+ ($(objpfx)tst-tls-dlinfo.out): Depend on $(objpfx)tst-tlsmod2.so.
+
+ * dlfcn/dlfcn.h (RTLD_DI_PROFILENAME, RTLD_DI_PROFILEOUT): New enum
+ values, reserve unsupported requested names used on Solaris.
+ (RTLD_DI_TLS_MODID, RTLD_DI_TLS_DATA): New enum values.
+ (RTLD_DI_MAX): Likewise.
+ * dlfcn/dlinfo.c (dlinfo_doit): Handle RTLD_DI_TLS_MODID and
+ RTLD_DI_TLS_DATA.
+
+ * elf/dl-tls.c (_dl_tls_get_addr_soft): New function.
+ * sysdeps/generic/ldsodefs.h: Declare it.
+ * elf/Versions (ld: GLIBC_PRIVATE): Add it.
+ * elf/link.h (struct dl_phdr_info): New members dlpi_tls_modid,
+ dlpi_tls_data.
+ * elf/dl-iteratephdr.c (__dl_iterate_phdr): Fill them in.
+
+ * include/link.h: Don't copy contents from elf/link.h.
+ Instead, #include it while #define'ing around link_map.
+ * elf/dl-debug.c (_dl_debug_initialize): Add a cast.
+ Add bogus extern decl to verify link_map members.
+ * elf/loadtest.c (MAPS): New macro, cast _r_debug._r_map.
+ (OUT, main): Use it in place of _r_debug._r_map.
+ * elf/unload.c: Likewise.
+ * elf/unload2.c: Likewise.
+ * elf/neededtest.c (check_loaded_objects): Likewise.
+ * elf/neededtest2.c (check_loaded_objects): Likewise.
+ * elf/neededtest3.c (check_loaded_objects): Likewise.
+ * elf/neededtest4.c (check_loaded_objects): Likewise.
+ * elf/circleload1.c (check_loaded_objects): Likewise.
+
* nscd/nscd_helper.c: Include <time.h> for `time' declaration.
* include/fcntl.h: Declare __openat, __open64. Use libc_hidden_proto.
diff --git a/dlfcn/dlfcn.h b/dlfcn/dlfcn.h
index 42c25b8b63..7e373eddf9 100644
--- a/dlfcn/dlfcn.h
+++ b/dlfcn/dlfcn.h
@@ -1,5 +1,6 @@
/* User functions for run-time dynamic loading.
- Copyright (C) 1995-1999,2000,2001,2003,2004 Free Software Foundation, Inc.
+ Copyright (C) 1995-1999,2000,2001,2003,2004,2006
+ Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -135,6 +136,8 @@ enum
store the `struct link_map *' for HANDLE there. */
RTLD_DI_LINKMAP = 2,
+ RTLD_DI_CONFIGADDR = 3, /* Unsupported, defined by Solaris. */
+
/* Treat ARG as `Dl_serinfo *' (see below), and fill in to describe the
directories that will be searched for dependencies of this object.
RTLD_DI_SERINFOSIZE fills in just the `dls_cnt' and `dls_size'
@@ -147,7 +150,21 @@ enum
expand $ORIGIN in this shared object's dependency file names. */
RTLD_DI_ORIGIN = 6,
- RTLD_DI_CONFIGADDR = 3 /* Unsupported, defined by Solaris. */
+ RTLD_DI_PROFILENAME = 7, /* Unsupported, defined by Solaris. */
+ RTLD_DI_PROFILEOUT = 8, /* Unsupported, defined by Solaris. */
+
+ /* Treat ARG as `size_t *', and store there the TLS module ID
+ of this object's PT_TLS segment, as used in TLS relocations;
+ store zero if this object does not define a PT_TLS segment. */
+ RTLD_DI_TLS_MODID = 9,
+
+ /* Treat ARG as `void **', and store there a pointer to the calling
+ thread's TLS block corresponding to this object's PT_TLS segment.
+ Store a null pointer if this object does not define a PT_TLS
+ segment, or if the calling thread has not allocated a block for it. */
+ RTLD_DI_TLS_DATA = 10,
+
+ RTLD_DI_MAX = 10,
};
diff --git a/dlfcn/dlinfo.c b/dlfcn/dlinfo.c
index 44af55a303..b1e2b009a5 100644
--- a/dlfcn/dlinfo.c
+++ b/dlfcn/dlinfo.c
@@ -1,5 +1,5 @@
/* dlinfo -- Get information from the dynamic linker.
- Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -32,6 +32,10 @@ dlinfo (void *handle, int request, void *arg)
#else
+# ifdef USE_TLS
+# include <dl-tls.h>
+# endif
+
struct dlinfo_args
{
ElfW(Addr) caller;
@@ -90,6 +94,24 @@ RTLD_SELF used in code not dynamically loaded"));
case RTLD_DI_ORIGIN:
strcpy (args->arg, l->l_origin);
break;
+
+ case RTLD_DI_TLS_MODID:
+ *(size_t *) args->arg = 0;
+#ifdef USE_TLS
+ *(size_t *) args->arg = l->l_tls_modid;
+#endif
+ break;
+
+ case RTLD_DI_TLS_DATA:
+ {
+ void *data = NULL;
+#ifdef USE_TLS
+ if (l->l_tls_modid != 0)
+ data = _dl_tls_get_addr_soft (l);
+#endif
+ *(void **) args->arg = data;
+ break;
+ }
}
}
diff --git a/elf/Makefile b/elf/Makefile
index 5cd78c2f83..791341758e 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -163,9 +163,11 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
neededtest3 neededtest4 unload2 lateglobal initfirst global \
restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \
circleload1 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 tst-tls8 \
- tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-tls15 tst-align \
- tst-align2 $(tests-execstack-$(have-z-execstack)) tst-dlmodcount \
- tst-dlopenrpath tst-deep1 tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
+ tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-tls15 \
+ tst-tls-dlinfo \
+ tst-align tst-align2 $(tests-execstack-$(have-z-execstack)) \
+ tst-dlmodcount tst-dlopenrpath tst-deep1 \
+ tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
unload3 unload4 unload5 unload6 tst-audit1 tst-global1 order2 \
tst-stackguard1
# reldep9
@@ -700,6 +702,11 @@ $(objpfx)tst-tls14.out: $(objpfx)tst-tlsmod14b.so
$(objpfx)tst-tls15: $(libdl)
$(objpfx)tst-tls15.out: $(objpfx)tst-tlsmod15a.so $(objpfx)tst-tlsmod15b.so
+$(objpfx)tst-tls-dlinfo: $(libdl)
+$(objpfx)tst-tls-dlinfo.out: $(objpfx)tst-tlsmod2.so
+
+
+
CFLAGS-tst-align.c = $(stack-align-test-flags)
CFLAGS-tst-align2.c = $(stack-align-test-flags)
CFLAGS-tst-alignmod.c = $(stack-align-test-flags)
diff --git a/elf/Versions b/elf/Versions
index 87e27c5a7a..967ebdb3a5 100644
--- a/elf/Versions
+++ b/elf/Versions
@@ -57,6 +57,7 @@ ld {
_dl_allocate_tls; _dl_deallocate_tls;
_dl_get_tls_static_info; _dl_allocate_tls_init;
_dl_tls_setup; _dl_rtld_di_serinfo;
+ _dl_tls_get_addr_soft;
_dl_make_stack_executable;
# Only here for gdb while a better method is developed.
_dl_debug_state;
diff --git a/elf/circleload1.c b/elf/circleload1.c
index f5f886a1da..990ff84a84 100644
--- a/elf/circleload1.c
+++ b/elf/circleload1.c
@@ -5,6 +5,8 @@
#include <stdlib.h>
#include <string.h>
+#define MAPS ((struct link_map *) _r_debug.r_map)
+
static int
check_loaded_objects (const char **loaded)
{
@@ -24,7 +26,7 @@ check_loaded_objects (const char **loaded)
printf(" Name\n");
printf(" --------------------------------------------------------\n");
- for (lm = _r_debug.r_map; lm; lm = lm->l_next)
+ for (lm = MAPS; lm; lm = lm->l_next)
{
if (lm->l_name && lm->l_name[0])
printf(" %s, count = %d\n", lm->l_name, (int) lm->l_direct_opencount);
diff --git a/elf/dl-debug.c b/elf/dl-debug.c
index bc7d793435..d00fe87fbb 100644
--- a/elf/dl-debug.c
+++ b/elf/dl-debug.c
@@ -1,5 +1,6 @@
/* Communicate dynamic linker state to the debugger at runtime.
- Copyright (C) 1996, 1998,2000,2002,2004,2005 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1998,2000,2002,2004,2005,2006
+ Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -19,6 +20,18 @@
#include <ldsodefs.h>
+
+/* These are the members in the public `struct link_map' type.
+ Sanity check that the internal type and the public type match. */
+#define VERIFY_MEMBER(name) \
+ (offsetof (struct link_map_public, name) == offsetof (struct link_map, name))
+extern const int verify_link_map_members[(VERIFY_MEMBER (l_addr)
+ && VERIFY_MEMBER (l_name)
+ && VERIFY_MEMBER (l_ld)
+ && VERIFY_MEMBER (l_next)
+ && VERIFY_MEMBER (l_prev))
+ ? 1 : -1];
+
/* This structure communicates dl state to the debugger. The debugger
normally finds it via the DT_DEBUG entry in the dynamic section, but in
a statically-linked program there is no dynamic section for the debugger
@@ -46,7 +59,7 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
/* Tell the debugger where to find the map of loaded objects. */
r->r_version = 1 /* R_DEBUG_VERSION XXX */;
r->r_ldbase = ldbase ?: _r_debug.r_ldbase;
- r->r_map = GL(dl_ns)[ns]._ns_loaded;
+ r->r_map = (void *) GL(dl_ns)[ns]._ns_loaded;
r->r_brk = (ElfW(Addr)) &_dl_debug_state;
}
diff --git a/elf/dl-iteratephdr.c b/elf/dl-iteratephdr.c
index 6ed90c73b1..52a114421d 100644
--- a/elf/dl-iteratephdr.c
+++ b/elf/dl-iteratephdr.c
@@ -1,5 +1,5 @@
/* Get loaded objects program headers.
- Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2001,2002,2003,2004,2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jakub@redhat.com>, 2001.
@@ -68,6 +68,13 @@ __dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info,
info.dlpi_phnum = l->l_phnum;
info.dlpi_adds = GL(dl_load_adds);
info.dlpi_subs = GL(dl_load_adds) - nloaded;
+ info.dlpi_tls_modid = 0;
+ info.dlpi_tls_data = NULL;
+#ifdef USE_TLS
+ info.dlpi_tls_modid = l->l_tls_modid;
+ if (info.dlpi_tls_modid != 0)
+ info.dlpi_tls_data = _dl_tls_get_addr_soft (l);
+#endif
ret = callback (&info, sizeof (struct dl_phdr_info), data);
if (ret)
break;
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index 4fed570d5c..a0f4f77ffa 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -1,5 +1,5 @@
/* Thread-local storage handling in the ELF dynamic linker. Generic version.
- Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002,2003,2004,2005,2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -735,9 +735,53 @@ __tls_get_addr (GET_ADDR_ARGS)
# endif
+/* Look up the module's TLS block as for __tls_get_addr,
+ but never touch anything. Return null if it's not allocated yet. */
+void *
+internal_function
+_dl_tls_get_addr_soft (struct link_map *l)
+{
+ if (__builtin_expect (l->l_tls_modid == 0, 0))
+ /* This module has no TLS segment. */
+ return NULL;
+
+ dtv_t *dtv = THREAD_DTV ();
+ if (__builtin_expect (dtv[0].counter != GL(dl_tls_generation), 0))
+ {
+ /* This thread's DTV is not completely current,
+ but it might already cover this module. */
+
+ if (l->l_tls_modid >= dtv[-1].counter)
+ /* Nope. */
+ return NULL;
+
+ size_t idx = l->l_tls_modid;
+ struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
+ while (idx >= listp->len)
+ {
+ idx -= listp->len;
+ listp = listp->next;
+ }
+
+ /* We've reached the slot for this module.
+ If its generation counter is higher than the DTV's,
+ this thread does not know about this module yet. */
+ if (dtv[0].counter < listp->slotinfo[idx].gen)
+ return NULL;
+ }
+
+ void *data = dtv[l->l_tls_modid].pointer.val;
+ if (__builtin_expect (data == TLS_DTV_UNALLOCATED, 0))
+ /* The DTV is current, but this thread has not yet needed
+ to allocate this module's segment. */
+ data = NULL;
+
+ return data;
+}
+
void
-_dl_add_to_slotinfo (struct link_map *l)
+_dl_add_to_slotinfo (struct link_map *l)
{
/* Now that we know the object is loaded successfully add
modules containing TLS data to the dtv info table. We
diff --git a/elf/link.h b/elf/link.h
index fdda019cbe..076531d6e7 100644
--- a/elf/link.h
+++ b/elf/link.h
@@ -1,6 +1,6 @@
/* Data structure for communication from the run-time dynamic linker for
loaded ELF shared objects.
- Copyright (C) 1995-2001, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1995-2001, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -135,7 +135,6 @@ enum
la_symbind call. */
};
-
struct dl_phdr_info
{
ElfW(Addr) dlpi_addr;
@@ -143,15 +142,24 @@ struct dl_phdr_info
const ElfW(Phdr) *dlpi_phdr;
ElfW(Half) dlpi_phnum;
- /* Note: the next two members were introduced after the first
+ /* Note: Following members were introduced after the first
version of this structure was available. Check the SIZE
- argument passed to the dl_iterate_phdr() callback to determine
- whether or not they are provided. */
+ argument passed to the dl_iterate_phdr callback to determine
+ whether or not each later member is available. */
/* Incremented when a new object may have been added. */
unsigned long long int dlpi_adds;
/* Incremented when an object may have been removed. */
unsigned long long int dlpi_subs;
+
+ /* If there is a PT_TLS segment, its module ID as used in
+ TLS relocations, else zero. */
+ size_t dlpi_tls_modid;
+
+ /* The address of the calling thread's instance of this module's
+ PT_TLS segment, if it has one and it has been allocated
+ in the calling thread, otherwise a null pointer. */
+ void *dlpi_tls_data;
};
__BEGIN_DECLS
diff --git a/elf/loadtest.c b/elf/loadtest.c
index ee106ea152..727469b496 100644
--- a/elf/loadtest.c
+++ b/elf/loadtest.c
@@ -70,8 +70,10 @@ static const struct
#include <include/link.h>
+#define MAPS ((struct link_map *) _r_debug.r_map)
+
#define OUT \
- for (map = _r_debug.r_map; map != NULL; map = map->l_next) \
+ for (map = MAPS; map != NULL; map = map->l_next) \
if (map->l_type == lt_loaded) \
printf ("name = \"%s\", direct_opencount = %d\n", \
map->l_name, (int) map->l_direct_opencount); \
@@ -147,7 +149,7 @@ main (int argc, char *argv[])
{
/* In this case none of the objects above should be
present. */
- for (map = _r_debug.r_map; map != NULL; map = map->l_next)
+ for (map = MAPS; map != NULL; map = map->l_next)
if (map->l_type == lt_loaded
&& (strstr (map->l_name, testobjs[0].name) != NULL
|| strstr (map->l_name, testobjs[1].name) != NULL
@@ -180,7 +182,7 @@ main (int argc, char *argv[])
}
/* Check whether all files are unloaded. */
- for (map = _r_debug.r_map; map != NULL; map = map->l_next)
+ for (map = MAPS; map != NULL; map = map->l_next)
if (map->l_type == lt_loaded)
{
printf ("name = \"%s\", direct_opencount = %d\n",
diff --git a/elf/neededtest.c b/elf/neededtest.c
index 6c7a952066..3cea499314 100644
--- a/elf/neededtest.c
+++ b/elf/neededtest.c
@@ -5,6 +5,8 @@
#include <stdlib.h>
#include <string.h>
+#define MAPS ((struct link_map *) _r_debug.r_map)
+
static int
check_loaded_objects (const char **loaded)
{
@@ -24,7 +26,7 @@ check_loaded_objects (const char **loaded)
printf(" Name\n");
printf(" --------------------------------------------------------\n");
- for (lm = _r_debug.r_map; lm; lm = lm->l_next)
+ for (lm = MAPS; lm; lm = lm->l_next)
{
if (lm->l_name && lm->l_name[0])
printf(" %s, count = %d\n", lm->l_name, (int) lm->l_direct_opencount);
diff --git a/elf/neededtest2.c b/elf/neededtest2.c
index b682f15792..17c75f2ba3 100644
--- a/elf/neededtest2.c
+++ b/elf/neededtest2.c
@@ -5,6 +5,8 @@
#include <stdlib.h>
#include <string.h>
+#define MAPS ((struct link_map *) _r_debug.r_map)
+
static int
check_loaded_objects (const char **loaded)
{
@@ -24,7 +26,7 @@ check_loaded_objects (const char **loaded)
printf(" Name\n");
printf(" --------------------------------------------------------\n");
- for (lm = _r_debug.r_map; lm; lm = lm->l_next)
+ for (lm = MAPS; lm; lm = lm->l_next)
{
if (lm->l_name && lm->l_name[0])
printf(" %s, count = %d\n", lm->l_name, (int) lm->l_direct_opencount);
diff --git a/elf/neededtest3.c b/elf/neededtest3.c
index ea1dcf4794..41970cf2c7 100644
--- a/elf/neededtest3.c
+++ b/elf/neededtest3.c
@@ -5,6 +5,8 @@
#include <stdlib.h>
#include <string.h>
+#define MAPS ((struct link_map *) _r_debug.r_map)
+
static int
check_loaded_objects (const char **loaded)
{
@@ -24,7 +26,7 @@ check_loaded_objects (const char **loaded)
printf(" Name\n");
printf(" --------------------------------------------------------\n");
- for (lm = _r_debug.r_map; lm; lm = lm->l_next)
+ for (lm = MAPS; lm; lm = lm->l_next)
{
if (lm->l_name && lm->l_name[0])
printf(" %s, count = %d\n", lm->l_name, (int) lm->l_direct_opencount);
diff --git a/elf/neededtest4.c b/elf/neededtest4.c
index 7514bed499..bd79341fb2 100644
--- a/elf/neededtest4.c
+++ b/elf/neededtest4.c
@@ -5,6 +5,8 @@
#include <stdlib.h>
#include <string.h>
+#define MAPS ((struct link_map *) _r_debug.r_map)
+
static int
check_loaded_objects (const char **loaded)
{
@@ -24,7 +26,7 @@ check_loaded_objects (const char **loaded)
printf(" Name\n");
printf(" --------------------------------------------------------\n");
- for (lm = _r_debug.r_map; lm; lm = lm->l_next)
+ for (lm = MAPS; lm; lm = lm->l_next)
{
if (lm->l_name && lm->l_name[0])
printf(" %s, count = %d\n", lm->l_name, (int) lm->l_direct_opencount);
diff --git a/elf/tst-tls-dlinfo.c b/elf/tst-tls-dlinfo.c
new file mode 100644
index 0000000000..e97b5081fd
--- /dev/null
+++ b/elf/tst-tls-dlinfo.c
@@ -0,0 +1,92 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <tls.h>
+
+
+#define TEST_FUNCTION do_test ()
+static int
+do_test (void)
+{
+#ifdef USE_TLS
+ static const char modname[] = "tst-tlsmod2.so";
+ int result = 0;
+ int *foop;
+ int (*fp) (int, int *);
+ void *h;
+
+ h = dlopen (modname, RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("cannot open '%s': %s\n", modname, dlerror ());
+ exit (1);
+ }
+
+ fp = dlsym (h, "in_dso");
+ if (fp == NULL)
+ {
+ printf ("cannot get symbol 'in_dso': %s\n", dlerror ());
+ exit (1);
+ }
+
+ size_t modid = -1;
+ if (dlinfo (h, RTLD_DI_TLS_MODID, &modid))
+ {
+ printf ("dlinfo RTLD_DI_TLS_MODID failed: %s\n", dlerror ());
+ result = 1;
+ }
+ else
+ printf ("dlinfo says TLS module ID %Zu\n", modid);
+
+ void *block;
+ if (dlinfo (h, RTLD_DI_TLS_DATA, &block))
+ {
+ printf ("dlinfo RTLD_DI_TLS_DATA failed: %s\n", dlerror ());
+ result = 1;
+ }
+ else if (block != NULL)
+ {
+ printf ("dlinfo RTLD_DI_TLS_DATA says %p but should be unallocated\n",
+ block);
+ result = 1;
+ }
+
+ result |= fp (0, NULL);
+
+ foop = dlsym (h, "foo");
+ if (foop == NULL)
+ {
+ printf ("cannot get symbol 'foo' the second time: %s\n", dlerror ());
+ exit (1);
+ }
+ if (*foop != 16)
+ {
+ puts ("foo != 16");
+ result = 1;
+ }
+
+ /* Now the module's TLS block has been used and should appear. */
+ if (dlinfo (h, RTLD_DI_TLS_DATA, &block))
+ {
+ printf ("dlinfo RTLD_DI_TLS_DATA failed the second time: %s\n",
+ dlerror ());
+ result = 1;
+ }
+ else if (block != foop)
+ {
+ printf ("dlinfo RTLD_DI_TLS_DATA says %p but should be %p\n",
+ block, foop);
+ result = 1;
+ }
+
+ dlclose (h);
+
+ return result;
+#else
+ return 0;
+#endif
+}
+
+
+#include "../test-skeleton.c"
diff --git a/elf/unload.c b/elf/unload.c
index ffb33482c0..4566f226f8 100644
--- a/elf/unload.c
+++ b/elf/unload.c
@@ -9,8 +9,10 @@
#include <stdio.h>
#include <stdlib.h>
+#define MAPS ((struct link_map *) _r_debug.r_map)
+
#define OUT \
- for (map = _r_debug.r_map; map != NULL; map = map->l_next) \
+ for (map = MAPS; map != NULL; map = map->l_next) \
if (map->l_type == lt_loaded) \
printf ("name = \"%s\", direct_opencount = %d\n", \
map->l_name, (int) map->l_direct_opencount); \
diff --git a/elf/unload2.c b/elf/unload2.c
index e14c6f06af..eef2bfd426 100644
--- a/elf/unload2.c
+++ b/elf/unload2.c
@@ -6,8 +6,10 @@
#include <stdio.h>
#include <stdlib.h>
+#define MAPS ((struct link_map *) _r_debug.r_map)
+
#define OUT \
- for (map = _r_debug.r_map; map != NULL; map = map->l_next) \
+ for (map = MAPS; map != NULL; map = map->l_next) \
if (map->l_type == lt_loaded) \
printf ("name = \"%s\", direct_opencount = %d\n", \
map->l_name, (int) map->l_direct_opencount); \
diff --git a/include/link.h b/include/link.h
index 0c35264096..3079ae8739 100644
--- a/include/link.h
+++ b/include/link.h
@@ -1,6 +1,6 @@
/* Data structure for communication from the run-time dynamic linker for
loaded ELF shared objects.
- Copyright (C) 1995-2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1995-2002,2003,2004,2005,2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -18,67 +18,32 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#ifndef _LINK_H
-#define _LINK_H 1
+#ifndef _PRIVATE_LINK_H
+#define _PRIVATE_LINK_H 1
-#include <elf.h>
-#include <dlfcn.h>
-#include <stddef.h>
-#include <sys/types.h>
+#ifdef _LINK_H
+# error this should be impossible
+#endif
+
+/* Get most of the contents from the public header, but we define a
+ different `struct link_map' type for private use. The la_objopen
+ prototype uses the type, so we have to declare it separately. */
+#define link_map link_map_public
+#define la_objopen la_objopen_wrongproto
+#include <elf/link.h>
+#undef link_map
+#undef la_objopen
+
+struct link_map;
+extern unsigned int la_objopen (struct link_map *__map, Lmid_t __lmid,
+ uintptr_t *__cookie);
-/* We use this macro to refer to ELF types independent of the native wordsize.
- `ElfW(TYPE)' is used in place of `Elf32_TYPE' or `Elf64_TYPE'. */
-#define ElfW(type) _ElfW (Elf, __ELF_NATIVE_CLASS, type)
-#define _ElfW(e,w,t) _ElfW_1 (e, w, _##t)
-#define _ElfW_1(e,w,t) e##w##t
-#include <bits/elfclass.h> /* Defines __ELF_NATIVE_CLASS. */
-#include <bits/link.h>
+#include <stddef.h>
#include <bits/linkmap.h>
#include <dl-lookupcfg.h>
#include <tls.h> /* Defines USE_TLS. */
-/* Rendezvous structure used by the run-time dynamic linker to communicate
- details of shared object loading to the debugger. If the executable's
- dynamic section has a DT_DEBUG element, the run-time linker sets that
- element's value to the address where this structure can be found. */
-
-struct r_debug
- {
- int r_version; /* Version number for this protocol. */
-
- struct link_map *r_map; /* Head of the chain of loaded objects. */
-
- /* This is the address of a function internal to the run-time linker,
- that will always be called when the linker begins to map in a
- library or unmap it, and again when the mapping change is complete.
- The debugger can set a breakpoint at this address if it wants to
- notice shared object mapping changes. */
- ElfW(Addr) r_brk;
- enum
- {
- /* This state value describes the mapping change taking place when
- the `r_brk' address is called. */
- RT_CONSISTENT, /* Mapping change is complete. */
- RT_ADD, /* Beginning to add a new object. */
- RT_DELETE /* Beginning to remove an object mapping. */
- } r_state;
-
- ElfW(Addr) r_ldbase; /* Base address the linker is loaded at. */
- };
-
-/* This is the instance of that structure used by the dynamic linker. */
-extern struct r_debug _r_debug;
-
-/* This symbol refers to the "dynamic structure" in the `.dynamic' section
- of whatever module refers to `_DYNAMIC'. So, to find its own
- `struct r_debug', a program could do:
- for (dyn = _DYNAMIC; dyn->d_tag != DT_NULL; ++dyn)
- if (dyn->d_tag == DT_DEBUG)
- r_debug = (struct r_debug *) dyn->d_un.d_ptr;
- */
-extern ElfW(Dyn) _DYNAMIC[];
-
/* Some internal data structures of the dynamic linker used in the
linker map. We only provide forward declarations. */
@@ -316,45 +281,6 @@ struct link_map
} l_audit[0];
};
-/* Version numbers for la_version handshake interface. */
-#define LAV_CURRENT 1
-
-/* Activity types signaled through la_activity. */
-enum
- {
- LA_ACT_CONSISTENT,
- LA_ACT_ADD,
- LA_ACT_DELETE
- };
-
-/* Values representing origin of name for dynamic loading. */
-enum
- {
- LA_SER_ORIG = 0x01, /* Original name. */
- LA_SER_LIBPATH = 0x02, /* Directory from LD_LIBRARY_PATH. */
- LA_SER_RUNPATH = 0x04, /* Directory from RPATH/RUNPATH. */
- LA_SER_CONFIG = 0x08, /* Found through ldconfig. */
- LA_SER_DEFAULT = 0x40, /* Default directory. */
- LA_SER_SECURE = 0x80 /* Unused. */
- };
-
-/* Values for la_objopen return value. */
-enum
- {
- LA_FLG_BINDTO = 0x01, /* Audit symbols bound to this object. */
- LA_FLG_BINDFROM = 0x02 /* Audit symbols bound from this object. */
- };
-
-/* Values for la_symbind flags parameter. */
-enum
- {
- LA_SYMB_NOPLTENTER = 0x01, /* la_pltenter will not be called. */
- LA_SYMB_NOPLTEXIT = 0x02, /* la_pltexit will not be called. */
- LA_SYMB_STRUCTCALL = 0x04, /* Return value is a structure. */
- LA_SYMB_DLSYM = 0x08, /* Binding due to dlsym call. */
- LA_SYMB_ALTVALUE = 0x10 /* Value has been changed by a previous
- la_symbind call. */
- };
#if __ELF_NATIVE_CLASS == 32
# define symbind symbind32
@@ -364,22 +290,8 @@ enum
# error "__ELF_NATIVE_CLASS must be defined"
#endif
-struct dl_phdr_info
- {
- ElfW(Addr) dlpi_addr;
- const char *dlpi_name;
- const ElfW(Phdr) *dlpi_phdr;
- ElfW(Half) dlpi_phnum;
-
- unsigned long long int dlpi_adds;
- unsigned long long int dlpi_subs;
- };
-
-extern int dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info,
- size_t size, void *data),
- void *data);
extern int __dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info,
size_t size, void *data),
void *data);
-#endif /* link.h */
+#endif /* include/link.h */
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index b5f7c3cae5..13fefd9e83 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -1113,6 +1113,11 @@ extern void _dl_add_to_slotinfo (struct link_map *l) attribute_hidden;
module with the given index. */
extern struct link_map *_dl_update_slotinfo (unsigned long int req_modid);
+/* Look up the module's TLS block as for __tls_get_addr,
+ but never touch anything. Return null if it's not allocated yet. */
+extern void *_dl_tls_get_addr_soft (struct link_map *l) internal_function;
+
+
__END_DECLS
#endif /* ldsodefs.h */