Bug 22978 - [2.30, 2.31 Regression] TLS local-dynamic incorrectly linked on hppa-linux
Summary: [2.30, 2.31 Regression] TLS local-dynamic incorrectly linked on hppa-linux
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.31
: P2 normal
Target Milestone: ---
Assignee: Alan Modra
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-03-18 19:49 UTC by John David Anglin
Modified: 2018-04-20 14:00 UTC (History)
0 users

See Also:
Host: hppa-unknown-linux-gnu
Target: hppa-unknown-linux-gnu
Build: hppa-unknown-linux-gnu
Last reconfirmed:


Attachments
fix (516 bytes, patch)
2018-04-19 01:53 UTC, Alan Modra
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description John David Anglin 2018-03-18 19:49:05 UTC
The run_ld.c test from gcc is incorrectly linked using binutils 2.30 and later
with -pie.

/* { dg-do run } */
/* { dg-require-effective-target tls_runtime } */
/* { dg-add-options tls } */

extern void abort (void);

__thread int tls_ld __attribute__((tls_model("local-dynamic"))) = 1;
__thread int tls_ld2 __attribute__((tls_model("local-dynamic"))) = 2;

int get_ld (void)
{
  return tls_ld + tls_ld2;
}

int *get_ldp (void)
{
  return &tls_ld;
}

int main (void)
{
  int val;

  val = get_ld ();
  if (val != 1 + 2)
    abort ();

  val = *get_ldp ();
  if (val != 1)
    abort ();

  return 0;
}

Executing on host: /home/dave/gnu/gcc/objdir/gcc/xgcc -B/home/dave/gnu/gcc/objdi
r/gcc/ /home/dave/gnu/gcc/gcc/gcc/testsuite/gcc.dg/torture/tls/run-ld.c     -fno
-diagnostics-show-caret -fdiagnostics-color=never    -O0  -pie -fPIE   -ansi -pe
dantic-errors  -lm  -o ./run-ld.exe    (timeout = 300)
spawn -ignore SIGHUP /home/dave/gnu/gcc/objdir/gcc/xgcc -B/home/dave/gnu/gcc/obj
dir/gcc/ /home/dave/gnu/gcc/gcc/gcc/testsuite/gcc.dg/torture/tls/run-ld.c -fno-d
iagnostics-show-caret -fdiagnostics-color=never -O0 -pie -fPIE -ansi -pedantic-e
rrors -lm -o ./run-ld.exe
PASS: gcc.dg/torture/tls/run-ld.c   -O0  -pie -fPIE  (test for excess errors)
Setting LD_LIBRARY_PATH to :/home/dave/gnu/gcc/objdir/gcc:/home/dave/gnu/gcc/obj
dir/hppa-linux-gnu/./libatomic/.libs::/home/dave/gnu/gcc/objdir/gcc:/home/dave/g
nu/gcc/objdir/hppa-linux-gnu/./libatomic/.libs:/home/dave/gnu/gcc/objdir/hppa-li
nux-gnu/libstdc++-v3/src/.libs:/home/dave/gnu/gcc/objdir/hppa-linux-gnu/libssp/.
libs:/home/dave/gnu/gcc/objdir/hppa-linux-gnu/libgomp/.libs:/home/dave/gnu/gcc/o
bjdir/hppa-linux-gnu/libatomic/.libs:/home/dave/gnu/gcc/objdir/./gcc:/home/dave/
gnu/gcc/objdir/./prev-gcc:/home/dave/gnu/gcc/objdir/hppa-linux-gnu/libstdc++-v3/
src/.libs:/home/dave/gnu/gcc/objdir/hppa-linux-gnu/libssp/.libs:/home/dave/gnu/g
cc/objdir/hppa-linux-gnu/libgomp/.libs:/home/dave/gnu/gcc/objdir/hppa-linux-gnu/
libatomic/.libs:/home/dave/gnu/gcc/objdir/./gcc:/home/dave/gnu/gcc/objdir/./prev
-gcc
Execution timeout is: 300
spawn [open ...]
FAIL: gcc.dg/torture/tls/run-ld.c   -O0  -pie -fPIE  execution test

Typical link command is:

/home/dave/gnu/binutils/objdir/ld/ld-new -plugin /home/dave/gnu/gcc/objdir/gcc/liblto_plugin.so -plugin-opt=/home/dave/gnu/gcc/objdir/gcc/lto-wrapper -plugin-opt=-fresolution=run-ld.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -dynamic-linker /lib/ld.so.1  -o ./run-ld.exe /usr/lib/hppa-linux-gnu/Scrt1.o /usr/lib/hppa-linux-gnu/crti.o /home/dave/gnu/gcc/objdir/gcc/crtbeginS.o -L/home/dave/gnu/gcc/objdir/gcc -L/lib/hppa-linux-gnu -L/usr/lib/hppa-linux-gnu run-ld.o -lm -v -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /home/dave/gnu/gcc/objdir/gcc/crtendS.o /usr/lib/hppa-linux-gnu/crtn.o -pie

As far as I can tell, the tls_ld and tls_ld2 variables are not linked correctly.
When it is linked correctly, I see the following:

Breakpoint 1, __GI___tls_get_addr (ti=0x41001214) at dl-tls.c:825
825     dl-tls.c: No such file or directory.
(gdb) x/2x $r26
0x41001214:     0x00000001      0x00000000
(gdb) c
Continuing.

Breakpoint 1, __GI___tls_get_addr (ti=0x41001200) at dl-tls.c:825
825     in dl-tls.c
(gdb) x/2x $r26
0x41001200:     0x00000001      0x00000004

With Debian 2.30, I see:

Starting program: /home/dave/gnu/gcc/objdir/gcc/testsuite/gcc/run-ld.exe

Breakpoint 1, __GI___tls_get_addr (ti=0x4100121c) at dl-tls.c:825
825     dl-tls.c: No such file or directory.
(gdb) x/2x $r26
0x4100121c:     0x00000001      0x00000000
(gdb) c
Continuing.

Breakpoint 1, __GI___tls_get_addr (ti=0x41001208) at dl-tls.c:825
825     in dl-tls.c
(gdb) x/2x $r26
0x41001208:     0x00000001      0x00000000
Comment 1 Alan Modra 2018-04-19 01:53:54 UTC
Created attachment 10959 [details]
fix

I believe this should cure the problem
Comment 2 Alan Modra 2018-04-19 09:42:55 UTC
Well it should have fixed the bug, but we then hit a glibc bug.  R_PARISC_TLS_DTPOFF32 addend is ignored.  :-(

When generating an executable it is possible to omit both of R_PARISC_TLS_DTPMOD32 and R_PARISC_TLS_DTPOFF32 dynamic relocs for local tls symbols, and it's also possible to omit R_PARISC_TLS_DTPOFF32 in shared libraries for local tls symbols.  So I'm going to have to implement that little optimisation for hppa..
Comment 3 Sourceware Commits 2018-04-20 13:51:04 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=4352556b36ab4f1c6f81a0ac3daf4619a419558d

commit 4352556b36ab4f1c6f81a0ac3daf4619a419558d
Author: Alan Modra <amodra@gmail.com>
Date:   Thu Apr 19 11:19:35 2018 +0930

    PR22978, TLS local-dynamic incorrectly linked on hppa-linux
    
    We were emitting dynamic relocs on the second word of a TLS GD GOT
    entry pair (the dtprel offset), without the addend necessary when no
    symbol is present on the dynamic reloc.  Unfortunately the simple
    solution of providing the proper addend doesn't work due to an hppa
    glibc ld.so bug that ignores such addends.  So instead optimize the
    relocs.  The dtprel offset is known at link time for locally defined
    symbols (the only case where we'll end up with no symbol on a dynamic
    reloc) so we can omit the dynamic reloc in that case.
    
    Furthermore, we can omit a dynamic reloc on the first word of a TLS GD
    GOT entry pair (the module id) if the symbol is local and we are
    producing an executable.  Similarly, a tprel reloc on a TLS IE GOT
    entry is not needed for local symbols in an executable.  So the
    condition for TLS GOT relocs can become bfd_link_dll(info) rather than
    bfd_link_pic(info) as needed for normal GOT relocs.
    
    This all presumes hppa ld.so doesn't need to differentiate TLS GD GOT
    pairs from TLS LD GOT pairs, which is currently true.
    
    	PR 22978
    	* elf32-hppa.c (got_relocs_needed): Add extra param to special
    	case both dtprel and tprel relocs.
    	(allocate_dynrelocs): Adjust conditions for got relocs.
    	(elf32_hppa_relocate_section): Likewise for local sym got relocs.
    	Emit dynamic relocs on TLS GOT entries for shared libraries,
    	not when pic.  Omit dynamic reloc on dtprel entry when local,
    	and on tprel entry when local and executable.
Comment 4 Alan Modra 2018-04-20 14:00:26 UTC
Patch applied.