Date: Fri, 1 Sep 2006 11:16:30 -0700 From: Marcel Moolenaar <xcllnt@mac.com> To: ppc@FreeBSD.org Subject: Status of threading and TLS Message-ID: <933C0437-DDF8-4A61-83BA-F4920D9E6E96@mac.com>
next in thread | raw e-mail | index | archive | help
All, I've been working on TLS for both ia64 and powerpc and all is well... except for one nasty bugger on powerpc. Here's the status on powerpc: TLS for non-threaded statically linked applications: working TLS for non-threaded dynamically linked applications: working TLS for statically linked 1:1 (libthr): working TLS for dynamically linked 1:1 (libthr): working TLS for statically linked M:N (libpthread): bugger! TLS for dynamically linked M:N (libpthread: bugger! The bugger for libpthread is that register r2 (the TLS pointer) is off by 8 bytes. I have no idea where that happens and I've been going over the code a hundred times. It's obvious that I either developed a blind spot, or I'm not looking in the right place. I need your help before I can have malloc(3) use TLS safely! To demon strate the problem, assume the following program: \begin{verbatim} #include <pthread.h> #include <stdio.h> int __thread i = -1; static void * thread(void *arg) { int j; j = (int)arg; return (arg); } int main(int argc, char *argv[]) { pthread_t pt; int err; err = pthread_create(&pt, NULL, thread, i); pthread_join(pt, NULL); return (0); } \end{verbatim} If I link it with libthr, run it in the debugger with breakpoints on main() and thread(), I can inspect register r2: : : (gdb) run Starting program: /nfs/home/marcel/t Breakpoint 1, main (argc=1, argv=0x7fffdc04) at t.c:21 21 err = pthread_create(&pt, NULL, thread, i); (gdb) p $r2 $1 = 27308344 (gdb) p ((int *)($r2 - 0x7008))[0] $2 = 27279680 (gdb) p ((int *)($r2 - 0x7008))[2] $3 = -1 The magic above means the following: r2 holds the address of the thread pointer of the main thread $2 holds the address of the DTV. The DTV is at TLS[0] $3 holds the value of the thread local variable i. It is -1. Now, to see how this pans out for the first thread: (gdb) c Continuing. Breakpoint 2, thread (arg=0xffffffff) at t.c:11 11 j = (int)arg; (gdb) p $r2 $4 = 27308376 (gdb) p ((int *)($r2 - 0x7008))[0] $5 = 27279712 (gdb) p ((int *)($r2 - 0x7008))[2] $6 = -1 Expected results. Now, if I link against libpthread I get the following: : : (gdb) run Starting program: /nfs/home/marcel/t Breakpoint 1, main (argc=1, argv=0x7fffdc04) at t.c:21 21 err = pthread_create(&pt, NULL, thread, i); (gdb) p $r2 $1 = 27493528 (gdb) p ((int *)($r2 - 0x7008))[0] $2 = 0 (gdb) p ((int *)($r2 - 0x7008))[2] $3 = 27279680 This is wrong. But... (gdb) p ((int *)($r2 - 0x7008))[4] $4 = -1 It appears that register r2 is off by 8 bytes. Let me double check. DTV entry 2 should point to the thread local variable i (lucky us): (gdb) p /x ((int *)$3)[2] $5 = 0x1a314a0 (gdb) p &((int *)($r2 - 0x7008))[4] $6 = (int *) 0x1a314a0 Yup. Now how this happens, I don't know. If anyone has any suggestions why for libpthread we end up with r2 off by 8 bytes, I'm happy to hear it... -- Marcel Moolenaar xcllnt@mac.com
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?933C0437-DDF8-4A61-83BA-F4920D9E6E96>