1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-30 22:43:12 +03:00

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.
This commit is contained in:
H.J. Lu
2020-12-05 07:01:58 -08:00
parent 86a4d3fa7d
commit efbbd9c33a
26 changed files with 598 additions and 110 deletions

View File

@ -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;
}