(I'm not sure that this is libc's fault so apologies in advance if this is noise and should be redirected. Please don't hesitate to ask for additional information; I'm not sure what else I should provide.) Doing a setcontext() on Linux/SPARC64 (kernel 2.6.26-rc4) using glibc 2.7 (Debian build 2.7-11) also writes over %g7, which is used to store the TLS pointer for pthread_self() (see libc/nptl/sysdeps/sparc/tls.h). This breaks plan9port's libthread but it will show up any time threads exchange or pool contexts. I've worked around it by manually setting uc_mcontext.mc_gregs[REG_G7] to pthread_self() before calling setcontext; if this is the correct fix, it would seem that setcontext() should be doing that itself. Thanks for your time.
I'd say the kernel setcontext 0x16f trap shouldn't change %g7, Dave, do you agree? Of course glibc can store %g7 to the setcontext structure before doing ta 0x6f too, but that means the context has to be modified by setcontext.
Subject: Re: SPARC64 get/setcontext smashes TLS From: "jakub at redhat dot com" <sourceware-bugzilla@sourceware.org> Date: 31 Jul 2008 17:18:35 -0000 > I'd say the kernel setcontext 0x16f trap shouldn't change %g7, Dave, do you > agree? Of course glibc can store %g7 to the setcontext structure before doing > ta 0x6f too, but that means the context has to be modified by setcontext. I agree, therefore I'll commit the following patch upstream. sparc64: Do not clobber %g7 in setcontext() trap. That's the userland thread register, so we should never try to change it like this. Based upon glibc bug nptl/6577 and suggestions by Jakub Jelinek. Signed-off-by: David S. Miller <davem@davemloft.net> --- arch/sparc64/kernel/signal.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c index d1b8445..ca5a6ae 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c @@ -2,7 +2,7 @@ * arch/sparc64/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1995, 2008 David S. Miller (davem@davemloft.net) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -91,7 +91,9 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs) err |= __get_user(regs->u_regs[UREG_G4], (&(*grp)[MC_G4])); err |= __get_user(regs->u_regs[UREG_G5], (&(*grp)[MC_G5])); err |= __get_user(regs->u_regs[UREG_G6], (&(*grp)[MC_G6])); - err |= __get_user(regs->u_regs[UREG_G7], (&(*grp)[MC_G7])); + + /* Skip %g7 as that's the thread register in userspace. */ + err |= __get_user(regs->u_regs[UREG_I0], (&(*grp)[MC_O0])); err |= __get_user(regs->u_regs[UREG_I1], (&(*grp)[MC_O1])); err |= __get_user(regs->u_regs[UREG_I2], (&(*grp)[MC_O2]));
Not a libc problem, this is fixed in the kernel.