On Thu, Aug 28, 2025 at 7:23 AM Sam James <s...@gentoo.org> wrote: > > GNU2 TLS descriptors were introduced in 2006 (r0-73091-g5bf5a10b1ccacf) > but were only opt-in with -mtls-dialect=gnu2. They are more efficient > and it's time to enable them by default. > > Builds on the --with-tls= machinery from r16-3355-g96a291c4bb0b8a. > > We achieve this for GNU/Linux IA-32/X86-64 targets by checking if ld emits > GLIBC_ABI_GNU2_TLS, using its presence to decide if we can default to > -mtls-dialect=gnu2. > > For PR ld/33130, newer ld will add GLIBC_ABI_GNU2_TLS if either unconfigured > (auto mode) or if configured with --enable-gnu2-tls-tag. In auto mode, > GLIBC_ABI_GNU2_TLS is only added if glibc provides it. In explicit mode, the > user has asked for this behavior and binaries will depend on > GLIBC_ABI_GNU2_TLS > and fixed glibc. Hence the presence of GLIBC_ABI_GNU2_TLS tells us if we can > safely default to GNU2 TLS descriptors. We added GLIBC_ABI_GNU2_TLS in glibc > to indicate that PR dynamic-link/33129 is fixed. > > If distributions wish to opt-out of this for systems which meet the above > conditions, they can either configure GCC using --with-tls=gnu, or configure > binutils with --disable-gnu2-tls-tag: if this is necessary, it is recommended > to use --with-tls=gnu instead, to avoid affecting the ecosystem negatively by > having unmarked binaries.
I wonder if we can piggy-back on the existing --with-glibc-version=... somehow? > Some implementation notes: > * The readelf check had to be moved earlier because we want > to set `with_tls` before `config.gcc` is processed (which has default > machinery for TLS). > > * The check doesn't really handle cross, but I don't see > this as a huge problem. The check is already opportunistic and if it > fails, it falls back to --with-tls=DIALECT if passed, and failing that, > the previous and safe default of 'gnu'. > > * The change is only made for glibc systems at this time. Enablement and > testing > can be done for other libcs as future work. > > * In future, we may do the same thing for ARM if/when appropriate equivalent > machinery is added to glibc and bfd. This makes the separate position of > the check (not with some of the others) a bit more palatable IMO. > > gcc/ChangeLog: > PR target/120933 > * configure: Regenerate. > * configure.ac (gcc_cv_readelf): Move check earlier. > (gcc_cv_libc_x86_tlsdesc_call): Define to 'yes' if > glibc has the GLIBC_ABI_GNU2_TLS version tag and ld emits it. > (with_tls): Default to 'gnu2' if --with-tls is not passed and > gcc_cv_libc_x86_tlsdesc_call is 'yes'. > --- > OK? > > gcc/configure | 217 +++++++++++++++++++++++++++++++---------------- > gcc/configure.ac | 112 ++++++++++++++++++------ > 2 files changed, 229 insertions(+), 100 deletions(-) > > diff --git a/gcc/configure b/gcc/configure > index 4a751d969bab..ba303469613c 100755 > --- a/gcc/configure > +++ b/gcc/configure > @@ -737,7 +737,6 @@ libgcc_visibility > ORIGINAL_DSYMUTIL_FOR_TARGET > gcc_cv_dsymutil > gcc_cv_otool > -gcc_cv_readelf > gcc_cv_objdump > ORIGINAL_NM_FOR_TARGET > gcc_cv_nm > @@ -801,6 +800,7 @@ HAVE_AUTO_BUILD > extra_opt_files > extra_modes_file > NATIVE_SYSTEM_HEADER_DIR > +gcc_cv_readelf > objext > manext > LIBICONV_DEP > @@ -12927,6 +12927,145 @@ if test "x$enable_win32_utf8_manifest" != xno; then > host_extra_objs_mingw=utf8-mingw32.o > fi > > + > +# Figure out what readelf we will be using. > +if ${gcc_cv_readelf+:} false; then : > + > +else > + > +if test -f $gcc_cv_binutils_srcdir/configure.ac \ > + && test -f ../binutils/Makefile \ > + && test x$build = x$host; then > + # Single tree build which includes binutils. > + gcc_cv_readelf=../binutils/readelf$build_exeext > +elif test -x readelf$build_exeext; then > + gcc_cv_readelf=./readelf$build_exeext > +elif ( set dummy $READELF_FOR_TARGET; test -x $2 ); then > + gcc_cv_readelf="$READELF_FOR_TARGET" > +else > + # Extract the first word of "$READELF_FOR_TARGET", so it can be a > program name with args. > +set dummy $READELF_FOR_TARGET; ac_word=$2 > +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 > +$as_echo_n "checking for $ac_word... " >&6; } > +if ${ac_cv_path_gcc_cv_readelf+:} false; then : > + $as_echo_n "(cached) " >&6 > +else > + case $gcc_cv_readelf in > + [\\/]* | ?:[\\/]*) > + ac_cv_path_gcc_cv_readelf="$gcc_cv_readelf" # Let the user override the > test with a path. > + ;; > + *) > + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR > +for as_dir in $PATH > +do > + IFS=$as_save_IFS > + test -z "$as_dir" && as_dir=. > + for ac_exec_ext in '' $ac_executable_extensions; do > + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then > + ac_cv_path_gcc_cv_readelf="$as_dir/$ac_word$ac_exec_ext" > + $as_echo "$as_me:${as_lineno-$LINENO}: found > $as_dir/$ac_word$ac_exec_ext" >&5 > + break 2 > + fi > +done > + done > +IFS=$as_save_IFS > + > + ;; > +esac > +fi > +gcc_cv_readelf=$ac_cv_path_gcc_cv_readelf > +if test -n "$gcc_cv_readelf"; then > + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_readelf" >&5 > +$as_echo "$gcc_cv_readelf" >&6; } > +else > + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 > +$as_echo "no" >&6; } > +fi > + > + > +fi > +fi > + > +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking what readelf to use" >&5 > +$as_echo_n "checking what readelf to use... " >&6; } > +if test "$gcc_cv_readelf" = ../binutils/readelf$build_exeext; then > + # Single tree build which includes binutils. > + { $as_echo "$as_me:${as_lineno-$LINENO}: result: newly built readelf" > >&5 > +$as_echo "newly built readelf" >&6; } > +elif test x$gcc_cv_readelf = x; then > + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 > +$as_echo "not found" >&6; } > +else > + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_readelf" >&5 > +$as_echo "$gcc_cv_readelf" >&6; } > +fi > + > +case $target in > + i[34567]86-*-gnu* | x86_64-*-gnu* ) > + # PR target/120933 > + # For GNU/Linux targets, check if ld emits GLIBC_ABI_GNU2_TLS. For > PR ld/33130, > + # newer ld will add GLIBC_ABI_GNU2_TLS if either unconfigured (auto > mode) or if > + # configured with --enable-gnu2-tls-tag. In auto mode, > GLIBC_ABI_GNU2_TLS > + # is only added if glibc provides it. In explicit mode, the user has > asked > + # for this behavior and binaries will depend on GLIBC_ABI_GNU2_TLS > and fixed > + # glibc. Hence the presence of GLIBC_ABI_GNU2_TLS tells us if we can > safely > + # default to GNU2 TLS descriptors. > + conftest_S=' > + .section .text.startup,"ax",@progbits > + .p2align 4 > + .globl main > + .type main, @function > + main: > + #ifdef __x86_64__ > + leaq foo@TLSDESC(%rip), %rax > + call *foo@TLSCALL(%rax) > + movl %fs:(%rax), %eax > + #else > + leal ld@TLSDESC(%ebx), %eax > + call *ld@TLSCALL(%eax) > + addl %gs:0, %eax > + #endif > + ret > + .size main, .-main > + .section .note.GNU-stack,"",@progbits > + ' > + > + { $as_echo "$as_me:${as_lineno-$LINENO}: checking libc has > GLIBC_ABI_GNU2_TLS symbol dep and ld emits it" >&5 > +$as_echo_n "checking libc has GLIBC_ABI_GNU2_TLS symbol dep and ld emits > it... " >&6; } > +if ${gcc_cv_libc_x86_tlsdesc_call+:} false; then : > + $as_echo_n "(cached) " >&6 > +else > + > + gcc_cv_libc_x86_tlsdesc_call=no > + echo "$conftest_S" > conftest.S > + if $CC $CFLAGS conftest.S -o conftest -shared > /dev/null > 2>&1; then > + if test x$gcc_cv_readelf != x; then > + if $gcc_cv_readelf --version-info conftest > 2>&1 \ > + | grep "GLIBC_ABI_GNU2_TLS" > > /dev/null 2>&1; then > + gcc_cv_libc_x86_tlsdesc_call=yes > + else > + gcc_cv_libc_x86_tlsdesc_call=no > + fi > + fi > + fi > + rm -f conftest.* > + > +fi > +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: > $gcc_cv_libc_x86_tlsdesc_call" >&5 > +$as_echo "$gcc_cv_libc_x86_tlsdesc_call" >&6; } > + > + # Set with_tls only if it's not already set via --with-tls=DIALECT > + case "$gcc_cv_libc_x86_tlsdesc_call" in > + yes) > + with_tls=${with_tls:-gnu2} > + ;; > + *) > + with_tls=${with_tls:-gnu} > + ;; > + esac > + ;; > +esac > + > # -------------------------------------------------------- > # Build, host, and target specific configuration fragments > # -------------------------------------------------------- > @@ -21484,7 +21623,7 @@ else > lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 > lt_status=$lt_dlunknown > cat > conftest.$ac_ext <<_LT_EOF > -#line 21487 "configure" > +#line 21626 "configure" > #include "confdefs.h" > > #if HAVE_DLFCN_H > @@ -21590,7 +21729,7 @@ else > lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 > lt_status=$lt_dlunknown > cat > conftest.$ac_ext <<_LT_EOF > -#line 21593 "configure" > +#line 21732 "configure" > #include "confdefs.h" > > #if HAVE_DLFCN_H > @@ -25419,78 +25558,6 @@ else > $as_echo "$gcc_cv_objdump" >&6; } > fi > > -# Figure out what readelf we will be using. > -if ${gcc_cv_readelf+:} false; then : > - > -else > - > -if test -f $gcc_cv_binutils_srcdir/configure.ac \ > - && test -f ../binutils/Makefile \ > - && test x$build = x$host; then > - # Single tree build which includes binutils. > - gcc_cv_readelf=../binutils/readelf$build_exeext > -elif test -x readelf$build_exeext; then > - gcc_cv_readelf=./readelf$build_exeext > -elif ( set dummy $READELF_FOR_TARGET; test -x $2 ); then > - gcc_cv_readelf="$READELF_FOR_TARGET" > -else > - # Extract the first word of "$READELF_FOR_TARGET", so it can be a > program name with args. > -set dummy $READELF_FOR_TARGET; ac_word=$2 > -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 > -$as_echo_n "checking for $ac_word... " >&6; } > -if ${ac_cv_path_gcc_cv_readelf+:} false; then : > - $as_echo_n "(cached) " >&6 > -else > - case $gcc_cv_readelf in > - [\\/]* | ?:[\\/]*) > - ac_cv_path_gcc_cv_readelf="$gcc_cv_readelf" # Let the user override the > test with a path. > - ;; > - *) > - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR > -for as_dir in $PATH > -do > - IFS=$as_save_IFS > - test -z "$as_dir" && as_dir=. > - for ac_exec_ext in '' $ac_executable_extensions; do > - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then > - ac_cv_path_gcc_cv_readelf="$as_dir/$ac_word$ac_exec_ext" > - $as_echo "$as_me:${as_lineno-$LINENO}: found > $as_dir/$ac_word$ac_exec_ext" >&5 > - break 2 > - fi > -done > - done > -IFS=$as_save_IFS > - > - ;; > -esac > -fi > -gcc_cv_readelf=$ac_cv_path_gcc_cv_readelf > -if test -n "$gcc_cv_readelf"; then > - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_readelf" >&5 > -$as_echo "$gcc_cv_readelf" >&6; } > -else > - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 > -$as_echo "no" >&6; } > -fi > - > - > -fi > -fi > - > -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking what readelf to use" >&5 > -$as_echo_n "checking what readelf to use... " >&6; } > -if test "$gcc_cv_readelf" = ../binutils/readelf$build_exeext; then > - # Single tree build which includes binutils. > - { $as_echo "$as_me:${as_lineno-$LINENO}: result: newly built readelf" > >&5 > -$as_echo "newly built readelf" >&6; } > -elif test x$gcc_cv_readelf = x; then > - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 > -$as_echo "not found" >&6; } > -else > - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_readelf" >&5 > -$as_echo "$gcc_cv_readelf" >&6; } > -fi > - > # Figure out what otool we will be using. > if ${gcc_cv_otool+:} false; then : > > diff --git a/gcc/configure.ac b/gcc/configure.ac > index 4532c5c22fe5..4c268d565d72 100644 > --- a/gcc/configure.ac > +++ b/gcc/configure.ac > @@ -1886,6 +1886,93 @@ if test "x$enable_win32_utf8_manifest" != xno; then > host_extra_objs_mingw=utf8-mingw32.o > fi > > + > +# Figure out what readelf we will be using. > +AS_VAR_SET_IF(gcc_cv_readelf,, [ > +if test -f $gcc_cv_binutils_srcdir/configure.ac \ > + && test -f ../binutils/Makefile \ > + && test x$build = x$host; then > + # Single tree build which includes binutils. > + gcc_cv_readelf=../binutils/readelf$build_exeext > +elif test -x readelf$build_exeext; then > + gcc_cv_readelf=./readelf$build_exeext > +elif ( set dummy $READELF_FOR_TARGET; test -x $[2] ); then > + gcc_cv_readelf="$READELF_FOR_TARGET" > +else > + AC_PATH_PROG(gcc_cv_readelf, $READELF_FOR_TARGET) > +fi]) > + > +AC_MSG_CHECKING(what readelf to use) > +if test "$gcc_cv_readelf" = ../binutils/readelf$build_exeext; then > + # Single tree build which includes binutils. > + AC_MSG_RESULT(newly built readelf) > +elif test x$gcc_cv_readelf = x; then > + AC_MSG_RESULT(not found) > +else > + AC_MSG_RESULT($gcc_cv_readelf) > +fi > + > +case $target in > +changequote(,)dnl > + i[34567]86-*-gnu* | x86_64-*-gnu* ) > +changequote([,])dnl > + # PR target/120933 > + # For GNU/Linux targets, check if ld emits GLIBC_ABI_GNU2_TLS. For > PR ld/33130, > + # newer ld will add GLIBC_ABI_GNU2_TLS if either unconfigured (auto > mode) or if > + # configured with --enable-gnu2-tls-tag. In auto mode, > GLIBC_ABI_GNU2_TLS > + # is only added if glibc provides it. In explicit mode, the user has > asked > + # for this behavior and binaries will depend on GLIBC_ABI_GNU2_TLS > and fixed > + # glibc. Hence the presence of GLIBC_ABI_GNU2_TLS tells us if we can > safely > + # default to GNU2 TLS descriptors. > + conftest_S=' > + .section .text.startup,"ax",@progbits > + .p2align 4 > + .globl main > + .type main, @function > + main: > + #ifdef __x86_64__ > + leaq foo@TLSDESC(%rip), %rax > + call *foo@TLSCALL(%rax) > + movl %fs:(%rax), %eax > + #else > + leal ld@TLSDESC(%ebx), %eax > + call *ld@TLSCALL(%eax) > + addl %gs:0, %eax > + #endif > + ret > + .size main, .-main > + .section .note.GNU-stack,"",@progbits > + ' > + > + AC_CACHE_CHECK([libc has GLIBC_ABI_GNU2_TLS symbol dep and ld emits > it], > + gcc_cv_libc_x86_tlsdesc_call, [ > + gcc_cv_libc_x86_tlsdesc_call=no > + echo "$conftest_S" > conftest.S > + if $CC $CFLAGS conftest.S -o conftest -shared > /dev/null > 2>&1; then > + if test x$gcc_cv_readelf != x; then > + if $gcc_cv_readelf --version-info conftest > 2>&1 \ > + | grep "GLIBC_ABI_GNU2_TLS" > > /dev/null 2>&1; then > + gcc_cv_libc_x86_tlsdesc_call=yes > + else > + gcc_cv_libc_x86_tlsdesc_call=no > + fi > + fi > + fi > + rm -f conftest.* > + ]) > + > + # Set with_tls only if it's not already set via --with-tls=DIALECT > + case "$gcc_cv_libc_x86_tlsdesc_call" in > + yes) > + with_tls=${with_tls:-gnu2} > + ;; > + *) > + with_tls=${with_tls:-gnu} > + ;; > + esac > + ;; > +esac > + > # -------------------------------------------------------- > # Build, host, and target specific configuration fragments > # -------------------------------------------------------- > @@ -2934,31 +3021,6 @@ else > AC_MSG_RESULT($gcc_cv_objdump) > fi > > -# Figure out what readelf we will be using. > -AS_VAR_SET_IF(gcc_cv_readelf,, [ > -if test -f $gcc_cv_binutils_srcdir/configure.ac \ > - && test -f ../binutils/Makefile \ > - && test x$build = x$host; then > - # Single tree build which includes binutils. > - gcc_cv_readelf=../binutils/readelf$build_exeext > -elif test -x readelf$build_exeext; then > - gcc_cv_readelf=./readelf$build_exeext > -elif ( set dummy $READELF_FOR_TARGET; test -x $[2] ); then > - gcc_cv_readelf="$READELF_FOR_TARGET" > -else > - AC_PATH_PROG(gcc_cv_readelf, $READELF_FOR_TARGET) > -fi]) > - > -AC_MSG_CHECKING(what readelf to use) > -if test "$gcc_cv_readelf" = ../binutils/readelf$build_exeext; then > - # Single tree build which includes binutils. > - AC_MSG_RESULT(newly built readelf) > -elif test x$gcc_cv_readelf = x; then > - AC_MSG_RESULT(not found) > -else > - AC_MSG_RESULT($gcc_cv_readelf) > -fi > - > # Figure out what otool we will be using. > AS_VAR_SET_IF(gcc_cv_otool,, [ > if test -x otool$build_exeext; then > -- > 2.51.0 >