NetBSD Problem Report #48709
From martin@duskware.de Fri Apr 4 19:28:35 2014
Return-Path: <martin@duskware.de>
Received: from mail.netbsd.org (mail.netbsd.org [149.20.53.66])
(using TLSv1 with cipher ECDHE-RSA-AES256-SHA (256/256 bits))
(Client CN "mail.netbsd.org", Issuer "Postmaster NetBSD.org" (verified OK))
by mollari.NetBSD.org (Postfix) with ESMTPS id 95940A5802
for <gnats-bugs@gnats.NetBSD.org>; Fri, 4 Apr 2014 19:28:35 +0000 (UTC)
From: martin@NetBSD.org
Reply-To: martin@NetBSD.org
To: gnats-bugs@NetBSD.org
Subject: static threaded programs crash
X-Send-Pr-Version: 3.95
>Number: 48709
>Category: port-alpha
>Synopsis: static threaded programs crash
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: port-alpha-maintainer
>State: closed
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Fri Apr 04 19:30:00 +0000 2014
>Closed-Date: Tue Aug 12 12:59:19 +0000 2014
>Last-Modified: Tue Aug 12 12:59:19 +0000 2014
>Originator: Martin Husemann
>Release: NetBSD 6.99.39
>Organization:
The NetBSD Foundation, Inc.
>Environment:
System: NetBSD gemini.duskware.de 6.99.39 NetBSD 6.99.39 (GENERIC-$Revision: 1.358 $) #11: Fri Apr 4 14:06:15 CEST 2014 martin@night-owl.duskware.de:/usr/src/sys/arch/alpha/compile/GENERIC alpha
Architecture: alpha
Machine: alpha
>Description:
The test program for staticaly linked TLS access dies on alpha with a segfault,
try:
cd /usr/tests/lib/libc/tls && ./t_tls_static -l
but also this minimalistic program dies, if compiled with -static -pthread:
--8<--
#include <stdlib.h>
#include <pthread.h>
void *func(void *arg) { return 0; }
int main(int arg, char **argv)
{
pthread_t t;
pthread_create(&t, NULL, func, NULL);
return 0;
}
-->8--
Nick and I traced this to register t12 getting corrupted in _libc_init when
calling __libc_thr_init. However, it is not that simple: the original object
code (with relocations) is fine:
Disassembly of section .text.startup:
0000000000000000 <_libc_init>:
0: 00 00 bb 27 ldah gp,0(t12)
0: GPDISP .text.startup+0x4
4: 00 00 bd 23 lda gp,0(gp)
8: f0 ff de 23 lda sp,-16(sp)
c: 00 00 5e b7 stq ra,0(sp)
[..]
64: 00 00 7d a7 ldq t12,0(gp)
64: ELF_LITERAL __guard_setup
68: 00 40 5b 6b jsr ra,(t12),6c <_libc_init+0x6c>
68: LITUSE .text.startup+0x3
68: HINT __guard_setup
6c: 00 00 ba 27 ldah gp,0(ra)
6c: GPDISP .text.startup+0x4
70: 00 00 bd 23 lda gp,0(gp)
74: 00 00 7d a7 ldq t12,0(gp)
74: ELF_LITERAL __libc_atomic_init
78: 00 40 5b 6b jsr ra,(t12),7c <_libc_init+0x7c>
78: LITUSE .text.startup+0x3
78: HINT __libc_atomic_init
7c: 00 00 ba 27 ldah gp,0(ra)
7c: GPDISP .text.startup+0x4
80: 00 00 bd 23 lda gp,0(gp)
84: 00 00 7d a7 ldq t12,0(gp)
84: ELF_LITERAL __libc_static_tls_setup
88: 00 40 5b 6b jsr ra,(t12),8c <_libc_init+0x8c>
88: LITUSE .text.startup+0x3
88: HINT __libc_static_tls_setup
8c: 00 00 ba 27 ldah gp,0(ra)
8c: GPDISP .text.startup+0x4
90: 00 00 bd 23 lda gp,0(gp)
94: 00 00 7d a7 ldq t12,0(gp)
94: ELF_LITERAL __libc_thr_init
98: 00 40 5b 6b jsr ra,(t12),9c <_libc_init+0x9c>
98: LITUSE .text.startup+0x3
98: HINT __libc_thr_init
As you can see, t12 is used for the jsr call and set up right before the
function call. I don't see where it is restored, but I might have
misunderstood something about the abi.
Now binutils is smart and optimizes this for static linked
(and small) binaries:
1200467b4: 00 00 fe 2f unop
1200467b8: 43 00 40 d3 bsr ra,1200468c8 <__guard_setup+0x8>
1200467bc: 00 00 fe 2f unop
1200467c0: 00 00 fe 2f unop
1200467c4: 00 00 fe 2f unop
1200467c8: 15 00 40 d3 bsr ra,120046820 <__libc_atomic_init>
1200467cc: 00 00 fe 2f unop
1200467d0: 00 00 fe 2f unop
1200467d4: 00 00 fe 2f unop
1200467d8: 9b 5a 5f d3 bsr ra,12001d248 <__libc_static_tls_setup+0x8>
1200467dc: 00 00 fe 2f unop
1200467e0: 00 00 fe 2f unop
1200467e4: 00 00 fe 2f unop
1200467e8: b1 f0 5e d3 bsr ra,120002ab0 <__libc_thr_init>
1200467ec: 00 00 fe 2f unop
1200467f0: 00 00 fe 2f unop
1200467f4: 00 00 fe 2f unop
The pattern is simple: the first two instructions in public functions
set up the gp register for this function. When it is known that the gp value
is not needed, or the same as in the calling function, the gp setup is skipped
and the jsr can be replaced by a bsr - but to past the two instructions (i.e.
typically function address + 8).
If you look at the disassembly above, you'll find some functions where the bsr
does not use the +8 offset: __libc_atomic_init and __libc_thr_init.
For the former, this is fine: it is an empty function and does not do
gp setup:
0000000120046820 <__libc_atomic_init>:
120046820: 01 80 fa 6b ret
120046824: 00 00 fe 2f unop
120046828: 1f 04 ff 47 nop
12004682c: 00 00 fe 2f unop
However, for __libc_thr_init it is not fine:
0000000120002ab0 <__libc_thr_init>:
120002ab0: 06 00 bb 27 ldah gp,6(t12)
120002ab4: 78 f6 bd 23 lda gp,-2440(gp)
120002ab8: c0 ff de 23 lda sp,-64(sp)
So the
1200467e8: b1 f0 5e d3 bsr ra,120002ab0 <__libc_thr_init>
actually modifies register t12 - and it is never restored.
I wonder if the "hidden" attribute of the function name is declared
inconsistently somewhere (__libc_thr_init is aliased for libpthread), or
if this is a binutils bug -- or if I am just missing something.
Does anyone have an idea why binutils things it is ok to convert the
__libc_thr_init call to bsr without an offset?
>How-To-Repeat:
cd /usr/tests/lib/libc/tls
./t_tls_static -l
>Fix:
n/a
>Release-Note:
>Audit-Trail:
From: Martin Husemann <martin@duskware.de>
To: gnats-bugs@NetBSD.org
Cc:
Subject: Re: port-alpha/48709: static threaded programs crash
Date: Sun, 27 Jul 2014 17:25:22 +0200
I filed an upstream bug report:
https://sourceware.org/bugzilla/show_bug.cgi?id=17205
Martin
From: "Nick Hudson" <skrll@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/48709 CVS commit: src/external/gpl3/binutils/dist/bfd
Date: Mon, 11 Aug 2014 20:53:16 +0000
Module Name: src
Committed By: skrll
Date: Mon Aug 11 20:53:16 UTC 2014
Modified Files:
src/external/gpl3/binutils/dist/bfd: ChangeLog elflink.c
Log Message:
Apply change from upstream to fix PR/48709 - port-alpha/48709: static
threaded programs crash.
With this fix the new weak symbol's st_other is not merged in, i.e. NOPV
is not copied from the libc __libc_thr_init.
* elflink.c (_bfd_elf_merge_symbol): If merging a new weak
symbol that will be skipped, we don't have a new definition.
To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.6 src/external/gpl3/binutils/dist/bfd/ChangeLog
cvs rdiff -u -r1.7 -r1.8 src/external/gpl3/binutils/dist/bfd/elflink.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/48709 CVS commit: [netbsd-7] src/external/gpl3/binutils/dist/bfd
Date: Tue, 12 Aug 2014 09:36:03 +0000
Module Name: src
Committed By: martin
Date: Tue Aug 12 09:36:03 UTC 2014
Modified Files:
src/external/gpl3/binutils/dist/bfd [netbsd-7]: ChangeLog elflink.c
Log Message:
Pull up following revision(s) (requested by skrll in ticket #5):
external/gpl3/binutils/dist/bfd/ChangeLog: revision 1.6
external/gpl3/binutils/dist/bfd/elflink.c: revision 1.8
Apply change from upstream to fix PR/48709 - port-alpha/48709: static
threaded programs crash.
With this fix the new weak symbol's st_other is not merged in, i.e. NOPV
is not copied from the libc __libc_thr_init.
* elflink.c (_bfd_elf_merge_symbol): If merging a new weak
symbol that will be skipped, we don't have a new definition.
To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.5.4.1 src/external/gpl3/binutils/dist/bfd/ChangeLog
cvs rdiff -u -r1.7 -r1.7.4.1 src/external/gpl3/binutils/dist/bfd/elflink.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
State-Changed-From-To: open->closed
State-Changed-By: skrll@NetBSD.org
State-Changed-When: Tue, 12 Aug 2014 12:59:19 +0000
State-Changed-Why:
Fixed.
>Unformatted:
(Contact us)
$NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2014
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.