From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-qv1-xf2e.google.com (mail-qv1-xf2e.google.com [IPv6:2607:f8b0:4864:20::f2e]) by sourceware.org (Postfix) with ESMTPS id A77F93858D29 for ; Tue, 12 Jan 2021 16:25:57 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org A77F93858D29 Received: by mail-qv1-xf2e.google.com with SMTP id et9so1123695qvb.10 for ; Tue, 12 Jan 2021 08:25:57 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:to:cc:references:from:autocrypt:subject :message-id:date:user-agent:mime-version:in-reply-to :content-language:content-transfer-encoding; bh=HgJogYqbgjEe+26DKhNVplUPEE7sSam1N3J2zNXH81c=; b=RSxyIMK3LU3D2xlYxEx5yGE31IDSYvM9nEC0KssrV8C5DK9eRYNwx7OElv65sI0S44 idmPdyKUE0crh/0Mt6d9NhdNHGo5UTvXU2WSLy/khzSC42DTkUp8nI0IgcI+3WcP9Ikw wAXsakeEAW1YuIFnZqRrQRB5ri9KISJHKF/hhQUPq0YMpf+hg5NQTrI3fWjb+aV4ysYg prGg6Z+s9I+gd0lqV9ganXdOfDUeL9njNu2UhzkM3SsjF7/MHvfkomMXfXoGtj8HmABv l4MjOU0zRHBFceoethR94iPchD58RUQFXVDArPIyWOBf6R9ycFfYsM8dd4Pmy2GyyN3r SRwA== X-Gm-Message-State: AOAM532FUv6doTDGYJDYUUItCduRljMHBV9M+lRlupcZSYy0wyWfZBoD BOG7gKzyOmjgkTNn5qSVFHLhajsejcmO/w== X-Google-Smtp-Source: ABdhPJwbeebeAf1hnqNj63MCRtELJX6rBHvwOAEnHOIJAOosdMhRmSlYKFa7XbyIJzlk7caMi8M1uA== X-Received: by 2002:a0c:da87:: with SMTP id z7mr158436qvj.41.1610468756042; Tue, 12 Jan 2021 08:25:56 -0800 (PST) Received: from [192.168.1.4] ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id 9sm1533706qke.123.2021.01.12.08.25.53 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 12 Jan 2021 08:25:55 -0800 (PST) To: "H.J. Lu" , Florian Weimer Cc: "H.J. Lu via Libc-alpha" References: <20201206144952.2109594-1-hjl.tools@gmail.com> <20201206144952.2109594-3-hjl.tools@gmail.com> <87sg8ikkal.fsf@oldenburg2.str.redhat.com> <871rg0e85j.fsf@oldenburg2.str.redhat.com> <87wnxscreu.fsf@oldenburg2.str.redhat.com> <87mtyocor7.fsf@oldenburg2.str.redhat.com> From: Adhemerval Zanella Autocrypt: addr=adhemerval.zanella@linaro.org; prefer-encrypt=mutual; keydata= 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 Subject: Re: [PATCH] ldconfig/x86: Store ISA level in cache and aux cache Message-ID: Date: Tue, 12 Jan 2021 13:25:51 -0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.10.0 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-13.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, NICE_REPLY_A, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 12 Jan 2021 16:26:03 -0000 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 wrote: >> >> On Tue, Dec 8, 2020 at 7:16 AM Florian Weimer 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" > 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 > #include <_itoa.h> > #include > +#include > > #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 > . */ > > +#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; > } 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 > + . */ > + > +/* 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 > +#include > +#include > +#include > + > +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 > + . */ > + > +/* 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 > + . */ > + > +#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 @@ > . */ > > > -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 @@ > . */ > > > -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 @@ > . */ > > > -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 @@ > . */ > > > -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 @@ > . */ > > > -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 @@ > . */ > > > -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 @@ > . */ > > > -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 > + . */ > + > +#ifndef _READ_PROP_H > +#define _READ_PROP_H > + > +#include > + > +/* 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 > . */ > > - > -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 > + . */ > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +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 > 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 > +#include > 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 > + . */ > + > +#include > + > +/* 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