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