diff mbox series

V5 [PATCH 1/2] x86: Support GNU_PROPERTY_X86_ISA_1_V[234] marker [BZ #26717]

Message ID 20201206144952.2109594-2-hjl.tools@gmail.com
State Superseded
Delegated to: Florian Weimer
Headers show
Series V5 [PATCH 1/2] x86: Support GNU_PROPERTY_X86_ISA_1_V[234] marker [BZ #26717] | expand

Commit Message

H.J. Lu Dec. 6, 2020, 2:49 p.m. UTC
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.

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]$
---
 config.h.in                        |   3 +
 elf/elf.h                          |  35 ++++-----
 sysdeps/x86/Makefile               |  10 +++
 sysdeps/x86/abi-note.c             |  29 ++++++++
 sysdeps/x86/configure              | 101 ++++++++++++++++++++++++++
 sysdeps/x86/configure.ac           |  26 +++++++
 sysdeps/x86/cpu-features.c         |   3 +
 sysdeps/x86/dl-cet.c               |  12 ++-
 sysdeps/x86/dl-prop.h              | 113 +++++++++++++++++++++--------
 sysdeps/x86/get-isa-level.h        |  66 +++++++++++++++++
 sysdeps/x86/include/cpu-features.h |   2 +
 sysdeps/x86/isa-level.c            |  95 ++++++++++++++++++++++++
 sysdeps/x86/link_map.h             |  18 +++--
 sysdeps/x86/tst-isa-level-1.c      |  74 +++++++++++++++++++
 sysdeps/x86/tst-isa-level-mod-1.c  |  23 ++++++
 sysdeps/x86/tst-isa-level-mod-1a.c |   2 +
 sysdeps/x86/tst-isa-level-mod-1b.c |   1 +
 sysdeps/x86_64/dl-hwcaps-subdirs.c |  30 ++------
 sysdeps/x86_64/tst-glibc-hwcaps.c  |  41 +++--------
 19 files changed, 571 insertions(+), 113 deletions(-)
 create mode 100644 sysdeps/x86/abi-note.c
 create mode 100644 sysdeps/x86/get-isa-level.h
 create mode 100644 sysdeps/x86/isa-level.c
 create mode 100644 sysdeps/x86/tst-isa-level-1.c
 create mode 100644 sysdeps/x86/tst-isa-level-mod-1.c
 create mode 100644 sysdeps/x86/tst-isa-level-mod-1a.c
 create mode 100644 sysdeps/x86/tst-isa-level-mod-1b.c

Comments

Adhemerval Zanella Jan. 6, 2021, noon UTC | #1
On 06/12/2020 11:49, H.J. Lu via Libc-alpha wrote:
> 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.
> 
> 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]$
> ---
>  config.h.in                        |   3 +
>  elf/elf.h                          |  35 ++++-----
>  sysdeps/x86/Makefile               |  10 +++
>  sysdeps/x86/abi-note.c             |  29 ++++++++
>  sysdeps/x86/configure              | 101 ++++++++++++++++++++++++++
>  sysdeps/x86/configure.ac           |  26 +++++++
>  sysdeps/x86/cpu-features.c         |   3 +
>  sysdeps/x86/dl-cet.c               |  12 ++-
>  sysdeps/x86/dl-prop.h              | 113 +++++++++++++++++++++--------
>  sysdeps/x86/get-isa-level.h        |  66 +++++++++++++++++
>  sysdeps/x86/include/cpu-features.h |   2 +
>  sysdeps/x86/isa-level.c            |  95 ++++++++++++++++++++++++
>  sysdeps/x86/link_map.h             |  18 +++--
>  sysdeps/x86/tst-isa-level-1.c      |  74 +++++++++++++++++++
>  sysdeps/x86/tst-isa-level-mod-1.c  |  23 ++++++
>  sysdeps/x86/tst-isa-level-mod-1a.c |   2 +
>  sysdeps/x86/tst-isa-level-mod-1b.c |   1 +
>  sysdeps/x86_64/dl-hwcaps-subdirs.c |  30 ++------
>  sysdeps/x86_64/tst-glibc-hwcaps.c  |  41 +++--------
>  19 files changed, 571 insertions(+), 113 deletions(-)
>  create mode 100644 sysdeps/x86/abi-note.c
>  create mode 100644 sysdeps/x86/get-isa-level.h
>  create mode 100644 sysdeps/x86/isa-level.c
>  create mode 100644 sysdeps/x86/tst-isa-level-1.c
>  create mode 100644 sysdeps/x86/tst-isa-level-mod-1.c
>  create mode 100644 sysdeps/x86/tst-isa-level-mod-1a.c
>  create mode 100644 sysdeps/x86/tst-isa-level-mod-1b.c
> 
> diff --git a/config.h.in b/config.h.in
> index b823c8e080..dc3854f4eb 100644
> --- a/config.h.in
> +++ b/config.h.in
> @@ -266,4 +266,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 bd7af7cca4..42fd697129 100644
> --- a/elf/elf.h
> +++ b/elf/elf.h
> @@ -1325,31 +1325,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.  */

Shouldn't it follow bintuils 32930e4edbc06 change and move current
GNU_PROPERTY_X86_ISA_1_ definitions to GNU_PROPERTY_X86_COMPAT_2_?
Not sure if this charecterize any exported ABI change, since the
most possible usual consumer (bintuils) does not use glibc version.

Also, maybe move this change to an specific patch.


> diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile
> index 081cc72e93..109f03e9b9 100644
> --- a/sysdeps/x86/Makefile
> +++ b/sysdeps/x86/Makefile
> @@ -9,6 +9,16 @@ 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 (yesyes,$(enable-x86-isa-level)$(config-cflags-skylake-avx512))
> +tests += tst-isa-level-1
> +modules-names += tst-isa-level-mod-1a tst-isa-level-mod-1b
> +
> +CFLAGS-tst-isa-level-mod-1a.c += -march=skylake-avx512 \
> +				-DINCLUDE_X86_ISA_LEVEL
> +$(objpfx)tst-isa-level-1: $(libdl)
> +$(objpfx)tst-isa-level-1.out: $(objpfx)tst-isa-level-mod-1a.so \
> +			      $(objpfx)tst-isa-level-mod-1b.so
> +endif
>  endif
>  
>  ifeq ($(subdir),math)

This will limit the test to a very narrow set of machines, couldn't
we check only for enable-x86-isa-level and make the conditional check 
for ISA inside the test itself?

What I have in mind would be something like:

  1. Create onde module object for each ISA variant, by varying either
     -march or using the specific gcc option (not sure it would clash
     with the ABI notes isa-level.c already include).

  2. On tst-isa-level-1.c check current ISA level with get_isa_level
     and check against the ISA_BASELINE and load the modules with a
     ISA number lower than baseline.

 Something like:

  const struct cpu_features *cpu_features 
    = __x86_get_cpu_features (COMMON_CPUID_INDEX_MAX);
  unsigned int isa_level = get_isa_level (cpu_features);
  
  bool check_isa_baseline = (isa_level & ISA_BASELINE) == ISA_BASELINE;
  bool check_isa_v2       = (isa_level & ISA_V2)       == ISA_V2;
  bool check_isa_v3       = (isa_level & ISA_V3)       == ISA_V3;
  bool check_isa_v4       = (isa_level & ISA_V4)       == ISA_V4;

  do_test_1 ("tst-isa-level-mod-1-baseline.so", true);
  do_test_1 ("tst-isa-level-mod-1-isa_v2.so", true);
  do_test_1 ("tst-isa-level-mod-1-isa_v3.so", true);
  do_test_1 ("tst-isa-level-mod-1-isa_v4.so", true);

You might require to just build the isa_v4 only for 
config-cflags-skylake-avx512 and conditionalize with HAVE_SKYLAKE_AVX512_SUPPORT
(which seems to be ununsed in this patch).

> 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>

Ok, 

> diff --git a/sysdeps/x86/configure b/sysdeps/x86/configure
> index 81cc4e80d6..2738fe47b2 100644
> --- a/sysdeps/x86/configure
> +++ b/sysdeps/x86/configure
> @@ -68,3 +68,104 @@ elif test $enable_cet = permissive; then
>  fi
>  config_vars="$config_vars
>  enable-cet = $enable_cet"
> +
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -march=skylake-avx512 support" >&5
> +$as_echo_n "checking for -march=skylake-avx512 support... " >&6; }
> +if ${libc_cv_cc_skylake_avx512+:} false; then :
> +  $as_echo_n "(cached) " >&6
> +else
> +  if { ac_try='${CC-cc} -march=skylake-avx512 -xc /dev/null -S -o /dev/null'
> +  { { 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 :
> +  libc_cv_cc_skylake_avx512=yes
> +else
> +  libc_cv_cc_skylake_avx512=no
> +fi
> +
> +fi
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_cc_skylake_avx512" >&5
> +$as_echo "$libc_cv_cc_skylake_avx512" >&6; }
> +if test $libc_cv_cc_skylake_avx512 = yes; then
> +  $as_echo "#define HAVE_SKYLAKE_AVX512_SUPPORT 1" >>confdefs.h
> +
> +fi
> +config_vars="$config_vars
> +config-cflags-skylake-avx512 = $libc_cv_cc_skylake_avx512"
> +
> +libc_cv_include_x86_isa_level=no
> +if test -z "`$LD --version | sed -n 's/^GNU \(gold\).*$/\1/p'`"; then
> +  # Check for ld 2.32 or higher.
> +  libc_cv_include_x86_isa_level=yes
> +  for ac_prog in $LD
> +do
> +  # Extract the first word of "$ac_prog", so it can be a program name with args.
> +set dummy $ac_prog; 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_prog_LD+:} false; then :
> +  $as_echo_n "(cached) " >&6
> +else
> +  if test -n "$LD"; then
> +  ac_cv_prog_LD="$LD" # Let the user override the test.
> +else
> +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_prog_LD="$ac_prog"
> +    $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
> +
> +fi
> +fi
> +LD=$ac_cv_prog_LD
> +if test -n "$LD"; then
> +  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
> +$as_echo "$LD" >&6; }
> +else
> +  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +$as_echo "no" >&6; }
> +fi
> +
> +
> +  test -n "$LD" && break
> +done
> +
> +if test -z "$LD"; then
> +  ac_verc_fail=yes
> +else
> +  # Found it, now check the version.
> +  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $LD" >&5
> +$as_echo_n "checking version of $LD... " >&6; }
> +  ac_prog_version=`$LD --version 2>&1 | sed -n 's/^.*GNU ld.* \([0-9][0-9]*\.[0-9.]*\).*$/\1/p'`
> +  case $ac_prog_version in
> +    '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
> +    2.3[2-9]*|2.[4-9][0-9]*|[3-9].*|[1-9][0-9]*)
> +       ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
> +    *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
> +
> +  esac
> +  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_prog_version" >&5
> +$as_echo "$ac_prog_version" >&6; }
> +fi
> +if test $ac_verc_fail = yes; then
> +  libc_cv_include_x86_isa_level=no
> +fi
> +
> +  if test $libc_cv_include_x86_isa_level = yes; then
> +    $as_echo "#define INCLUDE_X86_ISA_LEVEL 1" >>confdefs.h
> +
> +  fi
> +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..8f00b9663d 100644
> --- a/sysdeps/x86/configure.ac
> +++ b/sysdeps/x86/configure.ac
> @@ -43,3 +43,29 @@ elif test $enable_cet = permissive; then
>    AC_DEFINE(DEFAULT_DL_X86_CET_CONTROL, cet_permissive)
>  fi
>  LIBC_CONFIG_VAR([enable-cet], [$enable_cet])
> +
> +dnl Check if -march=skylake-avx512 works.
> +AC_CACHE_CHECK(for -march=skylake-avx512 support,
> +	       libc_cv_cc_skylake_avx512, [dnl
> +LIBC_TRY_CC_OPTION([-march=skylake-avx512],
> +		   [libc_cv_cc_skylake_avx512=yes],
> +		   [libc_cv_cc_skylake_avx512=no])
> +])
> +if test $libc_cv_cc_skylake_avx512 = yes; then
> +  AC_DEFINE(HAVE_SKYLAKE_AVX512_SUPPORT)
> +fi

Where is it used specifically? There is no config.h.in tag either.

> +LIBC_CONFIG_VAR([config-cflags-skylake-avx512], [$libc_cv_cc_skylake_avx512])
> +
> +libc_cv_include_x86_isa_level=no
> +if test -z "`$LD --version | sed -n 's/^GNU \(gold\).*$/\1/p'`"; then
> +  # Check for ld 2.32 or higher.
> +  libc_cv_include_x86_isa_level=yes
> +  AC_CHECK_PROG_VER(LD, $LD, --version,
> +		    [GNU ld.* \([0-9][0-9]*\.[0-9.]*\)],
> +		    [2.3[2-9]*|2.[4-9][0-9]*|[3-9].*|[1-9][0-9]*],
> +		    libc_cv_include_x86_isa_level=no)
> +  if test $libc_cv_include_x86_isa_level = yes; then
> +    AC_DEFINE(INCLUDE_X86_ISA_LEVEL)
> +  fi
> +fi
> +LIBC_CONFIG_VAR([enable-x86-isa-level], [$libc_cv_include_x86_isa_level])

Instead of version check, would it better to check if the linker actually
build a snippet with the expected notes?

> diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
> index fe080b63b2..ec5cdafe81 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

Ok.

> diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c
> index 5524b66038..8986c776e5 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));
>  	}
>  

Ok.

>        /* 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;

Ok.

> diff --git a/sysdeps/x86/dl-prop.h b/sysdeps/x86/dl-prop.h
> index 89911e19e2..61c0624c09 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"));
> +	}
> +    }
> +}
> +

Ok. Not sure if it is worth to translate the _dl_fatal_printf (it seems
that at least one use at elf/dl-open.c does it).


>  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
>  }
>  

Ok.

>  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

Ok.

> @@ -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

Ok.

> @@ -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;
>  

Ok.

> -		  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");

Ok.

> +		  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.  */

Ok.

> @@ -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 || feature_1_and)

No implicit checks.

> +    {
> +      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, 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))

Ok.

> diff --git a/sysdeps/x86/get-isa-level.h b/sysdeps/x86/get-isa-level.h
> new file mode 100644
> index 0000000000..166dd5df01
> --- /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 isa_level = 0;

s/unsigned/unsigned int/

> +
> +  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;
> +}

Do we actually support a isa level lower than baseline?

> diff --git a/sysdeps/x86/include/cpu-features.h b/sysdeps/x86/include/cpu-features.h
> index f62be0b9b3..ef0c6b4fbc 100644
> --- a/sysdeps/x86/include/cpu-features.h
> +++ b/sysdeps/x86/include/cpu-features.h
> @@ -129,6 +129,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
>  

Ok.

> diff --git a/sysdeps/x86/isa-level.c b/sysdeps/x86/isa-level.c
> new file mode 100644
> index 0000000000..0751e86f27
> --- /dev/null
> +++ b/sysdeps/x86/isa-level.c
> @@ -0,0 +1,95 @@
> +/* 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
> +
> +# define ISA_LEVEL (ISA_BASELINE | ISA_V2 | ISA_V3 | ISA_V4)
> +
> +# 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 */

Ok.

> diff --git a/sysdeps/x86/link_map.h b/sysdeps/x86/link_map.h
> index 2e4f8850f9..3c550e529a 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;
> +

Ok.

> +/* 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;

Ok.

> diff --git a/sysdeps/x86/tst-isa-level-1.c b/sysdeps/x86/tst-isa-level-1.c
> new file mode 100644
> index 0000000000..c263157c8c
> --- /dev/null
> +++ b/sysdeps/x86/tst-isa-level-1.c
> @@ -0,0 +1,74 @@
> +/* 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);
> +}
> +

Ok.

> +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);
> +  /* Skip on x86-64-v4 platforms since dlopen always works.  */
> +  if ((isa_level & GNU_PROPERTY_X86_ISA_1_V4) != 0)
> +    return EXIT_UNSUPPORTED;
> +  do_test_1 ("tst-isa-level-mod-1a.so", true);
> +  do_test_1 ("tst-isa-level-mod-1b.so", false);
> +  return EXIT_SUCCESS;
> +}
> +
> +#include <support/test-driver.c>

Maybe use my suggestion to improve test coverage.

> 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..3816536428
> --- /dev/null
> +++ b/sysdeps/x86/tst-isa-level-mod-1.c
> @@ -0,0 +1,23 @@
> +/* 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/>.  */
> +
> +int
> +test (void)
> +{
> +  return 0;
> +}

Ok.

> diff --git a/sysdeps/x86/tst-isa-level-mod-1a.c b/sysdeps/x86/tst-isa-level-mod-1a.c
> new file mode 100644
> index 0000000000..4f026dd915
> --- /dev/null
> +++ b/sysdeps/x86/tst-isa-level-mod-1a.c
> @@ -0,0 +1,2 @@
> +#include <isa-level.c>
> +#include "tst-isa-level-mod-1.c"
> diff --git a/sysdeps/x86/tst-isa-level-mod-1b.c b/sysdeps/x86/tst-isa-level-mod-1b.c
> new file mode 100644
> index 0000000000..d6fe0685a4
> --- /dev/null
> +++ b/sysdeps/x86/tst-isa-level-mod-1b.c
> @@ -0,0 +1 @@
> +#include "tst-isa-level-mod-1.c"

Ok.

> diff --git a/sysdeps/x86_64/dl-hwcaps-subdirs.c b/sysdeps/x86_64/dl-hwcaps-subdirs.c
> index 8810a822ef..e5640303f9 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;
>  

Ok.

> diff --git a/sysdeps/x86_64/tst-glibc-hwcaps.c b/sysdeps/x86_64/tst-glibc-hwcaps.c
> index 3075a8286d..a041a9047d 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
> 

Ok.
diff mbox series

Patch

diff --git a/config.h.in b/config.h.in
index b823c8e080..dc3854f4eb 100644
--- a/config.h.in
+++ b/config.h.in
@@ -266,4 +266,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 bd7af7cca4..42fd697129 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -1325,31 +1325,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..109f03e9b9 100644
--- a/sysdeps/x86/Makefile
+++ b/sysdeps/x86/Makefile
@@ -9,6 +9,16 @@  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 (yesyes,$(enable-x86-isa-level)$(config-cflags-skylake-avx512))
+tests += tst-isa-level-1
+modules-names += tst-isa-level-mod-1a tst-isa-level-mod-1b
+
+CFLAGS-tst-isa-level-mod-1a.c += -march=skylake-avx512 \
+				-DINCLUDE_X86_ISA_LEVEL
+$(objpfx)tst-isa-level-1: $(libdl)
+$(objpfx)tst-isa-level-1.out: $(objpfx)tst-isa-level-mod-1a.so \
+			      $(objpfx)tst-isa-level-mod-1b.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..2738fe47b2 100644
--- a/sysdeps/x86/configure
+++ b/sysdeps/x86/configure
@@ -68,3 +68,104 @@  elif test $enable_cet = permissive; then
 fi
 config_vars="$config_vars
 enable-cet = $enable_cet"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -march=skylake-avx512 support" >&5
+$as_echo_n "checking for -march=skylake-avx512 support... " >&6; }
+if ${libc_cv_cc_skylake_avx512+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if { ac_try='${CC-cc} -march=skylake-avx512 -xc /dev/null -S -o /dev/null'
+  { { 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 :
+  libc_cv_cc_skylake_avx512=yes
+else
+  libc_cv_cc_skylake_avx512=no
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_cc_skylake_avx512" >&5
+$as_echo "$libc_cv_cc_skylake_avx512" >&6; }
+if test $libc_cv_cc_skylake_avx512 = yes; then
+  $as_echo "#define HAVE_SKYLAKE_AVX512_SUPPORT 1" >>confdefs.h
+
+fi
+config_vars="$config_vars
+config-cflags-skylake-avx512 = $libc_cv_cc_skylake_avx512"
+
+libc_cv_include_x86_isa_level=no
+if test -z "`$LD --version | sed -n 's/^GNU \(gold\).*$/\1/p'`"; then
+  # Check for ld 2.32 or higher.
+  libc_cv_include_x86_isa_level=yes
+  for ac_prog in $LD
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; 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_prog_LD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$LD"; then
+  ac_cv_prog_LD="$LD" # Let the user override the test.
+else
+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_prog_LD="$ac_prog"
+    $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
+
+fi
+fi
+LD=$ac_cv_prog_LD
+if test -n "$LD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$LD" && break
+done
+
+if test -z "$LD"; then
+  ac_verc_fail=yes
+else
+  # Found it, now check the version.
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $LD" >&5
+$as_echo_n "checking version of $LD... " >&6; }
+  ac_prog_version=`$LD --version 2>&1 | sed -n 's/^.*GNU ld.* \([0-9][0-9]*\.[0-9.]*\).*$/\1/p'`
+  case $ac_prog_version in
+    '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
+    2.3[2-9]*|2.[4-9][0-9]*|[3-9].*|[1-9][0-9]*)
+       ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
+    *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
+
+  esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_prog_version" >&5
+$as_echo "$ac_prog_version" >&6; }
+fi
+if test $ac_verc_fail = yes; then
+  libc_cv_include_x86_isa_level=no
+fi
+
+  if test $libc_cv_include_x86_isa_level = yes; then
+    $as_echo "#define INCLUDE_X86_ISA_LEVEL 1" >>confdefs.h
+
+  fi
+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..8f00b9663d 100644
--- a/sysdeps/x86/configure.ac
+++ b/sysdeps/x86/configure.ac
@@ -43,3 +43,29 @@  elif test $enable_cet = permissive; then
   AC_DEFINE(DEFAULT_DL_X86_CET_CONTROL, cet_permissive)
 fi
 LIBC_CONFIG_VAR([enable-cet], [$enable_cet])
+
+dnl Check if -march=skylake-avx512 works.
+AC_CACHE_CHECK(for -march=skylake-avx512 support,
+	       libc_cv_cc_skylake_avx512, [dnl
+LIBC_TRY_CC_OPTION([-march=skylake-avx512],
+		   [libc_cv_cc_skylake_avx512=yes],
+		   [libc_cv_cc_skylake_avx512=no])
+])
+if test $libc_cv_cc_skylake_avx512 = yes; then
+  AC_DEFINE(HAVE_SKYLAKE_AVX512_SUPPORT)
+fi
+LIBC_CONFIG_VAR([config-cflags-skylake-avx512], [$libc_cv_cc_skylake_avx512])
+
+libc_cv_include_x86_isa_level=no
+if test -z "`$LD --version | sed -n 's/^GNU \(gold\).*$/\1/p'`"; then
+  # Check for ld 2.32 or higher.
+  libc_cv_include_x86_isa_level=yes
+  AC_CHECK_PROG_VER(LD, $LD, --version,
+		    [GNU ld.* \([0-9][0-9]*\.[0-9.]*\)],
+		    [2.3[2-9]*|2.[4-9][0-9]*|[3-9].*|[1-9][0-9]*],
+		    libc_cv_include_x86_isa_level=no)
+  if test $libc_cv_include_x86_isa_level = yes; then
+    AC_DEFINE(INCLUDE_X86_ISA_LEVEL)
+  fi
+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 fe080b63b2..ec5cdafe81 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 5524b66038..8986c776e5 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 89911e19e2..61c0624c09 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 || feature_1_and)
+    {
+      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, 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..166dd5df01
--- /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 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 f62be0b9b3..ef0c6b4fbc 100644
--- a/sysdeps/x86/include/cpu-features.h
+++ b/sysdeps/x86/include/cpu-features.h
@@ -129,6 +129,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..0751e86f27
--- /dev/null
+++ b/sysdeps/x86/isa-level.c
@@ -0,0 +1,95 @@ 
+/* 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
+
+# define ISA_LEVEL (ISA_BASELINE | ISA_V2 | ISA_V3 | ISA_V4)
+
+# 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 2e4f8850f9..3c550e529a 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..c263157c8c
--- /dev/null
+++ b/sysdeps/x86/tst-isa-level-1.c
@@ -0,0 +1,74 @@ 
+/* 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);
+  /* Skip on x86-64-v4 platforms since dlopen always works.  */
+  if ((isa_level & GNU_PROPERTY_X86_ISA_1_V4) != 0)
+    return EXIT_UNSUPPORTED;
+  do_test_1 ("tst-isa-level-mod-1a.so", true);
+  do_test_1 ("tst-isa-level-mod-1b.so", false);
+  return EXIT_SUCCESS;
+}
+
+#include <support/test-driver.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..3816536428
--- /dev/null
+++ b/sysdeps/x86/tst-isa-level-mod-1.c
@@ -0,0 +1,23 @@ 
+/* 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/>.  */
+
+int
+test (void)
+{
+  return 0;
+}
diff --git a/sysdeps/x86/tst-isa-level-mod-1a.c b/sysdeps/x86/tst-isa-level-mod-1a.c
new file mode 100644
index 0000000000..4f026dd915
--- /dev/null
+++ b/sysdeps/x86/tst-isa-level-mod-1a.c
@@ -0,0 +1,2 @@ 
+#include <isa-level.c>
+#include "tst-isa-level-mod-1.c"
diff --git a/sysdeps/x86/tst-isa-level-mod-1b.c b/sysdeps/x86/tst-isa-level-mod-1b.c
new file mode 100644
index 0000000000..d6fe0685a4
--- /dev/null
+++ b/sysdeps/x86/tst-isa-level-mod-1b.c
@@ -0,0 +1 @@ 
+#include "tst-isa-level-mod-1.c"
diff --git a/sysdeps/x86_64/dl-hwcaps-subdirs.c b/sysdeps/x86_64/dl-hwcaps-subdirs.c
index 8810a822ef..e5640303f9 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 3075a8286d..a041a9047d 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