about summary refs log tree commit diff
path: root/elf/readelflib.c
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2020-12-05 07:01:58 -0800
committerH.J. Lu <hjl.tools@gmail.com>2021-01-13 05:51:17 -0800
commitefbbd9c33adfa843d65860b1b02adebb8ecb57ce (patch)
tree79c61c55698036fc99ec936ea400c7a9975eef28 /elf/readelflib.c
parent86a4d3fa7d1bda3c02cf713cf289d6f893970117 (diff)
downloadglibc-efbbd9c33adfa843d65860b1b02adebb8ecb57ce.tar.gz
glibc-efbbd9c33adfa843d65860b1b02adebb8ecb57ce.tar.xz
glibc-efbbd9c33adfa843d65860b1b02adebb8ecb57ce.zip
ldconfig/x86: Store ISA level in cache and aux cache
Store ISA level in the portion of the unused upper 32 bits of the hwcaps
field in cache and the unused pad field in aux cache.  ISA level is stored
and checked only for shared objects in glibc-hwcaps subdirectories.  The
shared objects in the default directories aren't checked since there are
no fallbacks for these shared objects.

Tested on x86-64-v2, x86-64-v3 and x86-64-v4 machines with
--disable-hardcoded-path-in-tests and --enable-hardcoded-path-in-tests.
Diffstat (limited to 'elf/readelflib.c')
-rw-r--r--elf/readelflib.c81
1 files changed, 79 insertions, 2 deletions
diff --git a/elf/readelflib.c b/elf/readelflib.c
index cdea79d729..c09425a574 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 <elf-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
@@ -40,8 +42,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,
-		  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)
 {
   int i;
   unsigned int j;
@@ -86,6 +88,9 @@ process_elf_file (const char *file_name, const char *lib, int *flag,
      libc5/libc6.  */
   *flag = FLAG_ELF;
 
+  /* The default ISA level is 0.  */
+  *isa_level = 0;
+
   dynamic_addr = 0;
   dynamic_size = 0;
   program_interpreter = NULL;
@@ -164,6 +169,78 @@ 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:
+			       false: Continue processing the properties.
+			       true : Stop processing the properties.
+			   */
+			  if (read_gnu_property (isa_level, type,
+						 datasz, ptr))
+			    goto done;
+
+			  /* 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;
 	}