From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
To: "H.J. Lu" <hjl.tools@gmail.com>, Florian Weimer <fweimer@redhat.com>
Cc: "H.J. Lu via Libc-alpha" <libc-alpha@sourceware.org>
Subject: Re: [PATCH] ldconfig/x86: Store ISA level in cache and aux cache
Date: Tue, 12 Jan 2021 13:25:51 -0300 [thread overview]
Message-ID: <f8c0ad71-c5fd-1a10-f737-114d23e7c01a@linaro.org> (raw)
In-Reply-To: <CAMe9rOpqXMsxjO79Ejio12yb76KJMcgjMptuoiJfRR9LyoVYLA@mail.gmail.com>
On 09/12/2020 00:27, H.J. Lu via Libc-alpha wrote:
> On Tue, Dec 8, 2020 at 7:31 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>>
>> On Tue, Dec 8, 2020 at 7:16 AM Florian Weimer <fweimer@redhat.com> wrote:
>>>
>>> * H. J. Lu:
>>>
>>>>>> For each file entry for a shared object, the hwcap field has been used by
>>>>>> DL_CACHE_HWCAP_EXTENSION for glibc-hwcaps. Are you suggesting
>>>>>> to add another file entry for the same shared object to store ISA level
>>>>>> requirement?
>>>>>
>>>>> It's a 64-bit field. We do this:
>>>>>
>>>>> /* This bit in the hwcap field of struct file_entry_new indicates that
>>>>> the lower 32 bits contain an index into the
>>>>> cache_extension_tag_glibc_hwcaps section. Older glibc versions do
>>>>> not know about this HWCAP bit, so they will ignore these
>>>>> entries. */
>>>>> #define DL_CACHE_HWCAP_EXTENSION (1ULL << 62)
>>>>>
>>>>> /* Return true if the ENTRY->hwcap value indicates that
>>>>> DL_CACHE_HWCAP_EXTENSION is used. */
>>>>> static inline bool
>>>>> dl_cache_hwcap_extension (struct file_entry_new *entry)
>>>>> {
>>>>> /* If DL_CACHE_HWCAP_EXTENSION is set, but other bits as well, this
>>>>> is a different kind of extension. */
>>>>> return (entry->hwcap >> 32) == (DL_CACHE_HWCAP_EXTENSION >> 32);
>>>>> }
>>>>>
>>>>> So we can use a different bit pattern involving DL_CACHE_HWCAP_EXTENSION
>>>>> to express something else. In particular, only the lower 32 bits are
>>>>> currently used as an index.
>>>>
>>>> So bits 33-47 can be used for ISA level requirement. This should support
>>>> 65536 ISA levels.
>>>
>>> The question is whether the ISA levels and the glibc-hwcaps name are
>>> used in parallel. If not, we can use (1ULL << 62) | (1ULL << 32) as
>>> the marker bits and a 32-bit index in the lower half.
>>>
>>> (I do not think this is necessarily relevant for levels, but it could be
>>> used for locating objects according to other criteria.)
>>>
>>
>> I think ISA level and glibc-hwcaps should go together.
>>
>
> Here is the patch to 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.
>
>
> From f5053fabd1e8a5567b487ef4054793e043a7b817 Mon Sep 17 00:00:00 2001
> From: "H.J. Lu" <hjl.tools@gmail.com>
> Date: Sat, 5 Dec 2020 07:01:58 -0800
> Subject: [PATCH] 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.
Some comments below, most minor changes and code organization. The main
change I would like is to improve test coverage, as for the first patch.
> ---
> elf/cache.c | 34 +++++---
> elf/dl-cache.c | 4 +
> elf/ldconfig.c | 18 +++--
> elf/readelflib.c | 81 ++++++++++++++++++-
> 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/dl-cache.h | 15 +++-
> sysdeps/generic/dl-isa-level.h | 26 ++++++
> sysdeps/generic/ldconfig.h | 22 +++--
> sysdeps/generic/read-prop.h | 35 ++++++++
> sysdeps/unix/sysv/linux/arm/readelflib.c | 22 ++---
> sysdeps/unix/sysv/linux/ia64/readelflib.c | 22 ++---
> sysdeps/unix/sysv/linux/mips/readelflib.c | 22 ++---
> sysdeps/unix/sysv/linux/powerpc/readelflib.c | 22 ++---
> sysdeps/unix/sysv/linux/riscv/readelflib.c | 22 ++---
> sysdeps/unix/sysv/linux/s390/readelflib.c | 22 ++---
> sysdeps/unix/sysv/linux/sparc/readelflib.c | 22 ++---
> sysdeps/unix/sysv/linux/x86/read-prop.h | 61 ++++++++++++++
> sysdeps/unix/sysv/linux/x86/readelflib.c | 23 +++---
> sysdeps/unix/sysv/linux/x86_64/Makefile | 31 +++++++
> .../sysv/linux/x86_64/tst-glibc-hwcaps-2.c | 61 ++++++++++++++
> .../linux/x86_64/x86-64-isa-level-VALUE.c | 4 +
> sysdeps/x86/dl-isa-level.h | 32 ++++++++
> 26 files changed, 550 insertions(+), 111 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/dl-isa-level.h
> 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
> create mode 100644 sysdeps/x86/dl-isa-level.h
>
> diff --git a/elf/cache.c b/elf/cache.c
> index b03c5319f8..91a72381ae 100644
> --- a/elf/cache.c
> +++ b/elf/cache.c
> @@ -145,6 +145,7 @@ struct cache_entry
> struct stringtable_entry *path; /* Path to find library. */
> int flags; /* Flags to indicate kind of library. */
> unsigned int osversion; /* Required OS version. */
> + unsigned int isa_level; /* Required ISAL level. */
Maybe a typo here 'ISAL'?
> uint64_t hwcap; /* Important hardware capabilities. */
> int bits_hwcap; /* Number of bits set in hwcap. */
>
> @@ -660,8 +661,14 @@ save_cache (const char *cache_name)
> if (entry->hwcaps == NULL)
> file_entries_new->libs[idx_new].hwcap = entry->hwcap;
> else
> - file_entries_new->libs[idx_new].hwcap
> - = DL_CACHE_HWCAP_EXTENSION | entry->hwcaps->section_index;
> + {
> + if (entry->isa_level > (1 << DL_CACHE_HWCAP_ISA_LEVEL_COUNT))
Maybe wrap this on a macro at dl-cache.h? It already does it for
DL_CACHE_HWCAP_ISA_LEVEL_MASK.
> + abort ();
Maybe use 'error (...)' to print a proper error message?
> + file_entries_new->libs[idx_new].hwcap
> + = (DL_CACHE_HWCAP_EXTENSION
> + | (((uint64_t) entry->isa_level) << 32)
> + | entry->hwcaps->section_index);
> + }
Would be better to wrap this on a inline function at dl-cache.h?
static inline unsigned int dl_cache_hwcap_isa_level (struct file_entry_new *entry)
{
return DL_CACHE_HWCAP_EXTENSION
| ((uint64_t) entry->isa_level << 32)
| entry->hwcaps->sections_index;
}
> file_entries_new->libs[idx_new].key
> = str_offset + entry->lib->offset;
> file_entries_new->libs[idx_new].value
> @@ -776,7 +783,8 @@ save_cache (const char *cache_name)
> /* Add one library to the cache. */
> void
> add_to_cache (const char *path, const char *filename, const char *soname,
> - int flags, unsigned int osversion, uint64_t hwcap,
> + int flags, unsigned int osversion,
> + unsigned int isa_level, uint64_t hwcap,
> struct glibc_hwcaps_subdirectory *hwcaps)
> {
> struct cache_entry *new_entry = xmalloc (sizeof (*new_entry));
> @@ -794,6 +802,7 @@ add_to_cache (const char *path, const char *filename, const char *soname,
> new_entry->path = path_interned;
> new_entry->flags = flags;
> new_entry->osversion = osversion;
> + new_entry->isa_level = isa_level;
> new_entry->hwcap = hwcap;
> new_entry->hwcaps = hwcaps;
> new_entry->bits_hwcap = 0;
Ok.
> @@ -850,6 +859,7 @@ struct aux_cache_entry
> struct aux_cache_entry_id id;
> int flags;
> unsigned int osversion;
> + unsigned int isa_level;
> int used;
> char *soname;
> struct aux_cache_entry *next;
> @@ -863,7 +873,7 @@ struct aux_cache_file_entry
> int32_t flags; /* This is 1 for an ELF library. */
> uint32_t soname; /* String table indice. */
> uint32_t osversion; /* Required OS version. */
> - int32_t pad;
> + uint32_t isa_level; /* Required ISA level. */
> };
>
I think it would be good to have a _Static_assert with the
expected aux_cache_entry size.
> /* ldconfig maintains an auxiliary cache file that allows
> @@ -914,7 +924,8 @@ init_aux_cache (void)
>
> int
> search_aux_cache (struct stat64 *stat_buf, int *flags,
> - unsigned int *osversion, char **soname)
> + unsigned int *osversion, unsigned int *isa_level,
> + char **soname)
> {
> struct aux_cache_entry_id id;
> id.ino = (uint64_t) stat_buf->st_ino;
> @@ -932,6 +943,7 @@ search_aux_cache (struct stat64 *stat_buf, int *flags,
> {
> *flags = entry->flags;
> *osversion = entry->osversion;
> + *isa_level = entry->isa_level;
> if (entry->soname != NULL)
> *soname = xstrdup (entry->soname);
> else
Ok.
> @@ -945,7 +957,8 @@ search_aux_cache (struct stat64 *stat_buf, int *flags,
>
> static void
> insert_to_aux_cache (struct aux_cache_entry_id *id, int flags,
> - unsigned int osversion, const char *soname, int used)
> + unsigned int osversion, unsigned int isa_level,
> + const char *soname, int used)
> {
> size_t hash = aux_cache_entry_id_hash (id) % aux_hash_size;
> struct aux_cache_entry *entry;
> @@ -961,6 +974,7 @@ insert_to_aux_cache (struct aux_cache_entry_id *id, int flags,
> entry->id = *id;
> entry->flags = flags;
> entry->osversion = osversion;
> + entry->isa_level = isa_level;
> entry->used = used;
> if (soname != NULL)
> entry->soname = memcpy ((char *) (entry + 1), soname, len);
Ok.
> @@ -972,14 +986,15 @@ insert_to_aux_cache (struct aux_cache_entry_id *id, int flags,
>
> void
> add_to_aux_cache (struct stat64 *stat_buf, int flags,
> - unsigned int osversion, const char *soname)
> + unsigned int osversion, unsigned int isa_level,
> + const char *soname)
> {
> struct aux_cache_entry_id id;
> id.ino = (uint64_t) stat_buf->st_ino;
> id.ctime = (uint64_t) stat_buf->st_ctime;
> id.size = (uint64_t) stat_buf->st_size;
> id.dev = (uint64_t) stat_buf->st_dev;
> - insert_to_aux_cache (&id, flags, osversion, soname, 1);
> + insert_to_aux_cache (&id, flags, osversion, isa_level, soname, 1);
> }
>
> /* Load auxiliary cache to search for unchanged entries. */
> @@ -1025,6 +1040,7 @@ load_aux_cache (const char *aux_cache_name)
> insert_to_aux_cache (&aux_cache->libs[i].id,
> aux_cache->libs[i].flags,
> aux_cache->libs[i].osversion,
> + aux_cache->libs[i].isa_level,
> aux_cache->libs[i].soname == 0
> ? NULL : aux_cache_data + aux_cache->libs[i].soname,
> 0);
> @@ -1093,7 +1109,7 @@ save_aux_cache (const char *aux_cache_name)
> str_offset += len;
> }
> file_entries->libs[idx].osversion = entry->osversion;
> - file_entries->libs[idx++].pad = 0;
> + file_entries->libs[idx++].isa_level = entry->isa_level;
> }
>
> /* Write out auxiliary cache file. */
Ok.
> diff --git a/elf/dl-cache.c b/elf/dl-cache.c
> index 97093bb700..edeff7ccc1 100644
> --- a/elf/dl-cache.c
> +++ b/elf/dl-cache.c
> @@ -25,6 +25,7 @@
> #include <stdint.h>
> #include <_itoa.h>
> #include <dl-hwcaps.h>
> +#include <dl-isa-level.h>
>
> #ifndef _DL_PLATFORMS_COUNT
> # define _DL_PLATFORMS_COUNT 0
> @@ -284,6 +285,9 @@ search_cache (const char *string_table, uint32_t string_table_size,
>
> #ifdef SHARED
> named_hwcap = dl_cache_hwcap_extension (libnew);
> + if (named_hwcap
> + && !dl_cache_hwcap_isa_level_compatible (libnew))
> + continue;
> #endif
>
> /* The entries with named/extension hwcaps
Ok, so it skips non compatible ISA shared libraries.
> diff --git a/elf/ldconfig.c b/elf/ldconfig.c
> index 10927a8c7f..9dceac38aa 100644
> --- a/elf/ldconfig.c
> +++ b/elf/ldconfig.c
> @@ -655,6 +655,7 @@ manual_link (char *library)
> struct stat64 stat_buf;
> int flag;
> unsigned int osversion;
> + unsigned int isa_level;
>
> /* Prepare arguments for create_links call. Split library name in
> directory and filename first. Since path is allocated, we've got
> @@ -721,7 +722,7 @@ manual_link (char *library)
> }
>
> if (process_file (real_library, library, libname, &flag, &osversion,
> - &soname, 0, &stat_buf))
> + &isa_level, &soname, 0, &stat_buf))
> {
> error (0, 0, _("No link created since soname could not be found for %s"),
> library);
> @@ -768,6 +769,7 @@ struct dlib_entry
> int flag;
> int is_link;
> unsigned int osversion;
> + unsigned int isa_level;
> struct dlib_entry *next;
> };
>
Ok.
> @@ -980,17 +982,21 @@ search_dir (const struct dir_entry *entry)
> library already and it's not changed. */
> char *soname;
> unsigned int osversion;
> - if (!search_aux_cache (&lstat_buf, &flag, &osversion, &soname))
> + unsigned int isa_level;
> + if (!search_aux_cache (&lstat_buf, &flag, &osversion, &isa_level,
> + &soname))
> {
> if (process_file (real_name, file_name, direntry->d_name, &flag,
> - &osversion, &soname, is_link, &lstat_buf))
> + &osversion, &isa_level, &soname, is_link,
> + &lstat_buf))
> {
> if (real_name != real_file_name)
> free (real_name);
> continue;
> }
> else if (opt_build_cache)
> - add_to_aux_cache (&lstat_buf, flag, osversion, soname);
> + add_to_aux_cache (&lstat_buf, flag, osversion, isa_level,
> + soname);
> }
>
> if (soname == NULL)
Ok.
> @@ -1096,6 +1102,7 @@ search_dir (const struct dir_entry *entry)
> dlib_ptr->name = xstrdup (direntry->d_name);
> dlib_ptr->is_link = is_link;
> dlib_ptr->osversion = osversion;
> + dlib_ptr->isa_level = isa_level;
> }
> /* Don't add this library, abort loop. */
> /* Also free soname, since it's dynamically allocated. */
> @@ -1112,6 +1119,7 @@ search_dir (const struct dir_entry *entry)
> dlib_ptr->flag = flag;
> dlib_ptr->is_link = is_link;
> dlib_ptr->osversion = osversion;
> + dlib_ptr->isa_level = isa_level;
> /* Add at head of list. */
> dlib_ptr->next = dlibs;
> dlibs = dlib_ptr;
> @@ -1149,7 +1157,7 @@ search_dir (const struct dir_entry *entry)
> if (opt_build_cache)
> add_to_cache (entry->path, filename, dlib_ptr->soname,
> dlib_ptr->flag, dlib_ptr->osversion,
> - hwcap, entry->hwcaps);
> + dlib_ptr->isa_level, hwcap, entry->hwcaps);
> }
>
> /* Free all resources. */
Ok.
> diff --git a/elf/readelflib.c b/elf/readelflib.c
> index 5905f6d344..abb1ac61fa 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
> @@ -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;
> }
Ok, although this is quite similar to the _dl_process_pt_gnu_property
(maybe a future work to try refactor both to use a common code).
> diff --git a/elf/readlib.c b/elf/readlib.c
> index 994a4426a1..def0eafbeb 100644
> --- a/elf/readlib.c
> +++ b/elf/readlib.c
> @@ -75,7 +75,8 @@ is_gdb_python_file (const char *name)
> 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)
> + unsigned int *isa_level, char **soname, int is_link,
> + struct stat64 *stat_buf)
> {
> FILE *file;
> struct stat64 statbuf;
> @@ -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, flag, osversion, isa_level,
> + soname, file_contents, statbuf.st_size))
> ret = 1;
>
> done:
Ok.
> 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);
> + }
Maybe use support_capture_subprogram here?
char *command = xasprintf ("%s/ldconfig", support_install_rootsbindir);
struct support_capture_subprocess result =
support_capture_subprogram (command, &((char *) { NULL }));
support_capture_subprocess_check (&result, "ldconfig", 0, sc_allow_none);
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;
> +}
Ok.
> 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
Ok.
> 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
Ok.
> +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/dl-cache.h b/sysdeps/generic/dl-cache.h
> index 72a66b45ee..1138228e5c 100644
> --- a/sysdeps/generic/dl-cache.h
> +++ b/sysdeps/generic/dl-cache.h
> @@ -106,14 +106,23 @@ struct file_entry_new
> entries. */
> #define DL_CACHE_HWCAP_EXTENSION (1ULL << 62)
>
> +/* The number of the ISA level bits in the upper 32 bits of the hwcap
> + field. */
> +#define DL_CACHE_HWCAP_ISA_LEVEL_COUNT 10
> +
> +/* The mask of the ISA level bits in the hwcap field. */
> +#define DL_CACHE_HWCAP_ISA_LEVEL_MASK \
> + ((1 << DL_CACHE_HWCAP_ISA_LEVEL_COUNT) -1)
> +
Space after '-'.
> /* Return true if the ENTRY->hwcap value indicates that
> DL_CACHE_HWCAP_EXTENSION is used. */
> static inline bool
> dl_cache_hwcap_extension (struct file_entry_new *entry)
> {
> - /* If DL_CACHE_HWCAP_EXTENSION is set, but other bits as well, this
> - is a different kind of extension. */
> - return (entry->hwcap >> 32) == (DL_CACHE_HWCAP_EXTENSION >> 32);
> + /* If DL_CACHE_HWCAP_EXTENSION is set, but other bits, except for the
> + ISA level bits, as well, this is a different kind of extension. */
> + return (((entry->hwcap >> 32) & ~DL_CACHE_HWCAP_ISA_LEVEL_MASK)
> + == (DL_CACHE_HWCAP_EXTENSION >> 32));
> }
>
> /* See flags member of struct cache_file_new below. */
The comment sounds confusing.
> diff --git a/sysdeps/generic/dl-isa-level.h b/sysdeps/generic/dl-isa-level.h
> new file mode 100644
> index 0000000000..77735775b9
> --- /dev/null
> +++ b/sysdeps/generic/dl-isa-level.h
> @@ -0,0 +1,26 @@
> +/* Support for reading ISA level in /etc/ld.so.cache files written by
> + Linux ldconfig. Generic version.
> + Copyright (C) 2020 Free Software Foundation, Inc.
s/2020/2021
> + 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/>. */
> +
> +/* Return true if the ISA level in ENTRY is compatible with CPU. */
> +
My understanding is for function comment there is no need to add an
extra newline.
> +static inline bool
> +dl_cache_hwcap_isa_level_compatible (struct file_entry_new *entry)
> +{
> + return true;
> +}
Ok.
> diff --git a/sysdeps/generic/ldconfig.h b/sysdeps/generic/ldconfig.h
> index 1ad1528890..a5ed350237 100644
> --- a/sysdeps/generic/ldconfig.h
> +++ b/sysdeps/generic/ldconfig.h
> @@ -70,8 +70,9 @@ const char *glibc_hwcaps_subdirectory_name
> (const struct glibc_hwcaps_subdirectory *);
>
> extern void add_to_cache (const char *path, const char *filename,
> - const char *soname,
> - int flags, unsigned int osversion, uint64_t hwcap,
> + const char *soname, int flags,
> + unsigned int osversion, unsigned int isa_level,
> + uint64_t hwcap,
> struct glibc_hwcaps_subdirectory *);
>
> extern void init_aux_cache (void);
> @@ -79,23 +80,28 @@ extern void init_aux_cache (void);
> extern void load_aux_cache (const char *aux_cache_name);
>
> extern int search_aux_cache (struct stat64 *stat_buf, int *flags,
> - unsigned int *osversion, char **soname);
> + unsigned int *osversion,
> + unsigned int *isa_level, char **soname);
>
> extern void add_to_aux_cache (struct stat64 *stat_buf, int flags,
> - unsigned int osversion, const char *soname);
> + unsigned int osversion,
> + unsigned int isa_level, const char *soname);
>
> 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, int *flag,
> + unsigned int *osversion, unsigned int *isa_level,
> + 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,
> - unsigned int *osversion, char **soname,
> +extern int process_elf_file (const char *file_name, const char *lib,
> + int *flag, unsigned int *osversion,
> + unsigned int *isa_level, char **soname,
> void *file_contents, size_t file_length);
>
> /* Declared in chroot_canon.c. */
Ok.
> diff --git a/sysdeps/generic/read-prop.h b/sysdeps/generic/read-prop.h
> new file mode 100644
> index 0000000000..091bd2f6c1
> --- /dev/null
> +++ b/sysdeps/generic/read-prop.h
Maybe elf-read-prop.h to add more information on exactly this
file intends to?
> @@ -0,0 +1,35 @@
> +/* 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/>. */
> +
> +#ifndef _READ_PROP_H
> +#define _READ_PROP_H
> +
> +/* Called for each property in the NT_GNU_PROPERTY_TYPE_0 note of SEGMENT.
> + Return value:
> + false: Continue processing the properties.
> + true : Stop processing the properties.
> + */
> +
> +static inline bool __attribute__ ((always_inline))
> +read_gnu_property (unsigned int *isal_level, uint32_t type, uint32_t
> + datasz, void *data)
> +{
> + return true;
> +}
> +
> +#endif
Ok.
> diff --git a/sysdeps/unix/sysv/linux/arm/readelflib.c b/sysdeps/unix/sysv/linux/arm/readelflib.c
> index 9d03fa6405..7f444add14 100644
> --- a/sysdeps/unix/sysv/linux/arm/readelflib.c
> +++ b/sysdeps/unix/sysv/linux/arm/readelflib.c
> @@ -18,18 +18,20 @@
> <https://www.gnu.org/licenses/>. */
>
>
> -int process_elf32_file (const char *file_name, const char *lib, int *flag,
> - unsigned int *osversion, char **soname,
> +int process_elf32_file (const char *file_name, const char *lib,
> + int *flag, unsigned int *osversion,
> + unsigned int *isa_level, char **soname,
> void *file_contents, size_t file_length);
> -int process_elf64_file (const char *file_name, const char *lib, int *flag,
> - unsigned int *osversion, char **soname,
> +int process_elf64_file (const char *file_name, const char *lib,
> + int *flag, unsigned int *osversion,
> + unsigned int *isa_level, 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,
> - 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)
> {
> ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_contents;
> int ret;
> @@ -38,8 +40,8 @@ process_elf_file (const char *file_name, const char *lib, int *flag,
> {
> Elf32_Ehdr *elf32_header = (Elf32_Ehdr *) elf_header;
>
> - ret = process_elf32_file (file_name, lib, flag, osversion, soname,
> - file_contents, file_length);
> + ret = process_elf32_file (file_name, lib, flag, osversion, isa_level,
> + soname, file_contents, file_length);
>
> if (!ret && EF_ARM_EABI_VERSION (elf32_header->e_flags) == EF_ARM_EABI_VER5)
> {
> @@ -57,8 +59,8 @@ process_elf_file (const char *file_name, const char *lib, int *flag,
> }
> else
> {
> - ret = process_elf64_file (file_name, lib, flag, osversion, soname,
> - file_contents, file_length);
> + ret = process_elf64_file (file_name, lib, flag, osversion, isa_level,
> + soname, file_contents, file_length);
> /* AArch64 libraries are always libc.so.6+. */
> if (!ret)
> *flag = FLAG_AARCH64_LIB64|FLAG_ELF_LIBC6;
Ok.
> diff --git a/sysdeps/unix/sysv/linux/ia64/readelflib.c b/sysdeps/unix/sysv/linux/ia64/readelflib.c
> index d24a934351..19d37b438e 100644
> --- a/sysdeps/unix/sysv/linux/ia64/readelflib.c
> +++ b/sysdeps/unix/sysv/linux/ia64/readelflib.c
> @@ -16,29 +16,31 @@
> <https://www.gnu.org/licenses/>. */
>
>
> -int process_elf32_file (const char *file_name, const char *lib, int *flag,
> - unsigned int *osversion, char **soname,
> +int process_elf32_file (const char *file_name, const char *lib,
> + int *flag, unsigned int *osversion,
> + unsigned int *isa_level, char **soname,
> void *file_contents, size_t file_length);
> -int process_elf64_file (const char *file_name, const char *lib, int *flag,
> - unsigned int *osversion, char **soname,
> +int process_elf64_file (const char *file_name, const char *lib,
> + int *flag, unsigned int *osversion,
> + unsigned int *isa_level, 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,
> - 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)
> {
> ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_contents;
> int ret;
>
> if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
> - return process_elf32_file (file_name, lib, flag, osversion, soname,
> - file_contents, file_length);
> + return process_elf32_file (file_name, lib, flag, osversion, isa_level,
> + 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, flag, osversion, isa_level,
> + soname, file_contents, file_length);
> /* Intel 64bit libraries are always libc.so.6+. */
> if (!ret)
> *flag = FLAG_IA64_LIB64|FLAG_ELF_LIBC6;
Ok.
> diff --git a/sysdeps/unix/sysv/linux/mips/readelflib.c b/sysdeps/unix/sysv/linux/mips/readelflib.c
> index 8363b8afcc..a3399961c9 100644
> --- a/sysdeps/unix/sysv/linux/mips/readelflib.c
> +++ b/sysdeps/unix/sysv/linux/mips/readelflib.c
> @@ -20,18 +20,20 @@
> <https://www.gnu.org/licenses/>. */
>
>
> -int process_elf32_file (const char *file_name, const char *lib, int *flag,
> - unsigned int *osversion, char **soname,
> +int process_elf32_file (const char *file_name, const char *lib,
> + int *flag, unsigned int *osversion,
> + unsigned int *isa_level, char **soname,
> void *file_contents, size_t file_length);
> -int process_elf64_file (const char *file_name, const char *lib, int *flag,
> - unsigned int *osversion, char **soname,
> +int process_elf64_file (const char *file_name, const char *lib,
> + int *flag, unsigned int *osversion,
> + unsigned int *isa_level, 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,
> - 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)
> {
> union
> {
> @@ -45,8 +47,8 @@ process_elf_file (const char *file_name, const char *lib, int *flag,
> elf_header.eh = file_contents;
> if (elf_header.eh->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, flag, osversion, isa_level,
> + soname, file_contents, file_length);
> if (!ret)
> {
> Elf32_Word flags = elf_header.eh32->e_flags;
> @@ -62,8 +64,8 @@ process_elf_file (const char *file_name, const char *lib, int *flag,
> }
> else
> {
> - ret = process_elf64_file (file_name, lib, flag, osversion, soname,
> - file_contents, file_length);
> + ret = process_elf64_file (file_name, lib, flag, osversion, isa_level,
> + soname, file_contents, file_length);
> /* n64 libraries are always libc.so.6+. */
> if (!ret)
> {
Ok.
> diff --git a/sysdeps/unix/sysv/linux/powerpc/readelflib.c b/sysdeps/unix/sysv/linux/powerpc/readelflib.c
> index eb20680418..ce01658fb3 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/readelflib.c
> +++ b/sysdeps/unix/sysv/linux/powerpc/readelflib.c
> @@ -17,29 +17,31 @@
> <https://www.gnu.org/licenses/>. */
>
>
> -int process_elf32_file (const char *file_name, const char *lib, int *flag,
> - unsigned int *osversion, char **soname,
> +int process_elf32_file (const char *file_name, const char *lib,
> + int *flag, unsigned int *osversion,
> + unsigned int *isa_level, char **soname,
> void *file_contents, size_t file_length);
> -int process_elf64_file (const char *file_name, const char *lib, int *flag,
> - unsigned int *osversion, char **soname,
> +int process_elf64_file (const char *file_name, const char *lib,
> + int *flag, unsigned int *osversion,
> + unsigned int *isa_level, 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,
> - 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)
> {
> ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_contents;
> int ret;
>
> if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
> - return process_elf32_file (file_name, lib, flag, osversion, soname,
> - file_contents, file_length);
> + return process_elf32_file (file_name, lib, flag, osversion, isa_level,
> + 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, flag, osversion, isa_level,
> + soname, file_contents, file_length);
> /* PowerPC 64bit libraries are always libc.so.6+. */
> if (!ret)
> *flag = FLAG_POWERPC_LIB64|FLAG_ELF_LIBC6;
Ok.
> diff --git a/sysdeps/unix/sysv/linux/riscv/readelflib.c b/sysdeps/unix/sysv/linux/riscv/readelflib.c
> index 1e70735cc0..98ae3c0b2b 100644
> --- a/sysdeps/unix/sysv/linux/riscv/readelflib.c
> +++ b/sysdeps/unix/sysv/linux/riscv/readelflib.c
> @@ -17,11 +17,13 @@
> <https://www.gnu.org/licenses/>. */
>
>
> -int process_elf32_file (const char *file_name, const char *lib, int *flag,
> - unsigned int *osversion, char **soname,
> +int process_elf32_file (const char *file_name, const char *lib,
> + int *flag, unsigned int *osversion,
> + unsigned int *isa_level, char **soname,
> void *file_contents, size_t file_length);
> -int process_elf64_file (const char *file_name, const char *lib, int *flag,
> - unsigned int *osversion, char **soname,
> +int process_elf64_file (const char *file_name, const char *lib,
> + int *flag, unsigned int *osversion,
> + unsigned int *isa_level, char **soname,
> void *file_contents, size_t file_length);
>
> /* The ELF flags supported by our current glibc port:
> @@ -38,8 +40,8 @@ int process_elf64_file (const char *file_name, const char *lib, int *flag,
> /* 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)
> {
> ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_contents;
> Elf32_Ehdr *elf32_header = (Elf32_Ehdr *) elf_header;
> @@ -52,14 +54,14 @@ process_elf_file (const char *file_name, const char *lib, int *flag,
>
> 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, flag, osversion, isa_level,
> + soname, file_contents, file_length);
> flags = elf32_header->e_flags;
> }
> else
> {
> - ret = process_elf64_file (file_name, lib, flag, osversion, soname,
> - file_contents, file_length);
> + ret = process_elf64_file (file_name, lib, flag, osversion, isa_level,
> + soname, file_contents, file_length);
> flags = elf64_header->e_flags;
> }
>
Ok.
> diff --git a/sysdeps/unix/sysv/linux/s390/readelflib.c b/sysdeps/unix/sysv/linux/s390/readelflib.c
> index 1718efc9f9..6d19e351ba 100644
> --- a/sysdeps/unix/sysv/linux/s390/readelflib.c
> +++ b/sysdeps/unix/sysv/linux/s390/readelflib.c
> @@ -16,29 +16,31 @@
> <https://www.gnu.org/licenses/>. */
>
>
> -int process_elf32_file (const char *file_name, const char *lib, int *flag,
> - unsigned int *osversion, char **soname,
> +int process_elf32_file (const char *file_name, const char *lib,
> + int *flag, unsigned int *osversion,
> + unsigned int *isa_level, char **soname,
> void *file_contents, size_t file_length);
> -int process_elf64_file (const char *file_name, const char *lib, int *flag,
> - unsigned int *osversion, char **soname,
> +int process_elf64_file (const char *file_name, const char *lib,
> + int *flag, unsigned int *osversion,
> + unsigned int *isa_level, 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,
> - 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)
> {
> ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_contents;
> int ret;
>
> if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
> - return process_elf32_file (file_name, lib, flag, osversion, soname,
> - file_contents, file_length);
> + return process_elf32_file (file_name, lib, flag, osversion, isa_level,
> + 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, flag, osversion, isa_level,
> + soname, file_contents, file_length);
> /* S/390 64bit libraries are always libc.so.6+. */
> if (!ret)
> *flag = FLAG_S390_LIB64|FLAG_ELF_LIBC6;
Ok.
> diff --git a/sysdeps/unix/sysv/linux/sparc/readelflib.c b/sysdeps/unix/sysv/linux/sparc/readelflib.c
> index e027a11a37..3768003925 100644
> --- a/sysdeps/unix/sysv/linux/sparc/readelflib.c
> +++ b/sysdeps/unix/sysv/linux/sparc/readelflib.c
> @@ -18,29 +18,31 @@
> <https://www.gnu.org/licenses/>. */
>
>
> -int process_elf32_file (const char *file_name, const char *lib, int *flag,
> - unsigned int *osversion, char **soname,
> +int process_elf32_file (const char *file_name, const char *lib,
> + int *flag, unsigned int *osversion,
> + unsigned int *isa_level, char **soname,
> void *file_contents, size_t file_length);
> -int process_elf64_file (const char *file_name, const char *lib, int *flag,
> - unsigned int *osversion, char **soname,
> +int process_elf64_file (const char *file_name, const char *lib,
> + int *flag, unsigned int *osversion,
> + unsigned int *isa_level, 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,
> - 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)
> {
> ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_contents;
> int ret;
>
> if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
> - return process_elf32_file (file_name, lib, flag, osversion, soname,
> - file_contents, file_length);
> + return process_elf32_file (file_name, lib, flag, osversion, isa_level,
> + 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, flag, osversion, isa_level,
> + soname, file_contents, file_length);
> /* Sparc 64bit libraries are always libc.so.6+. */
> if (!ret)
> *flag = FLAG_SPARC_LIB64|FLAG_ELF_LIBC6;
Ok.
> 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..ac37fbc449
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/x86/read-prop.h
> @@ -0,0 +1,61 @@
> +/* Support for GNU properties in ldconfig. x86 version.
> + Copyright (C) 2020 Free Software Foundation, Inc.
s/2020/2021.
> + 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/>. */
> +
> +#ifndef _READ_PROP_H
> +#define _READ_PROP_H
> +
> +#include <dl-cache.h>
> +
> +/* Called for each property in the NT_GNU_PROPERTY_TYPE_0 note of SEGMENT.
> + Return value:
> + false: Continue processing the properties.
> + true : Stop processing the properties.
> + */
> +
> +static inline bool __attribute__ ((always_inline))
> +read_gnu_property (unsigned int *isal_level, uint32_t type,
> + uint32_t datasz, void *data)
> +{
> + /* Property type must be in ascending order. */
> + if (type > GNU_PROPERTY_X86_ISA_1_NEEDED)
> + return true;
> +
> + if (type == GNU_PROPERTY_X86_ISA_1_NEEDED)
> + {
> + if (datasz == 4)
> + {
> + /* 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. */
> + unsigned int isa_1_needed = *(unsigned int *) data;
> + _Static_assert (((sizeof (isa_1_needed) * 8)
> + <= (1 << DL_CACHE_HWCAP_ISA_LEVEL_COUNT)),
> + "DL_CACHE_HWCAP_ISA_LEVEL_COUNT is too small");
> + if (isa_1_needed)
Implicit check.
> + {
> + unsigned int level;
> + asm ("bsr %1, %0" : "=r" (level) : "g" (isa_1_needed));
> + *isal_level = level;
> + }
> + }
> + return true;
> + }
> +
> + return false;
> +}
> +
> +#endif
Ok.
> diff --git a/sysdeps/unix/sysv/linux/x86/readelflib.c b/sysdeps/unix/sysv/linux/x86/readelflib.c
> index 3e83419f5b..716629bf10 100644
> --- a/sysdeps/unix/sysv/linux/x86/readelflib.c
> +++ b/sysdeps/unix/sysv/linux/x86/readelflib.c
> @@ -17,19 +17,20 @@
> License along with the GNU C Library; if not, see
> <https://www.gnu.org/licenses/>. */
>
> -
> -int process_elf32_file (const char *file_name, const char *lib, int *flag,
> - unsigned int *osversion, char **soname,
> +int process_elf32_file (const char *file_name, const char *lib,
> + int *flag, unsigned int *osversion,
> + unsigned int *isa_level, char **soname,
> void *file_contents, size_t file_length);
> -int process_elf64_file (const char *file_name, const char *lib, int *flag,
> - unsigned int *osversion, char **soname,
> +int process_elf64_file (const char *file_name, const char *lib,
> + int *flag, unsigned int *osversion,
> + unsigned int *isa_level, 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,
> - 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)
> {
> ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_contents;
> int ret, file_flag = 0;
> @@ -68,11 +69,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, flag, osversion, isa_level,
> + 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, flag, osversion, isa_level,
> + soname, file_contents, file_length);
>
> if (!ret && file_flag)
> *flag = file_flag;
Ok.
> diff --git a/sysdeps/unix/sysv/linux/x86_64/Makefile b/sysdeps/unix/sysv/linux/x86_64/Makefile
> index 9b82155393..9a7b3cd8e5 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/Makefile
> +++ b/sysdeps/unix/sysv/linux/x86_64/Makefile
> @@ -13,3 +13,34 @@ 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))
As for first patch, I think we should extend the test coverage to check not
only for config-cflags-skylake-avx512. It means to build at least one
shared object with different ISA levels and run the ldconfig and check the
output against the system supported ISA level.
> +tests += tst-glibc-hwcaps-2
> +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
> +modules-names += libx86-64-isa-level-1 libx86-64-isa-level-4
> +
> +$(objpfx)tst-glibc-hwcaps-2: $(objpfx)libx86-64-isa-level.so
> +
> +$(objpfx)tst-glibc-hwcaps-2.out: \
> + $(objpfx)glibc-hwcaps/x86-64-v4/libx86-64-isa-level.so
> +$(objpfx)glibc-hwcaps/x86-64-v4/libx86-64-isa-level.so: \
> + $(objpfx)libx86-64-isa-level-4.so
> + cp $< $@
> +
> +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..8d6b17d658
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/x86_64/tst-glibc-hwcaps-2.c
> @@ -0,0 +1,61 @@
> +/* 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 <elf.h>
> +#include <get-isa-level.h>
> +#include <support/check.h>
> +#include <support/test-driver.h>
> +
> +extern int dso_isa_level (void);
> +
> +static int
> +do_test (void)
> +{
> + const struct cpu_features *cpu_features
> + = __x86_get_cpu_features (COMMON_CPUID_INDEX_MAX);
> + unsigned int isa_level = get_isa_level (cpu_features);
> + int level = dso_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");
> + if ((isa_level & GNU_PROPERTY_X86_ISA_1_V4) != 0)
> + ret = EXIT_FAILURE;
> + else
> + 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 on lesser CPU. */
> + printf ("x86-64 ISA level 4 shared library in x86-64-v2 is used.\n");
> + if ((isa_level & GNU_PROPERTY_X86_ISA_1_V4) != 0)
> + ret = EXIT_SUCCESS;
> + else
> + 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..2813d627cc
> --- /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 dso_isa_level
> +#include <isa-level.c>
> +#include <markermodMARKER-VALUE.c>
> diff --git a/sysdeps/x86/dl-isa-level.h b/sysdeps/x86/dl-isa-level.h
> new file mode 100644
> index 0000000000..c6ed8fb9d2
> --- /dev/null
> +++ b/sysdeps/x86/dl-isa-level.h
> @@ -0,0 +1,32 @@
> +/* Support for reading ISA level in /etc/ld.so.cache files written by
> + Linux 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/>. */
> +
> +#include <sys/platform/x86.h>
> +
> +/* Return true if the ISA level in ENTRY is compatible with CPU. */
> +
> +static inline bool
> +dl_cache_hwcap_isa_level_compatible (struct file_entry_new *entry)
> +{
> + const struct cpu_features *cpu_features = __get_cpu_features ();
> + unsigned int isa_level
> + = 1 << ((entry->hwcap >> 32) & DL_CACHE_HWCAP_ISA_LEVEL_MASK);
> +
> + return (isa_level & cpu_features->isa_1) == isa_level;
> +}
Ok.
> --
> 2.29.2
next prev parent reply other threads:[~2021-01-12 16:25 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-12-06 14:49 V5 [PATCH 0/2] x86: Support GNU_PROPERTY_X86_ISA_1_NEEDED marker [BZ #26717] H.J. Lu
2020-12-06 14:49 ` V5 [PATCH 1/2] x86: Support GNU_PROPERTY_X86_ISA_1_V[234] " H.J. Lu
2021-01-06 12:00 ` Adhemerval Zanella
2021-01-06 17:11 ` V6 " H.J. Lu
2021-01-07 20:09 ` Adhemerval Zanella
2021-01-07 20:58 ` H.J. Lu
2021-01-18 11:17 ` Florian Weimer
2021-01-18 13:49 ` H.J. Lu
2021-01-18 15:15 ` Florian Weimer
2020-12-06 14:49 ` V5 [PATCH 2/2] ldconfig/x86: Add ISA level check to glibc-hwcaps H.J. Lu
2020-12-07 10:00 ` Florian Weimer
2020-12-08 13:25 ` H.J. Lu
2020-12-08 13:31 ` Florian Weimer
2020-12-08 14:10 ` H.J. Lu
2020-12-08 14:18 ` Florian Weimer
2020-12-08 14:23 ` H.J. Lu
2020-12-08 15:15 ` Florian Weimer
2020-12-08 15:31 ` H.J. Lu
2020-12-09 3:27 ` [PATCH] ldconfig/x86: Store ISA level in cache and aux cache H.J. Lu
2021-01-12 16:25 ` Adhemerval Zanella [this message]
2021-01-12 23:32 ` V2 " H.J. Lu
2021-01-13 13:47 ` Adhemerval Zanella
2021-01-13 14:12 ` H.J. Lu
2021-01-28 20:20 ` Florian Weimer
2021-01-28 20:43 ` H.J. Lu
2021-01-29 8:56 ` Florian Weimer
2021-01-29 12:44 ` H.J. Lu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=f8c0ad71-c5fd-1a10-f737-114d23e7c01a@linaro.org \
--to=adhemerval.zanella@linaro.org \
--cc=fweimer@redhat.com \
--cc=hjl.tools@gmail.com \
--cc=libc-alpha@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).