]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
x86: Add GLIBC_ABI_GNU2_TLS version dependency
authorH.J. Lu <hjl.tools@gmail.com>
Fri, 4 Jul 2025 00:39:03 +0000 (08:39 +0800)
committerH.J. Lu <hjl.tools@gmail.com>
Wed, 20 Aug 2025 20:53:32 +0000 (13:53 -0700)
On Linux/x86, programs and shared libraries compiled with
-mtls-dialect=gnu2 may fail silently at run-time against glibc without
the GNU2 TLS run-time fixes for:

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

A version tag, GLIBC_ABI_GNU2_TLS, has been added to glibc to indicate
that glibc has the working GNU2 TLS run-time.  Add the --gnu2-tls-tag
option to i386/x86-64 ELF linker to add the GLIBC_ABI_GNU2_TLS version
dependency in output programs and shared libraries when linking against
glibc if input relocatable object files have R_386_TLS_DESC_CALL or
R_X86_64_TLSDESC_CALL relocation.  The output will fail to load and run
at run-time against glibc which doesn't define the GLIBC_ABI_GNU2_TLS
version.

Add the --enable-gnu2-tls-tag configure option to enable --gnu2-tls-tag
by default.  If unspecified, linker will add the GLIBC_ABI_GNU2_TLS
version dependency if input object files have R_386_TLS_DESC_CALL or
R_X86_64_TLSDESC_CALL relocation and libc.so defines the GLIBC_ABI_GNU2_TLS
version.

Update elf_link_add_glibc_verneed to properly add the GLIBC_2.36 version
dependency when -z mark-plt -z nopack-relative-relocs passed to x86-64
ELF linker.

bfd/

PR ld/33130
* elf-bfd.h (_bfd_elf_link_add_glibc_version_dependency): Add
a pointer to bool argument.
* elf-linker-x86.h (elf_linker_x86_params): Add
gnu2_tls_version_tag.
* elf32-i386.c (elf_i386_scan_relocs): Set has_tls_desc_call to
1 for R_386_TLS_DESC_CALL.
(elf_i386_add_glibc_version_dependency): New.  Undef before
FreeBSD support.
* elf64-x86-64.c (elf_x86_64_scan_relocs): Set has_tls_desc_call
to 1 for R_X86_64_TLSDESC_CALL.
(elf_x86_64_add_glibc_version_dependency): Add GLIBC_ABI_GNU2_TLS
version dependency if GLIBC_ABI_GNU2_TLS dependency isn't disabled
and has_tlsdesc_call isn't 0.
(elf_backend_add_glibc_version_dependency): Undef before FreeBSD
support and redefine for elf32-x86-64.
* elflink.c (elf_link_add_glibc_verneed): Changed to return bool.
Remove the pointer to elf_find_verdep_info argument.  Add a
pointer to bool argument, auto_version. Return true if linked
against glibc.  Otherwise return false.  If the version dependency
is added, set *auto_version to true.  If *auto_version is true,
add the version dependency only if libc.so defines the version.
(_bfd_elf_link_add_glibc_version_dependency): Add a pointer to
bool argument and pass it to elf_link_add_glibc_verneed.
(_bfd_elf_link_add_dt_relr_dependency): Pass NULL to
_bfd_elf_link_add_glibc_version_dependency.
* elfxx-x86.h (elf_x86_link_hash_table): Add has_tls_desc_call.

ld/

PR ld/33130
* NEWS: Mention --gnu2-tls-tag, --no-gnu2-tls-tag and
--enable-gnu2-tls-tag.
* config.in: Regenerated.
* configure: Likewise.
* configure.ac: Add --enable-gnu2-tls-tag.
* ld.texi: Document --gnu2-tls-tag/--no-gnu2-tls-tag.
* ldlex.h (option_values): Add OPTION_GNU2_TLS_VERSION_TAG and
OPTION_NO_GNU2_TLS_VERSION_TAG.
* emulparams/elf32_x86_64.sh (EXTRA_EM_FILE): Changed to
"elf-x86-64-glibc".
* emulparams/elf_i386.sh (EXTRA_EM_FILE): Set to "elf-i386-glibc".
* emulparams/elf_i386_fbsd.sh (EXTRA_EM_FILE): New.  Set to
"elf-x86".
        * emulparams/elf_i386_haiku.sh (EXTRA_EM_FILE): Likewise.
* emulparams/elf_x86_64.sh (EXTRA_EM_FILE): Likewise.
* emulparams/elf_x86_64_fbsd.sh (EXTRA_EM_FILE): New.  Set to
"elf-x86-64".
* emulparams/elf_x86_64_haiku.sh (EXTRA_EM_FILE): Likewise.
* (EXTRA_EM_FILE): Likewise.
* (EXTRA_EM_FILE): Likewise.
        * emultempl/elf-i386-glibc.em: New file.
* emultempl/elf-x86-64-glibc.em: Likewise.
* emultempl/elf-x86-64.em: Likewise.
* emultempl/elf-x86-glibc.em: Likewise.
* emultempl/elf-x86.em (elf_x86_64_before_parse): Removed.
(LDEMUL_BEFORE_PARSE): Likewise.
(elf_x86_64_before_allocation): Likewise.
(LDEMUL_BEFORE_ALLOCATION): Likewise.
* emultempl/solaris2-x86-64.em: New file.
* testsuite/ld-i386/gnu2-tls-1.s: Likewise.
* testsuite/ld-i386/gnu2-tls-1a.rd: Likewise.
* testsuite/ld-i386/gnu2-tls-1b.rd: Likewise.
* testsuite/ld-x86-64/gnu2-tls-1.s: Likewise.
* testsuite/ld-x86-64/gnu2-tls-1a.rd: Likewise.
* testsuite/ld-x86-64/gnu2-tls-1b.rd: Likewise.
* testsuite/ld-x86-64/mark-plt-2.rd: Likewise.
* testsuite/ld-x86-64/mark-plt-2.s: Likewise.
* testsuite/ld-i386/i386.exp: Run GLIBC_ABI_GNU2_TLS tests.
* testsuite/ld-x86-64/x86-64.exp: Likewise.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
35 files changed:
bfd/elf-bfd.h
bfd/elf-linker-x86.h
bfd/elf32-i386.c
bfd/elf64-x86-64.c
bfd/elflink.c
bfd/elfxx-x86.h
ld/NEWS
ld/config.in
ld/configure
ld/configure.ac
ld/emulparams/elf32_x86_64.sh
ld/emulparams/elf_i386.sh
ld/emulparams/elf_i386_fbsd.sh
ld/emulparams/elf_i386_haiku.sh
ld/emulparams/elf_x86_64.sh
ld/emulparams/elf_x86_64_fbsd.sh
ld/emulparams/elf_x86_64_haiku.sh
ld/emultempl/elf-i386-glibc.em [new file with mode: 0644]
ld/emultempl/elf-x86-64-glibc.em [new file with mode: 0644]
ld/emultempl/elf-x86-64.em [new file with mode: 0644]
ld/emultempl/elf-x86-glibc.em [new file with mode: 0644]
ld/emultempl/elf-x86.em
ld/emultempl/solaris2-x86-64.em [new file with mode: 0644]
ld/ld.texi
ld/ldlex.h
ld/testsuite/ld-i386/gnu2-tls-1.s [new file with mode: 0644]
ld/testsuite/ld-i386/gnu2-tls-1a.rd [new file with mode: 0644]
ld/testsuite/ld-i386/gnu2-tls-1b.rd [new file with mode: 0644]
ld/testsuite/ld-i386/i386.exp
ld/testsuite/ld-x86-64/gnu2-tls-1.s [new file with mode: 0644]
ld/testsuite/ld-x86-64/gnu2-tls-1a.rd [new file with mode: 0644]
ld/testsuite/ld-x86-64/gnu2-tls-1b.rd [new file with mode: 0644]
ld/testsuite/ld-x86-64/mark-plt-2.rd [new file with mode: 0644]
ld/testsuite/ld-x86-64/mark-plt-2.s [new file with mode: 0644]
ld/testsuite/ld-x86-64/x86-64.exp

index accdd6d41a8a7c99ea277321a2d00bcef0cff799..feb470fc4775c5706b4e4c624a910cfe05816211 100644 (file)
@@ -2632,7 +2632,7 @@ extern bool _bfd_elf_link_output_relocs
    struct elf_link_hash_entry **);
 
 extern void _bfd_elf_link_add_glibc_version_dependency
-  (struct elf_find_verdep_info *, const char *const []);
+  (struct elf_find_verdep_info *, const char *const [], bool *);
 
 extern void _bfd_elf_link_add_dt_relr_dependency
   (struct elf_find_verdep_info *);
index 2c98257038fc67a1b3d19c6c4f03b33e2640f8d6..fe322152e1400ac1c173cab1596b4a74e9b2493b 100644 (file)
@@ -72,6 +72,14 @@ struct elf_linker_x86_params
   /* Mark PLT with dynamic tags.  */
   unsigned int mark_plt : 1;
 
+  /* Add the GLIBC_ABI_GNU2_TLS version dependency if input object files
+     have R_386_TLS_DESC_CALL or R_X86_64_TLSDESC_CALL relocation:
+     0: Disable.
+     1: Enable.
+     2: Auto.  Enable if libc.so has the GLIBC_ABI_GNU2_TLS version.
+   */
+  unsigned int gnu2_tls_version_tag : 2;
+
   /* X86-64 ISA level needed.  */
   unsigned int isa_level;
 
index b755b39ab55c5c36cca6b90959205fa299dbd0ab..9d06f1494cf43e413f349310b30ee1c603fe2a52 100644 (file)
@@ -1687,6 +1687,10 @@ elf_i386_scan_relocs (bfd *abfd,
          size_reloc = true;
          goto do_size;
 
+       case R_386_TLS_DESC_CALL:
+         htab->has_tls_desc_call = 1;
+         goto need_got;
+
        case R_386_TLS_IE_32:
        case R_386_TLS_IE:
        case R_386_TLS_GOTIE:
@@ -1698,7 +1702,7 @@ elf_i386_scan_relocs (bfd *abfd,
        case R_386_GOT32X:
        case R_386_TLS_GD:
        case R_386_TLS_GOTDESC:
      case R_386_TLS_DESC_CALL:
need_got:
          /* This symbol requires a global offset table entry.  */
          {
            int tls_type, old_tls_type;
@@ -4492,6 +4496,40 @@ elf_i386_link_setup_gnu_properties (struct bfd_link_info *info)
   return _bfd_x86_elf_link_setup_gnu_properties (info, &init_table);
 }
 
+static void
+elf_i386_add_glibc_version_dependency
+  (struct elf_find_verdep_info *rinfo)
+{
+  int i = 0;
+  const char *version[3] = { NULL, NULL, NULL };
+  bool auto_version[3] = { false, false, false };
+  struct elf_x86_link_hash_table *htab;
+
+  if (rinfo->info->enable_dt_relr)
+    {
+      version[i] = "GLIBC_ABI_DT_RELR";
+      i++;
+    }
+
+  htab = elf_x86_hash_table (rinfo->info, I386_ELF_DATA);
+  if (htab != NULL)
+    {
+      if (htab->params->gnu2_tls_version_tag && htab->has_tls_desc_call)
+       {
+         version[i] = "GLIBC_ABI_GNU2_TLS";
+         /* 2 == auto, enable if libc.so defines the GLIBC_ABI_GNU2_TLS
+            version.  */
+         if (htab->params->gnu2_tls_version_tag == 2)
+           auto_version[i] = true;
+         i++;
+       }
+    }
+
+  if (i != 0)
+    _bfd_elf_link_add_glibc_version_dependency (rinfo, version,
+                                               auto_version);
+}
+
 #define TARGET_LITTLE_SYM              i386_elf32_vec
 #define TARGET_LITTLE_NAME             "elf32-i386"
 #define ELF_ARCH                       bfd_arch_i386
@@ -4532,6 +4570,8 @@ elf_i386_link_setup_gnu_properties (struct bfd_link_info *info)
 #define elf_backend_relocate_section         elf_i386_relocate_section
 #define elf_backend_setup_gnu_properties      elf_i386_link_setup_gnu_properties
 #define elf_backend_hide_symbol                      _bfd_x86_elf_hide_symbol
+#define elf_backend_add_glibc_version_dependency \
+  elf_i386_add_glibc_version_dependency
 
 #define elf_backend_linux_prpsinfo32_ugid16    true
 
@@ -4539,6 +4579,8 @@ elf_i386_link_setup_gnu_properties (struct bfd_link_info *info)
 
 #include "elf32-target.h"
 
+#undef elf_backend_add_glibc_version_dependency
+
 /* FreeBSD support.  */
 
 #undef TARGET_LITTLE_SYM
index 3ffeff9cd105950b0b6ae3b928b0b02e352fcbaa..352dca65fdd1ae92f348a15d1732fae7fb6c3be5 100644 (file)
@@ -2694,6 +2694,10 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info,
            eh->zero_undefweak &= 0x2;
          break;
 
+       case R_X86_64_TLSDESC_CALL:
+         htab->has_tls_desc_call = 1;
+         goto need_got;
+
        case R_X86_64_GOTTPOFF:
        case R_X86_64_CODE_4_GOTTPOFF:
        case R_X86_64_CODE_5_GOTTPOFF:
@@ -2715,7 +2719,7 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_X86_64_GOTPLT64:
        case R_X86_64_GOTPC32_TLSDESC:
        case R_X86_64_CODE_4_GOTPC32_TLSDESC:
-       case R_X86_64_TLSDESC_CALL:
+need_got:
          /* This symbol requires a global offset table entry.  */
          {
            int tls_type, old_tls_type;
@@ -6243,7 +6247,8 @@ elf_x86_64_add_glibc_version_dependency
   (struct elf_find_verdep_info *rinfo)
 {
   unsigned int i = 0;
-  const char *version[3] = { NULL, NULL, NULL };
+  const char *version[4] = { NULL, NULL, NULL, NULL };
+  bool auto_version[4] = { false, false, false, false };
   struct elf_x86_link_hash_table *htab;
 
   if (rinfo->info->enable_dt_relr)
@@ -6253,14 +6258,27 @@ elf_x86_64_add_glibc_version_dependency
     }
 
   htab = elf_x86_hash_table (rinfo->info, X86_64_ELF_DATA);
-  if (htab != NULL && htab->params->mark_plt)
+  if (htab != NULL)
     {
-      version[i] = "GLIBC_2.36";
-      i++;
+      if (htab->params->gnu2_tls_version_tag && htab->has_tls_desc_call)
+       {
+         version[i] = "GLIBC_ABI_GNU2_TLS";
+         /* 2 == auto, enable if libc.so defines the GLIBC_ABI_GNU2_TLS
+            version.  */
+         if (htab->params->gnu2_tls_version_tag == 2)
+           auto_version[i] = true;
+         i++;
+       }
+      if (htab->params->mark_plt)
+       {
+         version[i] = "GLIBC_2.36";
+         i++;
+       }
     }
 
   if (i != 0)
-    _bfd_elf_link_add_glibc_version_dependency (rinfo, version);
+    _bfd_elf_link_add_glibc_version_dependency (rinfo, version,
+                                               auto_version);
 }
 
 static const struct bfd_elf_special_section
@@ -6355,6 +6373,8 @@ elf_x86_64_special_sections[]=
 
 #include "elf64-target.h"
 
+#undef elf_backend_add_glibc_version_dependency
+
 /* FreeBSD support.  */
 
 #undef TARGET_LITTLE_SYM
@@ -6464,6 +6484,10 @@ elf64_x86_64_copy_solaris_special_section_fields (const bfd *ibfd ATTRIBUTE_UNUS
 #define elf_backend_bfd_from_remote_memory \
   _bfd_elf32_bfd_from_remote_memory
 
+#undef elf_backend_add_glibc_version_dependency
+#define elf_backend_add_glibc_version_dependency \
+  elf_x86_64_add_glibc_version_dependency
+
 #undef elf_backend_size_info
 #define elf_backend_size_info \
   _bfd_elf32_size_info
index f6c0c04e82e0c190fb9a8cf18b42f4895ab46733..d2c43f31bf5c0dd9959a8d03e8e8d71c9fd42762 100644 (file)
@@ -2281,68 +2281,85 @@ _bfd_elf_export_symbol (struct elf_link_hash_entry *h, void *data)
   return true;
 }
 \f
-/* Return the glibc version reference if VERSION_DEP is added to the
-   list of glibc version dependencies successfully.  VERSION_DEP will
-   be put into the .gnu.version_r section.  GLIBC_MINOR_BASE is the
-   pointer to the glibc minor base version.  */
+/* Return true if linked against glibc.  Otherwise return false.  If
+   linked against glibc, add VERSION_DEP to the list of glibc version
+   dependencies and set *AUTO_VERSION to true.  If *AUTO_VERSION is
+   true, add VERSION_DEP to the version dependency list only if libc.so
+   defines VERSION_DEP.  GLIBC_MINOR_BASE is the pointer to the glibc
+   minor base version.  */
 
-static Elf_Internal_Verneed *
+static bool
 elf_link_add_glibc_verneed (struct elf_find_verdep_info *rinfo,
-                           Elf_Internal_Verneed *glibc_verref,
                            const char *version_dep,
-                           int *glibc_minor_base)
+                           int *glibc_minor_base,
+                           bool *auto_version)
 {
   Elf_Internal_Verneed *t;
   Elf_Internal_Vernaux *a;
   size_t amt;
   int minor_version = -1;
+  bool added = false;
+  bool glibc = false;
 
-  if (glibc_verref != NULL)
+  for (t = elf_tdata (rinfo->info->output_bfd)->verref;
+       t != NULL;
+       t = t->vn_nextref)
     {
-      t = glibc_verref;
+      const char *soname = bfd_elf_get_dt_soname (t->vn_bfd);
+      if (soname != NULL && startswith (soname, "libc.so."))
+       break;
+    }
 
-      for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
+  /* Skip the shared library if it isn't libc.so.  */
+  if (t == NULL)
+    goto update_auto_version_and_return;
+
+  for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
+    {
+      /* Return if VERSION_DEP dependency has been added.  */
+      if (a->vna_nodename == version_dep
+         || strcmp (a->vna_nodename, version_dep) == 0)
        {
-         /* Return if VERSION_DEP dependency has been added.  */
-         if (a->vna_nodename == version_dep
-             || strcmp (a->vna_nodename, version_dep) == 0)
-           return t;
+         glibc = true;
+         goto update_auto_version_and_return;
        }
-    }
-  else
-    {
-      for (t = elf_tdata (rinfo->info->output_bfd)->verref;
-          t != NULL;
-          t = t->vn_nextref)
+
+      /* Check if libc.so provides GLIBC_2.XX version.  */
+      if (startswith (a->vna_nodename, "GLIBC_2."))
        {
-         const char *soname = bfd_elf_get_dt_soname (t->vn_bfd);
-         if (soname != NULL && startswith (soname, "libc.so."))
-           break;
+         minor_version = strtol (a->vna_nodename + 8, NULL, 10);
+         if (minor_version < *glibc_minor_base)
+           *glibc_minor_base = minor_version;
        }
+    }
 
-      /* Skip the shared library if it isn't libc.so.  */
-      if (t == NULL)
-       return t;
+  /* Skip if it isn't linked against glibc.  */
+  if (minor_version < 0)
+    goto update_auto_version_and_return;
 
-      for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
-       {
-         /* Return if VERSION_DEP dependency has been added.  */
-         if (a->vna_nodename == version_dep
-             || strcmp (a->vna_nodename, version_dep) == 0)
-           return t;
+  glibc = true;
 
-         /* Check if libc.so provides GLIBC_2.XX version.  */
-         if (startswith (a->vna_nodename, "GLIBC_2."))
-           {
-             minor_version = strtol (a->vna_nodename + 8, NULL, 10);
-             if (minor_version < *glibc_minor_base)
-               *glibc_minor_base = minor_version;
-           }
-       }
+  if (auto_version && *auto_version)
+    {
+      /* Add VERSION_DEP to the version dependency list only if
+        libc.so defines VERSION_DEP.  */
 
-      /* Skip if it isn't linked against glibc.  */
-      if (minor_version < 0)
-       return NULL;
+      bool defined = false;
+      Elf_Internal_Verdef *d;
+
+      for (d = elf_tdata (t->vn_bfd)->verdef;
+          d != NULL;
+          d = d->vd_nextdef)
+       if (strcmp (d->vd_nodename, version_dep) == 0)
+         {
+           defined = true;
+           break;
+         }
+
+      /* Set *AUTO_VERSION to false and return true to indicate that
+        libc.so doesn't define VERSION_DEP.  */
+      if (!defined)
+       goto update_auto_version_and_return;
     }
 
   /* Skip if 2.GLIBC_MINOR_BASE includes VERSION_DEP.  */
@@ -2350,7 +2367,7 @@ elf_link_add_glibc_verneed (struct elf_find_verdep_info *rinfo,
     {
       minor_version = strtol (version_dep + 8, NULL, 10);
       if (minor_version <= *glibc_minor_base)
-       return NULL;
+       goto update_auto_version_and_return;
     }
 
   amt = sizeof *a;
@@ -2358,7 +2375,8 @@ elf_link_add_glibc_verneed (struct elf_find_verdep_info *rinfo,
   if (a == NULL)
     {
       rinfo->failed = true;
-      return NULL;
+      glibc = false;
+      goto update_auto_version_and_return;
     }
 
   a->vna_nodename = version_dep;
@@ -2369,7 +2387,13 @@ elf_link_add_glibc_verneed (struct elf_find_verdep_info *rinfo,
 
   t->vn_auxptr = a;
 
-  return t;
+  added = true;
+
+ update_auto_version_and_return:
+  if (auto_version)
+    *auto_version = added;
+
+  return glibc;
 }
 
 /* Add VERSION_DEP to the list of version dependencies when linked
@@ -2378,19 +2402,19 @@ elf_link_add_glibc_verneed (struct elf_find_verdep_info *rinfo,
 void
 _bfd_elf_link_add_glibc_version_dependency
   (struct elf_find_verdep_info *rinfo,
-   const char *const version_dep[])
+   const char *const version_dep[],
+   bool *auto_version)
 {
-  Elf_Internal_Verneed *t = NULL;
   int glibc_minor_base = INT_MAX;
 
   do
     {
-      t = elf_link_add_glibc_verneed (rinfo, t, *version_dep,
-                                     &glibc_minor_base);
-      /* Return if there is no glibc version reference.  */
-      if (t == NULL)
+      /* Return if not linked against glibc.  */
+      if (!elf_link_add_glibc_verneed (rinfo, *version_dep,
+                                      &glibc_minor_base, auto_version))
        return;
       version_dep++;
+      auto_version++;
     }
   while (*version_dep != NULL);
 }
@@ -2408,7 +2432,7 @@ _bfd_elf_link_add_dt_relr_dependency (struct elf_find_verdep_info *rinfo)
          "GLIBC_ABI_DT_RELR",
          NULL
        };
-      _bfd_elf_link_add_glibc_version_dependency (rinfo, version);
+      _bfd_elf_link_add_glibc_version_dependency (rinfo, version, NULL);
     }
 }
 
index f6ee6a6535674df64eadbd4799ff5f47025b4c53..791a2a2592f4a07eaa71f946baf566309eff8e7b 100644 (file)
@@ -670,6 +670,10 @@ struct elf_x86_link_hash_table
   /* Number of relative reloc generation pass.  */
   unsigned int generate_relative_reloc_pass;
 
+  /* TRUE if inputs have R_386_TLS_DESC_CALL or R_X86_64_TLSDESC_CALL
+     relocation.  */
+  unsigned int has_tls_desc_call : 1;
+
    /* Value used to fill the unused bytes of the first PLT entry.  This
       is only used for i386.  */
   bfd_byte plt0_pad_byte;
diff --git a/ld/NEWS b/ld/NEWS
index 54c1df5aadf1a1f13702ac15d29d3a62adf19e25..bacabc8440e376b21fbc97c9dd9b8a5b00bd02d4 100644 (file)
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,11 @@
 -*- text -*-
 
+* Add --gnu2-tls-tag/--no-gnu2-tls-tag options to i386 and x86-64 ELF
+  linkers to add the GLIBC_ABI_GNU2_TLS version dependency in output if
+  input object files have R_386_TLS_DESC_CALL or R_X86_64_TLSDESC_CALL
+  relocation.  Also added --enable-gnu2-tls-tag configure option to
+  enable --gnu2-tls-tag by default.
+
 * NaCl target support is removed.
 
 Changes in 2.45:
index 37812241bd944e70bf0a89a69959af899b3480a2..64dbc3e0c8838573ff9c2515351a7996f389b18e 100644 (file)
    when a .note-GNU-stack section is missing. */
 #undef DEFAULT_LD_EXECSTACK
 
+/* Define to 1 if you want to enable --gnu2-tls-tag in ELF i386/x86-64 linker
+   by default. */
+#undef DEFAULT_LD_GNU2_TLS_TAG
+
 /* Define to 1 if you want to enable --rosegment in the ELF linker by default.
    */
 #undef DEFAULT_LD_ROSEGMENT
index 124b44182bc3e64750d32bdb6362621a64f94dbb..6f1a3559964bdfd84b0929265e1e5a44f9c19799 100755 (executable)
@@ -851,6 +851,7 @@ enable_textrel_check
 enable_separate_code
 enable_rosegment
 enable_mark_plt
+enable_gnu2_tls_tag
 enable_memory_seal
 enable_warn_execstack
 enable_error_execstack
@@ -1548,6 +1549,8 @@ Optional Features:
   --enable-separate-code  enable -z separate-code in ELF linker by default
   --enable-rosegment      enable --rosegment in the ELF linker by default
   --enable-mark-plt       enable -z mark-plt in ELF x86-64 linker by default
+  --enable-gnu2-tls-tag   enable --gnu2-tls-tag in ELF i386/x86-64 linker by
+                          default
   --enable-memory-seal    enable -z memory-seal in ELF linker by default
   --enable-warn-execstack enable warnings when creating an executable stack
   --enable-error-execstack
@@ -11514,7 +11517,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11517 "configure"
+#line 11520 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11620,7 +11623,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11623 "configure"
+#line 11626 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -15507,6 +15510,18 @@ esac
 fi
 
 
+# Decide if --gnu2-tls-tag should be enabled in ELF i386 and x86-64
+# linkers by default.
+ac_default_ld_enable_gnu2_tls_tag=unset
+# Check whether --enable-gnu2-tls-tag was given.
+if test "${enable_gnu2_tls_tag+set}" = set; then :
+  enableval=$enable_gnu2_tls_tag; case "${enableval}" in
+  yes) ac_default_ld_enable_gnu2_tls_tag=1 ;;
+  no) ac_default_ld_enable_gnu2_tls_tag=0 ;;
+esac
+fi
+
+
 # Decide if -z memory-seal should be enabled in ELF linker by default.
 ac_default_ld_z_memory_seal=unset
 # Check whether --enable-memory-seal was given.
@@ -18981,6 +18996,16 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
+if test "${ac_default_ld_enable_gnu2_tls_tag}" = unset; then
+  # Default to enable --gnu2-tls-tag if libc.so has the GLIBC_ABI_GNU2_TLS
+  # version.
+  ac_default_ld_enable_gnu2_tls_tag=2
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_LD_GNU2_TLS_TAG $ac_default_ld_enable_gnu2_tls_tag
+_ACEOF
+
 
 
 cat >>confdefs.h <<_ACEOF
index e306c1ded4afcea834eeb3b1970b80f58959a2cd..4b9068a415e1b19cea393a8bd19e9ff86cf6cac8 100644 (file)
@@ -245,6 +245,17 @@ AC_ARG_ENABLE(mark-plt,
   no) ac_default_ld_z_mark_plt=0 ;;
 esac])
 
+# Decide if --gnu2-tls-tag should be enabled in ELF i386 and x86-64
+# linkers by default.
+ac_default_ld_enable_gnu2_tls_tag=unset
+AC_ARG_ENABLE(gnu2-tls-tag,
+             AS_HELP_STRING([--enable-gnu2-tls-tag],
+             [enable --gnu2-tls-tag in ELF i386/x86-64 linker by default]),
+[case "${enableval}" in
+  yes) ac_default_ld_enable_gnu2_tls_tag=1 ;;
+  no) ac_default_ld_enable_gnu2_tls_tag=0 ;;
+esac])
+
 # Decide if -z memory-seal should be enabled in ELF linker by default.
 ac_default_ld_z_memory_seal=unset
 AC_ARG_ENABLE(memory-seal,
@@ -646,6 +657,14 @@ AC_DEFINE_UNQUOTED(DEFAULT_LD_Z_MEMORY_SEAL,
   $ac_default_ld_z_memory_seal,
   [Define to 1 if you want to enable -z memory_seal in ELF linker by default.])
 
+if test "${ac_default_ld_enable_gnu2_tls_tag}" = unset; then
+  # Default to enable --gnu2-tls-tag if libc.so has the GLIBC_ABI_GNU2_TLS
+  # version.
+  ac_default_ld_enable_gnu2_tls_tag=2
+fi
+AC_DEFINE_UNQUOTED(DEFAULT_LD_GNU2_TLS_TAG,
+  $ac_default_ld_enable_gnu2_tls_tag,
+  [Define to 1 if you want to enable --gnu2-tls-tag in ELF i386/x86-64 linker by default.])
 
 AC_DEFINE_UNQUOTED(DEFAULT_LD_WARN_EXECSTACK,
   $ac_default_ld_warn_execstack,
index 6a92eec129d9931a3c426941bce477c3be6eccb3..4db1a979058b6ee15b39020ebd3efeb1826af8a0 100644 (file)
@@ -20,7 +20,7 @@ COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)"
 ARCH="i386:x64-32"
 MACHINE=
 TEMPLATE_NAME=elf
-EXTRA_EM_FILE="elf-x86"
+EXTRA_EM_FILE="elf-x86-64-glibc"
 GENERATE_SHLIB_SCRIPT=yes
 GENERATE_PIE_SCRIPT=yes
 NO_SMALL_DATA=yes
index 6f698bb0b06ee130a346988f345c3fc0ab96899f..51a650f692e66f3999933eb01bee8e5691d12f63 100644 (file)
@@ -17,7 +17,7 @@ COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)"
 ARCH=i386
 MACHINE=
 TEMPLATE_NAME=elf
-EXTRA_EM_FILE="elf-x86"
+EXTRA_EM_FILE="elf-i386-glibc"
 GENERATE_SHLIB_SCRIPT=yes
 GENERATE_PIE_SCRIPT=yes
 NO_SMALL_DATA=yes
index d1d6604504adb607a551b92240e9766f5f946d26..d39a5cf882f33faf0bd0506d0e0537a859689069 100644 (file)
@@ -1,3 +1,4 @@
 source_sh ${srcdir}/emulparams/elf_i386.sh
 source_sh ${srcdir}/emulparams/elf_fbsd.sh
+EXTRA_EM_FILE="elf-x86"
 OUTPUT_FORMAT="elf32-i386-freebsd"
index 6c4001e4e05728e7028a30656841cc454d9f58ce..c931c0e3f91b1d4968b7af9e18a45334c1a57c25 100644 (file)
@@ -1,5 +1,6 @@
 source_sh ${srcdir}/emulparams/elf_i386.sh
 source_sh ${srcdir}/emulparams/elf_haiku.sh
+EXTRA_EM_FILE="elf-x86"
 TEXT_START_ADDR=0x200000
 NONPAGED_TEXT_START_ADDR=0x200000
 MAXPAGESIZE=0x1000
index 92449745c7a45023a90f4bffbe2724a6da8c2455..6e66f2e103596006f3d784d6efd1f5980882752d 100644 (file)
@@ -21,7 +21,7 @@ COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)"
 ARCH="i386:x86-64"
 MACHINE=
 TEMPLATE_NAME=elf
-EXTRA_EM_FILE="elf-x86"
+EXTRA_EM_FILE="elf-x86-64-glibc"
 GENERATE_SHLIB_SCRIPT=yes
 GENERATE_PIE_SCRIPT=yes
 NO_SMALL_DATA=yes
index 7ef974addca471a9ce8713238f6412d73ccf2695..17fdc83b075ea91187ed89ec0c3d9466f420495d 100644 (file)
@@ -1,3 +1,4 @@
 source_sh ${srcdir}/emulparams/elf_x86_64.sh
 source_sh ${srcdir}/emulparams/elf_fbsd.sh
+EXTRA_EM_FILE="elf-x86-64"
 OUTPUT_FORMAT="elf64-x86-64-freebsd"
index e6231cdfb15783da54b75677d4b02a6c8df079e2..7b033840fb631b8c8d34f8de30272ef107e49d4a 100644 (file)
@@ -1,2 +1,3 @@
 source_sh ${srcdir}/emulparams/elf_x86_64.sh
 source_sh ${srcdir}/emulparams/elf_haiku.sh
+EXTRA_EM_FILE="elf-x86-64"
diff --git a/ld/emultempl/elf-i386-glibc.em b/ld/emultempl/elf-i386-glibc.em
new file mode 100644 (file)
index 0000000..5478237
--- /dev/null
@@ -0,0 +1,41 @@
+# This shell script emits a C file. -*- C -*-
+#   Copyright (C) 2025 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the license, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING3. If not,
+# see <http://www.gnu.org/licenses/>.
+#
+
+# This file is sourced from elf.em, and defines i386 glibc specific
+# routines.
+#
+
+source_em ${srcdir}/emultempl/elf-x86.em
+source_em ${srcdir}/emultempl/elf-x86-glibc.em
+
+# Define some shell vars to insert bits of code into the standard elf
+# parse_args and list_options functions.
+#
+
+fragment <<EOF
+static void
+elf_i386_glibc_before_parse (void)
+{
+  elf_x86_before_parse ();
+  elf_x86_glibc_before_parse ();
+}
+EOF
+
+LDEMUL_BEFORE_PARSE=elf_i386_glibc_before_parse
diff --git a/ld/emultempl/elf-x86-64-glibc.em b/ld/emultempl/elf-x86-64-glibc.em
new file mode 100644 (file)
index 0000000..1e62d4f
--- /dev/null
@@ -0,0 +1,37 @@
+# This shell script emits a C file. -*- C -*-
+#   Copyright (C) 2025 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the license, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING3. If not,
+# see <http://www.gnu.org/licenses/>.
+#
+
+# This file is sourced from elf.em, and defines x86-64 glibc specific
+# routines.
+#
+
+source_em ${srcdir}/emultempl/elf-x86-64.em
+source_em ${srcdir}/emultempl/elf-x86-glibc.em
+
+fragment <<EOF
+static void
+elf_x86_64_glibc_before_parse (void)
+{
+  elf_x86_64_before_parse ();
+  elf_x86_glibc_before_parse ();
+}
+EOF
+
+LDEMUL_BEFORE_PARSE=elf_x86_64_glibc_before_parse
diff --git a/ld/emultempl/elf-x86-64.em b/ld/emultempl/elf-x86-64.em
new file mode 100644 (file)
index 0000000..ca7ccc0
--- /dev/null
@@ -0,0 +1,68 @@
+# This shell script emits a C file. -*- C -*-
+#   Copyright (C) 2025 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the license, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING3. If not,
+# see <http://www.gnu.org/licenses/>.
+#
+
+# This file is sourced from elf.em, and defines x86-64 specific routines.
+#
+
+source_em ${srcdir}/emultempl/elf-x86.em
+
+fragment <<EOF
+static void
+elf_x86_64_before_parse (void)
+{
+  params.mark_plt = DEFAULT_LD_Z_MARK_PLT;
+
+  elf_x86_before_parse ();
+}
+
+static void
+elf_x86_64_before_allocation (void)
+{
+  if (!bfd_link_relocatable (&link_info)
+      && is_elf_hash_table (link_info.hash)
+      && expld.phase != lang_mark_phase_enum)
+    {
+      struct elf_link_hash_table *htab = elf_hash_table (&link_info);
+      /* Run one_lang_size_sections_pass to estimate the output section
+        layout before sizing dynamic sections.  */
+      expld.dataseg.phase = exp_seg_none;
+      expld.phase = lang_mark_phase_enum;
+      /* NB: Exclude linker created GOT setions when estimating output
+        section layout as sizing dynamic sections may change linker
+        created GOT sections.  */
+      if (htab->sgot != NULL)
+       htab->sgot->flags |= SEC_EXCLUDE;
+      if (htab->sgotplt != NULL)
+       htab->sgotplt->flags |= SEC_EXCLUDE;
+      one_lang_size_sections_pass (NULL, false);
+      /* Restore linker created GOT setions.  */
+      if (htab->sgot != NULL)
+       htab->sgot->flags &= ~SEC_EXCLUDE;
+      if (htab->sgotplt != NULL)
+       htab->sgotplt->flags &= ~SEC_EXCLUDE;
+      lang_reset_memory_regions ();
+    }
+
+  gld${EMULATION_NAME}_before_allocation ();
+}
+EOF
+
+LDEMUL_BEFORE_PARSE=elf_x86_64_before_parse
+LDEMUL_BEFORE_ALLOCATION=elf_x86_64_before_allocation
diff --git a/ld/emultempl/elf-x86-glibc.em b/ld/emultempl/elf-x86-glibc.em
new file mode 100644 (file)
index 0000000..0fc37a6
--- /dev/null
@@ -0,0 +1,70 @@
+# This shell script emits a C file. -*- C -*-
+#   Copyright (C) 2025 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the license, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING3. If not,
+# see <http://www.gnu.org/licenses/>.
+#
+
+# This file is sourced from elf.em, and defines x86 glibc specific
+# routines.
+#
+
+fragment <<EOF
+static void
+elf_x86_glibc_before_parse (void)
+{
+  params.gnu2_tls_version_tag = DEFAULT_LD_GNU2_TLS_TAG;
+}
+EOF
+
+# Define some shell vars to insert bits of code into the standard elf
+# parse_args and list_options functions.
+#
+
+PARSE_AND_LIST_LONGOPTS_X86='
+  { "gnu2-tls-tag", no_argument, NULL, OPTION_GNU2_TLS_VERSION_TAG },
+  { "no-gnu2-tls-tag", no_argument, NULL, OPTION_NO_GNU2_TLS_VERSION_TAG },
+'
+
+PARSE_AND_LIST_OPTIONS_X86='
+  if (DEFAULT_LD_GNU2_TLS_TAG == 0)
+    fprintf (file, _("\
+  --gnu2-tls-tag              Add GNU2_ABI_GNU2_TLS dependency\n\
+  --no-gnu2-tls-tag           Do not add GNU2_ABI_GNU2_TLS dependency (default)\n"));
+  else if (DEFAULT_LD_GNU2_TLS_TAG == 1)
+    fprintf (file, _("\
+  --gnu2-tls-tag              Add GNU2_ABI_GNU2_TLS dependency (default)\n\
+  --no-gnu2-tls-tag           Do not add GNU2_ABI_GNU2_TLS dependency\n"));
+  else
+    fprintf (file, _("\
+  --gnu2-tls-tag              Add GNU2_ABI_GNU2_TLS dependency (auto)\n\
+                                when no options are specified (default)\n\
+  --no-gnu2-tls-tag           Do not add GNU2_ABI_GNU2_TLS dependency\n"));
+'
+
+PARSE_AND_LIST_ARGS_CASES_X86='
+    case OPTION_GNU2_TLS_VERSION_TAG:
+      params.gnu2_tls_version_tag = 1;
+      break;
+
+    case OPTION_NO_GNU2_TLS_VERSION_TAG:
+      params.gnu2_tls_version_tag = 0;
+      break;
+'
+
+PARSE_AND_LIST_LONGOPTS="$PARSE_AND_LIST_LONGOPTS $PARSE_AND_LIST_LONGOPTS_X86"
+PARSE_AND_LIST_OPTIONS="$PARSE_AND_LIST_OPTIONS $PARSE_AND_LIST_OPTIONS_X86"
+PARSE_AND_LIST_ARGS_CASES="$PARSE_AND_LIST_ARGS_CASES $PARSE_AND_LIST_ARGS_CASES_X86"
index f72a0cd0d4a7367d18620f57b7fdc8f3912de0b5..411a4d6229464e882b73ad7e8b5dcd871c1e1924 100644 (file)
@@ -56,61 +56,3 @@ EOF
 
 LDEMUL_BEFORE_PARSE=elf_x86_before_parse
 fi
-
-case x${OUTPUT_FORMAT}${CALL_NOP_BYTE} in
-  x*x86-64*0x67)
-fragment <<EOF
-
-static void
-elf_x86_64_before_parse (void)
-{
-  params.mark_plt = DEFAULT_LD_Z_MARK_PLT;
-
-  elf_x86_before_parse ();
-}
-EOF
-
-    LDEMUL_BEFORE_PARSE=elf_x86_64_before_parse
-    ;;
-esac
-
-case x${OUTPUT_FORMAT} in
-  x*x86-64*)
-fragment <<EOF
-
-static void
-elf_x86_64_before_allocation (void)
-{
-  if (!bfd_link_relocatable (&link_info)
-      && is_elf_hash_table (link_info.hash)
-      && expld.phase != lang_mark_phase_enum)
-    {
-      struct elf_link_hash_table *htab = elf_hash_table (&link_info);
-      /* Run one_lang_size_sections_pass to estimate the output section
-        layout before sizing dynamic sections.  */
-      expld.dataseg.phase = exp_seg_none;
-      expld.phase = lang_mark_phase_enum;
-      /* NB: Exclude linker created GOT setions when estimating output
-        section layout as sizing dynamic sections may change linker
-        created GOT sections.  */
-      if (htab->sgot != NULL)
-       htab->sgot->flags |= SEC_EXCLUDE;
-      if (htab->sgotplt != NULL)
-       htab->sgotplt->flags |= SEC_EXCLUDE;
-      one_lang_size_sections_pass (NULL, false);
-      /* Restore linker created GOT setions.  */
-      if (htab->sgot != NULL)
-       htab->sgot->flags &= ~SEC_EXCLUDE;
-      if (htab->sgotplt != NULL)
-       htab->sgotplt->flags &= ~SEC_EXCLUDE;
-      lang_reset_memory_regions ();
-    }
-
-  gld${EMULATION_NAME}_before_allocation ();
-}
-
-EOF
-
-LDEMUL_BEFORE_ALLOCATION=elf_x86_64_before_allocation
-    ;;
-esac
diff --git a/ld/emultempl/solaris2-x86-64.em b/ld/emultempl/solaris2-x86-64.em
new file mode 100644 (file)
index 0000000..788b3cf
--- /dev/null
@@ -0,0 +1,23 @@
+# This shell script emits a C file. -*- C -*-
+#   Copyright (C) 2025 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+source_em "${srcdir}/emultempl/elf-x86-64.em"
+source_em "${srcdir}/emultempl/solaris2.em"
index 413335ad765c169719dfc1fa0187e54d08322350..0e13f7d8e35a3428e9a4eb4c2ed1dcf7458f04da 100644 (file)
@@ -1745,6 +1745,21 @@ Supported for Linux/i386 and Linux/x86_64.
 
 Other keywords are ignored for Solaris compatibility.
 
+@item --gnu2-tls-tag
+@itemx --no-gnu2-tls-tag
+Add @code{GLIBC_ABI_GNU2_TLS} version tag dependency in output programs
+and shared libraries when linking against glibc if input relocatable
+object files have @code{R_386_TLS_DESC_CALL} or
+@code{R_X86_64_TLSDESC_CALL} relocation.  The output will fail to load
+and run at run-time against glibc which doesn't define the
+@code{GLIBC_ABI_GNU2_TLS} version tag.  Unless disabled by the
+@option{--disable-gnu2-tls-tag} configure option at the linker build
+time, when no options are specified, linker will add the
+@code{GLIBC_ABI_GNU2_TLS} version tag dependency if inputs have
+@code{R_386_TLS_DESC_CALL} or @code{R_X86_64_TLSDESC_CALL} relocation
+and libc.so defines the @code{GLIBC_ABI_GNU2_TLS} version tag.
+Supported for Linux/i386 and Linux/x86_64.
+
 @kindex -(
 @cindex groups of archives
 @item -( @var{archives} -)
index d0c2e5d6db80221aca04d9e3dc55cb9628cbeceb..020712df0e7355f5334315cc59ae21843de05709 100644 (file)
@@ -469,6 +469,9 @@ enum option_values
   OPTION_NO_LITERAL_MOVEMENT,
   OPTION_ABI_WINDOWED,
   OPTION_ABI_CALL0,
+  /* Used by emultempl/elf-x86-glibc.em.  */
+  OPTION_GNU2_TLS_VERSION_TAG,
+  OPTION_NO_GNU2_TLS_VERSION_TAG,
 };
 
 /* The initial parser states.  */
diff --git a/ld/testsuite/ld-i386/gnu2-tls-1.s b/ld/testsuite/ld-i386/gnu2-tls-1.s
new file mode 100644 (file)
index 0000000..e3841c7
--- /dev/null
@@ -0,0 +1,11 @@
+       .section        .text.startup,"ax",@progbits
+       .p2align 4
+       .globl  main
+       .type   main, @function
+main:
+       leal    ld@TLSDESC(%ebx), %eax
+       call    *ld@TLSCALL(%eax)
+       addl    %gs:0, %eax
+       ret
+       .size   main, .-main
+       .section        .note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-i386/gnu2-tls-1a.rd b/ld/testsuite/ld-i386/gnu2-tls-1a.rd
new file mode 100644 (file)
index 0000000..3eb926a
--- /dev/null
@@ -0,0 +1,7 @@
+#...
+Version needs section '.gnu.version_r' contains 1 entry:
+ Addr: 0x[0-9a-f]+ +Offset: 0x[0-9a-f]+ +Link: +[0-9]+ +\(.dynstr\)
+ +0+: Version: 1 +File: libc\.so\.6(|\.1) +Cnt: +[0-9]+
+#...
+  0x[a-f0-9]+:   Name: GLIBC_ABI_GNU2_TLS  Flags: none  Version: [0-9]+
+#pass
diff --git a/ld/testsuite/ld-i386/gnu2-tls-1b.rd b/ld/testsuite/ld-i386/gnu2-tls-1b.rd
new file mode 100644 (file)
index 0000000..33ef8ac
--- /dev/null
@@ -0,0 +1,4 @@
+#failif
+#...
+  0x[a-f0-9]+:   Name: GLIBC_ABI_GNU2_TLS  Flags: none  Version: [0-9]+
+#...
index 8633a663ec05a5a954fed8415c978476c7267dc8..622c06eefe7ebb61efa2257d86d695081931982e 100644 (file)
@@ -1519,6 +1519,29 @@ run_ld_link_tests [list \
     ] \
 ]
 
+# The musl C library does not support --gnu2-tls-tag.
+if { ![istarget *-*-musl]
+     && [check_compiler_available] } {
+    run_cc_link_tests [list \
+       [list \
+           "Build gnu2-tls-1a.so" \
+           "-shared -Wl,--no-as-needed,--gnu2-tls-tag" \
+           "-fPIC" \
+           { gnu2-tls-1.s } \
+           {{readelf {-W --version-info} gnu2-tls-1a.rd}} \
+           "gnu2-tls-1a.so" \
+       ] \
+       [list \
+           "Build gnu2-tls-1b.so" \
+           "-shared -Wl,--no-as-needed,--no-gnu2-tls-tag" \
+           "-fPIC" \
+           { gnu2-tls-1.s } \
+           {{readelf {-W --version-info} gnu2-tls-1b.rd}} \
+           "gnu2-tls-1b.so" \
+       ] \
+    ]
+}
+
 # Linux only tests
 run_dump_test "pltgot-1"
 run_dump_test "pltgot-2"
diff --git a/ld/testsuite/ld-x86-64/gnu2-tls-1.s b/ld/testsuite/ld-x86-64/gnu2-tls-1.s
new file mode 100644 (file)
index 0000000..eca788c
--- /dev/null
@@ -0,0 +1,11 @@
+       .section        .text.startup,"ax",@progbits
+       .p2align 4
+       .globl  main
+       .type   main, @function
+main:
+       leaq    foo@TLSDESC(%rip), %rax
+       call    *foo@TLSCALL(%rax)
+       movl    %fs:(%rax), %eax
+       ret
+       .size   main, .-main
+       .section        .note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-x86-64/gnu2-tls-1a.rd b/ld/testsuite/ld-x86-64/gnu2-tls-1a.rd
new file mode 100644 (file)
index 0000000..3eb926a
--- /dev/null
@@ -0,0 +1,7 @@
+#...
+Version needs section '.gnu.version_r' contains 1 entry:
+ Addr: 0x[0-9a-f]+ +Offset: 0x[0-9a-f]+ +Link: +[0-9]+ +\(.dynstr\)
+ +0+: Version: 1 +File: libc\.so\.6(|\.1) +Cnt: +[0-9]+
+#...
+  0x[a-f0-9]+:   Name: GLIBC_ABI_GNU2_TLS  Flags: none  Version: [0-9]+
+#pass
diff --git a/ld/testsuite/ld-x86-64/gnu2-tls-1b.rd b/ld/testsuite/ld-x86-64/gnu2-tls-1b.rd
new file mode 100644 (file)
index 0000000..33ef8ac
--- /dev/null
@@ -0,0 +1,4 @@
+#failif
+#...
+  0x[a-f0-9]+:   Name: GLIBC_ABI_GNU2_TLS  Flags: none  Version: [0-9]+
+#...
diff --git a/ld/testsuite/ld-x86-64/mark-plt-2.rd b/ld/testsuite/ld-x86-64/mark-plt-2.rd
new file mode 100644 (file)
index 0000000..b0ed702
--- /dev/null
@@ -0,0 +1,7 @@
+#...
+Version needs section '.gnu.version_r' contains 1 entry:
+ Addr: 0x[0-9a-f]+ +Offset: 0x[0-9a-f]+ +Link: +[0-9]+ +\(.dynstr\)
+ +0+: Version: 1 +File: libc\.so\.6(|\.1) +Cnt: +[0-9]+
+#...
+  0x[a-f0-9]+:   Name: (GLIBC_2.36|GLIBC_ABI_DT_X86_64_PLT)  Flags: none  Version: [0-9]+
+#pass
diff --git a/ld/testsuite/ld-x86-64/mark-plt-2.s b/ld/testsuite/ld-x86-64/mark-plt-2.s
new file mode 100644 (file)
index 0000000..c816567
--- /dev/null
@@ -0,0 +1,13 @@
+       .text
+       .globl  foo
+       .type   foo, @function
+foo:
+       subq    $8, %rsp
+       leaq    xxx@TLSDESC(%rip), %rax
+       .nops 10
+       call    *xxx@TLSCALL(%rax)
+       movl    %fs:(%rax), %eax
+       addq    $8, %rsp
+       call    bar
+       ret
+       .section        .note.GNU-stack,"",@progbits
index 9d975319cf542ab8a77ff268584789818c36fbad..63cf1e45c1464eea7966c36bad5e31de1ea620d5 100644 (file)
@@ -2360,7 +2360,7 @@ run_dump_test "ibt-plt-3b-x32"
 run_dump_test "ibt-plt-3c-x32"
 run_dump_test "ibt-plt-3d-x32"
 
-# Skip -z mark-plt tests on MUSL.
+# Skip -z mark-plt and --gnu2-tls-tag tests on MUSL.
 if { [istarget "x86_64-*-musl*"]} {
     set ASFLAGS "$saved_ASFLAGS"
     return
@@ -2386,6 +2386,30 @@ if { [check_compiler_available] } {
             {readelf {-W --version-info} mark-plt-1b.rd}} \
            "mark-plt-1.so" \
        ] \
+       [list \
+           "Build mark-plt-2.so" \
+           "-shared -Wl,--no-as-needed,-z,mark-plt,-z,nopack-relative-relocs" \
+           "-fPIC" \
+           { mark-plt-2.s } \
+           {{readelf {-W --version-info} mark-plt-2.rd}} \
+           "mark-plt-2.so" \
+       ] \
+       [list \
+           "Build gnu2-tls-1a.so" \
+           "-shared -Wl,--no-as-needed,--gnu2-tls-tag" \
+           "-fPIC" \
+           { gnu2-tls-1.s } \
+           {{readelf {-W --version-info} gnu2-tls-1a.rd}} \
+           "gnu2-tls-1a.so" \
+       ] \
+       [list \
+           "Build gnu2-tls-1b.so" \
+           "-shared -Wl,--no-as-needed,--no-gnu2-tls-tag" \
+           "-fPIC" \
+           { gnu2-tls-1.s } \
+           {{readelf {-W --version-info} gnu2-tls-1b.rd}} \
+           "gnu2-tls-1b.so" \
+       ] \
     ]
 }