aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/unix/sysv/linux
diff options
context:
space:
mode:
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>2023-12-06 10:24:01 -0300
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>2023-12-19 13:25:45 -0300
commit2a969b53c0b02fed7e43473a92f219d737fd217a (patch)
treeb55eda5dc496c260e9757a5fc3856838d85b38fd /sysdeps/unix/sysv/linux
parent5275fc784c8113c84c85ca028ce621f68fe6642b (diff)
downloadglibc-2a969b53c0b02fed7e43473a92f219d737fd217a.tar
glibc-2a969b53c0b02fed7e43473a92f219d737fd217a.tar.gz
glibc-2a969b53c0b02fed7e43473a92f219d737fd217a.tar.bz2
glibc-2a969b53c0b02fed7e43473a92f219d737fd217a.zip
elf: Do not duplicate the GLIBC_TUNABLES string
The tunable parsing duplicates the tunable environment variable so it null-terminates each one since it simplifies the later parsing. It has the drawback of adding another point of failure (__minimal_malloc failing), and the memory copy requires tuning the compiler to avoid mem operations calls. The parsing now tracks the tunable start and its size. The dl-tunable-parse.h adds helper functions to help parsing, like a strcmp that also checks for size and an iterator for suboptions that are comma-separated (used on hwcap parsing by x86, powerpc, and s390x). Since the environment variable is allocated on the stack by the kernel, it is safe to keep the references to the suboptions for later parsing of string tunables (as done by set_hwcaps by multiple architectures). Checked on x86_64-linux-gnu, powerpc64le-linux-gnu, and aarch64-linux-gnu. Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Diffstat (limited to 'sysdeps/unix/sysv/linux')
-rw-r--r--sysdeps/unix/sysv/linux/aarch64/cpu-features.c33
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/cpu-features.c45
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/tst-hwcap-tunables.c6
3 files changed, 38 insertions, 46 deletions
diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
index a11a86efab..c57f154b48 100644
--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
+++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
@@ -16,10 +16,12 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
+#include <array_length.h>
#include <cpu-features.h>
#include <sys/auxv.h>
#include <elf/dl-hwcaps.h>
#include <sys/prctl.h>
+#include <dl-tunables-parse.h>
#define DCZID_DZP_MASK (1 << 4)
#define DCZID_BS_MASK (0xf)
@@ -33,25 +35,28 @@
struct cpu_list
{
const char *name;
+ size_t len;
uint64_t midr;
};
-static struct cpu_list cpu_list[] = {
- {"thunderxt88", 0x430F0A10},
- {"thunderx2t99", 0x431F0AF0},
- {"thunderx2t99p1", 0x420F5160},
- {"ares", 0x411FD0C0},
- {"emag", 0x503F0001},
- {"kunpeng920", 0x481FD010},
- {"a64fx", 0x460F0010},
- {"generic", 0x0}
+static const struct cpu_list cpu_list[] =
+{
+#define CPU_LIST_ENTRY(__str, __num) { __str, sizeof (__str) - 1, __num }
+ CPU_LIST_ENTRY ("thunderxt88", 0x430F0A10),
+ CPU_LIST_ENTRY ("thunderx2t99", 0x431F0AF0),
+ CPU_LIST_ENTRY ("thunderx2t99p1", 0x420F5160),
+ CPU_LIST_ENTRY ("ares", 0x411FD0C0),
+ CPU_LIST_ENTRY ("emag", 0x503F0001),
+ CPU_LIST_ENTRY ("kunpeng920", 0x481FD010),
+ CPU_LIST_ENTRY ("a64fx", 0x460F0010),
+ CPU_LIST_ENTRY ("generic", 0x0),
};
static uint64_t
-get_midr_from_mcpu (const char *mcpu)
+get_midr_from_mcpu (const struct tunable_str_t *mcpu)
{
- for (int i = 0; i < sizeof (cpu_list) / sizeof (struct cpu_list); i++)
- if (strcmp (mcpu, cpu_list[i].name) == 0)
+ for (int i = 0; i < array_length (cpu_list); i++)
+ if (tunable_strcmp (mcpu, cpu_list[i].name, cpu_list[i].len))
return cpu_list[i].midr;
return UINT64_MAX;
@@ -63,7 +68,9 @@ init_cpu_features (struct cpu_features *cpu_features)
register uint64_t midr = UINT64_MAX;
/* Get the tunable override. */
- const char *mcpu = TUNABLE_GET (glibc, cpu, name, const char *, NULL);
+ const struct tunable_str_t *mcpu = TUNABLE_GET (glibc, cpu, name,
+ struct tunable_str_t *,
+ NULL);
if (mcpu != NULL)
midr = get_midr_from_mcpu (mcpu);
diff --git a/sysdeps/unix/sysv/linux/powerpc/cpu-features.c b/sysdeps/unix/sysv/linux/powerpc/cpu-features.c
index 7c6e20e702..390b3fd11a 100644
--- a/sysdeps/unix/sysv/linux/powerpc/cpu-features.c
+++ b/sysdeps/unix/sysv/linux/powerpc/cpu-features.c
@@ -20,6 +20,7 @@
#include <stdint.h>
#include <cpu-features.h>
#include <elf/dl-tunables.h>
+#include <dl-tunables-parse.h>
#include <unistd.h>
#include <string.h>
@@ -43,41 +44,26 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
struct cpu_features *cpu_features = &GLRO(dl_powerpc_cpu_features);
unsigned long int tcbv_hwcap = cpu_features->hwcap;
unsigned long int tcbv_hwcap2 = cpu_features->hwcap2;
- const char *token = valp->strval;
- do
+
+ struct tunable_str_comma_state_t ts;
+ tunable_str_comma_init (&ts, valp);
+
+ struct tunable_str_comma_t t;
+ while (tunable_str_comma_next (&ts, &t))
{
- const char *token_end, *feature;
- bool disable;
- size_t token_len, i, feature_len, offset = 0;
- /* Find token separator or end of string. */
- for (token_end = token; *token_end != ','; token_end++)
- if (*token_end == '\0')
- break;
+ if (t.len == 0)
+ continue;
- /* Determine feature. */
- token_len = token_end - token;
- if (*token == '-')
- {
- disable = true;
- feature = token + 1;
- feature_len = token_len - 1;
- }
- else
- {
- disable = false;
- feature = token;
- feature_len = token_len;
- }
- for (i = 0; i < array_length (hwcap_tunables); ++i)
+ size_t offset = 0;
+ for (int i = 0; i < array_length (hwcap_tunables); ++i)
{
const char *hwcap_name = hwcap_names + offset;
size_t hwcap_name_len = strlen (hwcap_name);
/* Check the tunable name on the supported list. */
- if (hwcap_name_len == feature_len
- && memcmp (feature, hwcap_name, feature_len) == 0)
+ if (tunable_str_comma_strcmp (&t, hwcap_name, hwcap_name_len))
{
/* Update the hwcap and hwcap2 bits. */
- if (disable)
+ if (t.disable)
{
/* Id is 1 for hwcap2 tunable. */
if (hwcap_tunables[i].id)
@@ -98,12 +84,7 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
}
offset += hwcap_name_len + 1;
}
- token += token_len;
- /* ... and skip token separator for next round. */
- if (*token == ',')
- token++;
}
- while (*token != '\0');
}
static inline void
diff --git a/sysdeps/unix/sysv/linux/powerpc/tst-hwcap-tunables.c b/sysdeps/unix/sysv/linux/powerpc/tst-hwcap-tunables.c
index 2631016a3a..049164f841 100644
--- a/sysdeps/unix/sysv/linux/powerpc/tst-hwcap-tunables.c
+++ b/sysdeps/unix/sysv/linux/powerpc/tst-hwcap-tunables.c
@@ -110,7 +110,11 @@ do_test (int argc, char *argv[])
run_test ("-arch_2_06", "__memcpy_power7");
if (hwcap & PPC_FEATURE_ARCH_2_05)
run_test ("-arch_2_06,-arch_2_05","__memcpy_power6");
- run_test ("-arch_2_06,-arch_2_05,-power5+,-power5,-power4", "__memcpy_power4");
+ run_test ("-arch_2_06,-arch_2_05,-power5+,-power5,-power4",
+ "__memcpy_power4");
+ /* Also run with valid, but empty settings. */
+ run_test (",-,-arch_2_06,-arch_2_05,-power5+,-power5,,-power4,-",
+ "__memcpy_power4");
}
else
{