mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-24 22:10:13 +00:00
x86: Support GNU_PROPERTY_X86_ISA_1_V[234] marker [BZ #26717]
GCC 11 supports -march=x86-64-v[234] to enable x86 micro-architecture ISA levels: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97250 and -mneeded to emit GNU_PROPERTY_X86_ISA_1_NEEDED property with GNU_PROPERTY_X86_ISA_1_V[234] marker: https://gitlab.com/x86-psABIs/x86-64-ABI/-/merge_requests/13 Binutils support for GNU_PROPERTY_X86_ISA_1_V[234] marker were added by commit b0ab06937385e0ae25cebf1991787d64f439bf12 Author: H.J. Lu <hjl.tools@gmail.com> Date: Fri Oct 30 06:49:57 2020 -0700 x86: Support GNU_PROPERTY_X86_ISA_1_BASELINE marker and commit 32930e4edbc06bc6f10c435dbcc63131715df678 Author: H.J. Lu <hjl.tools@gmail.com> Date: Fri Oct 9 05:05:57 2020 -0700 x86: Support GNU_PROPERTY_X86_ISA_1_V[234] marker GNU_PROPERTY_X86_ISA_1_NEEDED property in x86 ELF binaries indicate the micro-architecture ISA level required to execute the binary. The marker must be added by programmers explicitly in one of 3 ways: 1. Pass -mneeded to GCC. 2. Add the marker in the linker inputs as this patch does. 3. Pass -z x86-64-v[234] to the linker. Add GNU_PROPERTY_X86_ISA_1_BASELINE and GNU_PROPERTY_X86_ISA_1_V[234] marker support to ld.so if binutils 2.32 or newer is used to build glibc: 1. Add GNU_PROPERTY_X86_ISA_1_BASELINE and GNU_PROPERTY_X86_ISA_1_V[234] markers to elf.h. 2. Add GNU_PROPERTY_X86_ISA_1_BASELINE and GNU_PROPERTY_X86_ISA_1_V[234] marker to abi-note.o based on the ISA level used to compile abi-note.o, assuming that the same ISA level is used to compile the whole glibc. 3. Add isa_1 to cpu_features to record the supported x86 ISA level. 4. Rename _dl_process_cet_property_note to _dl_process_property_note and add GNU_PROPERTY_X86_ISA_1_V[234] marker detection. 5. Update _rtld_main_check and _dl_open_check to check loaded objects with the incompatible ISA level. 6. Add a testcase to verify that dlopen an x86-64-v4 shared object fails on lesser platforms. 7. Use <get-isa-level.h> in dl-hwcaps-subdirs.c and tst-glibc-hwcaps.c. Tested under i686, x32 and x86-64 modes on x86-64-v2, x86-64-v3 and x86-64-v4 machines. Marked elf/tst-isa-level-1 with x86-64-v4, ran it on x86-64-v3 machine and got: [hjl@gnu-cfl-2 build-x86_64-linux]$ ./elf/tst-isa-level-1 ./elf/tst-isa-level-1: CPU ISA level is lower than required [hjl@gnu-cfl-2 build-x86_64-linux]$
This commit is contained in:
parent
9e97f239ea
commit
ecce11aa07
@ -269,4 +269,7 @@
|
|||||||
/* The default value of x86 CET control. */
|
/* The default value of x86 CET control. */
|
||||||
#define DEFAULT_DL_X86_CET_CONTROL cet_elf_property
|
#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
|
#endif
|
||||||
|
35
elf/elf.h
35
elf/elf.h
@ -1324,31 +1324,26 @@ typedef struct
|
|||||||
|
|
||||||
/* The x86 instruction sets indicated by the corresponding bits are
|
/* The x86 instruction sets indicated by the corresponding bits are
|
||||||
used in program. Their support in the hardware is optional. */
|
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
|
/* The x86 instruction sets indicated by the corresponding bits are
|
||||||
used in program and they must be supported by the hardware. */
|
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. */
|
/* X86 processor-specific features used in program. */
|
||||||
#define GNU_PROPERTY_X86_FEATURE_1_AND 0xc0000002
|
#define GNU_PROPERTY_X86_FEATURE_1_AND 0xc0000002
|
||||||
|
|
||||||
#define GNU_PROPERTY_X86_ISA_1_486 (1U << 0)
|
/* GNU_PROPERTY_X86_ISA_1_BASELINE: CMOV, CX8 (cmpxchg8b), FPU (fld),
|
||||||
#define GNU_PROPERTY_X86_ISA_1_586 (1U << 1)
|
MMX, OSFXSR (fxsave), SCE (syscall), SSE and SSE2. */
|
||||||
#define GNU_PROPERTY_X86_ISA_1_686 (1U << 2)
|
#define GNU_PROPERTY_X86_ISA_1_BASELINE (1U << 0)
|
||||||
#define GNU_PROPERTY_X86_ISA_1_SSE (1U << 3)
|
/* GNU_PROPERTY_X86_ISA_1_V2: GNU_PROPERTY_X86_ISA_1_BASELINE,
|
||||||
#define GNU_PROPERTY_X86_ISA_1_SSE2 (1U << 4)
|
CMPXCHG16B (cmpxchg16b), LAHF-SAHF (lahf), POPCNT (popcnt), SSE3,
|
||||||
#define GNU_PROPERTY_X86_ISA_1_SSE3 (1U << 5)
|
SSSE3, SSE4.1 and SSE4.2. */
|
||||||
#define GNU_PROPERTY_X86_ISA_1_SSSE3 (1U << 6)
|
#define GNU_PROPERTY_X86_ISA_1_V2 (1U << 1)
|
||||||
#define GNU_PROPERTY_X86_ISA_1_SSE4_1 (1U << 7)
|
/* GNU_PROPERTY_X86_ISA_1_V3: GNU_PROPERTY_X86_ISA_1_V2, AVX, AVX2, BMI1,
|
||||||
#define GNU_PROPERTY_X86_ISA_1_SSE4_2 (1U << 8)
|
BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE. */
|
||||||
#define GNU_PROPERTY_X86_ISA_1_AVX (1U << 9)
|
#define GNU_PROPERTY_X86_ISA_1_V3 (1U << 2)
|
||||||
#define GNU_PROPERTY_X86_ISA_1_AVX2 (1U << 10)
|
/* GNU_PROPERTY_X86_ISA_1_V4: GNU_PROPERTY_X86_ISA_1_V3, AVX512F,
|
||||||
#define GNU_PROPERTY_X86_ISA_1_AVX512F (1U << 11)
|
AVX512BW, AVX512CD, AVX512DQ and AVX512VL. */
|
||||||
#define GNU_PROPERTY_X86_ISA_1_AVX512CD (1U << 12)
|
#define GNU_PROPERTY_X86_ISA_1_V4 (1U << 3)
|
||||||
#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)
|
|
||||||
|
|
||||||
/* This indicates that all executable sections are compatible with
|
/* This indicates that all executable sections are compatible with
|
||||||
IBT. */
|
IBT. */
|
||||||
|
@ -9,6 +9,36 @@ sysdep_headers += sys/platform/x86.h
|
|||||||
tests += tst-get-cpu-features tst-get-cpu-features-static \
|
tests += tst-get-cpu-features tst-get-cpu-features-static \
|
||||||
tst-cpu-features-cpuinfo tst-cpu-features-supports
|
tst-cpu-features-cpuinfo tst-cpu-features-supports
|
||||||
tests-static += tst-get-cpu-features-static
|
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
|
endif
|
||||||
|
|
||||||
ifeq ($(subdir),math)
|
ifeq ($(subdir),math)
|
||||||
|
29
sysdeps/x86/abi-note.c
Normal file
29
sysdeps/x86/abi-note.c
Normal file
@ -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>
|
79
sysdeps/x86/configure
vendored
79
sysdeps/x86/configure
vendored
@ -68,3 +68,82 @@ elif test $enable_cet = permissive; then
|
|||||||
fi
|
fi
|
||||||
config_vars="$config_vars
|
config_vars="$config_vars
|
||||||
enable-cet = $enable_cet"
|
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"
|
||||||
|
@ -43,3 +43,69 @@ elif test $enable_cet = permissive; then
|
|||||||
AC_DEFINE(DEFAULT_DL_X86_CET_CONTROL, cet_permissive)
|
AC_DEFINE(DEFAULT_DL_X86_CET_CONTROL, cet_permissive)
|
||||||
fi
|
fi
|
||||||
LIBC_CONFIG_VAR([enable-cet], [$enable_cet])
|
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])
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <cpuid.h>
|
#include <cpuid.h>
|
||||||
#include <dl-hwcap.h>
|
#include <dl-hwcap.h>
|
||||||
#include <libc-pointer-arith.h>
|
#include <libc-pointer-arith.h>
|
||||||
|
#include <get-isa-level.h>
|
||||||
#if IS_IN (libc) && !defined SHARED
|
#if IS_IN (libc) && !defined SHARED
|
||||||
# include <assert.h>
|
# include <assert.h>
|
||||||
# include <unistd.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, KL);
|
||||||
CPU_FEATURE_SET_USABLE (cpu_features, WIDE_KL);
|
CPU_FEATURE_SET_USABLE (cpu_features, WIDE_KL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cpu_features->isa_1 = get_isa_level (cpu_features);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -76,10 +76,12 @@ dl_cet_check (struct link_map *m, const char *program)
|
|||||||
*/
|
*/
|
||||||
enable_ibt &= (HAS_CPU_FEATURE (IBT)
|
enable_ibt &= (HAS_CPU_FEATURE (IBT)
|
||||||
&& (enable_ibt_type == cet_always_on
|
&& (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 &= (HAS_CPU_FEATURE (SHSTK)
|
||||||
&& (enable_shstk_type == cet_always_on
|
&& (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
|
/* 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
|
/* IBT is enabled only if it is enabled in executable as
|
||||||
well as all shared objects. */
|
well as all shared objects. */
|
||||||
enable_ibt &= (enable_ibt_type == cet_always_on
|
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)
|
if (!found_ibt_legacy && enable_ibt != ibt_enabled)
|
||||||
{
|
{
|
||||||
found_ibt_legacy = true;
|
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
|
/* SHSTK is enabled only if it is enabled in executable as
|
||||||
well as all shared objects. */
|
well as all shared objects. */
|
||||||
enable_shstk &= (enable_shstk_type == cet_always_on
|
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)
|
if (enable_shstk != shstk_enabled)
|
||||||
{
|
{
|
||||||
found_shstk_legacy = true;
|
found_shstk_legacy = true;
|
||||||
|
@ -19,14 +19,54 @@
|
|||||||
#ifndef _DL_PROP_H
|
#ifndef _DL_PROP_H
|
||||||
#define _DL_PROP_H
|
#define _DL_PROP_H
|
||||||
|
|
||||||
|
#include <libintl.h>
|
||||||
|
|
||||||
extern void _dl_cet_check (struct link_map *, const char *)
|
extern void _dl_cet_check (struct link_map *, const char *)
|
||||||
attribute_hidden;
|
attribute_hidden;
|
||||||
extern void _dl_cet_open_check (struct link_map *)
|
extern void _dl_cet_open_check (struct link_map *)
|
||||||
attribute_hidden;
|
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))
|
static inline void __attribute__ ((always_inline))
|
||||||
_rtld_main_check (struct link_map *m, const char *program)
|
_rtld_main_check (struct link_map *m, const char *program)
|
||||||
{
|
{
|
||||||
|
dl_isa_level_check (m, program);
|
||||||
#if CET_ENABLED
|
#if CET_ENABLED
|
||||||
_dl_cet_check (m, program);
|
_dl_cet_check (m, program);
|
||||||
#endif
|
#endif
|
||||||
@ -35,20 +75,18 @@ _rtld_main_check (struct link_map *m, const char *program)
|
|||||||
static inline void __attribute__ ((always_inline))
|
static inline void __attribute__ ((always_inline))
|
||||||
_dl_open_check (struct link_map *m)
|
_dl_open_check (struct link_map *m)
|
||||||
{
|
{
|
||||||
|
dl_isa_level_check (m, NULL);
|
||||||
#if CET_ENABLED
|
#if CET_ENABLED
|
||||||
_dl_cet_open_check (m);
|
_dl_cet_open_check (m);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void __attribute__ ((unused))
|
static inline void __attribute__ ((unused))
|
||||||
_dl_process_cet_property_note (struct link_map *l,
|
_dl_process_property_note (struct link_map *l, const ElfW(Nhdr) *note,
|
||||||
const ElfW(Nhdr) *note,
|
const ElfW(Addr) size, const ElfW(Addr) align)
|
||||||
const ElfW(Addr) size,
|
|
||||||
const ElfW(Addr) align)
|
|
||||||
{
|
{
|
||||||
#if CET_ENABLED
|
|
||||||
/* Skip if we have seen a NT_GNU_PROPERTY_TYPE_0 note before. */
|
/* 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;
|
return;
|
||||||
|
|
||||||
/* The NT_GNU_PROPERTY_TYPE_0 note must be aliged to 4 bytes in
|
/* 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;
|
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;
|
unsigned int last_type = 0;
|
||||||
|
|
||||||
while ((ElfW(Addr)) (note + 1) - start < size)
|
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
|
/* Stop if we see more than one GNU property note which may
|
||||||
be generated by the older linker. */
|
be generated by the older linker. */
|
||||||
if (l->l_cet != lc_unknown)
|
if (l->l_property != lc_property_unknown)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Check CET status now. */
|
/* Check CET status and ISA levels now. */
|
||||||
l->l_cet = lc_none;
|
l->l_property = lc_property_none;
|
||||||
|
|
||||||
/* Check for invalid property. */
|
/* Check for invalid property. */
|
||||||
if (note->n_descsz < 8
|
if (note->n_descsz < 8
|
||||||
@ -101,26 +140,37 @@ _dl_process_cet_property_note (struct link_map *l,
|
|||||||
|
|
||||||
last_type = type;
|
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
|
/* The sizes of types which we are searching for are
|
||||||
bytes. When seeing GNU_PROPERTY_X86_FEATURE_1_AND,
|
4 bytes. There is no point to continue if this
|
||||||
we stop the search regardless if its size is correct
|
note is ill-formed. */
|
||||||
or not. There is no point to continue if this note
|
|
||||||
is ill-formed. */
|
|
||||||
if (datasz != 4)
|
if (datasz != 4)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
feature_1 = *(unsigned int *) ptr;
|
/* 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
|
/* Keep searching for the next GNU property note
|
||||||
generated by the older linker. */
|
generated by the older linker. */
|
||||||
break;
|
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. */
|
/* Stop the scan since property type is in ascending
|
||||||
return;
|
order. */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check the next property item. */
|
/* 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. */
|
/* We get here only if there is one or no GNU property note. */
|
||||||
if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_IBT))
|
if (isa_1_needed != 0 || feature_1_and != 0)
|
||||||
l->l_cet |= lc_ibt;
|
{
|
||||||
if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_SHSTK))
|
l->l_property = lc_property_valid;
|
||||||
l->l_cet |= lc_shstk;
|
l->l_x86_isa_1_needed = isa_1_needed;
|
||||||
#endif
|
l->l_x86_feature_1_and = feature_1_and;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
l->l_property = lc_property_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void __attribute__ ((unused))
|
static inline void __attribute__ ((unused))
|
||||||
_dl_process_pt_note (struct link_map *l, int fd, const ElfW(Phdr) *ph)
|
_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);
|
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))
|
static inline int __attribute__ ((always_inline))
|
||||||
|
66
sysdeps/x86/get-isa-level.h
Normal file
66
sysdeps/x86/get-isa-level.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/* Get x86 ISA level.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
Copyright (C) 2020 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, see
|
||||||
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include <sys/platform/x86.h>
|
||||||
|
|
||||||
|
/* Get GNU_PROPERTY_X86_ISA_1_BASELINE and GNU_PROPERTY_X86_ISA_1_V[234]
|
||||||
|
ISA level. */
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
get_isa_level (const struct cpu_features *cpu_features)
|
||||||
|
{
|
||||||
|
unsigned int isa_level = 0;
|
||||||
|
|
||||||
|
if (CPU_FEATURE_USABLE_P (cpu_features, CMOV)
|
||||||
|
&& CPU_FEATURE_USABLE_P (cpu_features, CX8)
|
||||||
|
&& CPU_FEATURE_CPU_P (cpu_features, FPU)
|
||||||
|
&& CPU_FEATURE_USABLE_P (cpu_features, FXSR)
|
||||||
|
&& CPU_FEATURE_USABLE_P (cpu_features, MMX)
|
||||||
|
&& CPU_FEATURE_USABLE_P (cpu_features, SSE)
|
||||||
|
&& CPU_FEATURE_USABLE_P (cpu_features, SSE2))
|
||||||
|
{
|
||||||
|
isa_level = GNU_PROPERTY_X86_ISA_1_BASELINE;
|
||||||
|
if (CPU_FEATURE_USABLE_P (cpu_features, CMPXCHG16B)
|
||||||
|
&& CPU_FEATURE_USABLE_P (cpu_features, LAHF64_SAHF64)
|
||||||
|
&& CPU_FEATURE_USABLE_P (cpu_features, POPCNT)
|
||||||
|
&& CPU_FEATURE_USABLE_P (cpu_features, SSE3)
|
||||||
|
&& CPU_FEATURE_USABLE_P (cpu_features, SSSE3)
|
||||||
|
&& CPU_FEATURE_USABLE_P (cpu_features, SSE4_1)
|
||||||
|
&& CPU_FEATURE_USABLE_P (cpu_features, SSE4_2))
|
||||||
|
{
|
||||||
|
isa_level |= GNU_PROPERTY_X86_ISA_1_V2;
|
||||||
|
if (CPU_FEATURE_USABLE_P (cpu_features, AVX)
|
||||||
|
&& CPU_FEATURE_USABLE_P (cpu_features, AVX2)
|
||||||
|
&& CPU_FEATURE_USABLE_P (cpu_features, F16C)
|
||||||
|
&& CPU_FEATURE_USABLE_P (cpu_features, FMA)
|
||||||
|
&& CPU_FEATURE_USABLE_P (cpu_features, LZCNT)
|
||||||
|
&& CPU_FEATURE_USABLE_P (cpu_features, MOVBE))
|
||||||
|
{
|
||||||
|
isa_level |= GNU_PROPERTY_X86_ISA_1_V3;
|
||||||
|
if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F)
|
||||||
|
&& CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)
|
||||||
|
&& CPU_FEATURE_USABLE_P (cpu_features, AVX512CD)
|
||||||
|
&& CPU_FEATURE_USABLE_P (cpu_features, AVX512DQ)
|
||||||
|
&& CPU_FEATURE_USABLE_P (cpu_features, AVX512VL))
|
||||||
|
isa_level |= GNU_PROPERTY_X86_ISA_1_V4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return isa_level;
|
||||||
|
}
|
@ -123,6 +123,8 @@ struct cpu_features
|
|||||||
struct cpu_features_basic basic;
|
struct cpu_features_basic basic;
|
||||||
struct cpuid_features features[COMMON_CPUID_INDEX_MAX];
|
struct cpuid_features features[COMMON_CPUID_INDEX_MAX];
|
||||||
unsigned int preferred[PREFERRED_FEATURE_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
|
/* The state size for XSAVEC or XSAVE. The type must be unsigned long
|
||||||
int so that we use
|
int so that we use
|
||||||
|
|
||||||
|
97
sysdeps/x86/isa-level.c
Normal file
97
sysdeps/x86/isa-level.c
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/* ELF program property for x86 ISA level.
|
||||||
|
Copyright (C) 2020 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
In addition to the permissions in the GNU Lesser General Public
|
||||||
|
License, the Free Software Foundation gives you unlimited
|
||||||
|
permission to link the compiled version of this file with other
|
||||||
|
programs, and to distribute those programs without any restriction
|
||||||
|
coming from the use of this file. (The Lesser General Public
|
||||||
|
License restrictions do apply in other respects; for example, they
|
||||||
|
cover modification of the file, and distribution when not linked
|
||||||
|
into another program.)
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, see
|
||||||
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include <elf.h>
|
||||||
|
|
||||||
|
/* ELF program property for x86 ISA level. */
|
||||||
|
#ifdef INCLUDE_X86_ISA_LEVEL
|
||||||
|
# if defined __x86_64__ || defined __FXSR__ || !defined _SOFT_FLOAT \
|
||||||
|
|| defined __MMX__ || defined __SSE__ || defined __SSE2__
|
||||||
|
# define ISA_BASELINE GNU_PROPERTY_X86_ISA_1_BASELINE
|
||||||
|
# else
|
||||||
|
# define ISA_BASELINE 0
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 \
|
||||||
|
|| (defined __x86_64__ && defined __LAHF_SAHF__) \
|
||||||
|
|| defined __POPCNT__ || defined __SSE3__ \
|
||||||
|
|| defined __SSSE3__ || defined __SSE4_1__ || defined __SSE4_2__
|
||||||
|
# define ISA_V2 GNU_PROPERTY_X86_ISA_1_V2
|
||||||
|
# else
|
||||||
|
# define ISA_V2 0
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined __AVX__ || defined __AVX2__ || defined __F16C__ \
|
||||||
|
|| defined __FMA__ || defined __LZCNT__ || defined __MOVBE__ \
|
||||||
|
|| defined __XSAVE__
|
||||||
|
# define ISA_V3 GNU_PROPERTY_X86_ISA_1_V3
|
||||||
|
# else
|
||||||
|
# define ISA_V3 0
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined __AVX512F__ || defined __AVX512BW__ || defined __AVX512CD__ \
|
||||||
|
|| defined __AVX512DQ__ || defined __AVX512VL__
|
||||||
|
# define ISA_V4 GNU_PROPERTY_X86_ISA_1_V4
|
||||||
|
# else
|
||||||
|
# define ISA_V4 0
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifndef ISA_LEVEL
|
||||||
|
# define ISA_LEVEL (ISA_BASELINE | ISA_V2 | ISA_V3 | ISA_V4)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if ISA_LEVEL
|
||||||
|
# ifdef __LP64__
|
||||||
|
# define PROPERTY_ALIGN 3
|
||||||
|
# else
|
||||||
|
# define PROPERTY_ALIGN 2
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# define note_stringify(arg) note_stringify_1(arg)
|
||||||
|
# define note_stringify_1(arg) #arg
|
||||||
|
|
||||||
|
asm(".pushsection \".note.gnu.property\",\"a\",@note\n"
|
||||||
|
" .p2align " note_stringify (PROPERTY_ALIGN)
|
||||||
|
/* name length. */
|
||||||
|
"\n .long 1f - 0f\n"
|
||||||
|
/* data length. */
|
||||||
|
" .long 4f - 1f\n"
|
||||||
|
/* note type: NT_GNU_PROPERTY_TYPE_0. */
|
||||||
|
" .long " note_stringify (NT_GNU_PROPERTY_TYPE_0)
|
||||||
|
/* vendor name. */
|
||||||
|
"\n0: .asciz \"GNU\"\n"
|
||||||
|
"1: .p2align " note_stringify (PROPERTY_ALIGN)
|
||||||
|
/* pr_type: GNU_PROPERTY_X86_ISA_1_NEEDED. */
|
||||||
|
"\n .long " note_stringify (GNU_PROPERTY_X86_ISA_1_NEEDED)
|
||||||
|
/* pr_datasz. */
|
||||||
|
"\n .long 3f - 2f\n"
|
||||||
|
/* GNU_PROPERTY_X86_ISA_1_V[234]. */
|
||||||
|
"2:\n .long " note_stringify (ISA_LEVEL)
|
||||||
|
"\n3:\n .p2align " note_stringify (PROPERTY_ALIGN)
|
||||||
|
"\n4:\n .popsection");
|
||||||
|
# endif /* ISA_LEVEL */
|
||||||
|
#endif /* INCLUDE_X86_ISA_LEVEL */
|
@ -16,12 +16,16 @@
|
|||||||
License along with the GNU C Library; if not, see
|
License along with the GNU C Library; if not, see
|
||||||
<https://www.gnu.org/licenses/>. */
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
/* If this object is enabled with CET. */
|
/* if this object has GNU property. */
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
lc_unknown = 0, /* Unknown CET status. */
|
lc_property_unknown = 0, /* Unknown property status. */
|
||||||
lc_none = 1 << 0, /* Not enabled with CET. */
|
lc_property_none = 1 << 0, /* No property. */
|
||||||
lc_ibt = 1 << 1, /* Enabled with IBT. */
|
lc_property_valid = 1 << 1 /* Has valid property. */
|
||||||
lc_shstk = 1 << 2, /* Enabled with STSHK. */
|
} l_property:2;
|
||||||
lc_ibt_and_shstk = lc_ibt | lc_shstk /* Enabled with both. */
|
|
||||||
} l_cet:3;
|
/* 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;
|
||||||
|
104
sysdeps/x86/tst-isa-level-1.c
Normal file
104
sysdeps/x86/tst-isa-level-1.c
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/* Check ISA level on dlopened shared object.
|
||||||
|
Copyright (C) 2020 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, see
|
||||||
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <elf.h>
|
||||||
|
#include <get-isa-level.h>
|
||||||
|
#include <support/xdlfcn.h>
|
||||||
|
#include <support/check.h>
|
||||||
|
#include <support/test-driver.h>
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_test_1 (const char *modname, bool fail)
|
||||||
|
{
|
||||||
|
int (*fp) (void);
|
||||||
|
void *h;
|
||||||
|
|
||||||
|
h = dlopen (modname, RTLD_LAZY);
|
||||||
|
if (h == NULL)
|
||||||
|
{
|
||||||
|
const char *err = dlerror ();
|
||||||
|
if (fail)
|
||||||
|
{
|
||||||
|
if (strstr (err, "CPU ISA level is lower than required") == NULL)
|
||||||
|
FAIL_EXIT1 ("incorrect dlopen '%s' error: %s\n", modname, err);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FAIL_EXIT1 ("cannot open '%s': %s\n", modname, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fail)
|
||||||
|
FAIL_EXIT1 ("dlopen '%s' should have failed\n", modname);
|
||||||
|
|
||||||
|
fp = xdlsym (h, "test");
|
||||||
|
|
||||||
|
if (fp () != 0)
|
||||||
|
FAIL_EXIT1 ("test () != 0\n");
|
||||||
|
|
||||||
|
dlclose (h);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
do_test (void)
|
||||||
|
{
|
||||||
|
const struct cpu_features *cpu_features
|
||||||
|
= __x86_get_cpu_features (COMMON_CPUID_INDEX_MAX);
|
||||||
|
unsigned int isa_level = get_isa_level (cpu_features);
|
||||||
|
bool has_isa_baseline = ((isa_level & GNU_PROPERTY_X86_ISA_1_BASELINE)
|
||||||
|
== GNU_PROPERTY_X86_ISA_1_BASELINE);
|
||||||
|
bool has_isa_v2 = ((isa_level & GNU_PROPERTY_X86_ISA_1_V2)
|
||||||
|
== GNU_PROPERTY_X86_ISA_1_V2);
|
||||||
|
bool has_isa_v3 = ((isa_level & GNU_PROPERTY_X86_ISA_1_V3)
|
||||||
|
== GNU_PROPERTY_X86_ISA_1_V3);
|
||||||
|
bool has_isa_v4 = ((isa_level & GNU_PROPERTY_X86_ISA_1_V4)
|
||||||
|
== GNU_PROPERTY_X86_ISA_1_V4);
|
||||||
|
|
||||||
|
if (!has_isa_baseline)
|
||||||
|
{
|
||||||
|
do_test_1 ("tst-isa-level-mod-1-baseline.so", true);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
do_test_1 ("tst-isa-level-mod-1-baseline.so", false);
|
||||||
|
|
||||||
|
/* Skip on x86-64-v4 platforms since dlopen v4 module always works. */
|
||||||
|
if (has_isa_v4)
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
|
do_test_1 ("tst-isa-level-mod-1-v4.so", true);
|
||||||
|
|
||||||
|
/* Skip on x86-64-v3 platforms since dlopen v3 module always works. */
|
||||||
|
if (has_isa_v3)
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
|
do_test_1 ("tst-isa-level-mod-1-v3.so", true);
|
||||||
|
|
||||||
|
/* Skip on x86-64-v2 platforms since dlopen v2 module always works. */
|
||||||
|
if (has_isa_v2)
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
|
do_test_1 ("tst-isa-level-mod-1-v2.so", true);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <support/test-driver.c>
|
1
sysdeps/x86/tst-isa-level-mod-1-baseline.c
Normal file
1
sysdeps/x86/tst-isa-level-mod-1-baseline.c
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "tst-isa-level-mod-1.c"
|
1
sysdeps/x86/tst-isa-level-mod-1-v2.c
Normal file
1
sysdeps/x86/tst-isa-level-mod-1-v2.c
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "tst-isa-level-mod-1.c"
|
1
sysdeps/x86/tst-isa-level-mod-1-v3.c
Normal file
1
sysdeps/x86/tst-isa-level-mod-1-v3.c
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "tst-isa-level-mod-1.c"
|
1
sysdeps/x86/tst-isa-level-mod-1-v4.c
Normal file
1
sysdeps/x86/tst-isa-level-mod-1-v4.c
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "tst-isa-level-mod-1.c"
|
25
sysdeps/x86/tst-isa-level-mod-1.c
Normal file
25
sysdeps/x86/tst-isa-level-mod-1.c
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/* Check ISA level on dlopened shared object.
|
||||||
|
Copyright (C) 2019-2020 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, see
|
||||||
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include <isa-level.c>
|
||||||
|
|
||||||
|
int
|
||||||
|
test (void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include <dl-hwcaps.h>
|
#include <dl-hwcaps.h>
|
||||||
#include <cpu-features.h>
|
#include <cpu-features.h>
|
||||||
|
#include <get-isa-level.h>
|
||||||
|
|
||||||
const char _dl_hwcaps_subdirs[] = "x86-64-v4:x86-64-v3:x86-64-v2";
|
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. */
|
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
|
uint32_t
|
||||||
_dl_hwcaps_subdirs_active (void)
|
_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;
|
int active = 0;
|
||||||
|
|
||||||
/* Test in reverse preference order. */
|
/* Test in reverse preference order. */
|
||||||
|
|
||||||
/* x86-64-v2. */
|
/* x86-64-v2. */
|
||||||
if (!(CPU_FEATURE_USABLE (CMPXCHG16B)
|
if (!(isa_level & GNU_PROPERTY_X86_ISA_1_V2))
|
||||||
&& 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)))
|
|
||||||
return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
|
return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
|
||||||
++active;
|
++active;
|
||||||
|
|
||||||
/* x86-64-v3. */
|
/* x86-64-v3. */
|
||||||
if (!(CPU_FEATURE_USABLE (AVX)
|
if (!(isa_level & GNU_PROPERTY_X86_ISA_1_V3))
|
||||||
&& 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)))
|
|
||||||
return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
|
return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
|
||||||
++active;
|
++active;
|
||||||
|
|
||||||
/* x86-64-v4. */
|
/* x86-64-v4. */
|
||||||
if (!(CPU_FEATURE_USABLE (AVX512F)
|
if (!(isa_level & GNU_PROPERTY_X86_ISA_1_V4))
|
||||||
&& CPU_FEATURE_USABLE (AVX512BW)
|
|
||||||
&& CPU_FEATURE_USABLE (AVX512CD)
|
|
||||||
&& CPU_FEATURE_USABLE (AVX512DQ)
|
|
||||||
&& CPU_FEATURE_USABLE (AVX512VL)))
|
|
||||||
return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
|
return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
|
||||||
++active;
|
++active;
|
||||||
|
|
||||||
|
@ -19,7 +19,8 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <support/check.h>
|
#include <support/check.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/platform/x86.h>
|
#include <elf.h>
|
||||||
|
#include <get-isa-level.h>
|
||||||
|
|
||||||
extern int marker2 (void);
|
extern int marker2 (void);
|
||||||
extern int marker3 (void);
|
extern int marker3 (void);
|
||||||
@ -31,33 +32,13 @@ compute_level (void)
|
|||||||
{
|
{
|
||||||
const struct cpu_features *cpu_features
|
const struct cpu_features *cpu_features
|
||||||
= __x86_get_cpu_features (COMMON_CPUID_INDEX_MAX);
|
= __x86_get_cpu_features (COMMON_CPUID_INDEX_MAX);
|
||||||
|
unsigned int isa_level = get_isa_level (cpu_features);
|
||||||
|
|
||||||
if (!(CPU_FEATURE_USABLE_P (cpu_features, CMPXCHG16B)
|
if (!(isa_level & GNU_PROPERTY_X86_ISA_1_V2))
|
||||||
&& 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;
|
return 1;
|
||||||
if (!(CPU_FEATURE_USABLE_P (cpu_features, AVX)
|
if (!(isa_level & GNU_PROPERTY_X86_ISA_1_V3))
|
||||||
&& 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;
|
return 2;
|
||||||
if (!(CPU_FEATURE_USABLE_P (cpu_features, AVX512F)
|
if (!(isa_level & GNU_PROPERTY_X86_ISA_1_V4))
|
||||||
&& 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 3;
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user