https://gcc.gnu.org/g:3777a0b41f9fdcbb5fde4bdfce06031805cebc33

commit r16-5965-g3777a0b41f9fdcbb5fde4bdfce06031805cebc33
Author: Eric Botcazou <[email protected]>
Date:   Mon Dec 8 17:47:56 2025 +0100

    MinGW: Fix native TLS bug with -fdata-sections
    
    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 matches
    Clang's output.
    
    gcc/
            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.
    
    gcc/testsuite/
            * gcc.dg/tls/data-sections-1.c: New test.

Diff:
---
 gcc/config/mingw/winnt.cc                  | 10 ++++++----
 gcc/testsuite/gcc.dg/tls/data-sections-1.c | 14 ++++++++++++++
 2 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/gcc/config/mingw/winnt.cc b/gcc/config/mingw/winnt.cc
index b51fd8e9cc6a..fe2fb4cb267f 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)
diff --git a/gcc/testsuite/gcc.dg/tls/data-sections-1.c 
b/gcc/testsuite/gcc.dg/tls/data-sections-1.c
new file mode 100644
index 000000000000..c829256b0162
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tls/data-sections-1.c
@@ -0,0 +1,14 @@
+/* { 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