https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64697

jon.turney at dronecode dot org.uk changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jon.turney at dronecode dot 
org.uk

--- Comment #21 from jon.turney at dronecode dot org.uk ---
I looked into this a bit, as gdb 9.0 now uses thread_local in a way which trips
over this.

I came up with a slightly simpler reproduction:

$ cat def.h

extern thread_local int tlv;

$ cat def.cc

#include "def.h"

thread_local int tlv;

$ cat use.cc

#include "def.h"

int main()
{
  tlv = 1;
}

$ x86_64-pc-cygwin-gcc def.cc use.cc --save-temps
/tmp/ccMAKHhL.o:use.cc:(.text$_ZTW3tlv[_ZTW3tlv]+0x15): relocation truncated to
fit: R_X86_64_PC32 against undefined symbol `TLS init function for tlv'
collect2: error: ld returned 1 exit status

This compiles without error with x86_64-w64-mingw32-gcc.

Looking at use.s:

        .file   "use.cc"
        .text
        .section        .text$_ZTW3tlv,"x"
        .linkonce discard
        .globl  _ZTW3tlv
        .def    _ZTW3tlv;       .scl    2;      .type   32;     .endef
        .seh_proc       _ZTW3tlv
_ZTW3tlv:
.LFB1:
        pushq   %rbp
        .seh_pushreg    %rbp
        movq    %rsp, %rbp
        .seh_setframe   %rbp, 0
        subq    $32, %rsp
        .seh_stackalloc 32
        .seh_endprologue
        movq    .refptr._ZTH3tlv(%rip), %rax
        testq   %rax, %rax
        je      .L2
        call    _ZTH3tlv
.L2:
        movq    .refptr.__emutls_v.tlv(%rip), %rcx
        call    __emutls_get_address
        addq    $32, %rsp
        popq    %rbp
        ret
        .seh_endproc
        .def    __main; .scl    2;      .type   32;     .endef
        .text
        .globl  main
        .def    main;   .scl    2;      .type   32;     .endef
        .seh_proc       main
main:
.LFB0:
        pushq   %rbp
        .seh_pushreg    %rbp
        movq    %rsp, %rbp
        .seh_setframe   %rbp, 0
        subq    $32, %rsp
        .seh_stackalloc 32
        .seh_endprologue
        call    __main
        call    _ZTW3tlv
        movl    $1, (%rax)
        movl    $0, %eax
        addq    $32, %rsp
        popq    %rbp
        ret
        .seh_endproc
        .weak   _ZTH3tlv
        .ident  "GCC: (GNU) 7.4.0"
        .def    _ZTH3tlv;       .scl    2;      .type   32;     .endef
        .def    __emutls_get_address;   .scl    2;      .type   32;     .endef
        .section        .rdata$.refptr.__emutls_v.tlv, "dr"
        .globl  .refptr.__emutls_v.tlv
        .linkonce       discard
.refptr.__emutls_v.tlv:
        .quad   __emutls_v.tlv
        .section        .rdata$.refptr._ZTH3tlv, "dr"
        .globl  .refptr._ZTH3tlv
        .linkonce       discard
.refptr._ZTH3tlv:
        .quad   _ZTH3tlv

The problem seems to be in the TLS wrapper function (_ZTW3tlv):

[...]
        movq    .refptr._ZTH3tlv(%rip), %rax
        testq   %rax, %rax
        je      .L2
        call    _ZTH3tlv
[...]
        .weak   _ZTH3tlv
[...]
.refptr._ZTH3tlv:
        .quad   _ZTH3tlv

The call here is to absolute address 0 (since the weak symbol has no other
defintion), which is encoded relative to %rip.  This requires a relocation, and
the relative offset can't be contained in 32 signed bits, if the ImageBase is
>2GB.

As some confirmation of this analysis, this problem can be shown with
x86_64-w64-mingw32-gcc, if the ImageBase is altered from 0x40 0000 (the default
for that) to 0x1 0040 00000 (the default for x86_64 Cygwin)

$ x86_64-w64-mingw32-gcc def.cc use.cc -Wl,--image-base,0x100400000
/tmp/cc3XRN6L.o:use.cc:(.text$_ZTW3tlv[_ZTW3tlv]+0x15): relocation truncated to
fit: R_X86_64_PC32 against undefined symbol `TLS init function for tlv'
collect2: error: ld returned 1 exit status

Naively, I think this could be fixed by generating code which indirects the
call through the pseudo-reloc, but I'm not sure that makes sense.

Reply via email to