From e5d4a8ddcda71a15cd38c506c5db4a5685438476 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Fri, 9 Oct 2020 06:06:56 -0700
Subject: [PATCH] x86: Support GNU_PROPERTY_X86_ISA_1_V[234] marker [BZ #26717]
GCC 11 supports -march=x86-64-v[234] to enable x86 micro-architecture ISA
levels:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97250
Binutils has been updated to support GNU_PROPERTY_X86_ISA_1_V[234] marker:
https://gitlab.com/x86-psABIs/x86-64-ABI/-/merge_requests/13
with
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
in x86 ELF binaries to indicate the micro-architecture ISA level required
to execute the binary. The marker must be added by programmers explicitly
in one of 2 ways:
1. Add the marker in the linker inputs as this patch does.
2. Pass -z x86-64-v[234] to the linker.
Add 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_V[234] markers to elf.h.
2. Add 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.
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 | 34 ++++-----
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 | 58 +++++++++++++++
sysdeps/x86/include/cpu-features.h | 2 +
sysdeps/x86/isa-level.c | 87 ++++++++++++++++++++++
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 +
17 files changed, 535 insertions(+), 61 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
@@ -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
@@ -1327,31 +1327,25 @@ 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)
+/* Baseline: CMOV (cmov) CX8 (cmpxchg8b) FPU (fld), FXSR (fxsave),
+ SCE (syscall), MMX, SSE and SSE2. */
+
+/* GNU_PROPERTY_X86_ISA_1_V2: Baseline, CMPXCHG16B (cmpxchg16b),
+ LAHF-SAHF (lahf), POPCNT (popcnt), SSE3, SSSE3, SSE4.1 and SSE4.2. */
+#define GNU_PROPERTY_X86_ISA_1_V2 (1U << 0)
+/* 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 << 1)
+/* 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 << 2)
/* 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>
@@ -289,6 +290,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",
+ 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,58 @@
+/* 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_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, 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))
+ {
+ 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,87 @@
+/* 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 __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 \
+ || 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_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"
--
2.26.2