V5 [PATCH 1/2] x86: Support GNU_PROPERTY_X86_ISA_1_V[234] marker [BZ #26717]
Commit Message
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
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.
@@ -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
@@ -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. */
@@ -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)
new file mode 100644
@@ -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>
@@ -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"
@@ -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])
@@ -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
@@ -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;
@@ -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))
new file mode 100644
@@ -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;
+}
@@ -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
new file mode 100644
@@ -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 */
@@ -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;
new file mode 100644
@@ -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>
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -0,0 +1,2 @@
+#include <isa-level.c>
+#include "tst-isa-level-mod-1.c"
new file mode 100644
@@ -0,0 +1 @@
+#include "tst-isa-level-mod-1.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;
@@ -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