From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-Status: No, score=-4.3 required=3.0 tests=AWL,BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,MAILING_LIST_MULTI,NICE_REPLY_A, SPF_HELO_PASS,SPF_PASS shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by dcvr.yhbt.net (Postfix) with ESMTPS id EE3FF1F4B4 for ; Fri, 9 Oct 2020 13:19:51 +0000 (UTC) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 3953D3844008; Fri, 9 Oct 2020 13:19:50 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3953D3844008 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1602249590; bh=u1M5sPF7YiUMGVMLs/b3li6qmNH4kkAHXcSlMYgR3XQ=; h=To:References:Subject:Date:In-Reply-To:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=W+tgmz4Ni7fA+RF2GHOgqkymJTKm0g0jxnnwgX5QVeZRTNNxw7H5gXy2qBpDSLLWo mYlHRhgw/KVdW2XHUKPZmFfAHfs1DEme4BsSRDfnijEZAITSoZL8KuJ9TR25Qi3JDv KEszPh7GHHEBAnLsG2paubgBd65LoBFK7SXPQ6xk= Received: from mail-qt1-x82e.google.com (mail-qt1-x82e.google.com [IPv6:2607:f8b0:4864:20::82e]) by sourceware.org (Postfix) with ESMTPS id 2C6B03857C64 for ; Fri, 9 Oct 2020 13:19:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 2C6B03857C64 Received: by mail-qt1-x82e.google.com with SMTP id r8so7826670qtp.13 for ; Fri, 09 Oct 2020 06:19:45 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:to:references:from:autocrypt:subject:message-id :date:user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=u1M5sPF7YiUMGVMLs/b3li6qmNH4kkAHXcSlMYgR3XQ=; b=Byuei9MFTXxygIxd2bGsxPv+HwdwOO4k7/ZKz1LUuKWFmXXe+EHYHPDqJxk9tCclSq Zy4muCO2t8B6Jrubbchm8cGTROmsIziMdWA0YhjzWw3alzOCRrVCO6omfwI1tFdCAYSq TZ0s8P2bFGtMydw/VCqrnVjtczLHMVexjqZ6uTG3oQpUWovs8pQYnPwJp9IGpJxPSmhG 3TEwG9P3YZuOSDpGCDTlG9fGvkpTcANPQkvuTsSXquFAvDChkxkJg53TYA62WQjX9nHL Rtd64uFrPjEbdHQlUSIrrkfmDuuHhpXbnWBrWcZnlJpSid3iU5U+jgkpshROOZpccpYG 4C+A== X-Gm-Message-State: AOAM532o/ua8dUtgqNZ9Arnlo1PbE7LMcGFsYgysUlFZdS8j6PGqeh4I 7+kZTSuc5JZ5CBMkJc9cXy9Oqs4NX2MnUg== X-Google-Smtp-Source: ABdhPJzA7hIijUYf4OlVsZ9EV3SGCtFEglZVlk/XNQUeu57xczN6TBonm2GtRjQGLy8j6hVGFk65jg== X-Received: by 2002:ac8:6943:: with SMTP id n3mr5733575qtr.45.1602249583956; Fri, 09 Oct 2020 06:19:43 -0700 (PDT) Received: from [192.168.1.4] ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id j11sm5911473qko.111.2020.10.09.06.19.42 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 09 Oct 2020 06:19:43 -0700 (PDT) To: libc-alpha@sourceware.org References: <47cb6998ed91f70f122de115b2e03ea5e82e5884.1601569371.git.fweimer@redhat.com> Autocrypt: addr=adhemerval.zanella@linaro.org; prefer-encrypt=mutual; keydata= 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 Subject: Re: [PATCH 16/28] elf: Add glibc-hwcaps support for LD_LIBRARY_PATH Message-ID: <7bae9b81-f656-976f-7b2a-6c0330243936@linaro.org> Date: Fri, 9 Oct 2020 10:19:40 -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: <47cb6998ed91f70f122de115b2e03ea5e82e5884.1601569371.git.fweimer@redhat.com> Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 8bit 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: , From: Adhemerval Zanella via Libc-alpha Reply-To: Adhemerval Zanella Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" On 01/10/2020 13:33, Florian Weimer via Libc-alpha wrote: > This hacks non-power-set processing into _dl_important_hwcaps. > Once the legacy hwcaps handling goes away, the subdirectory > handling needs to be reworked, but it is premature to do this > while both approaches are still supported. Looks good, some nits below with the main suggestion being the bitmask type change as Szabolcs. > --- > elf/Makefile | 5 +- > elf/dl-hwcaps-subdirs.c | 29 ++++++++ > elf/dl-hwcaps.c | 138 +++++++++++++++++++++++++++++++----- > elf/dl-hwcaps.h | 83 ++++++++++++++++++++++ > elf/dl-hwcaps_split.c | 77 ++++++++++++++++++++ > elf/dl-load.c | 7 +- > elf/dl-main.h | 11 ++- > elf/dl-support.c | 5 +- > elf/dl-usage.c | 68 +++++++++++++++++- > elf/rtld.c | 18 +++++ > elf/tst-dl-hwcaps_split.c | 139 +++++++++++++++++++++++++++++++++++++ > sysdeps/generic/ldsodefs.h | 20 ++++-- > 12 files changed, 570 insertions(+), 30 deletions(-) > create mode 100644 elf/dl-hwcaps-subdirs.c > create mode 100644 elf/dl-hwcaps_split.c > create mode 100644 elf/tst-dl-hwcaps_split.c > > diff --git a/elf/Makefile b/elf/Makefile > index 7b97e773a5..2c36b08c73 100644 > --- a/elf/Makefile > +++ b/elf/Makefile > @@ -59,7 +59,8 @@ elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \ > # ld.so uses those routines, plus some special stuff for being the program > # interpreter and operating independent of libc. > rtld-routines = rtld $(all-dl-routines) dl-sysdep dl-environ dl-minimal \ > - dl-error-minimal dl-conflict dl-hwcaps dl-usage > + dl-error-minimal dl-conflict dl-hwcaps dl-hwcaps_split dl-hwcaps-subdirs \ > + dl-usage > all-rtld-routines = $(rtld-routines) $(sysdep-rtld-routines) > > CFLAGS-dl-runtime.c += -fexceptions -fasynchronous-unwind-tables Ok. > @@ -217,7 +218,7 @@ tests-internal += loadtest unload unload2 circleload1 \ > neededtest neededtest2 neededtest3 neededtest4 \ > tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \ > tst-ptrguard1 tst-stackguard1 tst-libc_dlvsym \ > - tst-create_format1 tst-tls-surplus > + tst-create_format1 tst-tls-surplus tst-dl-hwcaps_split > tests-container += tst-pldd tst-dlopen-tlsmodid-container \ > tst-dlopen-self-container > test-srcs = tst-pathopt Ok. > diff --git a/elf/dl-hwcaps-subdirs.c b/elf/dl-hwcaps-subdirs.c > new file mode 100644 > index 0000000000..b142a3b826 > --- /dev/null > +++ b/elf/dl-hwcaps-subdirs.c > @@ -0,0 +1,29 @@ > +/* Architecture-specific glibc-hwcaps subdirectories. 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 > + . */ > + > +#include > + > +/* In the generic version, there are no subdirectories defined. */ > + > +const char _dl_hwcaps_subdirs[] = ""; > + > +int32_t > +_dl_hwcaps_subdirs_active (void) > +{ > + return 0; > +} Although using a signed does not really afects how you use the bitmask on _dl_hwcaps_split_masked (by shift and checking the LSB bit), I tend to agree with Szabolzs that an unsigned type here would be better. > diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c > index 44dbac099f..4de94759a2 100644 > --- a/elf/dl-hwcaps.c > +++ b/elf/dl-hwcaps.c > @@ -26,20 +26,97 @@ > #include > #include > > +/* This is the result of counting the substrings in a colon-separated > + hwcaps string. */ > +struct count_hwcaps > +{ > + /* Number of substrings. */ > + size_t count; > + > + /* Sum of the individual substring lengths (without separates or > + null terminators). */ > + size_t total_length; > + > + /* Maximum length of an individual substring. */ > + size_t maximum_length; > +}; > + > +/* Update *COUNTS according to the contents of HWCAPS. Skip over > + entries whose bit is not set in MASK. */ > +static void > +count_hwcaps (struct count_hwcaps *counts, const char *hwcaps, > + int32_t bitmask, const char *mask) > +{ > + struct dl_hwcaps_split_masked sp; > + _dl_hwcaps_split_masked_init (&sp, hwcaps, bitmask, mask); > + while (_dl_hwcaps_split_masked (&sp)) > + { > + ++counts->count; > + counts->total_length += sp.split.length; > + if (sp.split.length > counts->maximum_length) > + counts->maximum_length = sp.split.length; > + } > +} > + Ok. Maybe define that this updates the input by rename to 'update_count_hwcaps'? > +/* State for copy_hwcaps. Must be initialized to point to > + the storage areas for the array and the strings themselves. */ > +struct copy_hwcaps > +{ > + struct r_strlenpair *next_pair; > + char *next_string; > +}; > + > +/* Copy HWCAPS into the string pairs and strings, advancing *TARGET. > + Skip over entries whose bit is not set in MASK. */ > +static void > +copy_hwcaps (struct copy_hwcaps *target, const char *hwcaps, > + int32_t bitmask, const char *mask) > +{ > + struct dl_hwcaps_split_masked sp; > + _dl_hwcaps_split_masked_init (&sp, hwcaps, bitmask, mask); > + while (_dl_hwcaps_split_masked (&sp)) > + { > + target->next_pair->str = target->next_string; > + char *slash = __mempcpy (__mempcpy (target->next_string, > + GLIBC_HWCAPS_PREFIX, > + strlen (GLIBC_HWCAPS_PREFIX)), > + sp.split.segment, sp.split.length); > + *slash = '/'; > + target->next_pair->len > + = strlen (GLIBC_HWCAPS_PREFIX) + sp.split.length + 1; > + ++target->next_pair; > + target->next_string = slash + 1; > + } > +} > + Ok. > /* Return an array of useful/necessary hardware capability names. */ > const struct r_strlenpair * > -_dl_important_hwcaps (size_t *sz, size_t *max_capstrlen) > +_dl_important_hwcaps (const char *glibc_hwcaps_prepend, > + const char *glibc_hwcaps_mask, > + size_t *sz, size_t *max_capstrlen) > { > uint64_t hwcap_mask = GET_HWCAP_MASK(); > /* Determine how many important bits are set. */ > uint64_t masked = GLRO(dl_hwcap) & hwcap_mask; > size_t cnt = GLRO (dl_platform) != NULL; > size_t n, m; > - size_t total; > struct r_strlenpair *result; > struct r_strlenpair *rp; > char *cp; > > + /* glibc-hwcaps subdirectories. These are exempted from the power > + set construction below below. */ > + int32_t hwcaps_subdirs_active = _dl_hwcaps_subdirs_active (); > + struct count_hwcaps hwcaps_counts = { 0, }; Are you trying to outline the first element must be 0 initilized here with the comma? > + count_hwcaps (&hwcaps_counts, glibc_hwcaps_prepend, -1, NULL); > + count_hwcaps (&hwcaps_counts, _dl_hwcaps_subdirs, hwcaps_subdirs_active, > + glibc_hwcaps_mask); > + > + /* Each hwcaps subdirectory has a GLIBC_HWCAPS_PREFIX string prefix > + and a "/" suffix once stored in the result. */ > + size_t total = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1) > + + hwcaps_counts.total_length); > + > /* Count the number of bits set in the masked value. */ > for (n = 0; (~((1ULL << n) - 1) & masked) != 0; ++n) > if ((masked & (1ULL << n)) != 0) Ok. > @@ -74,10 +151,10 @@ _dl_important_hwcaps (size_t *sz, size_t *max_capstrlen) > > /* Determine the total size of all strings together. */ > if (cnt == 1) > - total = temp[0].len + 1; > + total += temp[0].len + 1; > else > { > - total = temp[0].len + temp[cnt - 1].len + 2; > + total += temp[0].len + temp[cnt - 1].len + 2; > if (cnt > 2) > { > total <<= 1; > @@ -94,26 +171,48 @@ _dl_important_hwcaps (size_t *sz, size_t *max_capstrlen) > } > } > > - /* The result structure: we use a very compressed way to store the > - various combinations of capability names. */ > - *sz = 1 << cnt; > - result = (struct r_strlenpair *) malloc (*sz * sizeof (*result) + total); > - if (result == NULL) > + *sz = hwcaps_counts.count + (1 << cnt); > + > + /* This is the overall result, including both glibc-hwcaps > + subdirectories and the legacy hwcaps subdirectories using the > + power set construction. */ > + struct r_strlenpair *overall_result > + = malloc (*sz * sizeof (*result) + total); > + if (overall_result == NULL) > _dl_signal_error (ENOMEM, NULL, NULL, > N_("cannot create capability list")); > > + /* Fill in the glibc-hwcaps subdirectories. */ > + { > + struct copy_hwcaps target; > + target.next_pair = overall_result; > + target.next_string = (char *) (overall_result + *sz); > + copy_hwcaps (&target, glibc_hwcaps_prepend, -1, NULL); > + copy_hwcaps (&target, _dl_hwcaps_subdirs, > + hwcaps_subdirs_active, glibc_hwcaps_mask); > + /* Set up the write target for the power set construction. */ > + result = target.next_pair; > + cp = target.next_string; > + } > + > + Ok. > + /* Power set construction begins here. We use a very compressed way > + to store the various combinations of capability names. */ > + > if (cnt == 1) > { > - result[0].str = (char *) (result + *sz); > + result[0].str = cp; > result[0].len = temp[0].len + 1; > - result[1].str = (char *) (result + *sz); > + result[1].str = cp; > result[1].len = 0; > - cp = __mempcpy ((char *) (result + *sz), temp[0].str, temp[0].len); > + cp = __mempcpy (cp, temp[0].str, temp[0].len); > *cp = '/'; > - *sz = 2; > - *max_capstrlen = result[0].len; > + if (result[0].len > hwcaps_counts.maximum_length) > + *max_capstrlen = result[0].len; > + else > + *max_capstrlen = hwcaps_counts.maximum_length; > > - return result; > + return overall_result; > } > > /* Fill in the information. This follows the following scheme Ok. > @@ -124,7 +223,7 @@ _dl_important_hwcaps (size_t *sz, size_t *max_capstrlen) > #3: 0, 3 1001 > This allows the representation of all possible combinations of > capability names in the string. First generate the strings. */ > - result[1].str = result[0].str = cp = (char *) (result + *sz); > + result[1].str = result[0].str = cp; > #define add(idx) \ > cp = __mempcpy (__mempcpy (cp, temp[idx].str, temp[idx].len), "/", 1); > if (cnt == 2) > @@ -191,7 +290,10 @@ _dl_important_hwcaps (size_t *sz, size_t *max_capstrlen) > while (--n != 0); > > /* The maximum string length. */ > - *max_capstrlen = result[0].len; > + if (result[0].len > hwcaps_counts.maximum_length) > + *max_capstrlen = result[0].len; > + else > + *max_capstrlen = hwcaps_counts.maximum_length; > > - return result; > + return overall_result; > } Ok. > diff --git a/elf/dl-hwcaps.h b/elf/dl-hwcaps.h > index b66da59b89..a6453f15f3 100644 > --- a/elf/dl-hwcaps.h > +++ b/elf/dl-hwcaps.h > @@ -16,6 +16,11 @@ > License along with the GNU C Library; if not, see > . */ > > +#ifndef _DL_HWCAPS_H > +#define _DL_HWCAPS_H > + > +#include > + > #include > > #if HAVE_TUNABLES > @@ -28,3 +33,81 @@ > # define GET_HWCAP_MASK() (0) > # endif > #endif > + > +#define GLIBC_HWCAPS_SUBDIRECTORY "glibc-hwcaps" > +#define GLIBC_HWCAPS_PREFIX GLIBC_HWCAPS_SUBDIRECTORY "/" > + > +/* Used by _dl_hwcaps_split below, to split strings at ':' > + separators. */ > +struct dl_hwcaps_split > +{ > + const char *segment; /* Start of the current segment. */ > + size_t length; /* Number of bytes until ':' or NUL. */ > +}; > + > +/* Prepare *S to parse SUBJECT, for future _dl_hwcaps_split calls. If > + SUBJECT is NULL, it is treated as the empty string. */ > +static inline void > +_dl_hwcaps_split_init (struct dl_hwcaps_split *s, const char *subject) > +{ > + s->segment = subject; > + /* The initial call to _dl_hwcaps_split will not skip anything. */ > + s->length = 0; > +} > + Ok. > +/* Extract the next non-empty string segment, up to ':' or the null > + terminator. Return true if one more segment was found, or false if > + the end of the string was reached. On success, S->segment is the > + start of the segment found, and S->length is its length. > + (Typically, S->segment[S->length] is not null.) */ > +_Bool _dl_hwcaps_split (struct dl_hwcaps_split *s) attribute_hidden; > + > +/* Similar to dl_hwcaps_split, but with bit-based and name-based > + masking. */ > +struct dl_hwcaps_split_masked > +{ > + struct dl_hwcaps_split split; > + > + /* For used by the iterator implementation. */ > + const char *mask; > + int32_t bitmask; > +}; > + > +/* Prepare *S for iteration with _dl_hwcaps_split_masked. Only HWCAP > + names in SUBJECT whose bit is set in BITMASK and whose ane is in s/ane/one > + MASK will be returned. SUBJECT must not contain empty HWCAP names. > + If MASK is NULL, no name-based masking is applied. Likewise for > + BITMASK if BITMASK is -1 (infinite number of bits). */ > +static inline void > +_dl_hwcaps_split_masked_init (struct dl_hwcaps_split_masked *s, > + const char *subject, > + int32_t bitmask, const char *mask) > +{ > + _dl_hwcaps_split_init (&s->split, subject); > + s->bitmask = bitmask; > + s->mask = mask; > +} > + > +/* Like _dl_hwcaps_split, but apply masking. */ > +_Bool _dl_hwcaps_split_masked (struct dl_hwcaps_split_masked *s) > + attribute_hidden; > + > +/* Returns true if the colon-separated HWCAP list HWCAPS contains the > + capability NAME (with length NAME_LENGTH). If HWCAPS is NULL, the > + function returns true. */ > +_Bool _dl_hwcaps_contains (const char *hwcaps, const char *name, > + size_t name_length) attribute_hidden; > + > +/* Colon-separated string of glibc-hwcaps subdirectories, without the > + "glibc-hwcaps/" prefix. The most preferred subdirectory needs to > + be listed first. */ > +extern const char _dl_hwcaps_subdirs[] attribute_hidden; > + > +/* Returns a bitmap of active subdirectories in _dl_hwcaps_subdirs. > + Bit 0 (the LSB) corresponds to the first substring in > + _dl_hwcaps_subdirs, bit 1 to the second substring, and so on. > + There is no direct correspondence between HWCAP bitmasks and this > + bitmask. */ > +int32_t _dl_hwcaps_subdirs_active (void) attribute_hidden; > + > +#endif /* _DL_HWCAPS_H */ Ok. > diff --git a/elf/dl-hwcaps_split.c b/elf/dl-hwcaps_split.c > new file mode 100644 > index 0000000000..95225e9f40 > --- /dev/null > +++ b/elf/dl-hwcaps_split.c > @@ -0,0 +1,77 @@ > +/* Hardware capability support for run-time dynamic loader. String splitting. > + 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 > + > +_Bool > +_dl_hwcaps_split (struct dl_hwcaps_split *s) > +{ > + if (s->segment == NULL) > + return false; > + > + /* Skip over the previous segment. */ > + s->segment += s->length; > + > + /* Consume delimiters. This also avoids returning an empty > + segment. */ > + while (*s->segment == ':') > + ++s->segment; > + if (*s->segment == '\0') > + return false; > + > + /* This could use strchrnul, but we would have to link the function > + into ld.so for that. */ > + const char *colon = strchr (s->segment, ':'); > + if (colon == NULL) > + s->length = strlen (s->segment); > + else > + s->length = colon - s->segment; > + return true; > +} Ok. > + > +_Bool > +_dl_hwcaps_split_masked (struct dl_hwcaps_split_masked *s) > +{ > + while (true) > + { > + if (!_dl_hwcaps_split (&s->split)) > + return false; > + bool active = s->bitmask & 1; > + s->bitmask >>= 1; > + if (active && _dl_hwcaps_contains (s->mask, > + s->split.segment, s->split.length)) > + return true; > + } > +} > + > +_Bool > +_dl_hwcaps_contains (const char *hwcaps, const char *name, size_t name_length) > +{ > + if (hwcaps == NULL) > + return true; > + > + struct dl_hwcaps_split split; > + _dl_hwcaps_split_init (&split, hwcaps); > + while (_dl_hwcaps_split (&split)) > + if (split.length == name_length > + && memcmp (split.segment, name, name_length) == 0) > + return true; > + return false; > +} Ok. > diff --git a/elf/dl-load.c b/elf/dl-load.c > index f3201e7c14..9020f1646f 100644 > --- a/elf/dl-load.c > +++ b/elf/dl-load.c > @@ -682,7 +682,9 @@ cache_rpath (struct link_map *l, > > > void > -_dl_init_paths (const char *llp, const char *source) > +_dl_init_paths (const char *llp, const char *source, > + const char *glibc_hwcaps_prepend, > + const char *glibc_hwcaps_mask) > { > size_t idx; > const char *strp; > @@ -697,7 +699,8 @@ _dl_init_paths (const char *llp, const char *source) > > #ifdef SHARED > /* Get the capabilities. */ > - capstr = _dl_important_hwcaps (&ncapstr, &max_capstrlen); > + capstr = _dl_important_hwcaps (glibc_hwcaps_prepend, glibc_hwcaps_mask, > + &ncapstr, &max_capstrlen); > #endif > > /* First set up the rest of the default search directory entries. */ Ok. > diff --git a/elf/dl-main.h b/elf/dl-main.h > index 0df849d3cd..710d29685b 100644 > --- a/elf/dl-main.h > +++ b/elf/dl-main.h > @@ -80,6 +80,14 @@ struct dl_main_state > /* The preload list passed as a command argument. */ > const char *preloadarg; > > + /* Additional glibc-hwcaps subdirectories to search first. > + Colon-separated list. */ > + const char *glibc_hwcaps_prepend; > + > + /* Mask for the internal glibc-hwcaps subdirectories. > + Colon-separated list. */ > + const char *glibc_hwcaps_mask; > + > enum mode mode; > > /* True if any of the debugging options is enabled. */ Ok. > @@ -94,7 +102,8 @@ struct dl_main_state > static inline void > call_init_paths (const struct dl_main_state *state) > { > - _dl_init_paths (state->library_path, state->library_path_source); > + _dl_init_paths (state->library_path, state->library_path_source, > + state->glibc_hwcaps_prepend, state->glibc_hwcaps_mask); > } > > /* Print ld.so usage information and exit. */ Ok. > diff --git a/elf/dl-support.c b/elf/dl-support.c > index afbc94df54..3264262f4e 100644 > --- a/elf/dl-support.c > +++ b/elf/dl-support.c > @@ -323,7 +323,10 @@ _dl_non_dynamic_init (void) > > /* Initialize the data structures for the search paths for shared > objects. */ > - _dl_init_paths (getenv ("LD_LIBRARY_PATH"), "LD_LIBRARY_PATH"); > + _dl_init_paths (getenv ("LD_LIBRARY_PATH"), "LD_LIBRARY_PATH", > + /* No glibc-hwcaps selection support in statically > + linked binaries. */ > + NULL, NULL); > > /* Remember the last search directory added at startup. */ > _dl_init_all_dirs = GL(dl_all_dirs); Ok. > diff --git a/elf/dl-usage.c b/elf/dl-usage.c > index 9765d1b5c1..9a3cbb8b91 100644 > --- a/elf/dl-usage.c > +++ b/elf/dl-usage.c > @@ -82,7 +82,7 @@ print_search_path_for_help (struct dl_main_state *state) > { > if (__rtld_search_dirs.dirs == NULL) > /* The run-time search paths have not yet been initialized. */ > - _dl_init_paths (state->library_path, state->library_path_source); > + call_init_paths (state); > > _dl_printf ("\nShared library search path:\n"); > > @@ -131,6 +131,67 @@ print_hwcap_1_finish (bool *first) > _dl_printf (")\n"); > } > > +/* Print the header for print_hwcaps_subdirectories. */ > +static void > +print_hwcaps_subdirectories_header (bool *nothing_printed) > +{ > + if (*nothing_printed) > + { > + _dl_printf ("\n\ > +Subdirectories of glibc-hwcaps directories, in priority order:\n"); > + *nothing_printed = false; > + } > +} > + > +/* Print the HWCAP name itself, indented. */ > +static void > +print_hwcaps_subdirectories_name (const struct dl_hwcaps_split *split) > +{ > + _dl_write (STDOUT_FILENO, " ", 2); Maybe 'strlen (" ")" here? I usually see to use constants related to string size erro-prone. > + _dl_write (STDOUT_FILENO, split->segment, split->length); > +} > + > +/* Print the list of recognized glibc-hwcaps subdirectories. */ > +static void > +print_hwcaps_subdirectories (const struct dl_main_state *state) > +{ > + bool nothing_printed = true; > + struct dl_hwcaps_split split; > + > + /* The prepended glibc-hwcaps subdirectories. */ > + _dl_hwcaps_split_init (&split, state->glibc_hwcaps_prepend); > + while (_dl_hwcaps_split (&split)) > + { > + print_hwcaps_subdirectories_header (¬hing_printed); > + print_hwcaps_subdirectories_name (&split); > + bool first = true; > + print_hwcap_1 (&first, true, "searched"); > + print_hwcap_1_finish (&first); > + } > + > + /* The built-in glibc-hwcaps subdirectories. Do the filtering > + manually, so that more precise diagnostics are possible. */ > + int32_t mask = _dl_hwcaps_subdirs_active (); > + _dl_hwcaps_split_init (&split, _dl_hwcaps_subdirs); > + while (_dl_hwcaps_split (&split)) > + { > + print_hwcaps_subdirectories_header (¬hing_printed); > + print_hwcaps_subdirectories_name (&split); > + bool first = true; > + print_hwcap_1 (&first, mask & 1, "supported"); > + bool listed = _dl_hwcaps_contains (state->glibc_hwcaps_mask, > + split.segment, split.length); > + print_hwcap_1 (&first, !listed, "masked"); > + print_hwcap_1 (&first, (mask & 1) && listed, "searched"); > + print_hwcap_1_finish (&first); > + mask >>= 1; As before, I am not very found of this shift on a signed interger. > + } > + > + if (nothing_printed) > + _dl_printf ("\n\ > +No subdirectories of glibc-hwcaps directories are searched.\n"); > +} > + Ok. > /* Write a list of hwcap subdirectories to standard output. See > _dl_important_hwcaps in dl-hwcaps.c. */ > static void > @@ -185,6 +246,10 @@ setting environment variables (which would be inherted by subprocesses).\n\ > --inhibit-cache Do not use " LD_SO_CACHE "\n\ > --library-path PATH use given PATH instead of content of the environment\n\ > variable LD_LIBRARY_PATH\n\ > + --glibc-hwcaps-prepend LIST\n\ > + search glibc-hwcaps subdirectories in LIST\n\ > + --glibc-hwcaps-mask LIST\n\ > + only search built-in subdirectories if in LIST\n\ > --inhibit-rpath LIST ignore RUNPATH and RPATH information in object names\n\ > in LIST\n\ > --audit LIST use objects named in LIST as auditors\n\ > @@ -197,6 +262,7 @@ This program interpreter self-identifies as: " RTLD "\n\ > ", > argv0); > print_search_path_for_help (state); > + print_hwcaps_subdirectories (state); > print_legacy_hwcap_directories (); > _exit (0); > } Ok. > diff --git a/elf/rtld.c b/elf/rtld.c > index e0e8e98c2f..c9d2330364 100644 > --- a/elf/rtld.c > +++ b/elf/rtld.c > @@ -289,6 +289,8 @@ dl_main_state_init (struct dl_main_state *state) > state->library_path_source = NULL; > state->preloadlist = NULL; > state->preloadarg = NULL; > + state->glibc_hwcaps_prepend = NULL; > + state->glibc_hwcaps_mask = NULL; > state->mode = normal; > state->any_debug = false; > state->version_info = false; Ok. > @@ -1244,6 +1246,22 @@ dl_main (const ElfW(Phdr) *phdr, > { > argv0 = _dl_argv[2]; > > + _dl_skip_args += 2; > + _dl_argc -= 2; > + _dl_argv += 2; > + } > + else if (strcmp (_dl_argv[1], "--glibc-hwcaps-prepend") == 0 > + && _dl_argc > 2) > + { > + state.glibc_hwcaps_prepend = _dl_argv[2]; > + _dl_skip_args += 2; > + _dl_argc -= 2; > + _dl_argv += 2; > + } > + else if (strcmp (_dl_argv[1], "--glibc-hwcaps-mask") == 0 > + && _dl_argc > 2) > + { > + state.glibc_hwcaps_mask = _dl_argv[2]; > _dl_skip_args += 2; > _dl_argc -= 2; > _dl_argv += 2; Ok. > diff --git a/elf/tst-dl-hwcaps_split.c b/elf/tst-dl-hwcaps_split.c > new file mode 100644 > index 0000000000..929c99a23b > --- /dev/null > +++ b/elf/tst-dl-hwcaps_split.c > @@ -0,0 +1,139 @@ > +/* Unit tests for dl-hwcaps.c. > + 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 > + > +static void > +check_split_masked (const char *input, int32_t bitmask, const char *mask, > + const char *expected[], size_t expected_length) > +{ > + struct dl_hwcaps_split_masked split; > + _dl_hwcaps_split_masked_init (&split, input, bitmask, mask); > + size_t index = 0; > + while (_dl_hwcaps_split_masked (&split)) > + { > + TEST_VERIFY_EXIT (index < expected_length); > + TEST_COMPARE_BLOB (expected[index], strlen (expected[index]), > + split.split.segment, split.split.length); > + ++index; > + } > + TEST_COMPARE (index, expected_length); > +} > + Ok. > +static void > +check_split (const char *input, > + const char *expected[], size_t expected_length) > +{ > + struct dl_hwcaps_split split; > + _dl_hwcaps_split_init (&split, input); > + size_t index = 0; > + while (_dl_hwcaps_split (&split)) > + { > + TEST_VERIFY_EXIT (index < expected_length); > + TEST_COMPARE_BLOB (expected[index], strlen (expected[index]), > + split.segment, split.length); > + ++index; > + } > + TEST_COMPARE (index, expected_length); > + > + /* Reuse the test cases with masking that does not actually remove > + anything. */ > + check_split_masked (input, -1, NULL, expected, expected_length); > + check_split_masked (input, -1, input, expected, expected_length); > +} > + Ok. > +static int > +do_test (void) > +{ > + /* Splitting tests, without masking. */ > + check_split (NULL, NULL, 0); > + check_split ("", NULL, 0); > + check_split (":", NULL, 0); > + check_split ("::", NULL, 0); > + > + { > + const char *expected[] = { "first" }; > + check_split ("first", expected, array_length (expected)); > + check_split (":first", expected, array_length (expected)); > + check_split ("first:", expected, array_length (expected)); > + check_split (":first:", expected, array_length (expected)); > + } > + > + { > + const char *expected[] = { "first", "second" }; > + check_split ("first:second", expected, array_length (expected)); > + check_split ("first::second", expected, array_length (expected)); > + check_split (":first:second", expected, array_length (expected)); > + check_split ("first:second:", expected, array_length (expected)); > + check_split (":first:second:", expected, array_length (expected)); > + } > + > + /* Splitting tests with masking. */ > + { > + const char *expected[] = { "first" }; > + check_split_masked ("first", 3, "first:second", > + expected, array_length (expected)); > + check_split_masked ("first:second", 3, "first:", > + expected, array_length (expected)); > + check_split_masked ("first:second", 1, NULL, > + expected, array_length (expected)); > + } > + { > + const char *expected[] = { "second" }; > + check_split_masked ("first:second", 3, "second", > + expected, array_length (expected)); > + check_split_masked ("first:second:third", -1, "second:", > + expected, array_length (expected)); > + check_split_masked ("first:second", 2, NULL, > + expected, array_length (expected)); > + check_split_masked ("first:second:third", 2, "first:second", > + expected, array_length (expected)); > + } > + > + /* Tests for _dl_hwcaps_contains. */ > + TEST_VERIFY (_dl_hwcaps_contains (NULL, "first", strlen ("first"))); > + TEST_VERIFY (_dl_hwcaps_contains (NULL, "", 0)); > + TEST_VERIFY (! _dl_hwcaps_contains ("", "first", strlen ("first"))); > + TEST_VERIFY (! _dl_hwcaps_contains ("firs", "first", strlen ("first"))); > + TEST_VERIFY (_dl_hwcaps_contains ("firs", "first", strlen ("first") - 1)); > + for (int i = 0; i < strlen ("first"); ++i) > + TEST_VERIFY (! _dl_hwcaps_contains ("first", "first", i)); > + TEST_VERIFY (_dl_hwcaps_contains ("first", "first", strlen ("first"))); > + TEST_VERIFY (_dl_hwcaps_contains ("first:", "first", strlen ("first"))); > + TEST_VERIFY (_dl_hwcaps_contains ("first:second", > + "first", strlen ("first"))); > + TEST_VERIFY (_dl_hwcaps_contains (":first:second", "first", > + strlen ("first"))); > + TEST_VERIFY (_dl_hwcaps_contains ("first:second", "second", > + strlen ("second"))); > + TEST_VERIFY (_dl_hwcaps_contains ("first:second:", "second", > + strlen ("second"))); > + for (int i = 0; i < strlen ("second"); ++i) > + TEST_VERIFY (!_dl_hwcaps_contains ("first:second:", "sec", i)); > + > + return 0; > +} > + > +#include > + > +/* Rebuild the sources here because the object file is built for > + inclusion into the dynamic loader. */ > +#include "dl-hwcaps_split.c" Ok. > diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h > index 382eeb9be0..0b2babc70c 100644 > --- a/sysdeps/generic/ldsodefs.h > +++ b/sysdeps/generic/ldsodefs.h > @@ -1047,8 +1047,13 @@ extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns) > attribute_hidden; > > /* Initialize the basic data structure for the search paths. SOURCE > - is either "LD_LIBRARY_PATH" or "--library-path". */ > -extern void _dl_init_paths (const char *library_path, const char *source) > + is either "LD_LIBRARY_PATH" or "--library-path". > + GLIBC_HWCAPS_PREPEND adds additional glibc-hwcaps subdirectories to > + search. GLIBC_HWCAPS_MASK is used to filter the built-in > + subdirectories if not NULL. */ > +extern void _dl_init_paths (const char *library_path, const char *source, > + const char *glibc_hwcaps_prepend, > + const char *glibc_hwcaps_mask) > attribute_hidden; > Ok. > /* Gather the information needed to install the profiling tables and start > @@ -1072,9 +1077,14 @@ extern void _dl_show_auxv (void) attribute_hidden; > extern char *_dl_next_ld_env_entry (char ***position) attribute_hidden; > > /* Return an array with the names of the important hardware > - capabilities. The length of the array is written to *SZ, and the > - maximum of all strings length is written to *MAX_CAPSTRLEN. */ > -const struct r_strlenpair *_dl_important_hwcaps (size_t *sz, > + capabilities. PREPEND is a colon-separated list of glibc-hwcaps > + directories to search first. MASK is a colon-separated list used > + to filter the built-in glibc-hwcaps subdirectories. The length of > + the array is written to *SZ, and the maximum of all strings length > + is written to *MAX_CAPSTRLEN. */ > +const struct r_strlenpair *_dl_important_hwcaps (const char *prepend, > + const char *mask, > + size_t *sz, > size_t *max_capstrlen) > attribute_hidden; > > Ok.