Hi,

The problem comes from a quirk of the GNU PE-COFF linker, which wants to make 
sure that .tls$ZZZ is laid out last among the TLS sections, but first globs 
all .tls$* sections together.  The solution reportedly matches Clang's output.

Tested on x86_64-w64-mingw32, OK for the mainline?


2025-12-04  Eric Botcazou  <[email protected]>

        PR target/80881
        * config/mingw/winnt.cc (mingw_pe_unique_section): Put two dollar
        signs for TLS sections after the prefix.
        (mingw_pe_asm_named_section): Deal with all TLS sections uniformly.


2025-12-04  Eric Botcazou  <[email protected]>

        * gcc.dg/tls/data-sections-1.c: New test.
        
-- 
Eric Botcazou
diff --git a/gcc/config/mingw/winnt.cc b/gcc/config/mingw/winnt.cc
index b51fd8e9cc6..6a363dcd4bd 100644
--- a/gcc/config/mingw/winnt.cc
+++ b/gcc/config/mingw/winnt.cc
@@ -446,8 +446,11 @@ mingw_pe_unique_section (tree decl, int reloc)
     prefix = ".text$";
   else if (decl_readonly_section (decl, reloc))
     prefix = ".rdata$";
+  /* Note that we need two dollar signs for TLS sections
+     because they need to be ASCII-sorted before .tls$ZZZ
+     to be properly laid out by the GNU linker.  */
   else if (DECL_THREAD_LOCAL_P (decl))
-    prefix = ".tls$";
+    prefix = ".tls$$";
   else
     prefix = ".data$";
   len = strlen (name) + strlen (prefix);
@@ -522,9 +525,6 @@ mingw_pe_asm_named_section (const char *name, unsigned int flags,
     *f++ = 'e';
 #endif
 
-  if (strcmp (name, ".tls$") == 0)
-    *f++ = 'd';
-
   if ((flags & (SECTION_CODE | SECTION_WRITE)) == 0)
     /* readonly data */
     {
@@ -533,6 +533,8 @@ mingw_pe_asm_named_section (const char *name, unsigned int flags,
     }
   else
     {
+      if (startswith (name, ".tls$"))
+        *f++ = 'd';
       if (flags & SECTION_CODE)
         *f++ = 'x';
       if (flags & SECTION_WRITE)
/* { dg-do run } */
/* { dg-require-effective-target tls_runtime } */
/* { dg-options "-fdata-sections" } */
/* { dg-add-options tls } */

__thread int i = 1;

int main (void)
{
  if (i != 1)
    __builtin_abort ();

  return 0;
}

Reply via email to