aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/unix/sysv/linux
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/unix/sysv/linux')
-rw-r--r--sysdeps/unix/sysv/linux/arm/readelflib.c22
-rw-r--r--sysdeps/unix/sysv/linux/ia64/readelflib.c22
-rw-r--r--sysdeps/unix/sysv/linux/mips/readelflib.c22
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/readelflib.c22
-rw-r--r--sysdeps/unix/sysv/linux/riscv/readelflib.c22
-rw-r--r--sysdeps/unix/sysv/linux/s390/readelflib.c22
-rw-r--r--sysdeps/unix/sysv/linux/sparc/readelflib.c22
-rw-r--r--sysdeps/unix/sysv/linux/x86/elf-read-prop.h60
-rw-r--r--sysdeps/unix/sysv/linux/x86/readelflib.c23
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/Makefile51
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/tst-glibc-hwcaps-2.c84
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/x86-64-isa-level-VALUE.c4
12 files changed, 295 insertions, 81 deletions
diff --git a/sysdeps/unix/sysv/linux/arm/readelflib.c b/sysdeps/unix/sysv/linux/arm/readelflib.c
index 2d3ecb1eef..ade2f49aeb 100644
--- a/sysdeps/unix/sysv/linux/arm/readelflib.c
+++ b/sysdeps/unix/sysv/linux/arm/readelflib.c
@@ -18,18 +18,20 @@
<https://www.gnu.org/licenses/>. */
-int process_elf32_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname,
+int process_elf32_file (const char *file_name, const char *lib,
+ int *flag, unsigned int *osversion,
+ unsigned int *isa_level, char **soname,
void *file_contents, size_t file_length);
-int process_elf64_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname,
+int process_elf64_file (const char *file_name, const char *lib,
+ int *flag, unsigned int *osversion,
+ unsigned int *isa_level, char **soname,
void *file_contents, size_t file_length);
/* Returns 0 if everything is ok, != 0 in case of error. */
int
process_elf_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname, void *file_contents,
- size_t file_length)
+ unsigned int *osversion, unsigned int *isa_level,
+ char **soname, void *file_contents, size_t file_length)
{
ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_contents;
int ret;
@@ -38,8 +40,8 @@ process_elf_file (const char *file_name, const char *lib, int *flag,
{
Elf32_Ehdr *elf32_header = (Elf32_Ehdr *) elf_header;
- ret = process_elf32_file (file_name, lib, flag, osversion, soname,
- file_contents, file_length);
+ ret = process_elf32_file (file_name, lib, flag, osversion, isa_level,
+ soname, file_contents, file_length);
if (!ret && EF_ARM_EABI_VERSION (elf32_header->e_flags) == EF_ARM_EABI_VER5)
{
@@ -57,8 +59,8 @@ process_elf_file (const char *file_name, const char *lib, int *flag,
}
else
{
- ret = process_elf64_file (file_name, lib, flag, osversion, soname,
- file_contents, file_length);
+ ret = process_elf64_file (file_name, lib, flag, osversion, isa_level,
+ soname, file_contents, file_length);
/* AArch64 libraries are always libc.so.6+. */
if (!ret)
*flag = FLAG_AARCH64_LIB64|FLAG_ELF_LIBC6;
diff --git a/sysdeps/unix/sysv/linux/ia64/readelflib.c b/sysdeps/unix/sysv/linux/ia64/readelflib.c
index 7fb3ace359..2aa32666aa 100644
--- a/sysdeps/unix/sysv/linux/ia64/readelflib.c
+++ b/sysdeps/unix/sysv/linux/ia64/readelflib.c
@@ -16,29 +16,31 @@
<https://www.gnu.org/licenses/>. */
-int process_elf32_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname,
+int process_elf32_file (const char *file_name, const char *lib,
+ int *flag, unsigned int *osversion,
+ unsigned int *isa_level, char **soname,
void *file_contents, size_t file_length);
-int process_elf64_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname,
+int process_elf64_file (const char *file_name, const char *lib,
+ int *flag, unsigned int *osversion,
+ unsigned int *isa_level, char **soname,
void *file_contents, size_t file_length);
/* Returns 0 if everything is ok, != 0 in case of error. */
int
process_elf_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname,
- void *file_contents, size_t file_length)
+ unsigned int *osversion, unsigned int *isa_level,
+ char **soname, void *file_contents, size_t file_length)
{
ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_contents;
int ret;
if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
- return process_elf32_file (file_name, lib, flag, osversion, soname,
- file_contents, file_length);
+ return process_elf32_file (file_name, lib, flag, osversion, isa_level,
+ soname, file_contents, file_length);
else
{
- ret = process_elf64_file (file_name, lib, flag, osversion, soname,
- file_contents, file_length);
+ ret = process_elf64_file (file_name, lib, flag, osversion, isa_level,
+ soname, file_contents, file_length);
/* Intel 64bit libraries are always libc.so.6+. */
if (!ret)
*flag = FLAG_IA64_LIB64|FLAG_ELF_LIBC6;
diff --git a/sysdeps/unix/sysv/linux/mips/readelflib.c b/sysdeps/unix/sysv/linux/mips/readelflib.c
index e50bc3ce23..d0e809d893 100644
--- a/sysdeps/unix/sysv/linux/mips/readelflib.c
+++ b/sysdeps/unix/sysv/linux/mips/readelflib.c
@@ -20,18 +20,20 @@
<https://www.gnu.org/licenses/>. */
-int process_elf32_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname,
+int process_elf32_file (const char *file_name, const char *lib,
+ int *flag, unsigned int *osversion,
+ unsigned int *isa_level, char **soname,
void *file_contents, size_t file_length);
-int process_elf64_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname,
+int process_elf64_file (const char *file_name, const char *lib,
+ int *flag, unsigned int *osversion,
+ unsigned int *isa_level, char **soname,
void *file_contents, size_t file_length);
/* Returns 0 if everything is ok, != 0 in case of error. */
int
process_elf_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname, void *file_contents,
- size_t file_length)
+ unsigned int *osversion, unsigned int *isa_level,
+ char **soname, void *file_contents, size_t file_length)
{
union
{
@@ -45,8 +47,8 @@ process_elf_file (const char *file_name, const char *lib, int *flag,
elf_header.eh = file_contents;
if (elf_header.eh->e_ident [EI_CLASS] == ELFCLASS32)
{
- ret = process_elf32_file (file_name, lib, flag, osversion, soname,
- file_contents, file_length);
+ ret = process_elf32_file (file_name, lib, flag, osversion, isa_level,
+ soname, file_contents, file_length);
if (!ret)
{
Elf32_Word flags = elf_header.eh32->e_flags;
@@ -62,8 +64,8 @@ process_elf_file (const char *file_name, const char *lib, int *flag,
}
else
{
- ret = process_elf64_file (file_name, lib, flag, osversion, soname,
- file_contents, file_length);
+ ret = process_elf64_file (file_name, lib, flag, osversion, isa_level,
+ soname, file_contents, file_length);
/* n64 libraries are always libc.so.6+. */
if (!ret)
{
diff --git a/sysdeps/unix/sysv/linux/powerpc/readelflib.c b/sysdeps/unix/sysv/linux/powerpc/readelflib.c
index 4f9a9be254..51f8a9496a 100644
--- a/sysdeps/unix/sysv/linux/powerpc/readelflib.c
+++ b/sysdeps/unix/sysv/linux/powerpc/readelflib.c
@@ -17,29 +17,31 @@
<https://www.gnu.org/licenses/>. */
-int process_elf32_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname,
+int process_elf32_file (const char *file_name, const char *lib,
+ int *flag, unsigned int *osversion,
+ unsigned int *isa_level, char **soname,
void *file_contents, size_t file_length);
-int process_elf64_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname,
+int process_elf64_file (const char *file_name, const char *lib,
+ int *flag, unsigned int *osversion,
+ unsigned int *isa_level, char **soname,
void *file_contents, size_t file_length);
/* Returns 0 if everything is ok, != 0 in case of error. */
int
process_elf_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname, void *file_contents,
- size_t file_length)
+ unsigned int *osversion, unsigned int *isa_level,
+ char **soname, void *file_contents, size_t file_length)
{
ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_contents;
int ret;
if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
- return process_elf32_file (file_name, lib, flag, osversion, soname,
- file_contents, file_length);
+ return process_elf32_file (file_name, lib, flag, osversion, isa_level,
+ soname, file_contents, file_length);
else
{
- ret = process_elf64_file (file_name, lib, flag, osversion, soname,
- file_contents, file_length);
+ ret = process_elf64_file (file_name, lib, flag, osversion, isa_level,
+ soname, file_contents, file_length);
/* PowerPC 64bit libraries are always libc.so.6+. */
if (!ret)
*flag = FLAG_POWERPC_LIB64|FLAG_ELF_LIBC6;
diff --git a/sysdeps/unix/sysv/linux/riscv/readelflib.c b/sysdeps/unix/sysv/linux/riscv/readelflib.c
index 2aca6670a8..3822d63a05 100644
--- a/sysdeps/unix/sysv/linux/riscv/readelflib.c
+++ b/sysdeps/unix/sysv/linux/riscv/readelflib.c
@@ -17,11 +17,13 @@
<https://www.gnu.org/licenses/>. */
-int process_elf32_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname,
+int process_elf32_file (const char *file_name, const char *lib,
+ int *flag, unsigned int *osversion,
+ unsigned int *isa_level, char **soname,
void *file_contents, size_t file_length);
-int process_elf64_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname,
+int process_elf64_file (const char *file_name, const char *lib,
+ int *flag, unsigned int *osversion,
+ unsigned int *isa_level, char **soname,
void *file_contents, size_t file_length);
/* The ELF flags supported by our current glibc port:
@@ -38,8 +40,8 @@ int process_elf64_file (const char *file_name, const char *lib, int *flag,
/* Returns 0 if everything is ok, != 0 in case of error. */
int
process_elf_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname, void *file_contents,
- size_t file_length)
+ unsigned int *osversion, unsigned int *isa_level,
+ char **soname, void *file_contents, size_t file_length)
{
ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_contents;
Elf32_Ehdr *elf32_header = (Elf32_Ehdr *) elf_header;
@@ -52,14 +54,14 @@ process_elf_file (const char *file_name, const char *lib, int *flag,
if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
{
- ret = process_elf32_file (file_name, lib, flag, osversion, soname,
- file_contents, file_length);
+ ret = process_elf32_file (file_name, lib, flag, osversion, isa_level,
+ soname, file_contents, file_length);
flags = elf32_header->e_flags;
}
else
{
- ret = process_elf64_file (file_name, lib, flag, osversion, soname,
- file_contents, file_length);
+ ret = process_elf64_file (file_name, lib, flag, osversion, isa_level,
+ soname, file_contents, file_length);
flags = elf64_header->e_flags;
}
diff --git a/sysdeps/unix/sysv/linux/s390/readelflib.c b/sysdeps/unix/sysv/linux/s390/readelflib.c
index fc21af34d8..e190109e3d 100644
--- a/sysdeps/unix/sysv/linux/s390/readelflib.c
+++ b/sysdeps/unix/sysv/linux/s390/readelflib.c
@@ -16,29 +16,31 @@
<https://www.gnu.org/licenses/>. */
-int process_elf32_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname,
+int process_elf32_file (const char *file_name, const char *lib,
+ int *flag, unsigned int *osversion,
+ unsigned int *isa_level, char **soname,
void *file_contents, size_t file_length);
-int process_elf64_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname,
+int process_elf64_file (const char *file_name, const char *lib,
+ int *flag, unsigned int *osversion,
+ unsigned int *isa_level, char **soname,
void *file_contents, size_t file_length);
/* Returns 0 if everything is ok, != 0 in case of error. */
int
process_elf_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname, void *file_contents,
- size_t file_length)
+ unsigned int *osversion, unsigned int *isa_level,
+ char **soname, void *file_contents, size_t file_length)
{
ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_contents;
int ret;
if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
- return process_elf32_file (file_name, lib, flag, osversion, soname,
- file_contents, file_length);
+ return process_elf32_file (file_name, lib, flag, osversion, isa_level,
+ soname, file_contents, file_length);
else
{
- ret = process_elf64_file (file_name, lib, flag, osversion, soname,
- file_contents, file_length);
+ ret = process_elf64_file (file_name, lib, flag, osversion, isa_level,
+ soname, file_contents, file_length);
/* S/390 64bit libraries are always libc.so.6+. */
if (!ret)
*flag = FLAG_S390_LIB64|FLAG_ELF_LIBC6;
diff --git a/sysdeps/unix/sysv/linux/sparc/readelflib.c b/sysdeps/unix/sysv/linux/sparc/readelflib.c
index d54b8dfd28..bbfc81337a 100644
--- a/sysdeps/unix/sysv/linux/sparc/readelflib.c
+++ b/sysdeps/unix/sysv/linux/sparc/readelflib.c
@@ -18,29 +18,31 @@
<https://www.gnu.org/licenses/>. */
-int process_elf32_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname,
+int process_elf32_file (const char *file_name, const char *lib,
+ int *flag, unsigned int *osversion,
+ unsigned int *isa_level, char **soname,
void *file_contents, size_t file_length);
-int process_elf64_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname,
+int process_elf64_file (const char *file_name, const char *lib,
+ int *flag, unsigned int *osversion,
+ unsigned int *isa_level, char **soname,
void *file_contents, size_t file_length);
/* Returns 0 if everything is ok, != 0 in case of error. */
int
process_elf_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname, void *file_contents,
- size_t file_length)
+ unsigned int *osversion, unsigned int *isa_level,
+ char **soname, void *file_contents, size_t file_length)
{
ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_contents;
int ret;
if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
- return process_elf32_file (file_name, lib, flag, osversion, soname,
- file_contents, file_length);
+ return process_elf32_file (file_name, lib, flag, osversion, isa_level,
+ soname, file_contents, file_length);
else
{
- ret = process_elf64_file (file_name, lib, flag, osversion, soname,
- file_contents, file_length);
+ ret = process_elf64_file (file_name, lib, flag, osversion, isa_level,
+ soname, file_contents, file_length);
/* Sparc 64bit libraries are always libc.so.6+. */
if (!ret)
*flag = FLAG_SPARC_LIB64|FLAG_ELF_LIBC6;
diff --git a/sysdeps/unix/sysv/linux/x86/elf-read-prop.h b/sysdeps/unix/sysv/linux/x86/elf-read-prop.h
new file mode 100644
index 0000000000..85affa2864
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86/elf-read-prop.h
@@ -0,0 +1,60 @@
+/* Support for GNU properties in ldconfig. x86 version.
+ Copyright (C) 2021 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/>. */
+
+#ifndef _ELF_READ_PROP_H
+#define _ELF_READ_PROP_H
+
+#include <dl-cache.h>
+
+/* Called for each property in the NT_GNU_PROPERTY_TYPE_0 note of SEGMENT.
+ Return value:
+ false: Continue processing the properties.
+ true : Stop processing the properties.
+ */
+static inline bool __attribute__ ((always_inline))
+read_gnu_property (unsigned int *isal_level, uint32_t type,
+ uint32_t datasz, void *data)
+{
+ /* Property type must be in ascending order. */
+ if (type > GNU_PROPERTY_X86_ISA_1_NEEDED)
+ return true;
+
+ if (type == GNU_PROPERTY_X86_ISA_1_NEEDED)
+ {
+ if (datasz == 4)
+ {
+ /* The size of GNU_PROPERTY_X86_ISA_1_NEEDED must be 4 bytes.
+ There is no point to continue if this type is ill-formed. */
+ unsigned int isa_1_needed = *(unsigned int *) data;
+ _Static_assert (((sizeof (isa_1_needed) * 8)
+ <= (1 << DL_CACHE_HWCAP_ISA_LEVEL_COUNT)),
+ "DL_CACHE_HWCAP_ISA_LEVEL_COUNT is too small");
+ if (isa_1_needed != 0)
+ {
+ unsigned int level;
+ asm ("bsr %1, %0" : "=r" (level) : "g" (isa_1_needed));
+ *isal_level = level;
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/x86/readelflib.c b/sysdeps/unix/sysv/linux/x86/readelflib.c
index a4df70e7e6..4a9bcc82cb 100644
--- a/sysdeps/unix/sysv/linux/x86/readelflib.c
+++ b/sysdeps/unix/sysv/linux/x86/readelflib.c
@@ -17,19 +17,20 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
-
-int process_elf32_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname,
+int process_elf32_file (const char *file_name, const char *lib,
+ int *flag, unsigned int *osversion,
+ unsigned int *isa_level, char **soname,
void *file_contents, size_t file_length);
-int process_elf64_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname,
+int process_elf64_file (const char *file_name, const char *lib,
+ int *flag, unsigned int *osversion,
+ unsigned int *isa_level, char **soname,
void *file_contents, size_t file_length);
/* Returns 0 if everything is ok, != 0 in case of error. */
int
process_elf_file (const char *file_name, const char *lib, int *flag,
- unsigned int *osversion, char **soname, void *file_contents,
- size_t file_length)
+ unsigned int *osversion, unsigned int *isa_level,
+ char **soname, void *file_contents, size_t file_length)
{
ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_contents;
int ret, file_flag = 0;
@@ -68,11 +69,11 @@ failed:
}
if (elf_header->e_ident[EI_CLASS] == ELFCLASS32)
- ret = process_elf32_file (file_name, lib, flag, osversion, soname,
- file_contents, file_length);
+ ret = process_elf32_file (file_name, lib, flag, osversion, isa_level,
+ soname, file_contents, file_length);
else
- ret = process_elf64_file (file_name, lib, flag, osversion, soname,
- file_contents, file_length);
+ ret = process_elf64_file (file_name, lib, flag, osversion, isa_level,
+ soname, file_contents, file_length);
if (!ret && file_flag)
*flag = file_flag;
diff --git a/sysdeps/unix/sysv/linux/x86_64/Makefile b/sysdeps/unix/sysv/linux/x86_64/Makefile
index 9b82155393..5e19202ebf 100644
--- a/sysdeps/unix/sysv/linux/x86_64/Makefile
+++ b/sysdeps/unix/sysv/linux/x86_64/Makefile
@@ -13,3 +13,54 @@ endif
ifeq ($(subdir),misc)
gen-as-const-headers += sigaltstack-offsets.sym
endif
+
+ifeq ($(subdir),elf)
+ifeq (yes,$(enable-x86-isa-level))
+tests += \
+ tst-glibc-hwcaps-2
+ifeq (no,$(build-hardcoded-path-in-tests))
+# This is an ld.so.cache test, and RPATH/RUNPATH in the executable
+# interferes with its test objectives.
+tests-container += \
+ tst-glibc-hwcaps-2-cache
+endif
+modules-names += \
+ libx86-64-isa-level-1 \
+ libx86-64-isa-level-2 \
+ libx86-64-isa-level-3 \
+ libx86-64-isa-level-4
+
+$(objpfx)tst-glibc-hwcaps-2: $(objpfx)libx86-64-isa-level.so
+
+$(objpfx)tst-glibc-hwcaps-2.out: \
+ $(objpfx)glibc-hwcaps/x86-64-v2/libx86-64-isa-level.so \
+ $(objpfx)glibc-hwcaps/x86-64-v4/libx86-64-isa-level.so \
+ $(objpfx)glibc-hwcaps/x86-64-v3/libx86-64-isa-level.so
+$(objpfx)glibc-hwcaps/x86-64-v2/libx86-64-isa-level.so: \
+ $(objpfx)libx86-64-isa-level-2.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/x86-64-v3/libx86-64-isa-level.so: \
+ $(objpfx)libx86-64-isa-level-3.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/x86-64-v4/libx86-64-isa-level.so: \
+ $(objpfx)libx86-64-isa-level-4.so
+ $(make-target-directory)
+ cp $< $@
+
+CFLAGS-libx86-64-isa-level-1.os += -march=x86-64
+CFLAGS-libx86-64-isa-level-2.os += -march=x86-64
+CFLAGS-libx86-64-isa-level-3.os += -march=x86-64
+CFLAGS-libx86-64-isa-level-4.os += -march=x86-64
+
+# The test modules are parameterized by preprocessor macros.
+LDFLAGS-libx86-64-isa-level-1.so += -Wl,-soname,libx86-64-isa-level.so
+LDFLAGS-libx86-64-isa-level-4.so += -Wl,-soname,libx86-64-isa-level.so
+$(objpfx)libx86-64-isa-level%.os: $(..)/sysdeps/unix/sysv/linux/x86_64/x86-64-isa-level-VALUE.c
+ $(compile-command.c) -DVALUE=$(lastword $(subst -, ,$*)) \
+ -DISA_LEVEL="(1 << ($(lastword $(subst -, ,$*)) - 1))"
+$(objpfx)libx86-64-isa-level.so: $(objpfx)libx86-64-isa-level-1.so
+ cp $< $@
+endif
+endif # $(subdir) == elf
diff --git a/sysdeps/unix/sysv/linux/x86_64/tst-glibc-hwcaps-2.c b/sysdeps/unix/sysv/linux/x86_64/tst-glibc-hwcaps-2.c
new file mode 100644
index 0000000000..fe91bfd224
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86_64/tst-glibc-hwcaps-2.c
@@ -0,0 +1,84 @@
+/* Check ISA level on shared object in glibc-hwcaps subdirectories.
+ Copyright (C) 2021 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 <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <elf.h>
+#include <get-isa-level.h>
+#include <support/check.h>
+#include <support/test-driver.h>
+
+extern int dso_isa_level (void);
+
+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)
+ return EXIT_FAILURE;
+
+ int level = dso_isa_level ();
+ int ret;
+ switch (level)
+ {
+ case 1:
+ case 2:
+ /* The default libx86-64-isa-level.so is used. */
+ printf ("The default shared library is used.\n");
+ if (has_isa_v3 || has_isa_v4 || !has_isa_v2)
+ ret = EXIT_FAILURE;
+ else
+ ret = EXIT_SUCCESS;
+ break;
+ case 3:
+ /* libx86-64-isa-level.so marked as x86-64 ISA level 3 needed in
+ x86-64-v2 should be ignored on lesser CPU. */
+ printf ("x86-64 ISA level 3 shared library is used.\n");
+ if (has_isa_v4 || !has_isa_v3)
+ ret = EXIT_FAILURE;
+ else
+ ret = EXIT_SUCCESS;
+ break;
+ case 4:
+ /* libx86-64-isa-level.so marked as x86-64 ISA level 4 needed in
+ x86-64-v3 should be ignored on lesser CPU. */
+ printf ("x86-64 ISA level 4 shared library is used.\n");
+ if (has_isa_v4)
+ ret = EXIT_SUCCESS;
+ else
+ ret = EXIT_FAILURE;
+ break;
+ default:
+ abort ();
+ }
+ return ret;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/x86_64/x86-64-isa-level-VALUE.c b/sysdeps/unix/sysv/linux/x86_64/x86-64-isa-level-VALUE.c
new file mode 100644
index 0000000000..2813d627cc
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86_64/x86-64-isa-level-VALUE.c
@@ -0,0 +1,4 @@
+#define INCLUDE_X86_ISA_LEVEL
+#define MARKER dso_isa_level
+#include <isa-level.c>
+#include <markermodMARKER-VALUE.c>