V5 [PATCH 2/2] ldconfig/x86: Add ISA level check to glibc-hwcaps
H.J. Lu
hjl.tools@gmail.com
Sun Dec 6 14:49:52 GMT 2020
Add ISA level check to detect misplaced shared objects with incompatible
ISA level requirement in glibc-hwcaps subdirectories:
/sbin/ldconfig: /usr/lib64/glibc-hwcaps/x86-64-v2/libx86-64-isa-level.so: skipped, ISA level mismatch (x86-64-v4 > x86-64-v2)
---
elf/ldconfig.c | 9 +-
elf/readelflib.c | 83 ++++++++++++++++++-
elf/readlib.c | 7 +-
elf/tst-glibc-hwcaps-2-cache.c | 45 ++++++++++
.../etc/ld.so.conf | 2 +
.../postclean.req | 0
elf/tst-glibc-hwcaps-2-cache.script | 6 ++
sysdeps/generic/ldconfig.h | 9 +-
sysdeps/generic/read-prop.h | 32 +++++++
sysdeps/unix/sysv/linux/x86/read-prop.h | 57 +++++++++++++
sysdeps/unix/sysv/linux/x86/readelflib.c | 67 +++++++++++++--
sysdeps/unix/sysv/linux/x86_64/Makefile | 26 ++++++
.../sysv/linux/x86_64/tst-glibc-hwcaps-2.c | 50 +++++++++++
.../linux/x86_64/x86-64-isa-level-VALUE.c | 4 +
14 files changed, 379 insertions(+), 18 deletions(-)
create mode 100644 elf/tst-glibc-hwcaps-2-cache.c
create mode 100644 elf/tst-glibc-hwcaps-2-cache.root/etc/ld.so.conf
create mode 100644 elf/tst-glibc-hwcaps-2-cache.root/postclean.req
create mode 100644 elf/tst-glibc-hwcaps-2-cache.script
create mode 100644 sysdeps/generic/read-prop.h
create mode 100644 sysdeps/unix/sysv/linux/x86/read-prop.h
create mode 100644 sysdeps/unix/sysv/linux/x86_64/tst-glibc-hwcaps-2.c
create mode 100644 sysdeps/unix/sysv/linux/x86_64/x86-64-isa-level-VALUE.c
diff --git a/elf/ldconfig.c b/elf/ldconfig.c
index 10927a8c7f..f306d3df26 100644
--- a/elf/ldconfig.c
+++ b/elf/ldconfig.c
@@ -720,8 +720,8 @@ manual_link (char *library)
return;
}
- if (process_file (real_library, library, libname, &flag, &osversion,
- &soname, 0, &stat_buf))
+ if (process_file (real_library, library, libname, NULL, &flag,
+ &osversion, &soname, 0, &stat_buf))
{
error (0, 0, _("No link created since soname could not be found for %s"),
library);
@@ -982,8 +982,9 @@ search_dir (const struct dir_entry *entry)
unsigned int osversion;
if (!search_aux_cache (&lstat_buf, &flag, &osversion, &soname))
{
- if (process_file (real_name, file_name, direntry->d_name, &flag,
- &osversion, &soname, is_link, &lstat_buf))
+ if (process_file (real_name, file_name, direntry->d_name,
+ entry->hwcaps, &flag, &osversion,
+ &soname, is_link, &lstat_buf))
{
if (real_name != real_file_name)
free (real_name);
diff --git a/elf/readelflib.c b/elf/readelflib.c
index 5905f6d344..0784bbcc1f 100644
--- a/elf/readelflib.c
+++ b/elf/readelflib.c
@@ -17,6 +17,8 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
+#include <read-prop.h>
+
/* This code is a heavily simplified version of the readelf program
that's part of the current binutils development version. For architectures
which need to handle both 32bit and 64bit ELF libraries, this file is
@@ -39,7 +41,8 @@ do \
/* Returns 0 if everything is ok, != 0 in case of error. */
int
-process_elf_file (const char *file_name, const char *lib, int *flag,
+process_elf_file (const char *file_name, const char *lib,
+ struct glibc_hwcaps_subdirectory *hwcaps, int *flag,
unsigned int *osversion, char **soname, void *file_contents,
size_t file_length)
{
@@ -164,6 +167,84 @@ process_elf_file (const char *file_name, const char *lib, int *flag,
}
break;
+ case PT_GNU_PROPERTY:
+ /* The NT_GNU_PROPERTY_TYPE_0 note must be aligned to 4 bytes
+ in 32-bit objects and to 8 bytes in 64-bit objects. Skip
+ notes with incorrect alignment. */
+ if (segment->p_align == (__ELF_NATIVE_CLASS / 8))
+ {
+ const ElfW(Nhdr) *note = (const void *) (file_contents
+ + segment->p_offset);
+ const ElfW(Addr) size = segment->p_filesz;
+ const ElfW(Addr) align = segment->p_align;
+
+ const ElfW(Addr) start = (ElfW(Addr)) (uintptr_t) note;
+ unsigned int last_type = 0;
+
+ while ((ElfW(Addr)) (uintptr_t) (note + 1) - start < size)
+ {
+ /* Find the NT_GNU_PROPERTY_TYPE_0 note. */
+ if (note->n_namesz == 4
+ && note->n_type == NT_GNU_PROPERTY_TYPE_0
+ && memcmp (note + 1, "GNU", 4) == 0)
+ {
+ /* Check for invalid property. */
+ if (note->n_descsz < 8
+ || (note->n_descsz % sizeof (ElfW(Addr))) != 0)
+ goto done;
+
+ /* Start and end of property array. */
+ unsigned char *ptr = (unsigned char *) (note + 1) + 4;
+ unsigned char *ptr_end = ptr + note->n_descsz;
+
+ do
+ {
+ unsigned int type = *(unsigned int *) ptr;
+ unsigned int datasz = *(unsigned int *) (ptr + 4);
+
+ /* Property type must be in ascending order. */
+ if (type < last_type)
+ goto done;
+
+ ptr += 8;
+ if ((ptr + datasz) > ptr_end)
+ goto done;
+
+ last_type = type;
+
+ /* Target specific property processing.
+ Return value:
+ 0: Stop processing the properties.
+ > 0: Continue processing the properties.
+ < 0: Stop and skip the file.
+ */
+ int read_prop
+ = ElfW(read_gnu_property) (hwcaps, file_name,
+ segment, type,
+ datasz, ptr);
+ if (read_prop == 0)
+ goto done;
+ else if (read_prop < 0)
+ return 1;
+
+ /* Check the next property item. */
+ ptr += ALIGN_UP (datasz, sizeof (ElfW(Addr)));
+ }
+ while ((ptr_end - ptr) >= 8);
+
+ /* Only handle one NT_GNU_PROPERTY_TYPE_0. */
+ goto done;
+ }
+
+ note = ((const void *) note
+ + ELF_NOTE_NEXT_OFFSET (note->n_namesz,
+ note->n_descsz,
+ align));
+ }
+ }
+done:
+ break;
+
default:
break;
}
diff --git a/elf/readlib.c b/elf/readlib.c
index 994a4426a1..400f64bafa 100644
--- a/elf/readlib.c
+++ b/elf/readlib.c
@@ -74,7 +74,8 @@ is_gdb_python_file (const char *name)
/* Returns 0 if everything is ok, != 0 in case of error. */
int
process_file (const char *real_file_name, const char *file_name,
- const char *lib, int *flag, unsigned int *osversion,
+ const char *lib, struct glibc_hwcaps_subdirectory *hwcaps,
+ int *flag, unsigned int *osversion,
char **soname, int is_link, struct stat64 *stat_buf)
{
FILE *file;
@@ -173,8 +174,8 @@ process_file (const char *real_file_name, const char *file_name,
/* Libraries have to be shared object files. */
else if (elf_header->e_type != ET_DYN)
ret = 1;
- else if (process_elf_file (file_name, lib, flag, osversion, soname,
- file_contents, statbuf.st_size))
+ else if (process_elf_file (file_name, lib, hwcaps, flag, osversion,
+ soname, file_contents, statbuf.st_size))
ret = 1;
done:
diff --git a/elf/tst-glibc-hwcaps-2-cache.c b/elf/tst-glibc-hwcaps-2-cache.c
new file mode 100644
index 0000000000..2c30a2c911
--- /dev/null
+++ b/elf/tst-glibc-hwcaps-2-cache.c
@@ -0,0 +1,45 @@
+/* Wrapper to invoke tst-glibc-hwcaps-2 in a container to test ldconfig.
+ 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/>. */
+
+/* This program is just a wrapper that runs ldconfig followed by
+ tst-glibc-hwcaps-2. The actual test is provided via an
+ implementation in a sysdeps subdirectory. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/support.h>
+#include <unistd.h>
+
+int
+main (int argc, char **argv)
+{
+ /* Run ldconfig to populate the cache. */
+ {
+ char *command = xasprintf ("%s/ldconfig", support_install_rootsbindir);
+ if (system (command) != 0)
+ return 1;
+ free (command);
+ }
+
+ /* Reuse tst-glibc-hwcaps. Since this code is running in a
+ container, we can launch it directly. */
+ char *path = xasprintf ("%s/elf/tst-glibc-hwcaps-2", support_objdir_root);
+ execv (path, argv);
+ printf ("error: execv of %s failed: %m\n", path);
+ return 1;
+}
diff --git a/elf/tst-glibc-hwcaps-2-cache.root/etc/ld.so.conf b/elf/tst-glibc-hwcaps-2-cache.root/etc/ld.so.conf
new file mode 100644
index 0000000000..e1e74dbda2
--- /dev/null
+++ b/elf/tst-glibc-hwcaps-2-cache.root/etc/ld.so.conf
@@ -0,0 +1,2 @@
+# This file was created to suppress a warning from ldconfig:
+# /sbin/ldconfig: Warning: ignoring configuration file that cannot be opened: /etc/ld.so.conf: No such file or directory
diff --git a/elf/tst-glibc-hwcaps-2-cache.root/postclean.req b/elf/tst-glibc-hwcaps-2-cache.root/postclean.req
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/elf/tst-glibc-hwcaps-2-cache.script b/elf/tst-glibc-hwcaps-2-cache.script
new file mode 100644
index 0000000000..29ccfc3b49
--- /dev/null
+++ b/elf/tst-glibc-hwcaps-2-cache.script
@@ -0,0 +1,6 @@
+# test-container does not support scripts in sysdeps directories, so
+# collect everything in one file.
+
+mkdirp 0770 $L/glibc-hwcaps/x86-64-v2
+cp $B/elf/libx86-64-isa-level-1.so $L/libx86-64-isa-level.so
+cp $B/elf/libx86-64-isa-level-4.so $L/glibc-hwcaps/x86-64-v2/libx86-64-isa-level.so
diff --git a/sysdeps/generic/ldconfig.h b/sysdeps/generic/ldconfig.h
index 1ad1528890..f85eaa48cb 100644
--- a/sysdeps/generic/ldconfig.h
+++ b/sysdeps/generic/ldconfig.h
@@ -88,13 +88,16 @@ extern void save_aux_cache (const char *aux_cache_name);
/* Declared in readlib.c. */
extern int process_file (const char *real_file_name, const char *file_name,
- const char *lib, int *flag, unsigned int *osversion,
- char **soname, int is_link, struct stat64 *stat_buf);
+ const char *lib, struct glibc_hwcaps_subdirectory *,
+ int *flag, unsigned int *osversion, char **soname,
+ int is_link, struct stat64 *stat_buf);
extern char *implicit_soname (const char *lib, int flag);
/* Declared in readelflib.c. */
-extern int process_elf_file (const char *file_name, const char *lib, int *flag,
+extern int process_elf_file (const char *file_name, const char *lib,
+ struct glibc_hwcaps_subdirectory *hwcaps,
+ int *flag,
unsigned int *osversion, char **soname,
void *file_contents, size_t file_length);
diff --git a/sysdeps/generic/read-prop.h b/sysdeps/generic/read-prop.h
new file mode 100644
index 0000000000..49092f83f1
--- /dev/null
+++ b/sysdeps/generic/read-prop.h
@@ -0,0 +1,32 @@
+/* Support for GNU properties in ldconfig. Generic 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.
+
+ 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/>. */
+
+/* Called for each property in the NT_GNU_PROPERTY_TYPE_0 note of SEGMENT.
+ Return value:
+ 0: Stop processing the properties.
+ > 0: Continue processing the properties.
+ < 0: Stop and skip the file.
+ */
+
+static inline int __attribute__ ((always_inline))
+ElfW(read_gnu_property) (struct glibc_hwcaps_subdirectory *hwcaps,
+ const char *file_name, ElfW(Phdr) *segment,
+ uint32_t type, uint32_t datasz, void *data)
+{
+ return 0;
+}
diff --git a/sysdeps/unix/sysv/linux/x86/read-prop.h b/sysdeps/unix/sysv/linux/x86/read-prop.h
new file mode 100644
index 0000000000..c22395f851
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86/read-prop.h
@@ -0,0 +1,57 @@
+/* Support for GNU properties in ldconfig. x86 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.
+
+ 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/>. */
+
+/* Called for each property in the NT_GNU_PROPERTY_TYPE_0 note of SEGMENT.
+ Return value:
+ 0: Stop processing the properties.
+ > 0: Continue processing the properties.
+ < 0: Stop and skip the file for ISA level mismatch.
+ */
+
+static inline int __attribute__ ((always_inline))
+ElfW(read_gnu_property) (struct glibc_hwcaps_subdirectory *hwcaps,
+ const char *file_name, ElfW(Phdr) *segment,
+ uint32_t type, uint32_t datasz, void *data)
+{
+ if (type == GNU_PROPERTY_X86_ISA_1_NEEDED)
+ {
+ /* 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. */
+ if (hwcaps != NULL && datasz == 4)
+ {
+ const char *isa_string = glibc_hwcaps_subdirectory_name (hwcaps);
+ if (isa_string != NULL)
+ {
+ unsigned int isa_1_needed = *(unsigned int *) data;
+ unsigned int isa_level;
+ if (get_isa_level_from_string (isa_string, &isa_level) == 0
+ && isa_1_needed > isa_level)
+ {
+ error (0, 0,
+ _("%s: skipped, ISA level mismatch (%s > %s)"),
+ file_name,
+ get_isa_string_from_level (isa_1_needed),
+ isa_string);
+ return -1;
+ }
+ }
+ }
+ return 0;
+ }
+ return 1;
+}
diff --git a/sysdeps/unix/sysv/linux/x86/readelflib.c b/sysdeps/unix/sysv/linux/x86/readelflib.c
index 3e83419f5b..336ba57ae7 100644
--- a/sysdeps/unix/sysv/linux/x86/readelflib.c
+++ b/sysdeps/unix/sysv/linux/x86/readelflib.c
@@ -17,17 +17,70 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
+/* Get ISA level string from GNU_PROPERTY_X86_ISA_1_V[234] ISA level. */
-int process_elf32_file (const char *file_name, const char *lib, int *flag,
+static const char *
+get_isa_string_from_level (unsigned int isa_level)
+{
+ if ((isa_level & GNU_PROPERTY_X86_ISA_1_V4))
+ return "x86-64-v4";
+ else if ((isa_level & GNU_PROPERTY_X86_ISA_1_V3))
+ return "x86-64-v3";
+ else if ((isa_level & GNU_PROPERTY_X86_ISA_1_V2))
+ return "x86-64-v2";
+ abort ();
+ return NULL;
+}
+
+/* Get GNU_PROPERTY_X86_ISA_1_V[234] ISA level from ISA level string. */
+
+static int
+get_isa_level_from_string (const char *level, unsigned int *isa_level_p)
+{
+ if (memcmp (level, "x86-64-v", 8) == 0)
+ {
+ unsigned int isa_level = 0;
+ if (level[9] == '\0')
+ switch (level[8])
+ {
+ case '2':
+ isa_level = (GNU_PROPERTY_X86_ISA_1_BASELINE
+ | GNU_PROPERTY_X86_ISA_1_V2);
+ break;
+ case '3':
+ isa_level = (GNU_PROPERTY_X86_ISA_1_BASELINE
+ | GNU_PROPERTY_X86_ISA_1_V2
+ | GNU_PROPERTY_X86_ISA_1_V3);
+ break;
+ case '4':
+ isa_level = (GNU_PROPERTY_X86_ISA_1_BASELINE
+ | GNU_PROPERTY_X86_ISA_1_V2
+ | GNU_PROPERTY_X86_ISA_1_V3
+ | GNU_PROPERTY_X86_ISA_1_V4);
+ break;
+ }
+ if (isa_level)
+ {
+ *isa_level_p = isa_level;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int process_elf32_file (const char *file_name, const char *lib,
+ struct glibc_hwcaps_subdirectory *hwcaps, int *flag,
unsigned int *osversion, char **soname,
void *file_contents, size_t file_length);
-int process_elf64_file (const char *file_name, const char *lib, int *flag,
+int process_elf64_file (const char *file_name, const char *lib,
+ struct glibc_hwcaps_subdirectory *hwcaps, int *flag,
unsigned int *osversion, 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,
+process_elf_file (const char *file_name, const char *lib,
+ struct glibc_hwcaps_subdirectory *hwcaps, int *flag,
unsigned int *osversion, char **soname, void *file_contents,
size_t file_length)
{
@@ -68,11 +121,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, hwcaps, flag, osversion,
+ 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, hwcaps, flag, osversion,
+ 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..a22bb6321f 100644
--- a/sysdeps/unix/sysv/linux/x86_64/Makefile
+++ b/sysdeps/unix/sysv/linux/x86_64/Makefile
@@ -13,3 +13,29 @@ endif
ifeq ($(subdir),misc)
gen-as-const-headers += sigaltstack-offsets.sym
endif
+
+ifeq ($(subdir),elf)
+ifeq (yesyes,$(enable-x86-isa-level)$(config-cflags-skylake-avx512))
+tests += tst-glibc-hwcaps-2
+modules-names += libx86-64-isa-level-1 libx86-64-isa-level-4
+
+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
+
+$(objpfx)tst-glibc-hwcaps-2: $(objpfx)libx86-64-isa-level.so
+
+CFLAGS-libx86-64-isa-level-1.os += -march=x86-64
+CFLAGS-libx86-64-isa-level-4.os += -march=skylake-avx512
+
+# 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 -, ,$*))
+$(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..ce6b189415
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86_64/tst-glibc-hwcaps-2.c
@@ -0,0 +1,50 @@
+/* Check ISA level on shared object in glibc-hwcaps subdirectories.
+ 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 <stdio.h>
+#include <support/check.h>
+#include <support/test-driver.h>
+
+extern int isa_level (void);
+
+static int
+do_test (void)
+{
+ int level = isa_level ();
+ int ret;
+ switch (level)
+ {
+ case 1:
+ /* The default libx86-64-isa-level.so should be used. */
+ printf ("The default shared library is used.\n");
+ ret = EXIT_SUCCESS;
+ break;
+ case 4:
+ /* libx86-64-isa-level.so marked as x86-64 ISA level 4 needed in
+ x86-64-v2 should be ignored. */
+ printf ("x86-64 ISA level 4 shared library in x86-64-v2 is used.\n");
+ 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..892e4c464b
--- /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 isa_level
+#include <isa-level.c>
+#include <markermodMARKER-VALUE.c>
--
2.28.0
More information about the Libc-alpha
mailing list