aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2025-07-04 08:39:03 +0800
committerH.J. Lu <hjl.tools@gmail.com>2025-08-20 13:53:32 -0700
commit0d1e88f8bfb0e62f37bf8a89172cd91373ace5e6 (patch)
tree48053196a0e72a9cf2402883f5ac5f42bd4742e7
parentcf03cf4e8879bbfe6b90160ff3fda63feb2a898f (diff)
downloadgdb-0d1e88f8bfb0e62f37bf8a89172cd91373ace5e6.zip
gdb-0d1e88f8bfb0e62f37bf8a89172cd91373ace5e6.tar.gz
gdb-0d1e88f8bfb0e62f37bf8a89172cd91373ace5e6.tar.bz2
x86: Add GLIBC_ABI_GNU2_TLS version dependency
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>
-rw-r--r--bfd/elf-bfd.h2
-rw-r--r--bfd/elf-linker-x86.h8
-rw-r--r--bfd/elf32-i386.c44
-rw-r--r--bfd/elf64-x86-64.c36
-rw-r--r--bfd/elflink.c130
-rw-r--r--bfd/elfxx-x86.h4
-rw-r--r--ld/NEWS6
-rw-r--r--ld/config.in4
-rwxr-xr-xld/configure29
-rw-r--r--ld/configure.ac19
-rw-r--r--ld/emulparams/elf32_x86_64.sh2
-rw-r--r--ld/emulparams/elf_i386.sh2
-rw-r--r--ld/emulparams/elf_i386_fbsd.sh1
-rw-r--r--ld/emulparams/elf_i386_haiku.sh1
-rw-r--r--ld/emulparams/elf_x86_64.sh2
-rw-r--r--ld/emulparams/elf_x86_64_fbsd.sh1
-rw-r--r--ld/emulparams/elf_x86_64_haiku.sh1
-rw-r--r--ld/emultempl/elf-i386-glibc.em41
-rw-r--r--ld/emultempl/elf-x86-64-glibc.em37
-rw-r--r--ld/emultempl/elf-x86-64.em68
-rw-r--r--ld/emultempl/elf-x86-glibc.em70
-rw-r--r--ld/emultempl/elf-x86.em58
-rw-r--r--ld/emultempl/solaris2-x86-64.em23
-rw-r--r--ld/ld.texi15
-rw-r--r--ld/ldlex.h3
-rw-r--r--ld/testsuite/ld-i386/gnu2-tls-1.s11
-rw-r--r--ld/testsuite/ld-i386/gnu2-tls-1a.rd7
-rw-r--r--ld/testsuite/ld-i386/gnu2-tls-1b.rd4
-rw-r--r--ld/testsuite/ld-i386/i386.exp23
-rw-r--r--ld/testsuite/ld-x86-64/gnu2-tls-1.s11
-rw-r--r--ld/testsuite/ld-x86-64/gnu2-tls-1a.rd7
-rw-r--r--ld/testsuite/ld-x86-64/gnu2-tls-1b.rd4
-rw-r--r--ld/testsuite/ld-x86-64/mark-plt-2.rd7
-rw-r--r--ld/testsuite/ld-x86-64/mark-plt-2.s13
-rw-r--r--ld/testsuite/ld-x86-64/x86-64.exp26
35 files changed, 595 insertions, 125 deletions
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index accdd6d..feb470f 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -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 *);
diff --git a/bfd/elf-linker-x86.h b/bfd/elf-linker-x86.h
index 2c98257..fe32215 100644
--- a/bfd/elf-linker-x86.h
+++ b/bfd/elf-linker-x86.h
@@ -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;
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index b755b39..9d06f14 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -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
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 3ffeff9..352dca6 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -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
diff --git a/bfd/elflink.c b/bfd/elflink.c
index f6c0c04..d2c43f3 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -2281,68 +2281,85 @@ _bfd_elf_export_symbol (struct elf_link_hash_entry *h, void *data)
return true;
}
-/* 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);
}
}
diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
index f6ee6a6..791a2a2 100644
--- a/bfd/elfxx-x86.h
+++ b/bfd/elfxx-x86.h
@@ -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 54c1df5..bacabc8 100644
--- 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:
diff --git a/ld/config.in b/ld/config.in
index 3781224..64dbc3e 100644
--- a/ld/config.in
+++ b/ld/config.in
@@ -31,6 +31,10 @@
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
diff --git a/ld/configure b/ld/configure
index 124b441..6f1a3559 100755
--- a/ld/configure
+++ b/ld/configure
@@ -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
diff --git a/ld/configure.ac b/ld/configure.ac
index e306c1d..4b9068a 100644
--- a/ld/configure.ac
+++ b/ld/configure.ac
@@ -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,
diff --git a/ld/emulparams/elf32_x86_64.sh b/ld/emulparams/elf32_x86_64.sh
index 6a92eec..4db1a97 100644
--- a/ld/emulparams/elf32_x86_64.sh
+++ b/ld/emulparams/elf32_x86_64.sh
@@ -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
diff --git a/ld/emulparams/elf_i386.sh b/ld/emulparams/elf_i386.sh
index 6f698bb..51a650f 100644
--- a/ld/emulparams/elf_i386.sh
+++ b/ld/emulparams/elf_i386.sh
@@ -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
diff --git a/ld/emulparams/elf_i386_fbsd.sh b/ld/emulparams/elf_i386_fbsd.sh
index d1d6604..d39a5cf 100644
--- a/ld/emulparams/elf_i386_fbsd.sh
+++ b/ld/emulparams/elf_i386_fbsd.sh
@@ -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"
diff --git a/ld/emulparams/elf_i386_haiku.sh b/ld/emulparams/elf_i386_haiku.sh
index 6c4001e..c931c0e 100644
--- a/ld/emulparams/elf_i386_haiku.sh
+++ b/ld/emulparams/elf_i386_haiku.sh
@@ -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
diff --git a/ld/emulparams/elf_x86_64.sh b/ld/emulparams/elf_x86_64.sh
index 9244974..6e66f2e 100644
--- a/ld/emulparams/elf_x86_64.sh
+++ b/ld/emulparams/elf_x86_64.sh
@@ -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
diff --git a/ld/emulparams/elf_x86_64_fbsd.sh b/ld/emulparams/elf_x86_64_fbsd.sh
index 7ef974a..17fdc83 100644
--- a/ld/emulparams/elf_x86_64_fbsd.sh
+++ b/ld/emulparams/elf_x86_64_fbsd.sh
@@ -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"
diff --git a/ld/emulparams/elf_x86_64_haiku.sh b/ld/emulparams/elf_x86_64_haiku.sh
index e6231cd..7b03384 100644
--- a/ld/emulparams/elf_x86_64_haiku.sh
+++ b/ld/emulparams/elf_x86_64_haiku.sh
@@ -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
index 0000000..5478237
--- /dev/null
+++ b/ld/emultempl/elf-i386-glibc.em
@@ -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
index 0000000..1e62d4f
--- /dev/null
+++ b/ld/emultempl/elf-x86-64-glibc.em
@@ -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
index 0000000..ca7ccc0
--- /dev/null
+++ b/ld/emultempl/elf-x86-64.em
@@ -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
index 0000000..0fc37a6
--- /dev/null
+++ b/ld/emultempl/elf-x86-glibc.em
@@ -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"
diff --git a/ld/emultempl/elf-x86.em b/ld/emultempl/elf-x86.em
index f72a0cd..411a4d6 100644
--- a/ld/emultempl/elf-x86.em
+++ b/ld/emultempl/elf-x86.em
@@ -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
index 0000000..788b3cf
--- /dev/null
+++ b/ld/emultempl/solaris2-x86-64.em
@@ -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"
diff --git a/ld/ld.texi b/ld/ld.texi
index 413335a..0e13f7d 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -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} -)
diff --git a/ld/ldlex.h b/ld/ldlex.h
index d0c2e5d..020712d 100644
--- a/ld/ldlex.h
+++ b/ld/ldlex.h
@@ -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
index 0000000..e3841c7
--- /dev/null
+++ b/ld/testsuite/ld-i386/gnu2-tls-1.s
@@ -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
index 0000000..3eb926a
--- /dev/null
+++ b/ld/testsuite/ld-i386/gnu2-tls-1a.rd
@@ -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
index 0000000..33ef8ac
--- /dev/null
+++ b/ld/testsuite/ld-i386/gnu2-tls-1b.rd
@@ -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-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp
index 8633a66..622c06e 100644
--- a/ld/testsuite/ld-i386/i386.exp
+++ b/ld/testsuite/ld-i386/i386.exp
@@ -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
index 0000000..eca788c
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/gnu2-tls-1.s
@@ -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
index 0000000..3eb926a
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/gnu2-tls-1a.rd
@@ -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
index 0000000..33ef8ac
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/gnu2-tls-1b.rd
@@ -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
index 0000000..b0ed702
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mark-plt-2.rd
@@ -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
index 0000000..c816567
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mark-plt-2.s
@@ -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
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index 9d97531..63cf1e4 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -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" \
+ ] \
]
}