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.