x86: Support GNU_PROPERTY_X86_ISA_1_V[234] marker [BZ #26717]
authorH.J. Lu <hjl.tools@gmail.com>
Fri, 9 Oct 2020 13:06:56 +0000 (06:06 -0700)
committerH.J. Lu <hjl.tools@gmail.com>
Thu, 7 Jan 2021 21:10:13 +0000 (13:10 -0800)
GCC 11 supports -march=x86-64-v[234] to enable x86 micro-architecture ISA
levels:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97250

and -mneeded to emit GNU_PROPERTY_X86_ISA_1_NEEDED property with
GNU_PROPERTY_X86_ISA_1_V[234] marker:

https://gitlab.com/x86-psABIs/x86-64-ABI/-/merge_requests/13

Binutils support for GNU_PROPERTY_X86_ISA_1_V[234] marker were added by

commit b0ab06937385e0ae25cebf1991787d64f439bf12
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Fri Oct 30 06:49:57 2020 -0700

    x86: Support GNU_PROPERTY_X86_ISA_1_BASELINE marker

and

commit 32930e4edbc06bc6f10c435dbcc63131715df678
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Fri Oct 9 05:05:57 2020 -0700

    x86: Support GNU_PROPERTY_X86_ISA_1_V[234] marker

GNU_PROPERTY_X86_ISA_1_NEEDED property in x86 ELF binaries indicate the
micro-architecture ISA level required to execute the binary.  The marker
must be added by programmers explicitly in one of 3 ways:

1. Pass -mneeded to GCC.
2. Add the marker in the linker inputs as this patch does.
3. Pass -z x86-64-v[234] to the linker.

Add GNU_PROPERTY_X86_ISA_1_BASELINE and GNU_PROPERTY_X86_ISA_1_V[234]
marker support to ld.so if binutils 2.32 or newer is used to build glibc:

1. Add GNU_PROPERTY_X86_ISA_1_BASELINE and GNU_PROPERTY_X86_ISA_1_V[234]
markers to elf.h.
2. Add GNU_PROPERTY_X86_ISA_1_BASELINE and GNU_PROPERTY_X86_ISA_1_V[234]
marker to abi-note.o based on the ISA level used to compile abi-note.o,
assuming that the same ISA level is used to compile the whole glibc.
3. Add isa_1 to cpu_features to record the supported x86 ISA level.
4. Rename _dl_process_cet_property_note to _dl_process_property_note and
add GNU_PROPERTY_X86_ISA_1_V[234] marker detection.
5. Update _rtld_main_check and _dl_open_check to check loaded objects
with the incompatible ISA level.
6. Add a testcase to verify that dlopen an x86-64-v4 shared object fails
on lesser platforms.
7. Use <get-isa-level.h> in dl-hwcaps-subdirs.c and tst-glibc-hwcaps.c.

Tested under i686, x32 and x86-64 modes on x86-64-v2, x86-64-v3 and
x86-64-v4 machines.

Marked elf/tst-isa-level-1 with x86-64-v4, ran it on x86-64-v3 machine
and got:

[hjl@gnu-cfl-2 build-x86_64-linux]$ ./elf/tst-isa-level-1
./elf/tst-isa-level-1: CPU ISA level is lower than required
[hjl@gnu-cfl-2 build-x86_64-linux]$

21 files changed:
config.h.in
elf/elf.h
sysdeps/x86/Makefile
sysdeps/x86/abi-note.c [new file with mode: 0644]
sysdeps/x86/configure
sysdeps/x86/configure.ac
sysdeps/x86/cpu-features.c
sysdeps/x86/dl-cet.c
sysdeps/x86/dl-prop.h
sysdeps/x86/get-isa-level.h [new file with mode: 0644]
sysdeps/x86/include/cpu-features.h
sysdeps/x86/isa-level.c [new file with mode: 0644]
sysdeps/x86/link_map.h
sysdeps/x86/tst-isa-level-1.c [new file with mode: 0644]
sysdeps/x86/tst-isa-level-mod-1-baseline.c [new file with mode: 0644]
sysdeps/x86/tst-isa-level-mod-1-v2.c [new file with mode: 0644]
sysdeps/x86/tst-isa-level-mod-1-v3.c [new file with mode: 0644]
sysdeps/x86/tst-isa-level-mod-1-v4.c [new file with mode: 0644]
sysdeps/x86/tst-isa-level-mod-1.c [new file with mode: 0644]
sysdeps/x86_64/dl-hwcaps-subdirs.c
sysdeps/x86_64/tst-glibc-hwcaps.c

index eca2d66..947feef 100644 (file)
 /* The default value of x86 CET control.  */
 #define DEFAULT_DL_X86_CET_CONTROL cet_elf_property
 
+/* Define if x86 ISA level should be included in shared libraries.  */
+#undef INCLUDE_X86_ISA_LEVEL
+
 #endif
index 4a9ae97..9ebd052 100644 (file)
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -1324,31 +1324,26 @@ typedef struct
 
 /* The x86 instruction sets indicated by the corresponding bits are
    used in program.  Their support in the hardware is optional.  */
-#define GNU_PROPERTY_X86_ISA_1_USED            0xc0000000
+#define GNU_PROPERTY_X86_ISA_1_USED            0xc0010002
 /* The x86 instruction sets indicated by the corresponding bits are
    used in program and they must be supported by the hardware.   */
-#define GNU_PROPERTY_X86_ISA_1_NEEDED          0xc0000001
+#define GNU_PROPERTY_X86_ISA_1_NEEDED          0xc0008002
 /* X86 processor-specific features used in program.  */
 #define GNU_PROPERTY_X86_FEATURE_1_AND         0xc0000002
 
-#define GNU_PROPERTY_X86_ISA_1_486             (1U << 0)
-#define GNU_PROPERTY_X86_ISA_1_586             (1U << 1)
-#define GNU_PROPERTY_X86_ISA_1_686             (1U << 2)
-#define GNU_PROPERTY_X86_ISA_1_SSE             (1U << 3)
-#define GNU_PROPERTY_X86_ISA_1_SSE2            (1U << 4)
-#define GNU_PROPERTY_X86_ISA_1_SSE3            (1U << 5)
-#define GNU_PROPERTY_X86_ISA_1_SSSE3           (1U << 6)
-#define GNU_PROPERTY_X86_ISA_1_SSE4_1          (1U << 7)
-#define GNU_PROPERTY_X86_ISA_1_SSE4_2          (1U << 8)
-#define GNU_PROPERTY_X86_ISA_1_AVX             (1U << 9)
-#define GNU_PROPERTY_X86_ISA_1_AVX2            (1U << 10)
-#define GNU_PROPERTY_X86_ISA_1_AVX512F         (1U << 11)
-#define GNU_PROPERTY_X86_ISA_1_AVX512CD                (1U << 12)
-#define GNU_PROPERTY_X86_ISA_1_AVX512ER                (1U << 13)
-#define GNU_PROPERTY_X86_ISA_1_AVX512PF                (1U << 14)
-#define GNU_PROPERTY_X86_ISA_1_AVX512VL                (1U << 15)
-#define GNU_PROPERTY_X86_ISA_1_AVX512DQ                (1U << 16)
-#define GNU_PROPERTY_X86_ISA_1_AVX512BW                (1U << 17)
+/* GNU_PROPERTY_X86_ISA_1_BASELINE: CMOV, CX8 (cmpxchg8b), FPU (fld),
+   MMX, OSFXSR (fxsave), SCE (syscall), SSE and SSE2.  */
+#define GNU_PROPERTY_X86_ISA_1_BASELINE                (1U << 0)
+/* GNU_PROPERTY_X86_ISA_1_V2: GNU_PROPERTY_X86_ISA_1_BASELINE,
+   CMPXCHG16B (cmpxchg16b), LAHF-SAHF (lahf), POPCNT (popcnt), SSE3,
+   SSSE3, SSE4.1 and SSE4.2.  */
+#define GNU_PROPERTY_X86_ISA_1_V2              (1U << 1)
+/* GNU_PROPERTY_X86_ISA_1_V3: GNU_PROPERTY_X86_ISA_1_V2, AVX, AVX2, BMI1,
+   BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE.  */
+#define GNU_PROPERTY_X86_ISA_1_V3              (1U << 2)
+/* GNU_PROPERTY_X86_ISA_1_V4: GNU_PROPERTY_X86_ISA_1_V3, AVX512F,
+   AVX512BW, AVX512CD, AVX512DQ and AVX512VL.  */
+#define GNU_PROPERTY_X86_ISA_1_V4              (1U << 3)
 
 /* This indicates that all executable sections are compatible with
    IBT.  */
index 081cc72..c814d5a 100644 (file)
@@ -9,6 +9,36 @@ sysdep_headers += sys/platform/x86.h
 tests += tst-get-cpu-features tst-get-cpu-features-static \
         tst-cpu-features-cpuinfo tst-cpu-features-supports
 tests-static += tst-get-cpu-features-static
+ifeq (yes,$(enable-x86-isa-level))
+tests += tst-isa-level-1
+modules-names += tst-isa-level-mod-1-baseline \
+                tst-isa-level-mod-1-v2 \
+                tst-isa-level-mod-1-v3 \
+                tst-isa-level-mod-1-v4 \
+
+# X86 ISA level baseline
+CFLAGS-tst-isa-level-mod-1-baseline.c += -DINCLUDE_X86_ISA_LEVEL \
+                                        -DISA_LEVEL=0x1 \
+                                        -march=x86-64
+# X86 ISA level v2
+CFLAGS-tst-isa-level-mod-1-v2.c += -DINCLUDE_X86_ISA_LEVEL \
+                                  -DISA_LEVEL=0x3 \
+                                  -march=x86-64
+# X86 ISA level v3
+CFLAGS-tst-isa-level-mod-1-v3.c += -DINCLUDE_X86_ISA_LEVEL \
+                                  -DISA_LEVEL=0x7 \
+                                  -march=x86-64
+# X86 ISA level v4
+CFLAGS-tst-isa-level-mod-1-v4.c += -DINCLUDE_X86_ISA_LEVEL \
+                                  -DISA_LEVEL=0xf \
+                                  -march=x86-64
+
+$(objpfx)tst-isa-level-1: $(libdl)
+$(objpfx)tst-isa-level-1.out: $(objpfx)tst-isa-level-mod-1-baseline.so \
+                             $(objpfx)tst-isa-level-mod-1-v2.so \
+                             $(objpfx)tst-isa-level-mod-1-v3.so \
+                             $(objpfx)tst-isa-level-mod-1-v4.so
+endif
 endif
 
 ifeq ($(subdir),math)
diff --git a/sysdeps/x86/abi-note.c b/sysdeps/x86/abi-note.c
new file mode 100644 (file)
index 0000000..5140e6a
--- /dev/null
@@ -0,0 +1,29 @@
+/* Special .init and .fini section support.  x86-64 version.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file with other
+   programs, and to distribute those programs without any restriction
+   coming from the use of this file.  (The Lesser General Public
+   License restrictions do apply in other respects; for example, they
+   cover modification of the file, and distribution when not linked
+   into another program.)
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <isa-level.c>
+#include <csu/abi-note.c>
index 81cc4e8..5e32dc6 100644 (file)
@@ -68,3 +68,82 @@ elif test $enable_cet = permissive; then
 fi
 config_vars="$config_vars
 enable-cet = $enable_cet"
+
+# Check if linker supports x86 ISA level.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for linker x86 ISA level support" >&5
+$as_echo_n "checking for linker x86 ISA level support... " >&6; }
+if ${libc_cv_include_x86_isa_level+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat > conftest1.S <<EOF
+#ifdef __LP64__
+# define P2ALIGN 3
+#else
+# define P2ALIGN 2
+#endif
+       .section ".note.gnu.property", "a"
+       .p2align P2ALIGN
+       .long 1f - 0f           /* name length.  */
+       .long 4f - 1f           /* data length.  */
+       /* NT_GNU_PROPERTY_TYPE_0 */
+       .long 5                 /* note type.  */
+0:
+       .asciz "GNU"            /* vendor name.  */
+1:
+       .p2align P2ALIGN
+       /* GNU_PROPERTY_X86_ISA_1_NEEDED */
+       .long 0xc0008002        /* pr_type.  */
+       .long 3f - 2f           /* pr_datasz.  */
+2:
+       .long 0x1
+3:
+       .p2align P2ALIGN
+4:
+EOF
+cat > conftest2.S <<EOF
+#ifdef __LP64__
+# define P2ALIGN 3
+#else
+# define P2ALIGN 2
+#endif
+       .section ".note.gnu.property", "a"
+       .p2align P2ALIGN
+       .long 1f - 0f           /* name length.  */
+       .long 4f - 1f           /* data length.  */
+       /* NT_GNU_PROPERTY_TYPE_0 */
+       .long 5                 /* note type.  */
+0:
+       .asciz "GNU"            /* vendor name.  */
+1:
+       .p2align P2ALIGN
+       /* GNU_PROPERTY_X86_ISA_1_NEEDED */
+       .long 0xc0008002        /* pr_type.  */
+       .long 3f - 2f           /* pr_datasz.  */
+2:
+       .long 0x2
+3:
+       .p2align P2ALIGN
+4:
+EOF
+libc_cv_include_x86_isa_level=no
+if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -nostartfiles -nostdlib -r -o conftest conftest1.S conftest2.S'
+  { { 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
+  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
+  fi
+fi
+rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_include_x86_isa_level" >&5
+$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
+
+fi
+config_vars="$config_vars
+enable-x86-isa-level = $libc_cv_include_x86_isa_level"
index 8f3e119..f94088f 100644 (file)
@@ -43,3 +43,69 @@ elif test $enable_cet = permissive; then
   AC_DEFINE(DEFAULT_DL_X86_CET_CONTROL, cet_permissive)
 fi
 LIBC_CONFIG_VAR([enable-cet], [$enable_cet])
+
+# Check if linker supports x86 ISA level.
+AC_CACHE_CHECK([for linker x86 ISA level support],
+              libc_cv_include_x86_isa_level, [dnl
+cat > conftest1.S <<EOF
+#ifdef __LP64__
+# define P2ALIGN 3
+#else
+# define P2ALIGN 2
+#endif
+       .section ".note.gnu.property", "a"
+       .p2align P2ALIGN
+       .long 1f - 0f           /* name length.  */
+       .long 4f - 1f           /* data length.  */
+       /* NT_GNU_PROPERTY_TYPE_0 */
+       .long 5                 /* note type.  */
+0:
+       .asciz "GNU"            /* vendor name.  */
+1:
+       .p2align P2ALIGN
+       /* GNU_PROPERTY_X86_ISA_1_NEEDED */
+       .long 0xc0008002        /* pr_type.  */
+       .long 3f - 2f           /* pr_datasz.  */
+2:
+       .long 0x1
+3:
+       .p2align P2ALIGN
+4:
+EOF
+cat > conftest2.S <<EOF
+#ifdef __LP64__
+# define P2ALIGN 3
+#else
+# define P2ALIGN 2
+#endif
+       .section ".note.gnu.property", "a"
+       .p2align P2ALIGN
+       .long 1f - 0f           /* name length.  */
+       .long 4f - 1f           /* data length.  */
+       /* NT_GNU_PROPERTY_TYPE_0 */
+       .long 5                 /* note type.  */
+0:
+       .asciz "GNU"            /* vendor name.  */
+1:
+       .p2align P2ALIGN
+       /* GNU_PROPERTY_X86_ISA_1_NEEDED */
+       .long 0xc0008002        /* pr_type.  */
+       .long 3f - 2f           /* pr_datasz.  */
+2:
+       .long 0x2
+3:
+       .p2align P2ALIGN
+4:
+EOF
+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
+  fi
+fi
+rm -f conftest*])
+if test $libc_cv_include_x86_isa_level = yes; then
+  AC_DEFINE(INCLUDE_X86_ISA_LEVEL)
+fi
+LIBC_CONFIG_VAR([enable-x86-isa-level], [$libc_cv_include_x86_isa_level])
index 529c586..e7da682 100644 (file)
@@ -19,6 +19,7 @@
 #include <cpuid.h>
 #include <dl-hwcap.h>
 #include <libc-pointer-arith.h>
+#include <get-isa-level.h>
 #if IS_IN (libc) && !defined SHARED
 # include <assert.h>
 # include <unistd.h>
@@ -290,6 +291,8 @@ update_usable (struct cpu_features *cpu_features)
       CPU_FEATURE_SET_USABLE (cpu_features, KL);
       CPU_FEATURE_SET_USABLE (cpu_features, WIDE_KL);
     }
+
+  cpu_features->isa_1 = get_isa_level (cpu_features);
 }
 
 static void
index b4910f7..ed7fd6d 100644 (file)
@@ -76,10 +76,12 @@ dl_cet_check (struct link_map *m, const char *program)
           */
          enable_ibt &= (HAS_CPU_FEATURE (IBT)
                         && (enable_ibt_type == cet_always_on
-                            || (m->l_cet & lc_ibt) != 0));
+                            || (m->l_x86_feature_1_and
+                                & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0));
          enable_shstk &= (HAS_CPU_FEATURE (SHSTK)
                           && (enable_shstk_type == cet_always_on
-                              || (m->l_cet & lc_shstk) != 0));
+                              || (m->l_x86_feature_1_and
+                                  & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0));
        }
 
       /* ld.so is CET-enabled by kernel.  But shared objects may not
@@ -111,7 +113,8 @@ dl_cet_check (struct link_map *m, const char *program)
              /* IBT is enabled only if it is enabled in executable as
                 well as all shared objects.  */
              enable_ibt &= (enable_ibt_type == cet_always_on
-                            || (l->l_cet & lc_ibt) != 0);
+                            || (l->l_x86_feature_1_and
+                                & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0);
              if (!found_ibt_legacy && enable_ibt != ibt_enabled)
                {
                  found_ibt_legacy = true;
@@ -121,7 +124,8 @@ dl_cet_check (struct link_map *m, const char *program)
              /* SHSTK is enabled only if it is enabled in executable as
                 well as all shared objects.  */
              enable_shstk &= (enable_shstk_type == cet_always_on
-                              || (l->l_cet & lc_shstk) != 0);
+                              || (l->l_x86_feature_1_and
+                                  & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0);
              if (enable_shstk != shstk_enabled)
                {
                  found_shstk_legacy = true;
index ce1667d..56bd020 100644 (file)
 #ifndef _DL_PROP_H
 #define _DL_PROP_H
 
+#include <libintl.h>
+
 extern void _dl_cet_check (struct link_map *, const char *)
     attribute_hidden;
 extern void _dl_cet_open_check (struct link_map *)
     attribute_hidden;
 
+static void
+dl_isa_level_check (struct link_map *m, const char *program)
+{
+  const struct cpu_features *cpu_features = __get_cpu_features ();
+  unsigned int i;
+  struct link_map *l;
+
+  i = m->l_searchlist.r_nlist;
+  while (i-- > 0)
+    {
+      /* Check each shared object to see if ISA level is compatible.  */
+      l = m->l_initfini[i];
+
+      /* Skip ISA level check if functions have been executed.  */
+      if (l->l_init_called)
+       continue;
+
+#ifdef SHARED
+      /* Skip ISA level check for ld.so since ld.so won't run if its ISA
+        level is higher than CPU.  */
+      if (l == &GL(dl_rtld_map) || l->l_real == &GL(dl_rtld_map))
+       continue;
+#endif
+
+      if ((l->l_x86_isa_1_needed & cpu_features->isa_1)
+         != l->l_x86_isa_1_needed)
+       {
+         if (program)
+           _dl_fatal_printf ("%s: CPU ISA level is lower than required\n",
+                             *l->l_name != '\0' ? l->l_name : program);
+         else
+           _dl_signal_error (0, l->l_name, "dlopen",
+                             N_("CPU ISA level is lower than required"));
+       }
+    }
+}
+
 static inline void __attribute__ ((always_inline))
 _rtld_main_check (struct link_map *m, const char *program)
 {
+  dl_isa_level_check (m, program);
 #if CET_ENABLED
   _dl_cet_check (m, program);
 #endif
@@ -35,20 +75,18 @@ _rtld_main_check (struct link_map *m, const char *program)
 static inline void __attribute__ ((always_inline))
 _dl_open_check (struct link_map *m)
 {
+  dl_isa_level_check (m, NULL);
 #if CET_ENABLED
   _dl_cet_open_check (m);
 #endif
 }
 
 static inline void __attribute__ ((unused))
-_dl_process_cet_property_note (struct link_map *l,
-                             const ElfW(Nhdr) *note,
-                             const ElfW(Addr) size,
-                             const ElfW(Addr) align)
+_dl_process_property_note (struct link_map *l, const ElfW(Nhdr) *note,
+                          const ElfW(Addr) size, const ElfW(Addr) align)
 {
-#if CET_ENABLED
   /* Skip if we have seen a NT_GNU_PROPERTY_TYPE_0 note before.  */
-  if (l->l_cet != lc_unknown)
+  if (l->l_property != lc_property_unknown)
     return;
 
   /* The NT_GNU_PROPERTY_TYPE_0 note must be aliged to 4 bytes in
@@ -59,7 +97,8 @@ _dl_process_cet_property_note (struct link_map *l,
 
   const ElfW(Addr) start = (ElfW(Addr)) note;
 
-  unsigned int feature_1 = 0;
+  unsigned int feature_1_and = 0;
+  unsigned int isa_1_needed = 0;
   unsigned int last_type = 0;
 
   while ((ElfW(Addr)) (note + 1) - start < size)
@@ -71,11 +110,11 @@ _dl_process_cet_property_note (struct link_map *l,
        {
          /* Stop if we see more than one GNU property note which may
             be generated by the older linker.  */
-         if (l->l_cet != lc_unknown)
+         if (l->l_property != lc_property_unknown)
            return;
 
-         /* Check CET status now.  */
-         l->l_cet = lc_none;
+         /* Check CET status and ISA levels now.  */
+         l->l_property = lc_property_none;
 
          /* Check for invalid property.  */
          if (note->n_descsz < 8
@@ -101,26 +140,37 @@ _dl_process_cet_property_note (struct link_map *l,
 
              last_type = type;
 
-             if (type == GNU_PROPERTY_X86_FEATURE_1_AND)
+             if (type == GNU_PROPERTY_X86_FEATURE_1_AND
+                 || type == GNU_PROPERTY_X86_ISA_1_NEEDED)
                {
-                 /* The size of GNU_PROPERTY_X86_FEATURE_1_AND is 4
-                    bytes.  When seeing GNU_PROPERTY_X86_FEATURE_1_AND,
-                    we stop the search regardless if its size is correct
-                    or not.  There is no point to continue if this note
-                    is ill-formed.  */
+                 /* The sizes of types which we are searching for are
+                    4 bytes.  There is no point to continue if this
+                    note is ill-formed.  */
                  if (datasz != 4)
                    return;
 
-                 feature_1 = *(unsigned int *) ptr;
-
-                 /* Keep searching for the next GNU property note
-                    generated by the older linker.  */
-                 break;
+                 /* NB: Stop the scan only after seeing all types which
+                    we are searching for.  */
+                 _Static_assert ((GNU_PROPERTY_X86_ISA_1_NEEDED >
+                                  GNU_PROPERTY_X86_FEATURE_1_AND),
+                                 "GNU_PROPERTY_X86_ISA_1_NEEDED > "
+                                 "GNU_PROPERTY_X86_FEATURE_1_AND");
+                 if (type == GNU_PROPERTY_X86_FEATURE_1_AND)
+                   feature_1_and = *(unsigned int *) ptr;
+                 else
+                   {
+                     isa_1_needed = *(unsigned int *) ptr;
+
+                     /* Keep searching for the next GNU property note
+                        generated by the older linker.  */
+                     break;
+                   }
                }
-             else if (type > GNU_PROPERTY_X86_FEATURE_1_AND)
+             else if (type > GNU_PROPERTY_X86_ISA_1_NEEDED)
                {
-                 /* Stop since property type is in ascending order.  */
-                 return;
+                 /* Stop the scan since property type is in ascending
+                    order.  */
+                 break;
                }
 
              /* Check the next property item.  */
@@ -137,18 +187,21 @@ _dl_process_cet_property_note (struct link_map *l,
     }
 
   /* We get here only if there is one or no GNU property note.  */
-  if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_IBT))
-    l->l_cet |= lc_ibt;
-  if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_SHSTK))
-    l->l_cet |= lc_shstk;
-#endif
+  if (isa_1_needed != 0 || feature_1_and != 0)
+    {
+      l->l_property = lc_property_valid;
+      l->l_x86_isa_1_needed = isa_1_needed;
+      l->l_x86_feature_1_and = feature_1_and;
+    }
+  else
+    l->l_property = lc_property_none;
 }
 
 static inline void __attribute__ ((unused))
 _dl_process_pt_note (struct link_map *l, int fd, const ElfW(Phdr) *ph)
 {
   const ElfW(Nhdr) *note = (const void *) (ph->p_vaddr + l->l_addr);
-  _dl_process_cet_property_note (l, note, ph->p_memsz, ph->p_align);
+  _dl_process_property_note (l, note, ph->p_memsz, ph->p_align);
 }
 
 static inline int __attribute__ ((always_inline))
diff --git a/sysdeps/x86/get-isa-level.h b/sysdeps/x86/get-isa-level.h
new file mode 100644 (file)
index 0000000..a86e1e8
--- /dev/null
@@ -0,0 +1,66 @@
+/* Get x86 ISA level.
+   This file is part of the GNU C Library.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sys/platform/x86.h>
+
+/* Get GNU_PROPERTY_X86_ISA_1_BASELINE and GNU_PROPERTY_X86_ISA_1_V[234]
+   ISA level.  */
+
+static unsigned int
+get_isa_level (const struct cpu_features *cpu_features)
+{
+  unsigned int isa_level = 0;
+
+  if (CPU_FEATURE_USABLE_P (cpu_features, CMOV)
+      && CPU_FEATURE_USABLE_P (cpu_features, CX8)
+      && CPU_FEATURE_CPU_P (cpu_features, FPU)
+      && CPU_FEATURE_USABLE_P (cpu_features, FXSR)
+      && CPU_FEATURE_USABLE_P (cpu_features, MMX)
+      && CPU_FEATURE_USABLE_P (cpu_features, SSE)
+      && CPU_FEATURE_USABLE_P (cpu_features, SSE2))
+    {
+      isa_level = GNU_PROPERTY_X86_ISA_1_BASELINE;
+      if (CPU_FEATURE_USABLE_P (cpu_features, CMPXCHG16B)
+         && CPU_FEATURE_USABLE_P (cpu_features, LAHF64_SAHF64)
+         && CPU_FEATURE_USABLE_P (cpu_features, POPCNT)
+         && CPU_FEATURE_USABLE_P (cpu_features, SSE3)
+         && CPU_FEATURE_USABLE_P (cpu_features, SSSE3)
+         && CPU_FEATURE_USABLE_P (cpu_features, SSE4_1)
+         && CPU_FEATURE_USABLE_P (cpu_features, SSE4_2))
+       {
+         isa_level |= GNU_PROPERTY_X86_ISA_1_V2;
+         if (CPU_FEATURE_USABLE_P (cpu_features, AVX)
+             && CPU_FEATURE_USABLE_P (cpu_features, AVX2)
+             && CPU_FEATURE_USABLE_P (cpu_features, F16C)
+             && CPU_FEATURE_USABLE_P (cpu_features, FMA)
+             && CPU_FEATURE_USABLE_P (cpu_features, LZCNT)
+             && CPU_FEATURE_USABLE_P (cpu_features, MOVBE))
+           {
+             isa_level |= GNU_PROPERTY_X86_ISA_1_V3;
+             if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F)
+                 && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)
+                 && CPU_FEATURE_USABLE_P (cpu_features, AVX512CD)
+                 && CPU_FEATURE_USABLE_P (cpu_features, AVX512DQ)
+                 && CPU_FEATURE_USABLE_P (cpu_features, AVX512VL))
+               isa_level |= GNU_PROPERTY_X86_ISA_1_V4;
+           }
+       }
+    }
+
+  return isa_level;
+}
index ffe300c..99e7ee0 100644 (file)
@@ -123,6 +123,8 @@ struct cpu_features
   struct cpu_features_basic basic;
   struct cpuid_features features[COMMON_CPUID_INDEX_MAX];
   unsigned int preferred[PREFERRED_FEATURE_INDEX_MAX];
+  /* X86 micro-architecture ISA levels.  */
+  unsigned int isa_1;
   /* The state size for XSAVEC or XSAVE.  The type must be unsigned long
      int so that we use
 
diff --git a/sysdeps/x86/isa-level.c b/sysdeps/x86/isa-level.c
new file mode 100644 (file)
index 0000000..aaf524c
--- /dev/null
@@ -0,0 +1,97 @@
+/* ELF program property for x86 ISA level.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file with other
+   programs, and to distribute those programs without any restriction
+   coming from the use of this file.  (The Lesser General Public
+   License restrictions do apply in other respects; for example, they
+   cover modification of the file, and distribution when not linked
+   into another program.)
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <elf.h>
+
+/* 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)
+# endif
+
+# if ISA_LEVEL
+#  ifdef __LP64__
+#   define PROPERTY_ALIGN 3
+#  else
+#   define PROPERTY_ALIGN 2
+#  endif
+
+#  define note_stringify(arg) note_stringify_1(arg)
+#  define note_stringify_1(arg) #arg
+
+asm(".pushsection \".note.gnu.property\",\"a\",@note\n"
+"      .p2align " note_stringify (PROPERTY_ALIGN)
+       /* name length.  */
+"\n    .long 1f - 0f\n"
+       /* data length.  */
+"      .long 4f - 1f\n"
+       /* note type: NT_GNU_PROPERTY_TYPE_0.  */
+"      .long " note_stringify (NT_GNU_PROPERTY_TYPE_0)
+       /* vendor name.  */
+"\n0:  .asciz \"GNU\"\n"
+"1:    .p2align " note_stringify (PROPERTY_ALIGN)
+       /* pr_type: GNU_PROPERTY_X86_ISA_1_NEEDED.  */
+"\n    .long " note_stringify (GNU_PROPERTY_X86_ISA_1_NEEDED)
+       /* pr_datasz.  */
+"\n    .long 3f - 2f\n"
+       /* GNU_PROPERTY_X86_ISA_1_V[234].  */
+"2:\n   .long " note_stringify (ISA_LEVEL)
+"\n3:\n        .p2align " note_stringify (PROPERTY_ALIGN)
+"\n4:\n .popsection");
+# endif /* ISA_LEVEL */
+#endif /* INCLUDE_X86_ISA_LEVEL */
index 8074739..4c46a25 100644 (file)
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-/* If this object is enabled with CET.  */
+/* if this object has GNU property.  */
 enum
   {
-    lc_unknown = 0,                     /* Unknown CET status.  */
-    lc_none = 1 << 0,                   /* Not enabled with CET.  */
-    lc_ibt = 1 << 1,                    /* Enabled with IBT.  */
-    lc_shstk = 1 << 2,                  /* Enabled with STSHK.  */
-    lc_ibt_and_shstk = lc_ibt | lc_shstk /* Enabled with both.  */
-  } l_cet:3;
+    lc_property_unknown = 0,           /* Unknown property status.  */
+    lc_property_none = 1 << 0,         /* No property.  */
+    lc_property_valid = 1 << 1         /* Has valid property.  */
+  } l_property:2;
+
+/* GNU_PROPERTY_X86_FEATURE_1_AND of this object.  */
+unsigned int l_x86_feature_1_and;
+
+/* GNU_PROPERTY_X86_ISA_1_NEEDED of this object.  */
+unsigned int l_x86_isa_1_needed;
diff --git a/sysdeps/x86/tst-isa-level-1.c b/sysdeps/x86/tst-isa-level-1.c
new file mode 100644 (file)
index 0000000..cf611e8
--- /dev/null
@@ -0,0 +1,104 @@
+/* Check ISA level on dlopened shared object.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <elf.h>
+#include <get-isa-level.h>
+#include <support/xdlfcn.h>
+#include <support/check.h>
+#include <support/test-driver.h>
+
+static void
+do_test_1 (const char *modname, bool fail)
+{
+  int (*fp) (void);
+  void *h;
+
+  h = dlopen (modname, RTLD_LAZY);
+  if (h == NULL)
+    {
+      const char *err = dlerror ();
+      if (fail)
+       {
+         if (strstr (err, "CPU ISA level is lower than required") == NULL)
+           FAIL_EXIT1 ("incorrect dlopen '%s' error: %s\n", modname, err);
+
+         return;
+       }
+
+      FAIL_EXIT1 ("cannot open '%s': %s\n", modname, err);
+    }
+
+  if (fail)
+    FAIL_EXIT1 ("dlopen '%s' should have failed\n", modname);
+
+  fp = xdlsym (h, "test");
+
+  if (fp () != 0)
+    FAIL_EXIT1 ("test () != 0\n");
+
+  dlclose (h);
+}
+
+static int
+do_test (void)
+{
+  const struct cpu_features *cpu_features
+    = __x86_get_cpu_features (COMMON_CPUID_INDEX_MAX);
+  unsigned int isa_level = get_isa_level (cpu_features);
+  bool has_isa_baseline = ((isa_level & GNU_PROPERTY_X86_ISA_1_BASELINE)
+                          == GNU_PROPERTY_X86_ISA_1_BASELINE);
+  bool has_isa_v2 = ((isa_level & GNU_PROPERTY_X86_ISA_1_V2)
+                          == GNU_PROPERTY_X86_ISA_1_V2);
+  bool has_isa_v3 = ((isa_level & GNU_PROPERTY_X86_ISA_1_V3)
+                          == GNU_PROPERTY_X86_ISA_1_V3);
+  bool has_isa_v4 = ((isa_level & GNU_PROPERTY_X86_ISA_1_V4)
+                          == GNU_PROPERTY_X86_ISA_1_V4);
+
+  if (!has_isa_baseline)
+    {
+      do_test_1 ("tst-isa-level-mod-1-baseline.so", true);
+      return EXIT_SUCCESS;
+    }
+
+  do_test_1 ("tst-isa-level-mod-1-baseline.so", false);
+
+  /* Skip on x86-64-v4 platforms since dlopen v4 module always works.  */
+  if (has_isa_v4)
+    return EXIT_SUCCESS;
+
+  do_test_1 ("tst-isa-level-mod-1-v4.so", true);
+
+  /* Skip on x86-64-v3 platforms since dlopen v3 module always works.  */
+  if (has_isa_v3)
+    return EXIT_SUCCESS;
+
+  do_test_1 ("tst-isa-level-mod-1-v3.so", true);
+
+  /* Skip on x86-64-v2 platforms since dlopen v2 module always works.  */
+  if (has_isa_v2)
+    return EXIT_SUCCESS;
+
+  do_test_1 ("tst-isa-level-mod-1-v2.so", true);
+
+  return EXIT_SUCCESS;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/x86/tst-isa-level-mod-1-baseline.c b/sysdeps/x86/tst-isa-level-mod-1-baseline.c
new file mode 100644 (file)
index 0000000..d6fe068
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-isa-level-mod-1.c"
diff --git a/sysdeps/x86/tst-isa-level-mod-1-v2.c b/sysdeps/x86/tst-isa-level-mod-1-v2.c
new file mode 100644 (file)
index 0000000..d6fe068
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-isa-level-mod-1.c"
diff --git a/sysdeps/x86/tst-isa-level-mod-1-v3.c b/sysdeps/x86/tst-isa-level-mod-1-v3.c
new file mode 100644 (file)
index 0000000..d6fe068
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-isa-level-mod-1.c"
diff --git a/sysdeps/x86/tst-isa-level-mod-1-v4.c b/sysdeps/x86/tst-isa-level-mod-1-v4.c
new file mode 100644 (file)
index 0000000..d6fe068
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-isa-level-mod-1.c"
diff --git a/sysdeps/x86/tst-isa-level-mod-1.c b/sysdeps/x86/tst-isa-level-mod-1.c
new file mode 100644 (file)
index 0000000..40a2e1d
--- /dev/null
@@ -0,0 +1,25 @@
+/* Check ISA level on dlopened shared object.
+   Copyright (C) 2019-2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <isa-level.c>
+
+int
+test (void)
+{
+  return 0;
+}
index 0aaa635..e030534 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <dl-hwcaps.h>
 #include <cpu-features.h>
+#include <get-isa-level.h>
 
 const char _dl_hwcaps_subdirs[] = "x86-64-v4:x86-64-v3:x86-64-v2";
 enum { subdirs_count = 3 }; /* Number of components in _dl_hwcaps_subdirs.  */
@@ -25,40 +26,25 @@ enum { subdirs_count = 3 }; /* Number of components in _dl_hwcaps_subdirs.  */
 uint32_t
 _dl_hwcaps_subdirs_active (void)
 {
+  const struct cpu_features *cpu_features
+    = __x86_get_cpu_features (COMMON_CPUID_INDEX_MAX);
+  unsigned int isa_level = get_isa_level (cpu_features);
   int active = 0;
 
   /* Test in reverse preference order.  */
 
   /* x86-64-v2.  */
-  if (!(CPU_FEATURE_USABLE (CMPXCHG16B)
-        && CPU_FEATURE_USABLE (LAHF64_SAHF64)
-        && CPU_FEATURE_USABLE (POPCNT)
-        && CPU_FEATURE_USABLE (SSE3)
-        && CPU_FEATURE_USABLE (SSE4_1)
-        && CPU_FEATURE_USABLE (SSE4_2)
-        && CPU_FEATURE_USABLE (SSSE3)))
+  if (!(isa_level & GNU_PROPERTY_X86_ISA_1_V2))
     return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
   ++active;
 
   /* x86-64-v3.  */
-  if (!(CPU_FEATURE_USABLE (AVX)
-        && CPU_FEATURE_USABLE (AVX2)
-        && CPU_FEATURE_USABLE (BMI1)
-        && CPU_FEATURE_USABLE (BMI2)
-        && CPU_FEATURE_USABLE (F16C)
-        && CPU_FEATURE_USABLE (FMA)
-        && CPU_FEATURE_USABLE (LZCNT)
-        && CPU_FEATURE_USABLE (MOVBE)
-        && CPU_FEATURE_USABLE (OSXSAVE)))
+  if (!(isa_level & GNU_PROPERTY_X86_ISA_1_V3))
     return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
   ++active;
 
- /* x86-64-v4.  */
-  if (!(CPU_FEATURE_USABLE (AVX512F)
-        && CPU_FEATURE_USABLE (AVX512BW)
-        && CPU_FEATURE_USABLE (AVX512CD)
-        && CPU_FEATURE_USABLE (AVX512DQ)
-        && CPU_FEATURE_USABLE (AVX512VL)))
+  /* x86-64-v4.  */
+  if (!(isa_level & GNU_PROPERTY_X86_ISA_1_V4))
     return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
   ++active;
 
index 8bdcb91..37b61d3 100644 (file)
@@ -19,7 +19,8 @@
 #include <stdio.h>
 #include <support/check.h>
 #include <sys/param.h>
-#include <sys/platform/x86.h>
+#include <elf.h>
+#include <get-isa-level.h>
 
 extern int marker2 (void);
 extern int marker3 (void);
@@ -31,35 +32,15 @@ compute_level (void)
 {
   const struct cpu_features *cpu_features
     = __x86_get_cpu_features (COMMON_CPUID_INDEX_MAX);
-
- if (!(CPU_FEATURE_USABLE_P (cpu_features, CMPXCHG16B)
-       && CPU_FEATURE_USABLE_P (cpu_features, LAHF64_SAHF64)
-       && CPU_FEATURE_USABLE_P (cpu_features, POPCNT)
-       && CPU_FEATURE_USABLE_P (cpu_features, MMX)
-       && CPU_FEATURE_USABLE_P (cpu_features, SSE)
-       && CPU_FEATURE_USABLE_P (cpu_features, SSE2)
-       && CPU_FEATURE_USABLE_P (cpu_features, SSE3)
-       && CPU_FEATURE_USABLE_P (cpu_features, SSSE3)
-       && CPU_FEATURE_USABLE_P (cpu_features, SSE4_1)
-       && CPU_FEATURE_USABLE_P (cpu_features, SSE4_2)))
-   return 1;
- if (!(CPU_FEATURE_USABLE_P (cpu_features, AVX)
-       && CPU_FEATURE_USABLE_P (cpu_features, AVX2)
-       && CPU_FEATURE_USABLE_P (cpu_features, BMI1)
-       && CPU_FEATURE_USABLE_P (cpu_features, BMI2)
-       && CPU_FEATURE_USABLE_P (cpu_features, F16C)
-       && CPU_FEATURE_USABLE_P (cpu_features, FMA)
-       && CPU_FEATURE_USABLE_P (cpu_features, LZCNT)
-       && CPU_FEATURE_USABLE_P (cpu_features, MOVBE)
-       && CPU_FEATURE_USABLE_P (cpu_features, OSXSAVE)))
-   return 2;
- if (!(CPU_FEATURE_USABLE_P (cpu_features, AVX512F)
-       && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)
-       && CPU_FEATURE_USABLE_P (cpu_features, AVX512CD)
-       && CPU_FEATURE_USABLE_P (cpu_features, AVX512DQ)
-       && CPU_FEATURE_USABLE_P (cpu_features, AVX512VL)))
-   return 3;
- return 4;
+  unsigned int isa_level = get_isa_level (cpu_features);
+
+  if (!(isa_level & GNU_PROPERTY_X86_ISA_1_V2))
+    return 1;
+  if (!(isa_level & GNU_PROPERTY_X86_ISA_1_V3))
+    return 2;
+  if (!(isa_level & GNU_PROPERTY_X86_ISA_1_V4))
+    return 3;
+  return 4;
 }
 
 static int