From efbbd9c33adfa843d65860b1b02adebb8ecb57ce Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Sat, 5 Dec 2020 07:01:58 -0800 Subject: 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. --- elf/readelflib.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 2 deletions(-) (limited to 'elf/readelflib.c') diff --git a/elf/readelflib.c b/elf/readelflib.c index cdea79d..c09425a 100644 --- a/elf/readelflib.c +++ b/elf/readelflib.c @@ -17,6 +17,8 @@ License along with the GNU C Library; if not, see . */ +#include + /* 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; } -- cgit v1.1