From d78efd9f369a8fc46229fc9224e10e3781eecc43 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Wed, 1 Mar 2006 06:18:49 +0000 Subject: [PATCH] * 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. --- ChangeLog | 33 ++++++++++ dlfcn/dlfcn.h | 21 +++++- dlfcn/dlinfo.c | 24 ++++++- elf/Makefile | 13 +++- elf/Versions | 1 + elf/circleload1.c | 4 +- elf/dl-debug.c | 17 ++++- elf/dl-iteratephdr.c | 9 ++- elf/dl-tls.c | 48 +++++++++++++- elf/link.h | 18 +++-- elf/loadtest.c | 8 ++- elf/neededtest.c | 4 +- elf/neededtest2.c | 4 +- elf/neededtest3.c | 4 +- elf/neededtest4.c | 4 +- elf/tst-tls-dlinfo.c | 92 ++++++++++++++++++++++++++ elf/unload.c | 4 +- elf/unload2.c | 4 +- include/link.h | 130 ++++++------------------------------- sysdeps/generic/ldsodefs.h | 5 ++ 20 files changed, 312 insertions(+), 135 deletions(-) create mode 100644 elf/tst-tls-dlinfo.c diff --git a/ChangeLog b/ChangeLog index 6ccf70ada2..b35cd50a36 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,38 @@ 2006-02-28 Roland McGrath + * 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 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 +# 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 #include +#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 + +/* 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 , 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 +#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 #include +#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 #include +#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 #include +#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 #include +#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 +#include +#include + +#include + + +#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 #include +#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 #include +#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 -#include -#include -#include +#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 +#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 /* Defines __ELF_NATIVE_CLASS. */ -#include +#include #include #include #include /* 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 */