diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2025-07-04 08:39:03 +0800 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2025-08-20 13:53:32 -0700 |
commit | 0d1e88f8bfb0e62f37bf8a89172cd91373ace5e6 (patch) | |
tree | 48053196a0e72a9cf2402883f5ac5f42bd4742e7 | |
parent | cf03cf4e8879bbfe6b90160ff3fda63feb2a898f (diff) | |
download | gdb-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>
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; @@ -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" @@ -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} -) @@ -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" \ + ] \ ] } |