This is the mail archive of the
libc-help@sourceware.org
mailing list for the glibc project.
Re: TLS variables access for -static -lpthread executables
- From: "Carlos O'Donell" <carlos at redhat dot com>
- To: Jan Kratochvil <jan dot kratochvil at redhat dot com>, libc-help at sourceware dot org
- Cc: Ben Woodard <woodard at redhat dot com>, "Maciej W. Rozycki" <macro at codesourcery dot com>
- Date: Thu, 27 Mar 2014 03:45:21 -0400
- Subject: Re: TLS variables access for -static -lpthread executables
- Authentication-results: sourceware.org; auth=none
- References: <20140326182101 dot GA13552 at host2 dot jankratochvil dot net>
On 03/26/2014 02:21 PM, Jan Kratochvil wrote:
> Hi,
>
> Reproducer:
> gcc -g -o tlsvar tlsvar.c -pthread -static; gdb ./tlsvar -ex 'b 12' -ex r -ex 'info thread' -ex 'p *thread_local_p'
>
> Actual output:
> Cannot find executable file `.../tlsvar' in dynamic linker's load module list
>
> Expected output:
> $1 = 10 (or 20 or 30)
>
> With -static there is no _r_debug, no link_map, no '.dynamic' section so there
> is nothing to pass as 'psaddr_t __map_address' for td_thr_tls_get_addr.
There is _r_debug for a static link, it comes from libc.a (dl-debug.o),
but the r_map is going to be NULL because we never set it.
There is a valid internal link_map for static executables as of 2.18,
see bug 15022 and bug 16046 for some followup fixes. However, this isn't
exposed in any way to the user. It would require additional patches
to make _r_debug work for static binaries and that would make the
dependency 2.20 or later.
> Attached GDB fix that uses td_thr_tlsbase() instead of td_thr_tls_get_addr()
> and pass 'modid' as value 1. But I haven't found it documented anywhere.
It's an internal implementation detail that rtld sets the module ID to 1
for the application. The loader also starts as module ID 1 and eventually
selects it's own module ID. The module ID of 1 for the executable might
change at some point, but I doubt it.
Your use of td_thr_tlsbase() is exactly what td_thr_tls_get_addr() does,
but the latter looks up the module ID in the link map, which is what you'd
like to do, but can't because we didn't provide one.
> Is such patch acceptable for upstream GDB or is there some better way with
> glibc?
The best way forward would be to ensure you can get a link map even for
static executables, and then use that with td_thr_tls_get_addr(). This
would allow gdb to avoid doing two different things for static and
dynamic executables. It also helps all other applications using libthread_db
interfaces.
Would you mind testing something like this in fedora rawhide?
diff --git a/csu/libc-start.c b/csu/libc-start.c
index 3b7092b..d571a1a 100644
--- a/csu/libc-start.c
+++ b/csu/libc-start.c
@@ -264,6 +264,9 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
GLRO(dl_debug_printf) ("\ntransferring control: %s\n\n", argv[0]);
#endif
+#ifndef SHARED
+ _dl_debug_initialize (0, LM_ID_BASE);
+#endif
#ifdef HAVE_CLEANUP_JMP_BUF
/* Memory for the cancellation buffer. */
struct pthread_unwind_buf unwind_buf;
---
[carlos@koi ~]$ cat test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <link.h>
int
main (int argc, char **argv)
{
printf ("%p\n", &_r_debug);
printf ("%p\n", _r_debug.r_map);
return 0;
}
[carlos@koi ~]$ gcc -Wl,--build-id=none -nostdlib -nostartfiles -static -o ./test-static /home/carlos/build/glibc/csu/crt1.o /home/carlos/build/glibc/csu/crti.o `gcc -Wl,--build-id=none --print-file-name=crtbeginT.o` ./test-static.o -Wl,--start-group /home/carlos/build/glibc/libc.a -lgcc -lgcc_eh -Wl,--end-group `gcc -Wl,--build-id=none --print-file-name=crtend.o` /home/carlos/build/glibc/csu/crtn.o -Wl,-Map,linkmap.txt
[carlos@koi ~]$ ./test-static
0x6b4b40
0x6b2260
That link map has l_tls_modid set to 1 as expected, and is the new
_dl_main_map added in 2.18 by Maciej's work.
No matter what solution I propose you'll still have to support an older
glibc and the static executable won't have a link map in _r_debug's r_map.
In summary:
* Assuming modid of 1 for the executable is OK for now.
* glibc should be exposing a link map for the executable even when static
via _r_debug's r_map for use with td_thr_tls_get_addr().
Comments?
Cheers,
Carlos.