bug-binutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Bug ld/23825] Linker creates COPY relocs for reference to TLS symbols


From: wilson at gcc dot gnu.org
Subject: [Bug ld/23825] Linker creates COPY relocs for reference to TLS symbols
Date: Sun, 01 Sep 2019 03:50:27 +0000

https://sourceware.org/bugzilla/show_bug.cgi?id=23825

--- Comment #3 from Jim Wilson <wilson at gcc dot gnu.org> ---
I got an internal bug report with a simplified testcase related to this, took
another look, and found the problem.

hifiveu017:1097$ cat tmp.c
#include <stdio.h>
extern __thread int a;
int main (void) {printf ("a = %d\n", a); return 0; }
hifiveu017:1097$ cat tmp2.c
__thread int a = 10;
hifiveu017:1098$ gcc --shared -fpic -o libtmp.so tmp2.c
hifiveu017:1099$ gcc tmp.c libtmp.so -Wl,--rpath=`pwd`
hifiveu017:1100$ ./a.out
Segmentation fault (core dumped)
hifiveu017:1101$ 

Running objdump on a.out, we see

 15 .tdata        00000004  0000000000011df8  0000000000011df8  00000df8  2**2
                  ALLOC, THREAD_LOCAL
 16 .preinit_array 00000008  0000000000011df8  0000000000011df8  00000df8  2**0
                  CONTENTS, ALLOC, LOAD, DATA

So the problem here is that tdata has a size, and is alloc, but the next
section preinit_array starts at the same address as tdata which is wrong.

I tracked this down a bit of code in ld/ldlang.c which does

            /* .tbss sections effectively have zero size.  */
            if (!IS_TBSS (os->bfd_section)
                || bfd_link_relocatable (&link_info))
              dotdelta = TO_ADDR (os->bfd_section->size);
            else
              dotdelta = 0;
            dot += dotdelta;

This may be right for .tbss, but is not right for the RISC-V .tdata section. 
The RISC-V .tdata section ended up this way because we have code in
bfd/elfnn-riscv.c that does

      htab->sdyntdata =
        bfd_make_section_anyway_with_flags (dynobj, ".tdata.dyn",
                                            (SEC_ALLOC | SEC_THREAD_LOCAL
                                             | SEC_LINKER_CREATED));

So if there is a .tdata.dyn section and no .tdata section, .tdata.dyn gets
merged into .tdata and .tdata ends up looking like a .tbss section and gets
handled wrong by the linker.

There is also a second problem here, which is that a bss-like section can only
work at the end of a segment, but there is no code in the linker script to
ensure that .tdata.dyn ends up at the end of a segment.  It is is just mixed in
with the other .tdata.* sections, with no guarantee that it is the last one.

I think the solution to this is to just claim that .tdata.dyn has contents, to
ensure that space is allocated for it.  Normally, it is only used as a target
for copy relocs, and hence has no contents, but this causes multiple problems. 
This section will normally be small, so I don't think there is much performance
loss from just pretending that it has contents.  I have a patch that does this,
and it fixes my testcase, and elf/tst-tls12 from glibc.

-- 
You are receiving this mail because:
You are on the CC list for the bug.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]