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.

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