From patchwork Sun Dec 6 14:49:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "H.J. Lu" X-Patchwork-Id: 41325 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id CC0093892029; Sun, 6 Dec 2020 14:50:03 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CC0093892029 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1607266203; bh=9DKLnHoi/PgLV/1ovRbKQqC39XbbKv8go6f9Zm/3Mlo=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=yxXnBPOMtTroYVSJwPMvzFLWlg/aX38uGua4Nw3lN9jolpukT5xe39qtsoEjt30y2 hKsXscG16i9Kzqacsetj0olYAqwVgNxMit8B/4xZ+HgbCedivOc1L0EsvWS7haKuu7 lZdKouD4B2SRaBZd8kREZYRW5IOtH12ZA3g4ATh8= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-pj1-x1044.google.com (mail-pj1-x1044.google.com [IPv6:2607:f8b0:4864:20::1044]) by sourceware.org (Postfix) with ESMTPS id EA1C0388CC0B for ; Sun, 6 Dec 2020 14:49:58 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org EA1C0388CC0B Received: by mail-pj1-x1044.google.com with SMTP id l23so5954683pjg.1 for ; Sun, 06 Dec 2020 06:49:58 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=9DKLnHoi/PgLV/1ovRbKQqC39XbbKv8go6f9Zm/3Mlo=; b=CPwSHcscOMP33biJD2/yR6+8uvAr0Gue4pS8mtrz4zSZ9oBGl9jVvUCWE85zN6BWRh MiPP/APd6eFJzgCBJArSTW8IsBoqg/d78hXocrTk0YJX2KbtsfTNEyWl5MRUqY6CXY9Z H6yzHN2FsRj8vfEVIatra3iDIhgZpwBAdK1Xr2yspgaPKTval0RspNP1ZBBG1FwkVM2H Y9kwPH8JAF18qZnHj74aa8oTLl1E/NfEGr69fjx3SpsO39NFLktoks89UTckAwBhW4LO qtDF4NsbLz7aVjddJ1FDaj1Q4VpYPEI7RGavKS2ZGfNc5iswfgZHKQy2dmnqULCD5So0 3l3w== X-Gm-Message-State: AOAM530SOO6TQwuQHqU2GB9710lcE4g+eqfeGcNLJVpYGvfkJ7cQ4t7f ppzWJj3VPLyID60AKCjfg98= X-Google-Smtp-Source: ABdhPJztUdB/waIu8trcaTogxVxKiaIqTJIU3lZQ7Uh1JQvUFdj2aGV9Rj2ULjhwyrWMvbthLJKdjg== X-Received: by 2002:a17:902:6103:b029:da:c46c:b3d6 with SMTP id t3-20020a1709026103b02900dac46cb3d6mr11727502plj.46.1607266197778; Sun, 06 Dec 2020 06:49:57 -0800 (PST) Received: from gnu-cfl-2.localdomain (c-69-181-90-243.hsd1.ca.comcast.net. [69.181.90.243]) by smtp.gmail.com with ESMTPSA id d24sm11022048pfo.199.2020.12.06.06.49.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 06 Dec 2020 06:49:55 -0800 (PST) Received: from gnu-cfl-2.localdomain (localhost [IPv6:::1]) by gnu-cfl-2.localdomain (Postfix) with ESMTP id BA6C61A03E6; Sun, 6 Dec 2020 06:49:54 -0800 (PST) To: libc-alpha@sourceware.org Subject: V5 [PATCH 2/2] ldconfig/x86: Add ISA level check to glibc-hwcaps Date: Sun, 6 Dec 2020 06:49:52 -0800 Message-Id: <20201206144952.2109594-3-hjl.tools@gmail.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201206144952.2109594-1-hjl.tools@gmail.com> References: <20201206144952.2109594-1-hjl.tools@gmail.com> MIME-Version: 1.0 X-Spam-Status: No, score=-3040.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, 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-Patchwork-Original-From: "H.J. Lu via Libc-alpha" From: "H.J. Lu" Reply-To: "H.J. Lu" Cc: Florian Weimer Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" Add ISA level check to detect misplaced shared objects with incompatible ISA level requirement in glibc-hwcaps subdirectories: /sbin/ldconfig: /usr/lib64/glibc-hwcaps/x86-64-v2/libx86-64-isa-level.so: skipped, ISA level mismatch (x86-64-v4 > x86-64-v2) --- elf/ldconfig.c | 9 +- elf/readelflib.c | 83 ++++++++++++++++++- 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/ldconfig.h | 9 +- sysdeps/generic/read-prop.h | 32 +++++++ sysdeps/unix/sysv/linux/x86/read-prop.h | 57 +++++++++++++ sysdeps/unix/sysv/linux/x86/readelflib.c | 67 +++++++++++++-- sysdeps/unix/sysv/linux/x86_64/Makefile | 26 ++++++ .../sysv/linux/x86_64/tst-glibc-hwcaps-2.c | 50 +++++++++++ .../linux/x86_64/x86-64-isa-level-VALUE.c | 4 + 14 files changed, 379 insertions(+), 18 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/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 diff --git a/elf/ldconfig.c b/elf/ldconfig.c index 10927a8c7f..f306d3df26 100644 --- a/elf/ldconfig.c +++ b/elf/ldconfig.c @@ -720,8 +720,8 @@ manual_link (char *library) return; } - if (process_file (real_library, library, libname, &flag, &osversion, - &soname, 0, &stat_buf)) + if (process_file (real_library, library, libname, NULL, &flag, + &osversion, &soname, 0, &stat_buf)) { error (0, 0, _("No link created since soname could not be found for %s"), library); @@ -982,8 +982,9 @@ search_dir (const struct dir_entry *entry) unsigned int osversion; if (!search_aux_cache (&lstat_buf, &flag, &osversion, &soname)) { - if (process_file (real_name, file_name, direntry->d_name, &flag, - &osversion, &soname, is_link, &lstat_buf)) + if (process_file (real_name, file_name, direntry->d_name, + entry->hwcaps, &flag, &osversion, + &soname, is_link, &lstat_buf)) { if (real_name != real_file_name) free (real_name); diff --git a/elf/readelflib.c b/elf/readelflib.c index 5905f6d344..0784bbcc1f 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 @@ -39,7 +41,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, +process_elf_file (const char *file_name, const char *lib, + struct glibc_hwcaps_subdirectory *hwcaps, int *flag, unsigned int *osversion, char **soname, void *file_contents, size_t file_length) { @@ -164,6 +167,84 @@ 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: + 0: Stop processing the properties. + > 0: Continue processing the properties. + < 0: Stop and skip the file. + */ + int read_prop + = ElfW(read_gnu_property) (hwcaps, file_name, + segment, type, + datasz, ptr); + if (read_prop == 0) + goto done; + else if (read_prop < 0) + return 1; + + /* 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; } diff --git a/elf/readlib.c b/elf/readlib.c index 994a4426a1..400f64bafa 100644 --- a/elf/readlib.c +++ b/elf/readlib.c @@ -74,7 +74,8 @@ is_gdb_python_file (const char *name) /* Returns 0 if everything is ok, != 0 in case of error. */ int process_file (const char *real_file_name, const char *file_name, - const char *lib, int *flag, unsigned int *osversion, + const char *lib, struct glibc_hwcaps_subdirectory *hwcaps, + int *flag, unsigned int *osversion, char **soname, int is_link, struct stat64 *stat_buf) { FILE *file; @@ -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, hwcaps, flag, osversion, + soname, file_contents, statbuf.st_size)) ret = 1; done: 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); + } + + /* 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; +} 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 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 +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/ldconfig.h b/sysdeps/generic/ldconfig.h index 1ad1528890..f85eaa48cb 100644 --- a/sysdeps/generic/ldconfig.h +++ b/sysdeps/generic/ldconfig.h @@ -88,13 +88,16 @@ 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, struct glibc_hwcaps_subdirectory *, + int *flag, unsigned int *osversion, 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, +extern int process_elf_file (const char *file_name, const char *lib, + struct glibc_hwcaps_subdirectory *hwcaps, + int *flag, unsigned int *osversion, char **soname, void *file_contents, size_t file_length); diff --git a/sysdeps/generic/read-prop.h b/sysdeps/generic/read-prop.h new file mode 100644 index 0000000000..49092f83f1 --- /dev/null +++ b/sysdeps/generic/read-prop.h @@ -0,0 +1,32 @@ +/* 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 + . */ + +/* Called for each property in the NT_GNU_PROPERTY_TYPE_0 note of SEGMENT. + Return value: + 0: Stop processing the properties. + > 0: Continue processing the properties. + < 0: Stop and skip the file. + */ + +static inline int __attribute__ ((always_inline)) +ElfW(read_gnu_property) (struct glibc_hwcaps_subdirectory *hwcaps, + const char *file_name, ElfW(Phdr) *segment, + uint32_t type, uint32_t datasz, void *data) +{ + return 0; +} 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..c22395f851 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86/read-prop.h @@ -0,0 +1,57 @@ +/* Support for GNU properties in 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 + . */ + +/* Called for each property in the NT_GNU_PROPERTY_TYPE_0 note of SEGMENT. + Return value: + 0: Stop processing the properties. + > 0: Continue processing the properties. + < 0: Stop and skip the file for ISA level mismatch. + */ + +static inline int __attribute__ ((always_inline)) +ElfW(read_gnu_property) (struct glibc_hwcaps_subdirectory *hwcaps, + const char *file_name, ElfW(Phdr) *segment, + uint32_t type, uint32_t datasz, void *data) +{ + if (type == GNU_PROPERTY_X86_ISA_1_NEEDED) + { + /* 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. */ + if (hwcaps != NULL && datasz == 4) + { + const char *isa_string = glibc_hwcaps_subdirectory_name (hwcaps); + if (isa_string != NULL) + { + unsigned int isa_1_needed = *(unsigned int *) data; + unsigned int isa_level; + if (get_isa_level_from_string (isa_string, &isa_level) == 0 + && isa_1_needed > isa_level) + { + error (0, 0, + _("%s: skipped, ISA level mismatch (%s > %s)"), + file_name, + get_isa_string_from_level (isa_1_needed), + isa_string); + return -1; + } + } + } + return 0; + } + return 1; +} diff --git a/sysdeps/unix/sysv/linux/x86/readelflib.c b/sysdeps/unix/sysv/linux/x86/readelflib.c index 3e83419f5b..336ba57ae7 100644 --- a/sysdeps/unix/sysv/linux/x86/readelflib.c +++ b/sysdeps/unix/sysv/linux/x86/readelflib.c @@ -17,17 +17,70 @@ License along with the GNU C Library; if not, see . */ +/* Get ISA level string from GNU_PROPERTY_X86_ISA_1_V[234] ISA level. */ -int process_elf32_file (const char *file_name, const char *lib, int *flag, +static const char * +get_isa_string_from_level (unsigned int isa_level) +{ + if ((isa_level & GNU_PROPERTY_X86_ISA_1_V4)) + return "x86-64-v4"; + else if ((isa_level & GNU_PROPERTY_X86_ISA_1_V3)) + return "x86-64-v3"; + else if ((isa_level & GNU_PROPERTY_X86_ISA_1_V2)) + return "x86-64-v2"; + abort (); + return NULL; +} + +/* Get GNU_PROPERTY_X86_ISA_1_V[234] ISA level from ISA level string. */ + +static int +get_isa_level_from_string (const char *level, unsigned int *isa_level_p) +{ + if (memcmp (level, "x86-64-v", 8) == 0) + { + unsigned int isa_level = 0; + if (level[9] == '\0') + switch (level[8]) + { + case '2': + isa_level = (GNU_PROPERTY_X86_ISA_1_BASELINE + | GNU_PROPERTY_X86_ISA_1_V2); + break; + case '3': + isa_level = (GNU_PROPERTY_X86_ISA_1_BASELINE + | GNU_PROPERTY_X86_ISA_1_V2 + | GNU_PROPERTY_X86_ISA_1_V3); + break; + case '4': + isa_level = (GNU_PROPERTY_X86_ISA_1_BASELINE + | GNU_PROPERTY_X86_ISA_1_V2 + | GNU_PROPERTY_X86_ISA_1_V3 + | GNU_PROPERTY_X86_ISA_1_V4); + break; + } + if (isa_level) + { + *isa_level_p = isa_level; + return 0; + } + } + return -1; +} + +int process_elf32_file (const char *file_name, const char *lib, + struct glibc_hwcaps_subdirectory *hwcaps, int *flag, unsigned int *osversion, char **soname, void *file_contents, size_t file_length); -int process_elf64_file (const char *file_name, const char *lib, int *flag, +int process_elf64_file (const char *file_name, const char *lib, + struct glibc_hwcaps_subdirectory *hwcaps, int *flag, unsigned int *osversion, 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, +process_elf_file (const char *file_name, const char *lib, + struct glibc_hwcaps_subdirectory *hwcaps, int *flag, unsigned int *osversion, char **soname, void *file_contents, size_t file_length) { @@ -68,11 +121,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, hwcaps, flag, osversion, + 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, hwcaps, flag, osversion, + soname, file_contents, file_length); if (!ret && file_flag) *flag = file_flag; diff --git a/sysdeps/unix/sysv/linux/x86_64/Makefile b/sysdeps/unix/sysv/linux/x86_64/Makefile index 9b82155393..a22bb6321f 100644 --- a/sysdeps/unix/sysv/linux/x86_64/Makefile +++ b/sysdeps/unix/sysv/linux/x86_64/Makefile @@ -13,3 +13,29 @@ 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)) +tests += tst-glibc-hwcaps-2 +modules-names += libx86-64-isa-level-1 libx86-64-isa-level-4 + +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 + +$(objpfx)tst-glibc-hwcaps-2: $(objpfx)libx86-64-isa-level.so + +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..ce6b189415 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86_64/tst-glibc-hwcaps-2.c @@ -0,0 +1,50 @@ +/* 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 + +extern int isa_level (void); + +static int +do_test (void) +{ + int level = 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"); + 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. */ + printf ("x86-64 ISA level 4 shared library in x86-64-v2 is used.\n"); + 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..892e4c464b --- /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 isa_level +#include +#include