aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2020-10-09 06:06:56 -0700
committerH.J. Lu <hjl.tools@gmail.com>2021-01-07 13:10:13 -0800
commitecce11aa0752735c4fd730da6e7c9e0b98e12fb8 (patch)
tree985a02d3524d901f746cf085e2b68e34cde776aa
parent9e97f239eae1f2b1d2e694d844c0f6fd7c4dd271 (diff)
downloadglibc-ecce11aa0752735c4fd730da6e7c9e0b98e12fb8.tar
glibc-ecce11aa0752735c4fd730da6e7c9e0b98e12fb8.tar.gz
glibc-ecce11aa0752735c4fd730da6e7c9e0b98e12fb8.tar.bz2
glibc-ecce11aa0752735c4fd730da6e7c9e0b98e12fb8.zip
x86: Support GNU_PROPERTY_X86_ISA_1_V[234] marker [BZ #26717]
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]$
-rw-r--r--config.h.in3
-rw-r--r--elf/elf.h35
-rw-r--r--sysdeps/x86/Makefile30
-rw-r--r--sysdeps/x86/abi-note.c29
-rw-r--r--sysdeps/x86/configure79
-rw-r--r--sysdeps/x86/configure.ac66
-rw-r--r--sysdeps/x86/cpu-features.c3
-rw-r--r--sysdeps/x86/dl-cet.c12
-rw-r--r--sysdeps/x86/dl-prop.h113
-rw-r--r--sysdeps/x86/get-isa-level.h66
-rw-r--r--sysdeps/x86/include/cpu-features.h2
-rw-r--r--sysdeps/x86/isa-level.c97
-rw-r--r--sysdeps/x86/link_map.h18
-rw-r--r--sysdeps/x86/tst-isa-level-1.c104
-rw-r--r--sysdeps/x86/tst-isa-level-mod-1-baseline.c1
-rw-r--r--sysdeps/x86/tst-isa-level-mod-1-v2.c1
-rw-r--r--sysdeps/x86/tst-isa-level-mod-1-v3.c1
-rw-r--r--sysdeps/x86/tst-isa-level-mod-1-v4.c1
-rw-r--r--sysdeps/x86/tst-isa-level-mod-1.c25
-rw-r--r--sysdeps/x86_64/dl-hwcaps-subdirs.c30
-rw-r--r--sysdeps/x86_64/tst-glibc-hwcaps.c41
21 files changed, 644 insertions, 113 deletions
diff --git a/config.h.in b/config.h.in
index eca2d66a2c..947feeff36 100644
--- a/config.h.in
+++ b/config.h.in
@@ -269,4 +269,7 @@
/* 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
diff --git a/elf/elf.h b/elf/elf.h
index 4a9ae97dfc..9ebd052c8a 100644
--- 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. */
diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile
index 081cc72e93..c814d5a195 100644
--- a/sysdeps/x86/Makefile
+++ b/sysdeps/x86/Makefile
@@ -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
index 0000000000..5140e6ab47
--- /dev/null
+++ b/sysdeps/x86/abi-note.c
@@ -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>
diff --git a/sysdeps/x86/configure b/sysdeps/x86/configure
index 81cc4e80d6..5e32dc62b3 100644
--- a/sysdeps/x86/configure
+++ b/sysdeps/x86/configure
@@ -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"
diff --git a/sysdeps/x86/configure.ac b/sysdeps/x86/configure.ac
index 8f3e1191f6..f94088f377 100644
--- a/sysdeps/x86/configure.ac
+++ b/sysdeps/x86/configure.ac
@@ -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])
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
index 529c586193..e7da682a2e 100644
--- a/sysdeps/x86/cpu-features.c
+++ b/sysdeps/x86/cpu-features.c
@@ -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
diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c
index b4910f7634..ed7fd6d10d 100644
--- a/sysdeps/x86/dl-cet.c
+++ b/sysdeps/x86/dl-cet.c
@@ -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;
diff --git a/sysdeps/x86/dl-prop.h b/sysdeps/x86/dl-prop.h
index ce1667dc7a..56bd020b3c 100644
--- a/sysdeps/x86/dl-prop.h
+++ b/sysdeps/x86/dl-prop.h
@@ -19,14 +19,54 @@
#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
index 0000000000..a86e1e8941
--- /dev/null
+++ b/sysdeps/x86/get-isa-level.h
@@ -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;
+}
diff --git a/sysdeps/x86/include/cpu-features.h b/sysdeps/x86/include/cpu-features.h
index ffe300c931..99e7ee08cf 100644
--- a/sysdeps/x86/include/cpu-features.h
+++ b/sysdeps/x86/include/cpu-features.h
@@ -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
index 0000000000..aaf524cb56
--- /dev/null
+++ b/sysdeps/x86/isa-level.c
@@ -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 */
diff --git a/sysdeps/x86/link_map.h b/sysdeps/x86/link_map.h
index 8074739b47..4c46a25f83 100644
--- a/sysdeps/x86/link_map.h
+++ b/sysdeps/x86/link_map.h
@@ -16,12 +16,16 @@
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
index 0000000000..cf611e8b78
--- /dev/null
+++ b/sysdeps/x86/tst-isa-level-1.c
@@ -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
index 0000000000..d6fe0685a4
--- /dev/null
+++ b/sysdeps/x86/tst-isa-level-mod-1-baseline.c
@@ -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
index 0000000000..d6fe0685a4
--- /dev/null
+++ b/sysdeps/x86/tst-isa-level-mod-1-v2.c
@@ -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
index 0000000000..d6fe0685a4
--- /dev/null
+++ b/sysdeps/x86/tst-isa-level-mod-1-v3.c
@@ -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
index 0000000000..d6fe0685a4
--- /dev/null
+++ b/sysdeps/x86/tst-isa-level-mod-1-v4.c
@@ -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
index 0000000000..40a2e1d99f
--- /dev/null
+++ b/sysdeps/x86/tst-isa-level-mod-1.c
@@ -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;
+}
diff --git a/sysdeps/x86_64/dl-hwcaps-subdirs.c b/sysdeps/x86_64/dl-hwcaps-subdirs.c
index 0aaa635a00..e030534f1b 100644
--- a/sysdeps/x86_64/dl-hwcaps-subdirs.c
+++ b/sysdeps/x86_64/dl-hwcaps-subdirs.c
@@ -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;
diff --git a/sysdeps/x86_64/tst-glibc-hwcaps.c b/sysdeps/x86_64/tst-glibc-hwcaps.c
index 8bdcb91db0..37b61d3c84 100644
--- a/sysdeps/x86_64/tst-glibc-hwcaps.c
+++ b/sysdeps/x86_64/tst-glibc-hwcaps.c
@@ -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