/* 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
/* 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. */
tests += tst-get-cpu-features tst-get-cpu-features-static \
tst-cpu-features-cpuinfo tst-cpu-features-supports
tests-static += tst-get-cpu-features-static
+ifeq (yes,$(enable-x86-isa-level))
+tests += tst-isa-level-1
+modules-names += tst-isa-level-mod-1-baseline \
+ tst-isa-level-mod-1-v2 \
+ tst-isa-level-mod-1-v3 \
+ tst-isa-level-mod-1-v4 \
+
+# X86 ISA level baseline
+CFLAGS-tst-isa-level-mod-1-baseline.c += -DINCLUDE_X86_ISA_LEVEL \
+ -DISA_LEVEL=0x1 \
+ -march=x86-64
+# X86 ISA level v2
+CFLAGS-tst-isa-level-mod-1-v2.c += -DINCLUDE_X86_ISA_LEVEL \
+ -DISA_LEVEL=0x3 \
+ -march=x86-64
+# X86 ISA level v3
+CFLAGS-tst-isa-level-mod-1-v3.c += -DINCLUDE_X86_ISA_LEVEL \
+ -DISA_LEVEL=0x7 \
+ -march=x86-64
+# X86 ISA level v4
+CFLAGS-tst-isa-level-mod-1-v4.c += -DINCLUDE_X86_ISA_LEVEL \
+ -DISA_LEVEL=0xf \
+ -march=x86-64
+
+$(objpfx)tst-isa-level-1: $(libdl)
+$(objpfx)tst-isa-level-1.out: $(objpfx)tst-isa-level-mod-1-baseline.so \
+ $(objpfx)tst-isa-level-mod-1-v2.so \
+ $(objpfx)tst-isa-level-mod-1-v3.so \
+ $(objpfx)tst-isa-level-mod-1-v4.so
+endif
endif
ifeq ($(subdir),math)
--- /dev/null
+/* 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>
fi
config_vars="$config_vars
enable-cet = $enable_cet"
+
+# Check if linker supports x86 ISA level.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for linker x86 ISA level support" >&5
+$as_echo_n "checking for linker x86 ISA level support... " >&6; }
+if ${libc_cv_include_x86_isa_level+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat > conftest1.S <<EOF
+#ifdef __LP64__
+# define P2ALIGN 3
+#else
+# define P2ALIGN 2
+#endif
+ .section ".note.gnu.property", "a"
+ .p2align P2ALIGN
+ .long 1f - 0f /* name length. */
+ .long 4f - 1f /* data length. */
+ /* NT_GNU_PROPERTY_TYPE_0 */
+ .long 5 /* note type. */
+0:
+ .asciz "GNU" /* vendor name. */
+1:
+ .p2align P2ALIGN
+ /* GNU_PROPERTY_X86_ISA_1_NEEDED */
+ .long 0xc0008002 /* pr_type. */
+ .long 3f - 2f /* pr_datasz. */
+2:
+ .long 0x1
+3:
+ .p2align P2ALIGN
+4:
+EOF
+cat > conftest2.S <<EOF
+#ifdef __LP64__
+# define P2ALIGN 3
+#else
+# define P2ALIGN 2
+#endif
+ .section ".note.gnu.property", "a"
+ .p2align P2ALIGN
+ .long 1f - 0f /* name length. */
+ .long 4f - 1f /* data length. */
+ /* NT_GNU_PROPERTY_TYPE_0 */
+ .long 5 /* note type. */
+0:
+ .asciz "GNU" /* vendor name. */
+1:
+ .p2align P2ALIGN
+ /* GNU_PROPERTY_X86_ISA_1_NEEDED */
+ .long 0xc0008002 /* pr_type. */
+ .long 3f - 2f /* pr_datasz. */
+2:
+ .long 0x2
+3:
+ .p2align P2ALIGN
+4:
+EOF
+libc_cv_include_x86_isa_level=no
+if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -nostartfiles -nostdlib -r -o conftest conftest1.S conftest2.S'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ count=`LC_ALL=C $READELF -n conftest | grep NT_GNU_PROPERTY_TYPE_0 | wc -l`
+ if test "$count" = 1; then
+ libc_cv_include_x86_isa_level=yes
+ fi
+fi
+rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_include_x86_isa_level" >&5
+$as_echo "$libc_cv_include_x86_isa_level" >&6; }
+if test $libc_cv_include_x86_isa_level = yes; then
+ $as_echo "#define INCLUDE_X86_ISA_LEVEL 1" >>confdefs.h
+
+fi
+config_vars="$config_vars
+enable-x86-isa-level = $libc_cv_include_x86_isa_level"
AC_DEFINE(DEFAULT_DL_X86_CET_CONTROL, cet_permissive)
fi
LIBC_CONFIG_VAR([enable-cet], [$enable_cet])
+
+# Check if linker supports x86 ISA level.
+AC_CACHE_CHECK([for linker x86 ISA level support],
+ libc_cv_include_x86_isa_level, [dnl
+cat > conftest1.S <<EOF
+#ifdef __LP64__
+# define P2ALIGN 3
+#else
+# define P2ALIGN 2
+#endif
+ .section ".note.gnu.property", "a"
+ .p2align P2ALIGN
+ .long 1f - 0f /* name length. */
+ .long 4f - 1f /* data length. */
+ /* NT_GNU_PROPERTY_TYPE_0 */
+ .long 5 /* note type. */
+0:
+ .asciz "GNU" /* vendor name. */
+1:
+ .p2align P2ALIGN
+ /* GNU_PROPERTY_X86_ISA_1_NEEDED */
+ .long 0xc0008002 /* pr_type. */
+ .long 3f - 2f /* pr_datasz. */
+2:
+ .long 0x1
+3:
+ .p2align P2ALIGN
+4:
+EOF
+cat > conftest2.S <<EOF
+#ifdef __LP64__
+# define P2ALIGN 3
+#else
+# define P2ALIGN 2
+#endif
+ .section ".note.gnu.property", "a"
+ .p2align P2ALIGN
+ .long 1f - 0f /* name length. */
+ .long 4f - 1f /* data length. */
+ /* NT_GNU_PROPERTY_TYPE_0 */
+ .long 5 /* note type. */
+0:
+ .asciz "GNU" /* vendor name. */
+1:
+ .p2align P2ALIGN
+ /* GNU_PROPERTY_X86_ISA_1_NEEDED */
+ .long 0xc0008002 /* pr_type. */
+ .long 3f - 2f /* pr_datasz. */
+2:
+ .long 0x2
+3:
+ .p2align P2ALIGN
+4:
+EOF
+libc_cv_include_x86_isa_level=no
+if AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS -nostartfiles -nostdlib -r -o conftest conftest1.S conftest2.S); then
+ count=`LC_ALL=C $READELF -n conftest | grep NT_GNU_PROPERTY_TYPE_0 | wc -l`
+ if test "$count" = 1; then
+ libc_cv_include_x86_isa_level=yes
+ fi
+fi
+rm -f conftest*])
+if test $libc_cv_include_x86_isa_level = yes; then
+ AC_DEFINE(INCLUDE_X86_ISA_LEVEL)
+fi
+LIBC_CONFIG_VAR([enable-x86-isa-level], [$libc_cv_include_x86_isa_level])
#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>
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
*/
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
/* 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;
/* 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;
#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
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
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)
{
/* 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
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. */
}
/* We get here only if there is one or no GNU property note. */
- if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_IBT))
- l->l_cet |= lc_ibt;
- if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_SHSTK))
- l->l_cet |= lc_shstk;
-#endif
+ if (isa_1_needed != 0 || feature_1_and != 0)
+ {
+ l->l_property = lc_property_valid;
+ l->l_x86_isa_1_needed = isa_1_needed;
+ l->l_x86_feature_1_and = feature_1_and;
+ }
+ else
+ l->l_property = lc_property_none;
}
static inline void __attribute__ ((unused))
_dl_process_pt_note (struct link_map *l, int fd, const ElfW(Phdr) *ph)
{
const ElfW(Nhdr) *note = (const void *) (ph->p_vaddr + l->l_addr);
- _dl_process_cet_property_note (l, note, ph->p_memsz, ph->p_align);
+ _dl_process_property_note (l, note, ph->p_memsz, ph->p_align);
}
static inline int __attribute__ ((always_inline))
--- /dev/null
+/* Get x86 ISA level.
+ This file is part of the GNU C Library.
+ Copyright (C) 2020 Free Software Foundation, Inc.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <sys/platform/x86.h>
+
+/* Get GNU_PROPERTY_X86_ISA_1_BASELINE and GNU_PROPERTY_X86_ISA_1_V[234]
+ ISA level. */
+
+static unsigned int
+get_isa_level (const struct cpu_features *cpu_features)
+{
+ unsigned int isa_level = 0;
+
+ if (CPU_FEATURE_USABLE_P (cpu_features, CMOV)
+ && CPU_FEATURE_USABLE_P (cpu_features, CX8)
+ && CPU_FEATURE_CPU_P (cpu_features, FPU)
+ && CPU_FEATURE_USABLE_P (cpu_features, FXSR)
+ && CPU_FEATURE_USABLE_P (cpu_features, MMX)
+ && CPU_FEATURE_USABLE_P (cpu_features, SSE)
+ && CPU_FEATURE_USABLE_P (cpu_features, SSE2))
+ {
+ isa_level = GNU_PROPERTY_X86_ISA_1_BASELINE;
+ if (CPU_FEATURE_USABLE_P (cpu_features, CMPXCHG16B)
+ && CPU_FEATURE_USABLE_P (cpu_features, LAHF64_SAHF64)
+ && CPU_FEATURE_USABLE_P (cpu_features, POPCNT)
+ && CPU_FEATURE_USABLE_P (cpu_features, SSE3)
+ && CPU_FEATURE_USABLE_P (cpu_features, SSSE3)
+ && CPU_FEATURE_USABLE_P (cpu_features, SSE4_1)
+ && CPU_FEATURE_USABLE_P (cpu_features, SSE4_2))
+ {
+ isa_level |= GNU_PROPERTY_X86_ISA_1_V2;
+ if (CPU_FEATURE_USABLE_P (cpu_features, AVX)
+ && CPU_FEATURE_USABLE_P (cpu_features, AVX2)
+ && CPU_FEATURE_USABLE_P (cpu_features, F16C)
+ && CPU_FEATURE_USABLE_P (cpu_features, FMA)
+ && CPU_FEATURE_USABLE_P (cpu_features, LZCNT)
+ && CPU_FEATURE_USABLE_P (cpu_features, MOVBE))
+ {
+ isa_level |= GNU_PROPERTY_X86_ISA_1_V3;
+ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F)
+ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)
+ && CPU_FEATURE_USABLE_P (cpu_features, AVX512CD)
+ && CPU_FEATURE_USABLE_P (cpu_features, AVX512DQ)
+ && CPU_FEATURE_USABLE_P (cpu_features, AVX512VL))
+ isa_level |= GNU_PROPERTY_X86_ISA_1_V4;
+ }
+ }
+ }
+
+ return isa_level;
+}
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
--- /dev/null
+/* ELF program property for x86 ISA level.
+ Copyright (C) 2020 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ In addition to the permissions in the GNU Lesser General Public
+ License, the Free Software Foundation gives you unlimited
+ permission to link the compiled version of this file with other
+ programs, and to distribute those programs without any restriction
+ coming from the use of this file. (The Lesser General Public
+ License restrictions do apply in other respects; for example, they
+ cover modification of the file, and distribution when not linked
+ into another program.)
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <elf.h>
+
+/* ELF program property for x86 ISA level. */
+#ifdef INCLUDE_X86_ISA_LEVEL
+# if defined __x86_64__ || defined __FXSR__ || !defined _SOFT_FLOAT \
+ || defined __MMX__ || defined __SSE__ || defined __SSE2__
+# define ISA_BASELINE GNU_PROPERTY_X86_ISA_1_BASELINE
+# else
+# define ISA_BASELINE 0
+# endif
+
+# if defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 \
+ || (defined __x86_64__ && defined __LAHF_SAHF__) \
+ || defined __POPCNT__ || defined __SSE3__ \
+ || defined __SSSE3__ || defined __SSE4_1__ || defined __SSE4_2__
+# define ISA_V2 GNU_PROPERTY_X86_ISA_1_V2
+# else
+# define ISA_V2 0
+# endif
+
+# if defined __AVX__ || defined __AVX2__ || defined __F16C__ \
+ || defined __FMA__ || defined __LZCNT__ || defined __MOVBE__ \
+ || defined __XSAVE__
+# define ISA_V3 GNU_PROPERTY_X86_ISA_1_V3
+# else
+# define ISA_V3 0
+# endif
+
+# if defined __AVX512F__ || defined __AVX512BW__ || defined __AVX512CD__ \
+ || defined __AVX512DQ__ || defined __AVX512VL__
+# define ISA_V4 GNU_PROPERTY_X86_ISA_1_V4
+# else
+# define ISA_V4 0
+# endif
+
+# ifndef ISA_LEVEL
+# define ISA_LEVEL (ISA_BASELINE | ISA_V2 | ISA_V3 | ISA_V4)
+# endif
+
+# if ISA_LEVEL
+# ifdef __LP64__
+# define PROPERTY_ALIGN 3
+# else
+# define PROPERTY_ALIGN 2
+# endif
+
+# define note_stringify(arg) note_stringify_1(arg)
+# define note_stringify_1(arg) #arg
+
+asm(".pushsection \".note.gnu.property\",\"a\",@note\n"
+" .p2align " note_stringify (PROPERTY_ALIGN)
+ /* name length. */
+"\n .long 1f - 0f\n"
+ /* data length. */
+" .long 4f - 1f\n"
+ /* note type: NT_GNU_PROPERTY_TYPE_0. */
+" .long " note_stringify (NT_GNU_PROPERTY_TYPE_0)
+ /* vendor name. */
+"\n0: .asciz \"GNU\"\n"
+"1: .p2align " note_stringify (PROPERTY_ALIGN)
+ /* pr_type: GNU_PROPERTY_X86_ISA_1_NEEDED. */
+"\n .long " note_stringify (GNU_PROPERTY_X86_ISA_1_NEEDED)
+ /* pr_datasz. */
+"\n .long 3f - 2f\n"
+ /* GNU_PROPERTY_X86_ISA_1_V[234]. */
+"2:\n .long " note_stringify (ISA_LEVEL)
+"\n3:\n .p2align " note_stringify (PROPERTY_ALIGN)
+"\n4:\n .popsection");
+# endif /* ISA_LEVEL */
+#endif /* INCLUDE_X86_ISA_LEVEL */
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;
--- /dev/null
+/* Check ISA level on dlopened shared object.
+ Copyright (C) 2020 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <elf.h>
+#include <get-isa-level.h>
+#include <support/xdlfcn.h>
+#include <support/check.h>
+#include <support/test-driver.h>
+
+static void
+do_test_1 (const char *modname, bool fail)
+{
+ int (*fp) (void);
+ void *h;
+
+ h = dlopen (modname, RTLD_LAZY);
+ if (h == NULL)
+ {
+ const char *err = dlerror ();
+ if (fail)
+ {
+ if (strstr (err, "CPU ISA level is lower than required") == NULL)
+ FAIL_EXIT1 ("incorrect dlopen '%s' error: %s\n", modname, err);
+
+ return;
+ }
+
+ FAIL_EXIT1 ("cannot open '%s': %s\n", modname, err);
+ }
+
+ if (fail)
+ FAIL_EXIT1 ("dlopen '%s' should have failed\n", modname);
+
+ fp = xdlsym (h, "test");
+
+ if (fp () != 0)
+ FAIL_EXIT1 ("test () != 0\n");
+
+ dlclose (h);
+}
+
+static int
+do_test (void)
+{
+ const struct cpu_features *cpu_features
+ = __x86_get_cpu_features (COMMON_CPUID_INDEX_MAX);
+ unsigned int isa_level = get_isa_level (cpu_features);
+ bool has_isa_baseline = ((isa_level & GNU_PROPERTY_X86_ISA_1_BASELINE)
+ == GNU_PROPERTY_X86_ISA_1_BASELINE);
+ bool has_isa_v2 = ((isa_level & GNU_PROPERTY_X86_ISA_1_V2)
+ == GNU_PROPERTY_X86_ISA_1_V2);
+ bool has_isa_v3 = ((isa_level & GNU_PROPERTY_X86_ISA_1_V3)
+ == GNU_PROPERTY_X86_ISA_1_V3);
+ bool has_isa_v4 = ((isa_level & GNU_PROPERTY_X86_ISA_1_V4)
+ == GNU_PROPERTY_X86_ISA_1_V4);
+
+ if (!has_isa_baseline)
+ {
+ do_test_1 ("tst-isa-level-mod-1-baseline.so", true);
+ return EXIT_SUCCESS;
+ }
+
+ do_test_1 ("tst-isa-level-mod-1-baseline.so", false);
+
+ /* Skip on x86-64-v4 platforms since dlopen v4 module always works. */
+ if (has_isa_v4)
+ return EXIT_SUCCESS;
+
+ do_test_1 ("tst-isa-level-mod-1-v4.so", true);
+
+ /* Skip on x86-64-v3 platforms since dlopen v3 module always works. */
+ if (has_isa_v3)
+ return EXIT_SUCCESS;
+
+ do_test_1 ("tst-isa-level-mod-1-v3.so", true);
+
+ /* Skip on x86-64-v2 platforms since dlopen v2 module always works. */
+ if (has_isa_v2)
+ return EXIT_SUCCESS;
+
+ do_test_1 ("tst-isa-level-mod-1-v2.so", true);
+
+ return EXIT_SUCCESS;
+}
+
+#include <support/test-driver.c>
--- /dev/null
+#include "tst-isa-level-mod-1.c"
--- /dev/null
+#include "tst-isa-level-mod-1.c"
--- /dev/null
+#include "tst-isa-level-mod-1.c"
--- /dev/null
+#include "tst-isa-level-mod-1.c"
--- /dev/null
+/* Check ISA level on dlopened shared object.
+ Copyright (C) 2019-2020 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <isa-level.c>
+
+int
+test (void)
+{
+ return 0;
+}
#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. */
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;
#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);
{
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