mirror of
https://github.com/bminor/binutils-gdb.git
synced 2026-02-06 09:31:31 +00:00
i386: Add GLIBC_ABI_GNU_TLS version dependency
On Linux/i386, programs and shared libraries compiled with
-mtls-dialect=gnu may fail silently at run-time against glibc without
the GNU TLS run-time fix for:
https://sourceware.org/bugzilla/show_bug.cgi?id=32996
The glibc version tag, GLIBC_ABI_GNU_TLS, has been added to indicate
that glibc has the working GNU TLS run-time:
commit ed1b7a5a489ab555a27fad9c101ebe2e1c1ba881
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Mon Jul 28 12:16:11 2025 -0700
i386: Add GLIBC_ABI_GNU_TLS version [BZ #33221]
Add the --gnu-tls-tag option to x86-64 ELF linker to add the
GLIBC_ABI_GNU_TLS version dependency in output programs and shared
libraries when linking against glibc if input relocatable object files
call ___tls_get_addr. The output will fail to load and run at run-time
against glibc which doesn't define the GLIBC_ABI_GNU_TLS version.
Add the --enable-gnu-tls-tag configure option to enable --gnu-tls-tag
by default. If unspecified, linker will add the GLIBC_ABI_GNU_TLS
version dependency if input call ___tls_get_addr and libc.so defines
the GLIBC_ABI_GNU2_TLS version.
bfd/
PR ld/33287
* elf-linker-x86.h (elf_linker_x86_params): Add
gnu_tls_version_tag.
* elf32-i386.c (elf_backend_add_glibc_version_dependency): Add
GLIBC_ABI_GNU_TLS support.
* elfxx-x86.c (_bfd_x86_elf_link_check_relocs): Set
has_tls_get_addr_call to 1 if ___tls_get_addr is used.
* elfxx-x86.h (elf_x86_link_hash_table): Add has_tls_get_addr_call.
ld/
PR ld/33287
* Mention --gnu-tls-tag, --no-gnu-tls-tag and --enable-gnu-tls-tag.
* config.in: Regenerated.
* configure: Likewise.
* configure.ac: Add --enable-gnu-tls-tag.
* ld.texi: Document --gnu-tls-tag and --enable-gnu-tls-tag.
* ldlex.h (option_values): Add OPTION_GNU_TLS_VERSION_TAG and
OPTION_NO_GNU_TLS_VERSION_TAG.
* emultempl/elf-i386-glibc.em (elf_i386_glibc_before_parse):
Initialize params.gnu_tls_version_tag.
(PARSE_AND_LIST_LONGOPTS_386): New.
(PARSE_AND_LIST_OPTIONS_386): Likewise.
(PARSE_AND_LIST_ARGS_CASES_386): Likewise.
(PARSE_AND_LIST_LONGOPTS): Append $PARSE_AND_LIST_LONGOPTS_386.
(PARSE_AND_LIST_OPTIONS): Append $PARSE_AND_LIST_OPTIONS_386.
(PARSE_AND_LIST_ARGS_CASES): Append
$PARSE_AND_LIST_ARGS_CASES_386.
* testsuite/ld-i386/gnu-tls-1.s: Likewise.
* testsuite/ld-i386/gnu-tls-1a.rd: Likewise.
* testsuite/ld-i386/gnu-tls-1b.rd: Likewise.
* testsuite/ld-i386/i386.exp: Run PR ld/33287 tests.
(cherry picked from commit fbcdc06c23)
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
This commit is contained in:
@@ -80,6 +80,15 @@ struct elf_linker_x86_params
|
||||
*/
|
||||
unsigned int gnu2_tls_version_tag : 2;
|
||||
|
||||
/* Add the GLIBC_ABI_GNU_TLS version dependency if input object files
|
||||
call ___tls_get_addr:
|
||||
0: Disable.
|
||||
1: Enable.
|
||||
2: Auto. Enable if libc.so has the GLIBC_ABI_GNU_TLS version.
|
||||
This is only used by i386.
|
||||
*/
|
||||
unsigned int gnu_tls_version_tag : 2;
|
||||
|
||||
/* X86-64 ISA level needed. */
|
||||
unsigned int isa_level;
|
||||
|
||||
|
||||
@@ -4509,8 +4509,8 @@ 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 };
|
||||
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)
|
||||
@@ -4531,6 +4531,16 @@ elf_i386_add_glibc_version_dependency
|
||||
auto_version[i] = true;
|
||||
i++;
|
||||
}
|
||||
if (htab->params->gnu_tls_version_tag
|
||||
&& htab->has_tls_get_addr_call)
|
||||
{
|
||||
version[i] = "GLIBC_ABI_GNU_TLS";
|
||||
/* 2 == auto, enable if libc.so defines the GLIBC_ABI_GNU_TLS
|
||||
version. */
|
||||
if (htab->params->gnu_tls_version_tag == 2)
|
||||
auto_version[i] = true;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (i != 0)
|
||||
|
||||
@@ -882,6 +882,8 @@ _bfd_x86_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
|
||||
h = (struct elf_link_hash_entry *) h->root.u.i.link;
|
||||
elf_x86_hash_entry (h)->tls_get_addr = 1;
|
||||
}
|
||||
|
||||
htab->has_tls_get_addr_call = 1;
|
||||
}
|
||||
|
||||
/* Pass NULL for __ehdr_start which will be defined by
|
||||
|
||||
@@ -671,6 +671,9 @@ struct elf_x86_link_hash_table
|
||||
relocation. */
|
||||
unsigned int has_tls_desc_call : 1;
|
||||
|
||||
/* TRUE if inputs call ___tls_get_addr. This is only used for i386. */
|
||||
unsigned int has_tls_get_addr_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;
|
||||
|
||||
5
ld/NEWS
5
ld/NEWS
@@ -1,5 +1,10 @@
|
||||
-*- text -*-
|
||||
|
||||
* Add --gnu-tls-tag/--no-gnu-tls-tag options to i386 ELF linker to add
|
||||
the GLIBC_ABI_GNU_TLS version dependency in output if input object
|
||||
files call ___tls_get_addr. Also added --enable-gnu-tls-tag configure
|
||||
option to enable --gnu-tls-tag by default.
|
||||
|
||||
* 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
|
||||
|
||||
@@ -35,6 +35,10 @@
|
||||
by default. */
|
||||
#undef DEFAULT_LD_GNU2_TLS_TAG
|
||||
|
||||
/* Define to 1 if you want to enable --gnu-tls-tag in ELF i386 linker by
|
||||
default. */
|
||||
#undef DEFAULT_LD_GNU_TLS_TAG
|
||||
|
||||
/* Define to 1 if you want to enable --rosegment in the ELF linker by default.
|
||||
*/
|
||||
#undef DEFAULT_LD_ROSEGMENT
|
||||
|
||||
28
ld/configure
vendored
28
ld/configure
vendored
@@ -852,6 +852,7 @@ enable_separate_code
|
||||
enable_rosegment
|
||||
enable_mark_plt
|
||||
enable_gnu2_tls_tag
|
||||
enable_gnu_tls_tag
|
||||
enable_memory_seal
|
||||
enable_warn_execstack
|
||||
enable_error_execstack
|
||||
@@ -1551,6 +1552,7 @@ Optional Features:
|
||||
--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-gnu-tls-tag enable --gnu-tls-tag in ELF i386 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
|
||||
@@ -11517,7 +11519,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 11520 "configure"
|
||||
#line 11522 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@@ -11623,7 +11625,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 11626 "configure"
|
||||
#line 11628 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@@ -15522,6 +15524,17 @@ esac
|
||||
fi
|
||||
|
||||
|
||||
# Decide if --gnu-tls-tag should be enabled in ELF i386 linker by default.
|
||||
ac_default_ld_enable_gnu_tls_tag=unset
|
||||
# Check whether --enable-gnu-tls-tag was given.
|
||||
if test "${enable_gnu_tls_tag+set}" = set; then :
|
||||
enableval=$enable_gnu_tls_tag; case "${enableval}" in
|
||||
yes) ac_default_ld_enable_gnu_tls_tag=1 ;;
|
||||
no) ac_default_ld_enable_gnu_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.
|
||||
@@ -19007,6 +19020,17 @@ cat >>confdefs.h <<_ACEOF
|
||||
_ACEOF
|
||||
|
||||
|
||||
if test "${ac_default_ld_enable_gnu_tls_tag}" = unset; then
|
||||
# Default to enable --gnu-tls-tag if libc.so has the GLIBC_ABI_GNU_TLS
|
||||
# version.
|
||||
ac_default_ld_enable_gnu_tls_tag=2
|
||||
fi
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define DEFAULT_LD_GNU_TLS_TAG $ac_default_ld_enable_gnu_tls_tag
|
||||
_ACEOF
|
||||
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define DEFAULT_LD_WARN_EXECSTACK $ac_default_ld_warn_execstack
|
||||
|
||||
@@ -256,6 +256,16 @@ AC_ARG_ENABLE(gnu2-tls-tag,
|
||||
no) ac_default_ld_enable_gnu2_tls_tag=0 ;;
|
||||
esac])
|
||||
|
||||
# Decide if --gnu-tls-tag should be enabled in ELF i386 linker by default.
|
||||
ac_default_ld_enable_gnu_tls_tag=unset
|
||||
AC_ARG_ENABLE(gnu-tls-tag,
|
||||
AS_HELP_STRING([--enable-gnu-tls-tag],
|
||||
[enable --gnu-tls-tag in ELF i386 linker by default]),
|
||||
[case "${enableval}" in
|
||||
yes) ac_default_ld_enable_gnu_tls_tag=1 ;;
|
||||
no) ac_default_ld_enable_gnu_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,
|
||||
@@ -667,6 +677,15 @@ 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.])
|
||||
|
||||
if test "${ac_default_ld_enable_gnu_tls_tag}" = unset; then
|
||||
# Default to enable --gnu-tls-tag if libc.so has the GLIBC_ABI_GNU_TLS
|
||||
# version.
|
||||
ac_default_ld_enable_gnu_tls_tag=2
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_LD_GNU_TLS_TAG,
|
||||
$ac_default_ld_enable_gnu_tls_tag,
|
||||
[Define to 1 if you want to enable --gnu-tls-tag in ELF i386 linker by default.])
|
||||
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_LD_WARN_EXECSTACK,
|
||||
$ac_default_ld_warn_execstack,
|
||||
[Define to 1 if you want to enable --warn-execstack in ELF linker by default.])
|
||||
|
||||
@@ -35,7 +35,43 @@ elf_i386_glibc_before_parse (void)
|
||||
{
|
||||
elf_x86_before_parse ();
|
||||
elf_x86_glibc_before_parse ();
|
||||
params.gnu_tls_version_tag = DEFAULT_LD_GNU_TLS_TAG;
|
||||
}
|
||||
EOF
|
||||
|
||||
LDEMUL_BEFORE_PARSE=elf_i386_glibc_before_parse
|
||||
|
||||
PARSE_AND_LIST_LONGOPTS_386='
|
||||
{ "gnu-tls-tag", no_argument, NULL, OPTION_GNU_TLS_VERSION_TAG },
|
||||
{ "no-gnu-tls-tag", no_argument, NULL, OPTION_NO_GNU_TLS_VERSION_TAG },
|
||||
'
|
||||
|
||||
PARSE_AND_LIST_OPTIONS_386='
|
||||
if (DEFAULT_LD_GNU_TLS_TAG == 0)
|
||||
fprintf (file, _("\
|
||||
--gnu-tls-tag Add GLIBC_ABI_GNU_TLS dependency\n\
|
||||
--no-gnu-tls-tag Do not add GLIBC_ABI_GNU_TLS dependency (default)\n"));
|
||||
else if (DEFAULT_LD_GNU_TLS_TAG == 1)
|
||||
fprintf (file, _("\
|
||||
--gnu-tls-tag Add GLIBC_ABI_GNU_TLS dependency (default)\n\
|
||||
--no-gnu-tls-tag Do not add GLIBC_ABI_GNU_TLS dependency\n"));
|
||||
else
|
||||
fprintf (file, _("\
|
||||
--gnu-tls-tag Add GLIBC_ABI_GNU_TLS dependency (auto)\n\
|
||||
when no options are specified (default)\n\
|
||||
--no-gnu-tls-tag Do not add GLIBC_ABI_GNU_TLS dependency\n"));
|
||||
'
|
||||
|
||||
PARSE_AND_LIST_ARGS_CASES_386='
|
||||
case OPTION_GNU_TLS_VERSION_TAG:
|
||||
params.gnu_tls_version_tag = 1;
|
||||
break;
|
||||
|
||||
case OPTION_NO_GNU_TLS_VERSION_TAG:
|
||||
params.gnu_tls_version_tag = 0;
|
||||
break;
|
||||
'
|
||||
|
||||
PARSE_AND_LIST_LONGOPTS="$PARSE_AND_LIST_LONGOPTS $PARSE_AND_LIST_LONGOPTS_386"
|
||||
PARSE_AND_LIST_OPTIONS="$PARSE_AND_LIST_OPTIONS $PARSE_AND_LIST_OPTIONS_386"
|
||||
PARSE_AND_LIST_ARGS_CASES="$PARSE_AND_LIST_ARGS_CASES $PARSE_AND_LIST_ARGS_CASES_386"
|
||||
|
||||
13
ld/ld.texi
13
ld/ld.texi
@@ -1745,6 +1745,19 @@ Supported for Linux/i386 and Linux/x86_64.
|
||||
|
||||
Other keywords are ignored for Solaris compatibility.
|
||||
|
||||
@item --gnu-tls-tag
|
||||
@itemx --no-gnu-tls-tag
|
||||
Add @code{GLIBC_ABI_GNU_TLS} version tag dependency in output programs
|
||||
and shared libraries when linking against glibc if input relocatable
|
||||
object files call @code{___tls_get_addr}. The output will fail to load
|
||||
and run at run-time against glibc which doesn't define the
|
||||
@code{GLIBC_ABI_GNU_TLS} version tag. Unless disabled by the
|
||||
@option{--disable-gnu-tls-tag} configure option at the linker build
|
||||
time, when no options are specified, linker will add the
|
||||
@code{GLIBC_ABI_GNU_TLS} version tag dependency if inputs have
|
||||
@code{___tls_get_addr} call and libc.so defines the
|
||||
@code{GLIBC_ABI_GNU_TLS} version tag. Supported for Linux/i386.
|
||||
|
||||
@item --gnu2-tls-tag
|
||||
@itemx --no-gnu2-tls-tag
|
||||
Add @code{GLIBC_ABI_GNU2_TLS} version tag dependency in output programs
|
||||
|
||||
@@ -474,6 +474,9 @@ enum option_values
|
||||
/* Used by emultempl/elf-x86-glibc.em. */
|
||||
OPTION_GNU2_TLS_VERSION_TAG,
|
||||
OPTION_NO_GNU2_TLS_VERSION_TAG,
|
||||
/* Used by emultempl/elf-i386-glibc.em. */
|
||||
OPTION_GNU_TLS_VERSION_TAG,
|
||||
OPTION_NO_GNU_TLS_VERSION_TAG,
|
||||
};
|
||||
|
||||
/* The initial parser states. */
|
||||
|
||||
9
ld/testsuite/ld-i386/gnu-tls-1.s
Normal file
9
ld/testsuite/ld-i386/gnu-tls-1.s
Normal file
@@ -0,0 +1,9 @@
|
||||
.text
|
||||
.p2align 4
|
||||
.globl func
|
||||
.type func, @function
|
||||
func:
|
||||
leal foo@tlsgd(,%ebx,1), %eax
|
||||
call ___tls_get_addr@PLT
|
||||
ret
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
7
ld/testsuite/ld-i386/gnu-tls-1a.rd
Normal file
7
ld/testsuite/ld-i386/gnu-tls-1a.rd
Normal file
@@ -0,0 +1,7 @@
|
||||
#...
|
||||
Version needs section '.gnu.version_r' contains [0-9]+ entries:
|
||||
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_GNU_TLS Flags: none Version: [0-9]+
|
||||
#pass
|
||||
4
ld/testsuite/ld-i386/gnu-tls-1b.rd
Normal file
4
ld/testsuite/ld-i386/gnu-tls-1b.rd
Normal file
@@ -0,0 +1,4 @@
|
||||
#failif
|
||||
#...
|
||||
0x[a-f0-9]+: Name: GLIBC_ABI_GNU_TLS Flags: none Version: [0-9]+
|
||||
#...
|
||||
@@ -1514,10 +1514,26 @@ run_ld_link_tests [list \
|
||||
] \
|
||||
]
|
||||
|
||||
# The musl C library does not support --gnu2-tls-tag.
|
||||
# The musl C library does not support --gnu-tls-tag nor --gnu2-tls-tag.
|
||||
if { ![istarget *-*-musl]
|
||||
&& [check_compiler_available] } {
|
||||
run_cc_link_tests [list \
|
||||
[list \
|
||||
"Build gnu-tls-1a.so" \
|
||||
"-shared -Wl,--no-as-needed,--gnu-tls-tag" \
|
||||
"-fPIC" \
|
||||
{ gnu-tls-1.s } \
|
||||
{{readelf {-W --version-info} gnu-tls-1a.rd}} \
|
||||
"gnu-tls-1a.so" \
|
||||
] \
|
||||
[list \
|
||||
"Build gnu-tls-1b.so" \
|
||||
"-shared -Wl,--no-as-needed,--no-gnu-tls-tag" \
|
||||
"-fPIC" \
|
||||
{ gnu-tls-1.s } \
|
||||
{{readelf {-W --version-info} gnu-tls-1b.rd}} \
|
||||
"gnu-tls-1b.so" \
|
||||
] \
|
||||
[list \
|
||||
"Build gnu2-tls-1a.so" \
|
||||
"-shared -Wl,--no-as-needed,--gnu2-tls-tag" \
|
||||
|
||||
Reference in New Issue
Block a user