From 432402b377b9ded33fd294cb2f819be139161472 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Tue, 2 Feb 2021 13:45:58 -0800
Subject: [PATCH v3] x86: Disable x86-64 level marker [BZ #27318]

Since -march=sandybridge enables some ISAs in x86-64 ISA level v3, the v3
marker is set on libc.so.  We couldn't set the needed ISA marker to v2
since this libc won't run on all v2 machines.  Technically, the v3 marker
is correct.  But the resulting libc.so won't run on Sandybrigde, which
isn't a v3 machine, even when libc is compiled with -march=sandybridge:

$ ./elf/ld.so ./libc.so
./libc.so: (p) CPU ISA level is lower than required: needed: 7; got: 3

1. Disable x86-64 ISA level marker for 32-bit build.
2. Disable x86-64 ISA level marker for -march=XXX if its ISA set isn't a
complete subnet of a ISA level.
---
 config.h.in              |   3 +
 sysdeps/x86/configure    | 119 ++++++++++++++++++++++++++++++++++++++-
 sysdeps/x86/configure.ac | 101 ++++++++++++++++++++++++++++++++-
 sysdeps/x86/isa-level.c  |  33 +----------
 4 files changed, 222 insertions(+), 34 deletions(-)

diff --git a/config.h.in b/config.h.in
index 06ee8ae26a..3c9035c2f2 100644
--- a/config.h.in
+++ b/config.h.in
@@ -275,4 +275,7 @@
 /* Define if x86 ISA level should be included in shared libraries.  */
 #undef INCLUDE_X86_ISA_LEVEL
 
+/* The default x86 ISA level.  */
+#define DEFAULT_ISA_LEVEL 0
+
 #endif
diff --git a/sysdeps/x86/configure b/sysdeps/x86/configure
index 5e32dc62b3..3812ba288e 100644
--- a/sysdeps/x86/configure
+++ b/sysdeps/x86/configure
@@ -134,7 +134,120 @@ if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -nostartfiles -nostdlib -r -o conftest c
   test $ac_status = 0; }; }; then
   count=`LC_ALL=C $READELF -n conftest | grep NT_GNU_PROPERTY_TYPE_0 | wc -l`
   if test "$count" = 1; then
-    libc_cv_include_x86_isa_level=yes
+    cat > conftest.c <<EOF
+extern long double fmodl(long double x, long double y);
+extern long double x, y;
+long double
+foo (void)
+{
+  return fmodl (x, y);
+}
+EOF
+    ISA_LEVEL_CPPFLAGS=
+    if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -Os -ffast-math -S -o - conftest.c'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; } | grep -q "	sahf"; then
+      ISA_LEVEL_CPPFLAGS=-D__LAHF_SAHF__
+    fi
+    cat > conftest.c <<EOF
+extern int x;
+int
+bar ()
+{
+  return __builtin_bswap32 (x);
+}
+EOF
+    if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -O2 -S -o - conftest.c'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; } | grep -q "	movbe"; then
+      ISA_LEVEL_CPPFLAGS="$ISA_LEVEL_CPPFLAGS -D__MOVBE__"
+    fi
+    cat > conftest.c <<EOF
+#ifndef __x86_64__
+# error "x86-64 ISA level is only for x86-64"
+#endif
+
+#if defined __SSE__ || defined __SSE2__
+/* NB: Some ISAs in x86-64 ISA level baseline are used.  */
+# if defined __SSE__ && defined __SSE2__
+/* NB: Enable x86-64 ISA level baseline marker only if all ISAs are
+   enabled.  */
+#  define ISA_BASELINE	GNU_PROPERTY_X86_ISA_1_BASELINE
+# else
+#  error "Missing ISAs for x86-64 ISA level baseline"
+# endif
+#else
+# define ISA_BASELINE	0
+#endif
+
+#if defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 \
+   || defined __LAHF_SAHF__ || defined __POPCNT__ || defined __SSE3__ \
+   || defined __SSSE3__ || defined __SSE4_1__ || defined __SSE4_2__
+/* NB: Some ISAs in x86-64 ISA level v2 are used.  */
+# if defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 \
+     && defined __LAHF_SAHF__ && defined __POPCNT__ && defined __SSE3__ \
+     && defined __SSSE3__ && defined __SSE4_1__ && defined __SSE4_2__
+/* NB: Enable x86-64 ISA level v2 marker only if all ISAs are enabled.  */
+#  define ISA_V2	GNU_PROPERTY_X86_ISA_1_V2
+# else
+/* NB: We can't use the lesser x86-64 ISA level marker since some v2 ISAs
+   are used.  */
+#  error "Missing ISAs for x86-64 ISA level v2"
+# endif
+#else
+# define ISA_V2	0
+#endif
+
+#if defined __AVX__ || defined __AVX2__ || defined __F16C__ \
+    || defined __FMA__ || defined __LZCNT__ || defined __MOVBE__
+/* NB: Some ISAs in x86-64 ISA level v3 are used.  */
+# if defined __AVX__ && defined __AVX2__ && defined __F16C__ \
+     && defined __FMA__ && defined __LZCNT__ && defined __MOVBE__
+/* NB: Enable x86-64 ISA level v3 marker only if all ISAs are enabled.  */
+#  define ISA_V3	GNU_PROPERTY_X86_ISA_1_V3
+# else
+/* NB: We can't use the lesser x86-64 ISA level marker since some v3 ISAs
+   are used.  */
+#  error "Missing ISAs for x86-64 ISA level v3"
+# endif
+#else
+# define ISA_V3	0
+#endif
+
+#if defined __AVX512F__ || defined __AVX512BW__ || defined __AVX512CD__ \
+    || defined __AVX512DQ__ || defined __AVX512VL__
+/* NB: Some ISAs in x86-64 ISA level v4 are used.  */
+# if defined __AVX512F__ && defined __AVX512BW__ \
+     && defined __AVX512CD__ && defined __AVX512DQ__ \
+     && defined __AVX512VL__
+/* NB: Enable x86-64 ISA level v4 marker only if all ISAs are enabled.  */
+#  define ISA_V4	GNU_PROPERTY_X86_ISA_1_V4
+# else
+/* NB: We can't use the lesser x86-64 ISA level marker since some v4 ISAs
+   are used.  */
+#  error "Missing ISAs for x86-64 ISA level v4"
+# endif
+#else
+# define ISA_V4	0
+#endif
+
+DEFAULT_ISA_LEVEL=(ISA_BASELINE | ISA_V2 | ISA_V3 | ISA_V4)
+EOF
+    if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $ISA_LEVEL_CPPFLAGS -E -o conftest.i conftest.c'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+      eval `grep DEFAULT_ISA_LEVEL= conftest.i | sed -e "s/DEFAULT_ISA_LEVEL=\(.*\)/DEFAULT_ISA_LEVEL=\"\1\"/"`
+      libc_cv_include_x86_isa_level=yes
+    fi
   fi
 fi
 rm -f conftest*
@@ -144,6 +257,10 @@ $as_echo "$libc_cv_include_x86_isa_level" >&6; }
 if test $libc_cv_include_x86_isa_level = yes; then
   $as_echo "#define INCLUDE_X86_ISA_LEVEL 1" >>confdefs.h
 
+  cat >>confdefs.h <<_ACEOF
+#define DEFAULT_ISA_LEVEL $DEFAULT_ISA_LEVEL
+_ACEOF
+
 fi
 config_vars="$config_vars
 enable-x86-isa-level = $libc_cv_include_x86_isa_level"
diff --git a/sysdeps/x86/configure.ac b/sysdeps/x86/configure.ac
index f94088f377..39d307a6d1 100644
--- a/sysdeps/x86/configure.ac
+++ b/sysdeps/x86/configure.ac
@@ -101,11 +101,110 @@ libc_cv_include_x86_isa_level=no
 if AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS -nostartfiles -nostdlib -r -o conftest conftest1.S conftest2.S); then
   count=`LC_ALL=C $READELF -n conftest | grep NT_GNU_PROPERTY_TYPE_0 | wc -l`
   if test "$count" = 1; then
-    libc_cv_include_x86_isa_level=yes
+    cat > conftest.c <<EOF
+extern long double fmodl(long double x, long double y);
+extern long double x, y;
+long double
+foo (void)
+{
+  return fmodl (x, y);
+}
+EOF
+    ISA_LEVEL_CPPFLAGS=
+    if AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS -Os -ffast-math -S -o - conftest.c) | grep -q "	sahf"; then
+      ISA_LEVEL_CPPFLAGS=-D__LAHF_SAHF__
+    fi
+    cat > conftest.c <<EOF
+extern int x;
+int
+bar ()
+{
+  return __builtin_bswap32 (x);
+}
+EOF
+    if AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS -O2 -S -o - conftest.c) | grep -q "	movbe"; then
+      ISA_LEVEL_CPPFLAGS="$ISA_LEVEL_CPPFLAGS -D__MOVBE__"
+    fi
+    cat > conftest.c <<EOF
+#ifndef __x86_64__
+# error "x86-64 ISA level is only for x86-64"
+#endif
+
+#if defined __SSE__ || defined __SSE2__
+/* NB: Some ISAs in x86-64 ISA level baseline are used.  */
+# if defined __SSE__ && defined __SSE2__
+/* NB: Enable x86-64 ISA level baseline marker only if all ISAs are
+   enabled.  */
+#  define ISA_BASELINE	GNU_PROPERTY_X86_ISA_1_BASELINE
+# else
+#  error "Missing ISAs for x86-64 ISA level baseline"
+# endif
+#else
+# define ISA_BASELINE	0
+#endif
+
+#if defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 \
+   || defined __LAHF_SAHF__ || defined __POPCNT__ || defined __SSE3__ \
+   || defined __SSSE3__ || defined __SSE4_1__ || defined __SSE4_2__
+/* NB: Some ISAs in x86-64 ISA level v2 are used.  */
+# if defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 \
+     && defined __LAHF_SAHF__ && defined __POPCNT__ && defined __SSE3__ \
+     && defined __SSSE3__ && defined __SSE4_1__ && defined __SSE4_2__
+/* NB: Enable x86-64 ISA level v2 marker only if all ISAs are enabled.  */
+#  define ISA_V2	GNU_PROPERTY_X86_ISA_1_V2
+# else
+/* NB: We can't use the lesser x86-64 ISA level marker since some v2 ISAs
+   are used.  */
+#  error "Missing ISAs for x86-64 ISA level v2"
+# endif
+#else
+# define ISA_V2	0
+#endif
+
+#if defined __AVX__ || defined __AVX2__ || defined __F16C__ \
+    || defined __FMA__ || defined __LZCNT__ || defined __MOVBE__
+/* NB: Some ISAs in x86-64 ISA level v3 are used.  */
+# if defined __AVX__ && defined __AVX2__ && defined __F16C__ \
+     && defined __FMA__ && defined __LZCNT__ && defined __MOVBE__
+/* NB: Enable x86-64 ISA level v3 marker only if all ISAs are enabled.  */
+#  define ISA_V3	GNU_PROPERTY_X86_ISA_1_V3
+# else
+/* NB: We can't use the lesser x86-64 ISA level marker since some v3 ISAs
+   are used.  */
+#  error "Missing ISAs for x86-64 ISA level v3"
+# endif
+#else
+# define ISA_V3	0
+#endif
+
+#if defined __AVX512F__ || defined __AVX512BW__ || defined __AVX512CD__ \
+    || defined __AVX512DQ__ || defined __AVX512VL__
+/* NB: Some ISAs in x86-64 ISA level v4 are used.  */
+# if defined __AVX512F__ && defined __AVX512BW__ \
+     && defined __AVX512CD__ && defined __AVX512DQ__ \
+     && defined __AVX512VL__
+/* NB: Enable x86-64 ISA level v4 marker only if all ISAs are enabled.  */
+#  define ISA_V4	GNU_PROPERTY_X86_ISA_1_V4
+# else
+/* NB: We can't use the lesser x86-64 ISA level marker since some v4 ISAs
+   are used.  */
+#  error "Missing ISAs for x86-64 ISA level v4"
+# endif
+#else
+# define ISA_V4	0
+#endif
+
+DEFAULT_ISA_LEVEL=(ISA_BASELINE | ISA_V2 | ISA_V3 | ISA_V4)
+EOF
+    if AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS $ISA_LEVEL_CPPFLAGS -E -o conftest.i conftest.c); then
+      eval `grep DEFAULT_ISA_LEVEL= conftest.i | sed -e "s/DEFAULT_ISA_LEVEL=\(.*\)/DEFAULT_ISA_LEVEL=\"\1\"/"`
+      libc_cv_include_x86_isa_level=yes
+    fi
   fi
 fi
 rm -f conftest*])
 if test $libc_cv_include_x86_isa_level = yes; then
   AC_DEFINE(INCLUDE_X86_ISA_LEVEL)
+  AC_DEFINE_UNQUOTED([DEFAULT_ISA_LEVEL], [$DEFAULT_ISA_LEVEL])
 fi
 LIBC_CONFIG_VAR([enable-x86-isa-level], [$libc_cv_include_x86_isa_level])
diff --git a/sysdeps/x86/isa-level.c b/sysdeps/x86/isa-level.c
index aaf524cb56..cb7667d9d5 100644
--- a/sysdeps/x86/isa-level.c
+++ b/sysdeps/x86/isa-level.c
@@ -29,39 +29,8 @@
 
 /* ELF program property for x86 ISA level.  */
 #ifdef INCLUDE_X86_ISA_LEVEL
-# if defined __x86_64__ || defined __FXSR__ || !defined _SOFT_FLOAT \
-     || defined  __MMX__ || defined __SSE__ || defined __SSE2__
-#  define ISA_BASELINE	GNU_PROPERTY_X86_ISA_1_BASELINE
-# else
-#  define ISA_BASELINE	0
-# endif
-
-# if defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 \
-     || (defined __x86_64__ && defined __LAHF_SAHF__) \
-     || defined __POPCNT__ || defined __SSE3__ \
-     || defined __SSSE3__ || defined __SSE4_1__ || defined __SSE4_2__
-#  define ISA_V2	GNU_PROPERTY_X86_ISA_1_V2
-# else
-#  define ISA_V2	0
-# endif
-
-# if defined __AVX__ || defined __AVX2__ || defined __F16C__ \
-     || defined __FMA__ || defined __LZCNT__ || defined __MOVBE__ \
-     || defined __XSAVE__
-#  define ISA_V3	GNU_PROPERTY_X86_ISA_1_V3
-# else
-#  define ISA_V3	0
-# endif
-
-# if defined __AVX512F__ || defined __AVX512BW__ || defined __AVX512CD__ \
-     || defined __AVX512DQ__ || defined __AVX512VL__
-#  define ISA_V4	GNU_PROPERTY_X86_ISA_1_V4
-# else
-#  define ISA_V4	0
-# endif
-
 # ifndef ISA_LEVEL
-#  define ISA_LEVEL (ISA_BASELINE | ISA_V2 | ISA_V3 | ISA_V4)
+#  define ISA_LEVEL DEFAULT_ISA_LEVEL
 # endif
 
 # if ISA_LEVEL
-- 
2.29.2

