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
>

Reply via email to