From b1dca6a878144456ce0365f45c8588e49b49700e Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Jan 06 2021 18:08:38 +0000 Subject: import glibc-2.28-145.el8 --- diff --git a/SOURCES/glibc-rh1817513-1.patch b/SOURCES/glibc-rh1817513-1.patch new file mode 100644 index 0000000..5bfd84c --- /dev/null +++ b/SOURCES/glibc-rh1817513-1.patch @@ -0,0 +1,53 @@ +commit 82c80ac2ebf9acc81ec460adfd951d4884836c7c +Author: H.J. Lu +Date: Wed Aug 1 04:57:34 2018 -0700 + + x86: Rename get_common_indeces to get_common_indices + + Reviewed-by: Carlos O'Donell + + * sysdeps/x86/cpu-features.c (get_common_indeces): Renamed to + ... + (get_common_indices): This. + (init_cpu_features): Updated. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index ac74f408343191b0..41f2d15fa5c8a756 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -56,7 +56,7 @@ get_extended_indices (struct cpu_features *cpu_features) + } + + static void +-get_common_indeces (struct cpu_features *cpu_features, ++get_common_indices (struct cpu_features *cpu_features, + unsigned int *family, unsigned int *model, + unsigned int *extended_model, unsigned int *stepping) + { +@@ -234,7 +234,7 @@ init_cpu_features (struct cpu_features *cpu_features) + + kind = arch_kind_intel; + +- get_common_indeces (cpu_features, &family, &model, &extended_model, ++ get_common_indices (cpu_features, &family, &model, &extended_model, + &stepping); + + get_extended_indices (cpu_features); +@@ -356,7 +356,7 @@ init_cpu_features (struct cpu_features *cpu_features) + + kind = arch_kind_amd; + +- get_common_indeces (cpu_features, &family, &model, &extended_model, ++ get_common_indices (cpu_features, &family, &model, &extended_model, + &stepping); + + get_extended_indices (cpu_features); +@@ -393,7 +393,7 @@ init_cpu_features (struct cpu_features *cpu_features) + else + { + kind = arch_kind_other; +- get_common_indeces (cpu_features, NULL, NULL, NULL, NULL); ++ get_common_indices (cpu_features, NULL, NULL, NULL, NULL); + } + + /* Support i586 if CX8 is available. */ diff --git a/SOURCES/glibc-rh1817513-10.patch b/SOURCES/glibc-rh1817513-10.patch new file mode 100644 index 0000000..fe934ce --- /dev/null +++ b/SOURCES/glibc-rh1817513-10.patch @@ -0,0 +1,41 @@ +commit 2dd8e58cc533ee840d37725b11bc0dc0308a5dc0 +Author: H.J. Lu +Date: Sun Oct 21 00:37:11 2018 -0700 + + x86: Don't include + + Use __builtin_ia32_rdtsc directly since including makes + building glibc very slow. On Intel Core i5-6260U, this patch reduces + x86-64 build time from 8 minutes 33 seconds to 3 minutes 48 seconds + with "make -j4" and GCC 8.2.1. + + * sysdeps/x86/hp-timing.h: Don't include . + (HP_TIMING_NOW): Replace _rdtsc with __builtin_ia32_rdtsc. + +diff --git a/sysdeps/x86/hp-timing.h b/sysdeps/x86/hp-timing.h +index 1c20e9d8289cc15b..77a1360748ca4535 100644 +--- a/sysdeps/x86/hp-timing.h ++++ b/sysdeps/x86/hp-timing.h +@@ -22,8 +22,6 @@ + #include + + #if MINIMUM_ISA == 686 || MINIMUM_ISA == 8664 +-# include +- + /* We always assume having the timestamp register. */ + # define HP_TIMING_AVAIL (1) + # define HP_SMALL_TIMING_AVAIL (1) +@@ -38,8 +36,11 @@ typedef unsigned long long int hp_timing_t; + might not be 100% accurate since there might be some more instructions + running in this moment. This could be changed by using a barrier like + 'cpuid' right before the `rdtsc' instruciton. But we are not interested +- in accurate clock cycles here so we don't do this. */ +-# define HP_TIMING_NOW(Var) ((Var) = _rdtsc ()) ++ in accurate clock cycles here so we don't do this. ++ ++ NB: Use __builtin_ia32_rdtsc directly since including ++ makes building glibc very slow. */ ++# define HP_TIMING_NOW(Var) ((Var) = __builtin_ia32_rdtsc ()) + + # include + #else diff --git a/SOURCES/glibc-rh1817513-100.patch b/SOURCES/glibc-rh1817513-100.patch new file mode 100644 index 0000000..9917f06 --- /dev/null +++ b/SOURCES/glibc-rh1817513-100.patch @@ -0,0 +1,82 @@ +commit bb5fd5ce64b598085bdb8a05cb53777480fe093c +Author: Florian Weimer +Date: Fri Oct 9 10:13:14 2020 +0200 + + elf: Do not pass GLRO(dl_platform), GLRO(dl_platformlen) to _dl_important_hwcaps + + In the current code, the function can easily obtain the information + on its own. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c +index ae2e4ca7fe91d407..82ee89c36a1eb4ab 100644 +--- a/elf/dl-hwcaps.c ++++ b/elf/dl-hwcaps.c +@@ -28,13 +28,12 @@ + + /* Return an array of useful/necessary hardware capability names. */ + const struct r_strlenpair * +-_dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, +- size_t *max_capstrlen) ++_dl_important_hwcaps (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 = platform != NULL; ++ size_t cnt = GLRO (dl_platform) != NULL; + size_t n, m; + size_t total; + struct r_strlenpair *result; +@@ -60,10 +59,10 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, + masked ^= 1ULL << n; + ++m; + } +- if (platform != NULL) ++ if (GLRO (dl_platform) != NULL) + { +- temp[m].str = platform; +- temp[m].len = platform_len; ++ temp[m].str = GLRO (dl_platform); ++ temp[m].len = GLRO (dl_platformlen); + ++m; + } + +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 2eb4f35b2467f7d8..d2be21ea7d1545fe 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -697,8 +697,7 @@ _dl_init_paths (const char *llp, const char *source) + + #ifdef SHARED + /* Get the capabilities. */ +- capstr = _dl_important_hwcaps (GLRO(dl_platform), GLRO(dl_platformlen), +- &ncapstr, &max_capstrlen); ++ capstr = _dl_important_hwcaps (&ncapstr, &max_capstrlen); + #endif + + /* First set up the rest of the default search directory entries. */ +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index aa006afafaf46dee..2c9fdeb286bdaadf 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1069,12 +1069,12 @@ extern void _dl_show_auxv (void) attribute_hidden; + other. */ + extern char *_dl_next_ld_env_entry (char ***position) attribute_hidden; + +-/* Return an array with the names of the important hardware capabilities. */ +-extern const struct r_strlenpair *_dl_important_hwcaps (const char *platform, +- size_t paltform_len, +- size_t *sz, +- size_t *max_capstrlen) +- 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, ++ size_t *max_capstrlen) ++ attribute_hidden; + + /* Look up NAME in ld.so.cache and return the file name stored there, + or null if none is found. Caller must free returned string. */ diff --git a/SOURCES/glibc-rh1817513-101.patch b/SOURCES/glibc-rh1817513-101.patch new file mode 100644 index 0000000..bcf0aae --- /dev/null +++ b/SOURCES/glibc-rh1817513-101.patch @@ -0,0 +1,65 @@ +commit 7674695cf7e28528be7243ceb30c9a600bbaa7b5 +Author: H.J. Lu +Date: Thu Oct 8 08:19:15 2020 -0700 + + : Add Intel UINTR support + + Add Intel UINTR support to . + +diff --git a/manual/platform.texi b/manual/platform.texi +index 95b0ed0642c9f8a9..0dd12a4353a93bf2 100644 +--- a/manual/platform.texi ++++ b/manual/platform.texi +@@ -583,6 +583,9 @@ using a TSC deadline value. + @item + @code{TSXLDTRK} -- TSXLDTRK instructions. + ++@item ++@code{UINTR} -- User interrupts. ++ + @item + @code{UMIP} -- User-mode instruction prevention. + +diff --git a/sysdeps/x86/sys/platform/x86.h b/sysdeps/x86/sys/platform/x86.h +index bcc81ab5f8ac8265..2760b81a56e6c7d7 100644 +--- a/sysdeps/x86/sys/platform/x86.h ++++ b/sysdeps/x86/sys/platform/x86.h +@@ -241,7 +241,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + #define bit_cpu_AVX512_4VNNIW (1u << 2) + #define bit_cpu_AVX512_4FMAPS (1u << 3) + #define bit_cpu_FSRM (1u << 4) +-#define bit_cpu_INDEX_7_EDX_5 (1u << 5) ++#define bit_cpu_UINTR (1u << 5) + #define bit_cpu_INDEX_7_EDX_6 (1u << 6) + #define bit_cpu_INDEX_7_EDX_7 (1u << 7) + #define bit_cpu_AVX512_VP2INTERSECT (1u << 8) +@@ -460,7 +460,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + #define index_cpu_AVX512_4VNNIW COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512_4FMAPS COMMON_CPUID_INDEX_7 + #define index_cpu_FSRM COMMON_CPUID_INDEX_7 +-#define index_cpu_INDEX_7_EDX_5 COMMON_CPUID_INDEX_7 ++#define index_cpu_UINTR COMMON_CPUID_INDEX_7 + #define index_cpu_INDEX_7_EDX_6 COMMON_CPUID_INDEX_7 + #define index_cpu_INDEX_7_EDX_7 COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512_VP2INTERSECT COMMON_CPUID_INDEX_7 +@@ -679,7 +679,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + #define reg_AVX512_4VNNIW edx + #define reg_AVX512_4FMAPS edx + #define reg_FSRM edx +-#define reg_INDEX_7_EDX_5 edx ++#define reg_UINTR edx + #define reg_INDEX_7_EDX_6 edx + #define reg_INDEX_7_EDX_7 edx + #define reg_AVX512_VP2INTERSECT edx +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index 3ec94e0c9a191f36..6fa092a8c10486a0 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -180,6 +180,7 @@ do_test (void) + CHECK_CPU_FEATURE (AVX512_4VNNIW); + CHECK_CPU_FEATURE (AVX512_4FMAPS); + CHECK_CPU_FEATURE (FSRM); ++ CHECK_CPU_FEATURE (UINTR); + CHECK_CPU_FEATURE (AVX512_VP2INTERSECT); + CHECK_CPU_FEATURE (MD_CLEAR); + CHECK_CPU_FEATURE (SERIALIZE); diff --git a/SOURCES/glibc-rh1817513-102.patch b/SOURCES/glibc-rh1817513-102.patch new file mode 100644 index 0000000..73fa041 --- /dev/null +++ b/SOURCES/glibc-rh1817513-102.patch @@ -0,0 +1,86 @@ +commit ebe454bcca6a5421512ad228595a5391506e990a +Author: H.J. Lu +Date: Thu Oct 8 08:24:47 2020 -0700 + + : Add AVX512_FP16 support + + Add AVX512_FP16 support to . + +diff --git a/manual/platform.texi b/manual/platform.texi +index 0dd12a4353a93bf2..4f5fdff9d9ef16fd 100644 +--- a/manual/platform.texi ++++ b/manual/platform.texi +@@ -210,6 +210,9 @@ The supported processor features are: + @item + @code{AVX512_BITALG} -- The AVX512_BITALG instruction extensions. + ++@item ++@code{AVX512_FP16} -- The AVX512_FP16 instruction extensions. ++ + @item + @code{AVX512_IFMA} -- The AVX512_IFMA instruction extensions. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 7f2ff00f2b4b45f2..67f137259fccf4ad 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -175,6 +175,8 @@ update_usable (struct cpu_features *cpu_features) + AVX512_VP2INTERSECT); + /* Determine if AVX512_BF16 is usable. */ + CPU_FEATURE_SET_USABLE (cpu_features, AVX512_BF16); ++ /* Determine if AVX512_FP16 is usable. */ ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512_FP16); + } + } + } +diff --git a/sysdeps/x86/sys/platform/x86.h b/sysdeps/x86/sys/platform/x86.h +index 2760b81a56e6c7d7..0b18257e20105ea4 100644 +--- a/sysdeps/x86/sys/platform/x86.h ++++ b/sysdeps/x86/sys/platform/x86.h +@@ -259,7 +259,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + #define bit_cpu_IBT (1u << 20) + #define bit_cpu_INDEX_7_EDX_21 (1u << 21) + #define bit_cpu_AMX_BF16 (1u << 22) +-#define bit_cpu_INDEX_7_EDX_23 (1u << 23) ++#define bit_cpu_AVX512_FP16 (1u << 23) + #define bit_cpu_AMX_TILE (1u << 24) + #define bit_cpu_AMX_INT8 (1u << 25) + #define bit_cpu_IBRS_IBPB (1u << 26) +@@ -478,7 +478,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + #define index_cpu_IBT COMMON_CPUID_INDEX_7 + #define index_cpu_INDEX_7_EDX_21 COMMON_CPUID_INDEX_7 + #define index_cpu_AMX_BF16 COMMON_CPUID_INDEX_7 +-#define index_cpu_INDEX_7_EDX_23 COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512_FP16 COMMON_CPUID_INDEX_7 + #define index_cpu_AMX_TILE COMMON_CPUID_INDEX_7 + #define index_cpu_AMX_INT8 COMMON_CPUID_INDEX_7 + #define index_cpu_IBRS_IBPB COMMON_CPUID_INDEX_7 +@@ -697,7 +697,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + #define reg_IBT edx + #define reg_INDEX_7_EDX_21 edx + #define reg_AMX_BF16 edx +-#define reg_INDEX_7_EDX_23 edx ++#define reg_AVX512_FP16 edx + #define reg_AMX_TILE edx + #define reg_AMX_INT8 edx + #define reg_IBRS_IBPB edx +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index 6fa092a8c10486a0..bcdeb243a82c4adc 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -189,6 +189,7 @@ do_test (void) + CHECK_CPU_FEATURE (PCONFIG); + CHECK_CPU_FEATURE (IBT); + CHECK_CPU_FEATURE (AMX_BF16); ++ CHECK_CPU_FEATURE (AVX512_FP16); + CHECK_CPU_FEATURE (AMX_TILE); + CHECK_CPU_FEATURE (AMX_INT8); + CHECK_CPU_FEATURE (IBRS_IBPB); +@@ -343,6 +344,7 @@ do_test (void) + CHECK_CPU_FEATURE_USABLE (TSXLDTRK); + CHECK_CPU_FEATURE_USABLE (PCONFIG); + CHECK_CPU_FEATURE_USABLE (AMX_BF16); ++ CHECK_CPU_FEATURE_USABLE (AVX512_FP16); + CHECK_CPU_FEATURE_USABLE (AMX_TILE); + CHECK_CPU_FEATURE_USABLE (AMX_INT8); + CHECK_CPU_FEATURE_USABLE (IBRS_IBPB); diff --git a/SOURCES/glibc-rh1817513-103.patch b/SOURCES/glibc-rh1817513-103.patch new file mode 100644 index 0000000..0c4db8f --- /dev/null +++ b/SOURCES/glibc-rh1817513-103.patch @@ -0,0 +1,83 @@ +commit 875a50ff63b2c86af770949d563ee851d08eb46e +Author: H.J. Lu +Date: Thu Oct 8 08:33:45 2020 -0700 + + : Add AVX-VNNI support + + Add AVX-VNNI support to . + +diff --git a/manual/platform.texi b/manual/platform.texi +index 4f5fdff9d9ef16fd..283f255679643d3e 100644 +--- a/manual/platform.texi ++++ b/manual/platform.texi +@@ -198,6 +198,9 @@ The supported processor features are: + @item + @code{AVX2} -- The AVX2 instruction extensions. + ++@item ++@code{AVX_VNNI} -- The AVX-VNNI instruction extensions. ++ + @item + @code{AVX512_4FMAPS} -- The AVX512_4FMAPS instruction extensions. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 67f137259fccf4ad..3e5b9341c9756009 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -119,6 +119,8 @@ update_usable (struct cpu_features *cpu_features) + cpu_features->preferred[index_arch_AVX_Fast_Unaligned_Load] + |= bit_arch_AVX_Fast_Unaligned_Load; + } ++ /* Determine if AVX-VNNI is usable. */ ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX_VNNI); + /* Determine if FMA is usable. */ + CPU_FEATURE_SET_USABLE (cpu_features, FMA); + /* Determine if VAES is usable. */ +diff --git a/sysdeps/x86/sys/platform/x86.h b/sysdeps/x86/sys/platform/x86.h +index 0b18257e20105ea4..0942ad7a7f7d4ce2 100644 +--- a/sysdeps/x86/sys/platform/x86.h ++++ b/sysdeps/x86/sys/platform/x86.h +@@ -311,6 +311,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* COMMON_CPUID_INDEX_7_ECX_1. */ + + /* EAX. */ ++#define bit_cpu_AVX_VNNI (1u << 4) + #define bit_cpu_AVX512_BF16 (1u << 5) + + /* COMMON_CPUID_INDEX_19. */ +@@ -530,6 +531,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* COMMON_CPUID_INDEX_7_ECX_1. */ + + /* EAX. */ ++#define index_cpu_AVX_VNNI COMMON_CPUID_INDEX_7_ECX_1 + #define index_cpu_AVX512_BF16 COMMON_CPUID_INDEX_7_ECX_1 + + /* COMMON_CPUID_INDEX_19. */ +@@ -749,6 +751,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* COMMON_CPUID_INDEX_7_ECX_1. */ + + /* EAX. */ ++#define reg_AVX_VNNI eax + #define reg_AVX512_BF16 eax + + /* COMMON_CPUID_INDEX_19. */ +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index bcdeb243a82c4adc..8894d9f08ac36633 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -219,6 +219,7 @@ do_test (void) + CHECK_CPU_FEATURE (XFD); + CHECK_CPU_FEATURE (INVARIANT_TSC); + CHECK_CPU_FEATURE (WBNOINVD); ++ CHECK_CPU_FEATURE (AVX_VNNI); + CHECK_CPU_FEATURE (AVX512_BF16); + CHECK_CPU_FEATURE (AESKLE); + CHECK_CPU_FEATURE (WIDE_KL); +@@ -374,6 +375,7 @@ do_test (void) + CHECK_CPU_FEATURE_USABLE (XFD); + CHECK_CPU_FEATURE_USABLE (INVARIANT_TSC); + CHECK_CPU_FEATURE_USABLE (WBNOINVD); ++ CHECK_CPU_FEATURE_USABLE (AVX_VNNI); + CHECK_CPU_FEATURE_USABLE (AVX512_BF16); + CHECK_CPU_FEATURE_USABLE (AESKLE); + CHECK_CPU_FEATURE_USABLE (WIDE_KL); diff --git a/SOURCES/glibc-rh1817513-104.patch b/SOURCES/glibc-rh1817513-104.patch new file mode 100644 index 0000000..8e0f358 --- /dev/null +++ b/SOURCES/glibc-rh1817513-104.patch @@ -0,0 +1,62 @@ +commit c712401bc641b66d9bd558884751d8979e2e0e96 +Author: H.J. Lu +Date: Thu Oct 8 08:38:03 2020 -0700 + + : Add Intel HRESET support + + Add Intel HRESET support to . + +diff --git a/manual/platform.texi b/manual/platform.texi +index 283f255679643d3e..1e44525552f5bda5 100644 +--- a/manual/platform.texi ++++ b/manual/platform.texi +@@ -346,6 +346,9 @@ extensions. + @item + @code{HTT} -- Max APIC IDs reserved field is Valid. + ++@item ++@code{HRESET} -- History reset. ++ + @item + @code{HYBRID} -- Hybrid processor. + +diff --git a/sysdeps/x86/sys/platform/x86.h b/sysdeps/x86/sys/platform/x86.h +index 0942ad7a7f7d4ce2..357c6f1c5605d82d 100644 +--- a/sysdeps/x86/sys/platform/x86.h ++++ b/sysdeps/x86/sys/platform/x86.h +@@ -313,6 +313,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* EAX. */ + #define bit_cpu_AVX_VNNI (1u << 4) + #define bit_cpu_AVX512_BF16 (1u << 5) ++#define bit_cpu_HRESET (1u << 22) + + /* COMMON_CPUID_INDEX_19. */ + +@@ -533,6 +534,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* EAX. */ + #define index_cpu_AVX_VNNI COMMON_CPUID_INDEX_7_ECX_1 + #define index_cpu_AVX512_BF16 COMMON_CPUID_INDEX_7_ECX_1 ++#define index_cpu_HRESET COMMON_CPUID_INDEX_7_ECX_1 + + /* COMMON_CPUID_INDEX_19. */ + +@@ -753,6 +755,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* EAX. */ + #define reg_AVX_VNNI eax + #define reg_AVX512_BF16 eax ++#define reg_HRESET eax + + /* COMMON_CPUID_INDEX_19. */ + +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index 8894d9f08ac36633..1516af1d461a801b 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -221,6 +221,7 @@ do_test (void) + CHECK_CPU_FEATURE (WBNOINVD); + CHECK_CPU_FEATURE (AVX_VNNI); + CHECK_CPU_FEATURE (AVX512_BF16); ++ CHECK_CPU_FEATURE (HRESET); + CHECK_CPU_FEATURE (AESKLE); + CHECK_CPU_FEATURE (WIDE_KL); + diff --git a/SOURCES/glibc-rh1817513-105.patch b/SOURCES/glibc-rh1817513-105.patch new file mode 100644 index 0000000..5767dbc --- /dev/null +++ b/SOURCES/glibc-rh1817513-105.patch @@ -0,0 +1,107 @@ +commit 428985c436f442e91e27173bccaf28f547233586 +Author: H.J. Lu +Date: Thu Oct 8 08:50:44 2020 -0700 + + : Add FSRCS/FSRS/FZLRM support + + Add Fast Short REP CMP and SCA (FSRCS), Fast Short REP STO (FSRS) and + Fast Zero-Length REP MOV (FZLRM) support to . + +diff --git a/manual/platform.texi b/manual/platform.texi +index 1e44525552f5bda5..8fec2933d6442823 100644 +--- a/manual/platform.texi ++++ b/manual/platform.texi +@@ -331,12 +331,21 @@ extensions. + @item + @code{FSGSBASE} -- RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE instructions. + ++@item ++@code{FSRCS} -- Fast Short REP CMP and SCA. ++ + @item + @code{FSRM} -- Fast Short REP MOV. + ++@item ++@code{FSRS} -- Fast Short REP STO. ++ + @item + @code{FXSR} -- FXSAVE and FXRSTOR instructions. + ++@item ++@code{FZLRM} -- Fast Zero-Length REP MOV. ++ + @item + @code{GFNI} -- GFNI instruction extensions. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 3e5b9341c9756009..5f0548fe08134236 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -93,6 +93,9 @@ update_usable (struct cpu_features *cpu_features) + CPU_FEATURE_SET_USABLE (cpu_features, TBM); + CPU_FEATURE_SET_USABLE (cpu_features, RDTSCP); + CPU_FEATURE_SET_USABLE (cpu_features, WBNOINVD); ++ CPU_FEATURE_SET_USABLE (cpu_features, FZLRM); ++ CPU_FEATURE_SET_USABLE (cpu_features, FSRS); ++ CPU_FEATURE_SET_USABLE (cpu_features, FSRCS); + + /* Can we call xgetbv? */ + if (CPU_FEATURES_CPU_P (cpu_features, OSXSAVE)) +diff --git a/sysdeps/x86/sys/platform/x86.h b/sysdeps/x86/sys/platform/x86.h +index 357c6f1c5605d82d..e5cc7c683a20b5a0 100644 +--- a/sysdeps/x86/sys/platform/x86.h ++++ b/sysdeps/x86/sys/platform/x86.h +@@ -313,6 +313,9 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* EAX. */ + #define bit_cpu_AVX_VNNI (1u << 4) + #define bit_cpu_AVX512_BF16 (1u << 5) ++#define bit_cpu_FZLRM (1u << 10) ++#define bit_cpu_FSRS (1u << 11) ++#define bit_cpu_FSRCS (1u << 12) + #define bit_cpu_HRESET (1u << 22) + + /* COMMON_CPUID_INDEX_19. */ +@@ -534,6 +537,9 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* EAX. */ + #define index_cpu_AVX_VNNI COMMON_CPUID_INDEX_7_ECX_1 + #define index_cpu_AVX512_BF16 COMMON_CPUID_INDEX_7_ECX_1 ++#define index_cpu_FZLRM COMMON_CPUID_INDEX_7_ECX_1 ++#define index_cpu_FSRS COMMON_CPUID_INDEX_7_ECX_1 ++#define index_cpu_FSRCS COMMON_CPUID_INDEX_7_ECX_1 + #define index_cpu_HRESET COMMON_CPUID_INDEX_7_ECX_1 + + /* COMMON_CPUID_INDEX_19. */ +@@ -755,6 +761,9 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* EAX. */ + #define reg_AVX_VNNI eax + #define reg_AVX512_BF16 eax ++#define reg_FZLRM eax ++#define reg_FSRS eax ++#define reg_FSRCS eax + #define reg_HRESET eax + + /* COMMON_CPUID_INDEX_19. */ +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index 1516af1d461a801b..2763deb6d008597f 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -221,6 +221,9 @@ do_test (void) + CHECK_CPU_FEATURE (WBNOINVD); + CHECK_CPU_FEATURE (AVX_VNNI); + CHECK_CPU_FEATURE (AVX512_BF16); ++ CHECK_CPU_FEATURE (FZLRM); ++ CHECK_CPU_FEATURE (FSRS); ++ CHECK_CPU_FEATURE (FSRCS); + CHECK_CPU_FEATURE (HRESET); + CHECK_CPU_FEATURE (AESKLE); + CHECK_CPU_FEATURE (WIDE_KL); +@@ -378,6 +381,9 @@ do_test (void) + CHECK_CPU_FEATURE_USABLE (WBNOINVD); + CHECK_CPU_FEATURE_USABLE (AVX_VNNI); + CHECK_CPU_FEATURE_USABLE (AVX512_BF16); ++ CHECK_CPU_FEATURE_USABLE (FZLRM); ++ CHECK_CPU_FEATURE_USABLE (FSRS); ++ CHECK_CPU_FEATURE_USABLE (FSRCS); + CHECK_CPU_FEATURE_USABLE (AESKLE); + CHECK_CPU_FEATURE_USABLE (WIDE_KL); + diff --git a/SOURCES/glibc-rh1817513-106.patch b/SOURCES/glibc-rh1817513-106.patch new file mode 100644 index 0000000..9e30fb5 --- /dev/null +++ b/SOURCES/glibc-rh1817513-106.patch @@ -0,0 +1,18 @@ +commit 21181d1c7b181c4bb71e587c7944e100d923b393 +Author: Matheus Castanho +Date: Mon Oct 12 11:28:18 2020 +0200 + + elf: Add missing header to elf/dl-usage.c + +diff --git a/elf/dl-usage.c b/elf/dl-usage.c +index c07f43835bd771cf..796ad38b43c2211b 100644 +--- a/elf/dl-usage.c ++++ b/elf/dl-usage.c +@@ -22,6 +22,7 @@ + #include + #include "version.h" + ++#include + #include + + void diff --git a/SOURCES/glibc-rh1817513-107.patch b/SOURCES/glibc-rh1817513-107.patch new file mode 100644 index 0000000..ac33688 --- /dev/null +++ b/SOURCES/glibc-rh1817513-107.patch @@ -0,0 +1,2017 @@ +commit 0f09154c64005e78b61484ae87b5ea2028051ea0 +Author: H.J. Lu +Date: Sat Jul 4 06:35:49 2020 -0700 + + x86: Initialize CPU info via IFUNC relocation [BZ 26203] + + X86 CPU features in ld.so are initialized by init_cpu_features, which is + invoked by DL_PLATFORM_INIT from _dl_sysdep_start. But when ld.so is + loaded by static executable, DL_PLATFORM_INIT is never called. Also + x86 cache info in libc.o and libc.a is initialized by a constructor + which may be called too late. Since some fields in _rtld_global_ro + in ld.so are initialized by dynamic relocation, we can also initialize + x86 CPU features in _rtld_global_ro in ld.so and cache info in libc.so + by initializing dummy function pointers in ld.so and libc.so via IFUNC + relocation. + + Key points: + + 1. IFUNC is always supported, independent of --enable-multi-arch or + --disable-multi-arch. Linker generates IFUNC relocations from input + IFUNC objects and ld.so performs IFUNC relocations. + 2. There are no IFUNC dependencies in ld.so before dynamic relocation + have been performed, + 3. The x86 CPU features in ld.so is initialized by DL_PLATFORM_INIT + in dynamic executable and by IFUNC relocation in dlopen in static + executable. + 4. The x86 cache info in libc.o is initialized by IFUNC relocation. + 5. In libc.a, both x86 CPU features and cache info are initialized from + ARCH_INIT_CPU_FEATURES, not by IFUNC relocation, before __libc_early_init + is called. + + Note: _dl_x86_init_cpu_features can be called more than once from + DL_PLATFORM_INIT and during relocation in ld.so. + +Conflicts: + sysdeps/x86/cacheinfo.c + (Copyright year difference, and AMD Zen cache computation + backports downstream. These changes were reapplied to + sysdeps/x86/cacheinfo.h, mirroring the upstream refactoring + in the backported commit.) + sysdeps/x86/dl-get-cpu-features.c + (Copyright year difference.) + +diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h +index 8c959e39457c8c41..e5776ef7bc8ad749 100644 +--- a/sysdeps/i386/dl-machine.h ++++ b/sysdeps/i386/dl-machine.h +@@ -25,7 +25,6 @@ + #include + #include + #include +-#include + + /* Return nonzero iff ELF header is compatible with the running host. */ + static inline int __attribute__ ((unused)) +@@ -248,9 +247,9 @@ static inline void __attribute__ ((unused)) + dl_platform_init (void) + { + #if IS_IN (rtld) +- /* init_cpu_features has been called early from __libc_start_main in +- static executable. */ +- init_cpu_features (&GLRO(dl_x86_cpu_features)); ++ /* _dl_x86_init_cpu_features is a wrapper for init_cpu_features which ++ has been called early from __libc_start_main in static executable. */ ++ _dl_x86_init_cpu_features (); + #else + if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0') + /* Avoid an empty string which would disturb us. */ +diff --git a/sysdeps/x86/cacheinfo.c b/sysdeps/x86/cacheinfo.c +index fdfe2684759d968c..84b10f6dd8d23a51 100644 +--- a/sysdeps/x86/cacheinfo.c ++++ b/sysdeps/x86/cacheinfo.c +@@ -1,5 +1,5 @@ +-/* x86_64 cache info. +- Copyright (C) 2003-2018 Free Software Foundation, Inc. ++/* x86 cache info. ++ Copyright (C) 2003-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 +@@ -19,473 +19,10 @@ + #if IS_IN (libc) + + #include +-#include +-#include + #include + #include +-#include +- +-static const struct intel_02_cache_info +-{ +- unsigned char idx; +- unsigned char assoc; +- unsigned char linesize; +- unsigned char rel_name; +- unsigned int size; +-} intel_02_known [] = +- { +-#define M(sc) ((sc) - _SC_LEVEL1_ICACHE_SIZE) +- { 0x06, 4, 32, M(_SC_LEVEL1_ICACHE_SIZE), 8192 }, +- { 0x08, 4, 32, M(_SC_LEVEL1_ICACHE_SIZE), 16384 }, +- { 0x09, 4, 32, M(_SC_LEVEL1_ICACHE_SIZE), 32768 }, +- { 0x0a, 2, 32, M(_SC_LEVEL1_DCACHE_SIZE), 8192 }, +- { 0x0c, 4, 32, M(_SC_LEVEL1_DCACHE_SIZE), 16384 }, +- { 0x0d, 4, 64, M(_SC_LEVEL1_DCACHE_SIZE), 16384 }, +- { 0x0e, 6, 64, M(_SC_LEVEL1_DCACHE_SIZE), 24576 }, +- { 0x21, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, +- { 0x22, 4, 64, M(_SC_LEVEL3_CACHE_SIZE), 524288 }, +- { 0x23, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 1048576 }, +- { 0x25, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 2097152 }, +- { 0x29, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 4194304 }, +- { 0x2c, 8, 64, M(_SC_LEVEL1_DCACHE_SIZE), 32768 }, +- { 0x30, 8, 64, M(_SC_LEVEL1_ICACHE_SIZE), 32768 }, +- { 0x39, 4, 64, M(_SC_LEVEL2_CACHE_SIZE), 131072 }, +- { 0x3a, 6, 64, M(_SC_LEVEL2_CACHE_SIZE), 196608 }, +- { 0x3b, 2, 64, M(_SC_LEVEL2_CACHE_SIZE), 131072 }, +- { 0x3c, 4, 64, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, +- { 0x3d, 6, 64, M(_SC_LEVEL2_CACHE_SIZE), 393216 }, +- { 0x3e, 4, 64, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, +- { 0x3f, 2, 64, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, +- { 0x41, 4, 32, M(_SC_LEVEL2_CACHE_SIZE), 131072 }, +- { 0x42, 4, 32, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, +- { 0x43, 4, 32, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, +- { 0x44, 4, 32, M(_SC_LEVEL2_CACHE_SIZE), 1048576 }, +- { 0x45, 4, 32, M(_SC_LEVEL2_CACHE_SIZE), 2097152 }, +- { 0x46, 4, 64, M(_SC_LEVEL3_CACHE_SIZE), 4194304 }, +- { 0x47, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 8388608 }, +- { 0x48, 12, 64, M(_SC_LEVEL2_CACHE_SIZE), 3145728 }, +- { 0x49, 16, 64, M(_SC_LEVEL2_CACHE_SIZE), 4194304 }, +- { 0x4a, 12, 64, M(_SC_LEVEL3_CACHE_SIZE), 6291456 }, +- { 0x4b, 16, 64, M(_SC_LEVEL3_CACHE_SIZE), 8388608 }, +- { 0x4c, 12, 64, M(_SC_LEVEL3_CACHE_SIZE), 12582912 }, +- { 0x4d, 16, 64, M(_SC_LEVEL3_CACHE_SIZE), 16777216 }, +- { 0x4e, 24, 64, M(_SC_LEVEL2_CACHE_SIZE), 6291456 }, +- { 0x60, 8, 64, M(_SC_LEVEL1_DCACHE_SIZE), 16384 }, +- { 0x66, 4, 64, M(_SC_LEVEL1_DCACHE_SIZE), 8192 }, +- { 0x67, 4, 64, M(_SC_LEVEL1_DCACHE_SIZE), 16384 }, +- { 0x68, 4, 64, M(_SC_LEVEL1_DCACHE_SIZE), 32768 }, +- { 0x78, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 1048576 }, +- { 0x79, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 131072 }, +- { 0x7a, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, +- { 0x7b, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, +- { 0x7c, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 1048576 }, +- { 0x7d, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 2097152 }, +- { 0x7f, 2, 64, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, +- { 0x80, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, +- { 0x82, 8, 32, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, +- { 0x83, 8, 32, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, +- { 0x84, 8, 32, M(_SC_LEVEL2_CACHE_SIZE), 1048576 }, +- { 0x85, 8, 32, M(_SC_LEVEL2_CACHE_SIZE), 2097152 }, +- { 0x86, 4, 64, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, +- { 0x87, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 1048576 }, +- { 0xd0, 4, 64, M(_SC_LEVEL3_CACHE_SIZE), 524288 }, +- { 0xd1, 4, 64, M(_SC_LEVEL3_CACHE_SIZE), 1048576 }, +- { 0xd2, 4, 64, M(_SC_LEVEL3_CACHE_SIZE), 2097152 }, +- { 0xd6, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 1048576 }, +- { 0xd7, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 2097152 }, +- { 0xd8, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 4194304 }, +- { 0xdc, 12, 64, M(_SC_LEVEL3_CACHE_SIZE), 2097152 }, +- { 0xdd, 12, 64, M(_SC_LEVEL3_CACHE_SIZE), 4194304 }, +- { 0xde, 12, 64, M(_SC_LEVEL3_CACHE_SIZE), 8388608 }, +- { 0xe2, 16, 64, M(_SC_LEVEL3_CACHE_SIZE), 2097152 }, +- { 0xe3, 16, 64, M(_SC_LEVEL3_CACHE_SIZE), 4194304 }, +- { 0xe4, 16, 64, M(_SC_LEVEL3_CACHE_SIZE), 8388608 }, +- { 0xea, 24, 64, M(_SC_LEVEL3_CACHE_SIZE), 12582912 }, +- { 0xeb, 24, 64, M(_SC_LEVEL3_CACHE_SIZE), 18874368 }, +- { 0xec, 24, 64, M(_SC_LEVEL3_CACHE_SIZE), 25165824 }, +- }; +- +-#define nintel_02_known (sizeof (intel_02_known) / sizeof (intel_02_known [0])) +- +-static int +-intel_02_known_compare (const void *p1, const void *p2) +-{ +- const struct intel_02_cache_info *i1; +- const struct intel_02_cache_info *i2; +- +- i1 = (const struct intel_02_cache_info *) p1; +- i2 = (const struct intel_02_cache_info *) p2; +- +- if (i1->idx == i2->idx) +- return 0; +- +- return i1->idx < i2->idx ? -1 : 1; +-} +- +- +-static long int +-__attribute__ ((noinline)) +-intel_check_word (int name, unsigned int value, bool *has_level_2, +- bool *no_level_2_or_3, +- const struct cpu_features *cpu_features) +-{ +- if ((value & 0x80000000) != 0) +- /* The register value is reserved. */ +- return 0; +- +- /* Fold the name. The _SC_ constants are always in the order SIZE, +- ASSOC, LINESIZE. */ +- int folded_rel_name = (M(name) / 3) * 3; +- +- while (value != 0) +- { +- unsigned int byte = value & 0xff; +- +- if (byte == 0x40) +- { +- *no_level_2_or_3 = true; +- +- if (folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE)) +- /* No need to look further. */ +- break; +- } +- else if (byte == 0xff) +- { +- /* CPUID leaf 0x4 contains all the information. We need to +- iterate over it. */ +- unsigned int eax; +- unsigned int ebx; +- unsigned int ecx; +- unsigned int edx; +- +- unsigned int round = 0; +- while (1) +- { +- __cpuid_count (4, round, eax, ebx, ecx, edx); +- +- enum { null = 0, data = 1, inst = 2, uni = 3 } type = eax & 0x1f; +- if (type == null) +- /* That was the end. */ +- break; +- +- unsigned int level = (eax >> 5) & 0x7; +- +- if ((level == 1 && type == data +- && folded_rel_name == M(_SC_LEVEL1_DCACHE_SIZE)) +- || (level == 1 && type == inst +- && folded_rel_name == M(_SC_LEVEL1_ICACHE_SIZE)) +- || (level == 2 && folded_rel_name == M(_SC_LEVEL2_CACHE_SIZE)) +- || (level == 3 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE)) +- || (level == 4 && folded_rel_name == M(_SC_LEVEL4_CACHE_SIZE))) +- { +- unsigned int offset = M(name) - folded_rel_name; +- +- if (offset == 0) +- /* Cache size. */ +- return (((ebx >> 22) + 1) +- * (((ebx >> 12) & 0x3ff) + 1) +- * ((ebx & 0xfff) + 1) +- * (ecx + 1)); +- if (offset == 1) +- return (ebx >> 22) + 1; +- +- assert (offset == 2); +- return (ebx & 0xfff) + 1; +- } +- +- ++round; +- } +- /* There is no other cache information anywhere else. */ +- break; +- } +- else +- { +- if (byte == 0x49 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE)) +- { +- /* Intel reused this value. For family 15, model 6 it +- specifies the 3rd level cache. Otherwise the 2nd +- level cache. */ +- unsigned int family = cpu_features->basic.family; +- unsigned int model = cpu_features->basic.model; +- +- if (family == 15 && model == 6) +- { +- /* The level 3 cache is encoded for this model like +- the level 2 cache is for other models. Pretend +- the caller asked for the level 2 cache. */ +- name = (_SC_LEVEL2_CACHE_SIZE +- + (name - _SC_LEVEL3_CACHE_SIZE)); +- folded_rel_name = M(_SC_LEVEL2_CACHE_SIZE); +- } +- } +- +- struct intel_02_cache_info *found; +- struct intel_02_cache_info search; +- +- search.idx = byte; +- found = bsearch (&search, intel_02_known, nintel_02_known, +- sizeof (intel_02_known[0]), intel_02_known_compare); +- if (found != NULL) +- { +- if (found->rel_name == folded_rel_name) +- { +- unsigned int offset = M(name) - folded_rel_name; +- +- if (offset == 0) +- /* Cache size. */ +- return found->size; +- if (offset == 1) +- return found->assoc; +- +- assert (offset == 2); +- return found->linesize; +- } +- +- if (found->rel_name == M(_SC_LEVEL2_CACHE_SIZE)) +- *has_level_2 = true; +- } +- } +- +- /* Next byte for the next round. */ +- value >>= 8; +- } +- +- /* Nothing found. */ +- return 0; +-} +- +- +-static long int __attribute__ ((noinline)) +-handle_intel (int name, const struct cpu_features *cpu_features) +-{ +- unsigned int maxidx = cpu_features->basic.max_cpuid; +- +- /* Return -1 for older CPUs. */ +- if (maxidx < 2) +- return -1; +- +- /* OK, we can use the CPUID instruction to get all info about the +- caches. */ +- unsigned int cnt = 0; +- unsigned int max = 1; +- long int result = 0; +- bool no_level_2_or_3 = false; +- bool has_level_2 = false; +- +- while (cnt++ < max) +- { +- unsigned int eax; +- unsigned int ebx; +- unsigned int ecx; +- unsigned int edx; +- __cpuid (2, eax, ebx, ecx, edx); +- +- /* The low byte of EAX in the first round contain the number of +- rounds we have to make. At least one, the one we are already +- doing. */ +- if (cnt == 1) +- { +- max = eax & 0xff; +- eax &= 0xffffff00; +- } +- +- /* Process the individual registers' value. */ +- result = intel_check_word (name, eax, &has_level_2, +- &no_level_2_or_3, cpu_features); +- if (result != 0) +- return result; +- +- result = intel_check_word (name, ebx, &has_level_2, +- &no_level_2_or_3, cpu_features); +- if (result != 0) +- return result; +- +- result = intel_check_word (name, ecx, &has_level_2, +- &no_level_2_or_3, cpu_features); +- if (result != 0) +- return result; +- +- result = intel_check_word (name, edx, &has_level_2, +- &no_level_2_or_3, cpu_features); +- if (result != 0) +- return result; +- } +- +- if (name >= _SC_LEVEL2_CACHE_SIZE && name <= _SC_LEVEL3_CACHE_LINESIZE +- && no_level_2_or_3) +- return -1; +- +- return 0; +-} +- +- +-static long int __attribute__ ((noinline)) +-handle_amd (int name) +-{ +- unsigned int eax; +- unsigned int ebx; +- unsigned int ecx; +- unsigned int edx; +- __cpuid (0x80000000, eax, ebx, ecx, edx); +- +- /* No level 4 cache (yet). */ +- if (name > _SC_LEVEL3_CACHE_LINESIZE) +- return 0; +- +- unsigned int fn = 0x80000005 + (name >= _SC_LEVEL2_CACHE_SIZE); +- if (eax < fn) +- return 0; +- +- __cpuid (fn, eax, ebx, ecx, edx); +- +- if (name < _SC_LEVEL1_DCACHE_SIZE) +- { +- name += _SC_LEVEL1_DCACHE_SIZE - _SC_LEVEL1_ICACHE_SIZE; +- ecx = edx; +- } +- +- switch (name) +- { +- case _SC_LEVEL1_DCACHE_SIZE: +- return (ecx >> 14) & 0x3fc00; +- +- case _SC_LEVEL1_DCACHE_ASSOC: +- ecx >>= 16; +- if ((ecx & 0xff) == 0xff) +- /* Fully associative. */ +- return (ecx << 2) & 0x3fc00; +- return ecx & 0xff; +- +- case _SC_LEVEL1_DCACHE_LINESIZE: +- return ecx & 0xff; +- +- case _SC_LEVEL2_CACHE_SIZE: +- return (ecx & 0xf000) == 0 ? 0 : (ecx >> 6) & 0x3fffc00; +- +- case _SC_LEVEL2_CACHE_ASSOC: +- switch ((ecx >> 12) & 0xf) +- { +- case 0: +- case 1: +- case 2: +- case 4: +- return (ecx >> 12) & 0xf; +- case 6: +- return 8; +- case 8: +- return 16; +- case 10: +- return 32; +- case 11: +- return 48; +- case 12: +- return 64; +- case 13: +- return 96; +- case 14: +- return 128; +- case 15: +- return ((ecx >> 6) & 0x3fffc00) / (ecx & 0xff); +- default: +- return 0; +- } +- /* NOTREACHED */ +- +- case _SC_LEVEL2_CACHE_LINESIZE: +- return (ecx & 0xf000) == 0 ? 0 : ecx & 0xff; +- +- case _SC_LEVEL3_CACHE_SIZE: +- return (edx & 0xf000) == 0 ? 0 : (edx & 0x3ffc0000) << 1; +- +- case _SC_LEVEL3_CACHE_ASSOC: +- switch ((edx >> 12) & 0xf) +- { +- case 0: +- case 1: +- case 2: +- case 4: +- return (edx >> 12) & 0xf; +- case 6: +- return 8; +- case 8: +- return 16; +- case 10: +- return 32; +- case 11: +- return 48; +- case 12: +- return 64; +- case 13: +- return 96; +- case 14: +- return 128; +- case 15: +- return ((edx & 0x3ffc0000) << 1) / (edx & 0xff); +- default: +- return 0; +- } +- /* NOTREACHED */ +- +- case _SC_LEVEL3_CACHE_LINESIZE: +- return (edx & 0xf000) == 0 ? 0 : edx & 0xff; +- +- default: +- assert (! "cannot happen"); +- } +- return -1; +-} +- +- +-static long int __attribute__ ((noinline)) +-handle_zhaoxin (int name) +-{ +- unsigned int eax; +- unsigned int ebx; +- unsigned int ecx; +- unsigned int edx; +- +- int folded_rel_name = (M(name) / 3) * 3; +- +- unsigned int round = 0; +- while (1) +- { +- __cpuid_count (4, round, eax, ebx, ecx, edx); +- +- enum { null = 0, data = 1, inst = 2, uni = 3 } type = eax & 0x1f; +- if (type == null) +- break; +- +- unsigned int level = (eax >> 5) & 0x7; +- +- if ((level == 1 && type == data +- && folded_rel_name == M(_SC_LEVEL1_DCACHE_SIZE)) +- || (level == 1 && type == inst +- && folded_rel_name == M(_SC_LEVEL1_ICACHE_SIZE)) +- || (level == 2 && folded_rel_name == M(_SC_LEVEL2_CACHE_SIZE)) +- || (level == 3 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE))) +- { +- unsigned int offset = M(name) - folded_rel_name; +- +- if (offset == 0) +- /* Cache size. */ +- return (((ebx >> 22) + 1) +- * (((ebx >> 12) & 0x3ff) + 1) +- * ((ebx & 0xfff) + 1) +- * (ecx + 1)); +- if (offset == 1) +- return (ebx >> 22) + 1; +- +- assert (offset == 2); +- return (ebx & 0xfff) + 1; +- } +- +- ++round; +- } +- +- /* Nothing found. */ +- return 0; +-} +- ++#include ++#include + + /* Get the value of the system variable NAME. */ + long int +@@ -509,409 +46,18 @@ __cache_sysconf (int name) + return 0; + } + ++# ifdef SHARED ++/* NB: In libc.a, cacheinfo.h is included in libc-start.c. In libc.so, ++ cacheinfo.h is included here and call init_cacheinfo by initializing ++ a dummy function pointer via IFUNC relocation after CPU features in ++ ld.so have been initialized by DL_PLATFORM_INIT or IFUNC relocation. */ ++# include ++# include + +-/* Data cache size for use in memory and string routines, typically +- L1 size, rounded to multiple of 256 bytes. */ +-long int __x86_data_cache_size_half attribute_hidden = 32 * 1024 / 2; +-long int __x86_data_cache_size attribute_hidden = 32 * 1024; +-/* Similar to __x86_data_cache_size_half, but not rounded. */ +-long int __x86_raw_data_cache_size_half attribute_hidden = 32 * 1024 / 2; +-/* Similar to __x86_data_cache_size, but not rounded. */ +-long int __x86_raw_data_cache_size attribute_hidden = 32 * 1024; +-/* Shared cache size for use in memory and string routines, typically +- L2 or L3 size, rounded to multiple of 256 bytes. */ +-long int __x86_shared_cache_size_half attribute_hidden = 1024 * 1024 / 2; +-long int __x86_shared_cache_size attribute_hidden = 1024 * 1024; +-/* Similar to __x86_shared_cache_size_half, but not rounded. */ +-long int __x86_raw_shared_cache_size_half attribute_hidden = 1024 * 1024 / 2; +-/* Similar to __x86_shared_cache_size, but not rounded. */ +-long int __x86_raw_shared_cache_size attribute_hidden = 1024 * 1024; +- +-/* Threshold to use non temporal store. */ +-long int __x86_shared_non_temporal_threshold attribute_hidden; +- +-/* Threshold to use Enhanced REP MOVSB. */ +-long int __x86_rep_movsb_threshold attribute_hidden = 2048; +- +-/* Threshold to use Enhanced REP STOSB. */ +-long int __x86_rep_stosb_threshold attribute_hidden = 2048; +- +- +-static void +-get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, +- long int core) +-{ +- unsigned int eax; +- unsigned int ebx; +- unsigned int ecx; +- unsigned int edx; +- +- /* Number of logical processors sharing L2 cache. */ +- int threads_l2; +- +- /* Number of logical processors sharing L3 cache. */ +- int threads_l3; +- +- const struct cpu_features *cpu_features = __get_cpu_features (); +- int max_cpuid = cpu_features->basic.max_cpuid; +- unsigned int family = cpu_features->basic.family; +- unsigned int model = cpu_features->basic.model; +- long int shared = *shared_ptr; +- unsigned int threads = *threads_ptr; +- bool inclusive_cache = true; +- bool support_count_mask = true; +- +- /* Try L3 first. */ +- unsigned int level = 3; +- +- if (cpu_features->basic.kind == arch_kind_zhaoxin && family == 6) +- support_count_mask = false; +- +- if (shared <= 0) +- { +- /* Try L2 otherwise. */ +- level = 2; +- shared = core; +- threads_l2 = 0; +- threads_l3 = -1; +- } +- else +- { +- threads_l2 = 0; +- threads_l3 = 0; +- } +- +- /* A value of 0 for the HTT bit indicates there is only a single +- logical processor. */ +- if (CPU_FEATURE_USABLE (HTT)) +- { +- /* Figure out the number of logical threads that share the +- highest cache level. */ +- if (max_cpuid >= 4) +- { +- int i = 0; +- +- /* Query until cache level 2 and 3 are enumerated. */ +- int check = 0x1 | (threads_l3 == 0) << 1; +- do +- { +- __cpuid_count (4, i++, eax, ebx, ecx, edx); +- +- /* There seems to be a bug in at least some Pentium Ds +- which sometimes fail to iterate all cache parameters. +- Do not loop indefinitely here, stop in this case and +- assume there is no such information. */ +- if (cpu_features->basic.kind == arch_kind_intel +- && (eax & 0x1f) == 0 ) +- goto intel_bug_no_cache_info; +- +- switch ((eax >> 5) & 0x7) +- { +- default: +- break; +- case 2: +- if ((check & 0x1)) +- { +- /* Get maximum number of logical processors +- sharing L2 cache. */ +- threads_l2 = (eax >> 14) & 0x3ff; +- check &= ~0x1; +- } +- break; +- case 3: +- if ((check & (0x1 << 1))) +- { +- /* Get maximum number of logical processors +- sharing L3 cache. */ +- threads_l3 = (eax >> 14) & 0x3ff; +- +- /* Check if L2 and L3 caches are inclusive. */ +- inclusive_cache = (edx & 0x2) != 0; +- check &= ~(0x1 << 1); +- } +- break; +- } +- } +- while (check); +- +- /* If max_cpuid >= 11, THREADS_L2/THREADS_L3 are the maximum +- numbers of addressable IDs for logical processors sharing +- the cache, instead of the maximum number of threads +- sharing the cache. */ +- if (max_cpuid >= 11 && support_count_mask) +- { +- /* Find the number of logical processors shipped in +- one core and apply count mask. */ +- i = 0; +- +- /* Count SMT only if there is L3 cache. Always count +- core if there is no L3 cache. */ +- int count = ((threads_l2 > 0 && level == 3) +- | ((threads_l3 > 0 +- || (threads_l2 > 0 && level == 2)) << 1)); +- +- while (count) +- { +- __cpuid_count (11, i++, eax, ebx, ecx, edx); +- +- int shipped = ebx & 0xff; +- int type = ecx & 0xff00; +- if (shipped == 0 || type == 0) +- break; +- else if (type == 0x100) +- { +- /* Count SMT. */ +- if ((count & 0x1)) +- { +- int count_mask; +- +- /* Compute count mask. */ +- asm ("bsr %1, %0" +- : "=r" (count_mask) : "g" (threads_l2)); +- count_mask = ~(-1 << (count_mask + 1)); +- threads_l2 = (shipped - 1) & count_mask; +- count &= ~0x1; +- } +- } +- else if (type == 0x200) +- { +- /* Count core. */ +- if ((count & (0x1 << 1))) +- { +- int count_mask; +- int threads_core +- = (level == 2 ? threads_l2 : threads_l3); +- +- /* Compute count mask. */ +- asm ("bsr %1, %0" +- : "=r" (count_mask) : "g" (threads_core)); +- count_mask = ~(-1 << (count_mask + 1)); +- threads_core = (shipped - 1) & count_mask; +- if (level == 2) +- threads_l2 = threads_core; +- else +- threads_l3 = threads_core; +- count &= ~(0x1 << 1); +- } +- } +- } +- } +- if (threads_l2 > 0) +- threads_l2 += 1; +- if (threads_l3 > 0) +- threads_l3 += 1; +- if (level == 2) +- { +- if (threads_l2) +- { +- threads = threads_l2; +- if (cpu_features->basic.kind == arch_kind_intel +- && threads > 2 +- && family == 6) +- switch (model) +- { +- case 0x37: +- case 0x4a: +- case 0x4d: +- case 0x5a: +- case 0x5d: +- /* Silvermont has L2 cache shared by 2 cores. */ +- threads = 2; +- break; +- default: +- break; +- } +- } +- } +- else if (threads_l3) +- threads = threads_l3; +- } +- else +- { +-intel_bug_no_cache_info: +- /* Assume that all logical threads share the highest cache +- level. */ +- threads +- = ((cpu_features->features[COMMON_CPUID_INDEX_1].cpuid.ebx +- >> 16) & 0xff); +- } +- +- /* Cap usage of highest cache level to the number of supported +- threads. */ +- if (shared > 0 && threads > 0) +- shared /= threads; +- } +- +- /* Account for non-inclusive L2 and L3 caches. */ +- if (!inclusive_cache) +- { +- if (threads_l2 > 0) +- core /= threads_l2; +- shared += core; +- } +- +- *shared_ptr = shared; +- *threads_ptr = threads; +-} +- +- +-static void +-__attribute__((constructor)) +-init_cacheinfo (void) +-{ +- /* Find out what brand of processor. */ +- unsigned int ebx; +- unsigned int ecx; +- unsigned int edx; +- int max_cpuid_ex; +- long int data = -1; +- long int shared = -1; +- long int core; +- unsigned int threads = 0; +- const struct cpu_features *cpu_features = __get_cpu_features (); +- +- if (cpu_features->basic.kind == arch_kind_intel) +- { +- data = handle_intel (_SC_LEVEL1_DCACHE_SIZE, cpu_features); +- core = handle_intel (_SC_LEVEL2_CACHE_SIZE, cpu_features); +- shared = handle_intel (_SC_LEVEL3_CACHE_SIZE, cpu_features); +- +- get_common_cache_info (&shared, &threads, core); +- } +- else if (cpu_features->basic.kind == arch_kind_zhaoxin) +- { +- data = handle_zhaoxin (_SC_LEVEL1_DCACHE_SIZE); +- core = handle_zhaoxin (_SC_LEVEL2_CACHE_SIZE); +- shared = handle_zhaoxin (_SC_LEVEL3_CACHE_SIZE); +- +- get_common_cache_info (&shared, &threads, core); +- } +- else if (cpu_features->basic.kind == arch_kind_amd) +- { +- data = handle_amd (_SC_LEVEL1_DCACHE_SIZE); +- long int core = handle_amd (_SC_LEVEL2_CACHE_SIZE); +- shared = handle_amd (_SC_LEVEL3_CACHE_SIZE); ++extern void __x86_cacheinfo (void) attribute_hidden; ++const void (*__x86_cacheinfo_p) (void) attribute_hidden ++ = __x86_cacheinfo; + +- /* Get maximum extended function. */ +- __cpuid (0x80000000, max_cpuid_ex, ebx, ecx, edx); +- +- if (shared <= 0) +- /* No shared L3 cache. All we have is the L2 cache. */ +- shared = core; +- else +- { +- /* Figure out the number of logical threads that share L3. */ +- if (max_cpuid_ex >= 0x80000008) +- { +- /* Get width of APIC ID. */ +- __cpuid (0x80000008, max_cpuid_ex, ebx, ecx, edx); +- threads = 1 << ((ecx >> 12) & 0x0f); +- } +- +- if (threads == 0 || cpu_features->basic.family >= 0x17) +- { +- /* If APIC ID width is not available, use logical +- processor count. */ +- __cpuid (0x00000001, max_cpuid_ex, ebx, ecx, edx); +- +- if ((edx & (1 << 28)) != 0) +- threads = (ebx >> 16) & 0xff; +- } +- +- /* Cap usage of highest cache level to the number of +- supported threads. */ +- if (threads > 0) +- shared /= threads; +- +- /* Get shared cache per ccx for Zen architectures. */ +- if (cpu_features->basic.family >= 0x17) +- { +- unsigned int eax; +- +- /* Get number of threads share the L3 cache in CCX. */ +- __cpuid_count (0x8000001D, 0x3, eax, ebx, ecx, edx); +- +- unsigned int threads_per_ccx = ((eax >> 14) & 0xfff) + 1; +- shared *= threads_per_ccx; +- } +- else +- { +- /* Account for exclusive L2 and L3 caches. */ +- shared += core; +- } +- } +- } +- +- if (cpu_features->data_cache_size != 0) +- data = cpu_features->data_cache_size; +- +- if (data > 0) +- { +- __x86_raw_data_cache_size_half = data / 2; +- __x86_raw_data_cache_size = data; +- /* Round data cache size to multiple of 256 bytes. */ +- data = data & ~255L; +- __x86_data_cache_size_half = data / 2; +- __x86_data_cache_size = data; +- } +- +- if (cpu_features->shared_cache_size != 0) +- shared = cpu_features->shared_cache_size; +- +- if (shared > 0) +- { +- __x86_raw_shared_cache_size_half = shared / 2; +- __x86_raw_shared_cache_size = shared; +- /* Round shared cache size to multiple of 256 bytes. */ +- shared = shared & ~255L; +- __x86_shared_cache_size_half = shared / 2; +- __x86_shared_cache_size = shared; +- } +- +- /* The default setting for the non_temporal threshold is 3/4 of one +- thread's share of the chip's cache. For most Intel and AMD processors +- with an initial release date between 2017 and 2020, a thread's typical +- share of the cache is from 500 KBytes to 2 MBytes. Using the 3/4 +- threshold leaves 125 KBytes to 500 KBytes of the thread's data +- in cache after a maximum temporal copy, which will maintain +- in cache a reasonable portion of the thread's stack and other +- active data. If the threshold is set higher than one thread's +- share of the cache, it has a substantial risk of negatively +- impacting the performance of other threads running on the chip. */ +- __x86_shared_non_temporal_threshold +- = (cpu_features->non_temporal_threshold != 0 +- ? cpu_features->non_temporal_threshold +- : __x86_shared_cache_size * 3 / 4); +- +- /* NB: The REP MOVSB threshold must be greater than VEC_SIZE * 8. */ +- unsigned int minimum_rep_movsb_threshold; +- /* NB: The default REP MOVSB threshold is 2048 * (VEC_SIZE / 16). */ +- unsigned int rep_movsb_threshold; +- if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F) +- && !CPU_FEATURE_PREFERRED_P (cpu_features, Prefer_No_AVX512)) +- { +- rep_movsb_threshold = 2048 * (64 / 16); +- minimum_rep_movsb_threshold = 64 * 8; +- } +- else if (CPU_FEATURE_PREFERRED_P (cpu_features, +- AVX_Fast_Unaligned_Load)) +- { +- rep_movsb_threshold = 2048 * (32 / 16); +- minimum_rep_movsb_threshold = 32 * 8; +- } +- else +- { +- rep_movsb_threshold = 2048 * (16 / 16); +- minimum_rep_movsb_threshold = 16 * 8; +- } +- if (cpu_features->rep_movsb_threshold > minimum_rep_movsb_threshold) +- __x86_rep_movsb_threshold = cpu_features->rep_movsb_threshold; +- else +- __x86_rep_movsb_threshold = rep_movsb_threshold; +- +-# if HAVE_TUNABLES +- __x86_rep_stosb_threshold = cpu_features->rep_stosb_threshold; ++__ifunc (__x86_cacheinfo, __x86_cacheinfo, NULL, void, init_cacheinfo); + # endif +-} +- + #endif +diff --git a/sysdeps/x86/cacheinfo.h b/sysdeps/x86/cacheinfo.h +new file mode 100644 +index 0000000000000000..0255696163b7b8ff +--- /dev/null ++++ b/sysdeps/x86/cacheinfo.h +@@ -0,0 +1,427 @@ ++/* x86 cache info. ++ 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 ++ ++/* Data cache size for use in memory and string routines, typically ++ L1 size, rounded to multiple of 256 bytes. */ ++long int __x86_data_cache_size_half attribute_hidden = 32 * 1024 / 2; ++long int __x86_data_cache_size attribute_hidden = 32 * 1024; ++/* Similar to __x86_data_cache_size_half, but not rounded. */ ++long int __x86_raw_data_cache_size_half attribute_hidden = 32 * 1024 / 2; ++/* Similar to __x86_data_cache_size, but not rounded. */ ++long int __x86_raw_data_cache_size attribute_hidden = 32 * 1024; ++/* Shared cache size for use in memory and string routines, typically ++ L2 or L3 size, rounded to multiple of 256 bytes. */ ++long int __x86_shared_cache_size_half attribute_hidden = 1024 * 1024 / 2; ++long int __x86_shared_cache_size attribute_hidden = 1024 * 1024; ++/* Similar to __x86_shared_cache_size_half, but not rounded. */ ++long int __x86_raw_shared_cache_size_half attribute_hidden = 1024 * 1024 / 2; ++/* Similar to __x86_shared_cache_size, but not rounded. */ ++long int __x86_raw_shared_cache_size attribute_hidden = 1024 * 1024; ++ ++/* Threshold to use non temporal store. */ ++long int __x86_shared_non_temporal_threshold attribute_hidden; ++ ++/* Threshold to use Enhanced REP MOVSB. */ ++long int __x86_rep_movsb_threshold attribute_hidden = 2048; ++ ++/* Threshold to use Enhanced REP STOSB. */ ++long int __x86_rep_stosb_threshold attribute_hidden = 2048; ++ ++static void ++get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, ++ long int core) ++{ ++ unsigned int eax; ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++ ++ /* Number of logical processors sharing L2 cache. */ ++ int threads_l2; ++ ++ /* Number of logical processors sharing L3 cache. */ ++ int threads_l3; ++ ++ const struct cpu_features *cpu_features = __get_cpu_features (); ++ int max_cpuid = cpu_features->basic.max_cpuid; ++ unsigned int family = cpu_features->basic.family; ++ unsigned int model = cpu_features->basic.model; ++ long int shared = *shared_ptr; ++ unsigned int threads = *threads_ptr; ++ bool inclusive_cache = true; ++ bool support_count_mask = true; ++ ++ /* Try L3 first. */ ++ unsigned int level = 3; ++ ++ if (cpu_features->basic.kind == arch_kind_zhaoxin && family == 6) ++ support_count_mask = false; ++ ++ if (shared <= 0) ++ { ++ /* Try L2 otherwise. */ ++ level = 2; ++ shared = core; ++ threads_l2 = 0; ++ threads_l3 = -1; ++ } ++ else ++ { ++ threads_l2 = 0; ++ threads_l3 = 0; ++ } ++ ++ /* A value of 0 for the HTT bit indicates there is only a single ++ logical processor. */ ++ if (HAS_CPU_FEATURE (HTT)) ++ { ++ /* Figure out the number of logical threads that share the ++ highest cache level. */ ++ if (max_cpuid >= 4) ++ { ++ int i = 0; ++ ++ /* Query until cache level 2 and 3 are enumerated. */ ++ int check = 0x1 | (threads_l3 == 0) << 1; ++ do ++ { ++ __cpuid_count (4, i++, eax, ebx, ecx, edx); ++ ++ /* There seems to be a bug in at least some Pentium Ds ++ which sometimes fail to iterate all cache parameters. ++ Do not loop indefinitely here, stop in this case and ++ assume there is no such information. */ ++ if (cpu_features->basic.kind == arch_kind_intel ++ && (eax & 0x1f) == 0 ) ++ goto intel_bug_no_cache_info; ++ ++ switch ((eax >> 5) & 0x7) ++ { ++ default: ++ break; ++ case 2: ++ if ((check & 0x1)) ++ { ++ /* Get maximum number of logical processors ++ sharing L2 cache. */ ++ threads_l2 = (eax >> 14) & 0x3ff; ++ check &= ~0x1; ++ } ++ break; ++ case 3: ++ if ((check & (0x1 << 1))) ++ { ++ /* Get maximum number of logical processors ++ sharing L3 cache. */ ++ threads_l3 = (eax >> 14) & 0x3ff; ++ ++ /* Check if L2 and L3 caches are inclusive. */ ++ inclusive_cache = (edx & 0x2) != 0; ++ check &= ~(0x1 << 1); ++ } ++ break; ++ } ++ } ++ while (check); ++ ++ /* If max_cpuid >= 11, THREADS_L2/THREADS_L3 are the maximum ++ numbers of addressable IDs for logical processors sharing ++ the cache, instead of the maximum number of threads ++ sharing the cache. */ ++ if (max_cpuid >= 11 && support_count_mask) ++ { ++ /* Find the number of logical processors shipped in ++ one core and apply count mask. */ ++ i = 0; ++ ++ /* Count SMT only if there is L3 cache. Always count ++ core if there is no L3 cache. */ ++ int count = ((threads_l2 > 0 && level == 3) ++ | ((threads_l3 > 0 ++ || (threads_l2 > 0 && level == 2)) << 1)); ++ ++ while (count) ++ { ++ __cpuid_count (11, i++, eax, ebx, ecx, edx); ++ ++ int shipped = ebx & 0xff; ++ int type = ecx & 0xff00; ++ if (shipped == 0 || type == 0) ++ break; ++ else if (type == 0x100) ++ { ++ /* Count SMT. */ ++ if ((count & 0x1)) ++ { ++ int count_mask; ++ ++ /* Compute count mask. */ ++ asm ("bsr %1, %0" ++ : "=r" (count_mask) : "g" (threads_l2)); ++ count_mask = ~(-1 << (count_mask + 1)); ++ threads_l2 = (shipped - 1) & count_mask; ++ count &= ~0x1; ++ } ++ } ++ else if (type == 0x200) ++ { ++ /* Count core. */ ++ if ((count & (0x1 << 1))) ++ { ++ int count_mask; ++ int threads_core ++ = (level == 2 ? threads_l2 : threads_l3); ++ ++ /* Compute count mask. */ ++ asm ("bsr %1, %0" ++ : "=r" (count_mask) : "g" (threads_core)); ++ count_mask = ~(-1 << (count_mask + 1)); ++ threads_core = (shipped - 1) & count_mask; ++ if (level == 2) ++ threads_l2 = threads_core; ++ else ++ threads_l3 = threads_core; ++ count &= ~(0x1 << 1); ++ } ++ } ++ } ++ } ++ if (threads_l2 > 0) ++ threads_l2 += 1; ++ if (threads_l3 > 0) ++ threads_l3 += 1; ++ if (level == 2) ++ { ++ if (threads_l2) ++ { ++ threads = threads_l2; ++ if (cpu_features->basic.kind == arch_kind_intel ++ && threads > 2 ++ && family == 6) ++ switch (model) ++ { ++ case 0x37: ++ case 0x4a: ++ case 0x4d: ++ case 0x5a: ++ case 0x5d: ++ /* Silvermont has L2 cache shared by 2 cores. */ ++ threads = 2; ++ break; ++ default: ++ break; ++ } ++ } ++ } ++ else if (threads_l3) ++ threads = threads_l3; ++ } ++ else ++ { ++intel_bug_no_cache_info: ++ /* Assume that all logical threads share the highest cache ++ level. */ ++ threads ++ = ((cpu_features->features[COMMON_CPUID_INDEX_1].cpuid.ebx ++ >> 16) & 0xff); ++ } ++ ++ /* Cap usage of highest cache level to the number of supported ++ threads. */ ++ if (shared > 0 && threads > 0) ++ shared /= threads; ++ } ++ ++ /* Account for non-inclusive L2 and L3 caches. */ ++ if (!inclusive_cache) ++ { ++ if (threads_l2 > 0) ++ core /= threads_l2; ++ shared += core; ++ } ++ ++ *shared_ptr = shared; ++ *threads_ptr = threads; ++} ++ ++static void ++init_cacheinfo (void) ++{ ++ /* Find out what brand of processor. */ ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++ int max_cpuid_ex; ++ long int data = -1; ++ long int shared = -1; ++ long int core; ++ unsigned int threads = 0; ++ const struct cpu_features *cpu_features = __get_cpu_features (); ++ ++ /* NB: In libc.so, cpu_features is defined in ld.so and is initialized ++ by DL_PLATFORM_INIT or IFUNC relocation before init_cacheinfo is ++ called by IFUNC relocation. In libc.a, init_cacheinfo is called ++ from init_cpu_features by ARCH_INIT_CPU_FEATURES. */ ++ assert (cpu_features->basic.kind != arch_kind_unknown); ++ ++ if (cpu_features->basic.kind == arch_kind_intel) ++ { ++ data = handle_intel (_SC_LEVEL1_DCACHE_SIZE, cpu_features); ++ core = handle_intel (_SC_LEVEL2_CACHE_SIZE, cpu_features); ++ shared = handle_intel (_SC_LEVEL3_CACHE_SIZE, cpu_features); ++ ++ get_common_cache_info (&shared, &threads, core); ++ } ++ else if (cpu_features->basic.kind == arch_kind_zhaoxin) ++ { ++ data = handle_zhaoxin (_SC_LEVEL1_DCACHE_SIZE); ++ core = handle_zhaoxin (_SC_LEVEL2_CACHE_SIZE); ++ shared = handle_zhaoxin (_SC_LEVEL3_CACHE_SIZE); ++ ++ get_common_cache_info (&shared, &threads, core); ++ } ++ else if (cpu_features->basic.kind == arch_kind_amd) ++ { ++ data = handle_amd (_SC_LEVEL1_DCACHE_SIZE); ++ long int core = handle_amd (_SC_LEVEL2_CACHE_SIZE); ++ shared = handle_amd (_SC_LEVEL3_CACHE_SIZE); ++ ++ /* Get maximum extended function. */ ++ __cpuid (0x80000000, max_cpuid_ex, ebx, ecx, edx); ++ ++ if (shared <= 0) ++ /* No shared L3 cache. All we have is the L2 cache. */ ++ shared = core; ++ else ++ { ++ /* Figure out the number of logical threads that share L3. */ ++ if (max_cpuid_ex >= 0x80000008) ++ { ++ /* Get width of APIC ID. */ ++ __cpuid (0x80000008, max_cpuid_ex, ebx, ecx, edx); ++ threads = 1 << ((ecx >> 12) & 0x0f); ++ } ++ ++ if (threads == 0 || cpu_features->basic.family >= 0x17) ++ { ++ /* If APIC ID width is not available, use logical ++ processor count. */ ++ __cpuid (0x00000001, max_cpuid_ex, ebx, ecx, edx); ++ ++ if ((edx & (1 << 28)) != 0) ++ threads = (ebx >> 16) & 0xff; ++ } ++ ++ /* Cap usage of highest cache level to the number of ++ supported threads. */ ++ if (threads > 0) ++ shared /= threads; ++ ++ /* Get shared cache per ccx for Zen architectures. */ ++ if (cpu_features->basic.family >= 0x17) ++ { ++ unsigned int eax; ++ ++ /* Get number of threads share the L3 cache in CCX. */ ++ __cpuid_count (0x8000001D, 0x3, eax, ebx, ecx, edx); ++ ++ unsigned int threads_per_ccx = ((eax >> 14) & 0xfff) + 1; ++ shared *= threads_per_ccx; ++ } ++ else ++ { ++ /* Account for exclusive L2 and L3 caches. */ ++ shared += core; ++ } ++ } ++ } ++ ++ if (cpu_features->data_cache_size != 0) ++ data = cpu_features->data_cache_size; ++ ++ if (data > 0) ++ { ++ __x86_raw_data_cache_size_half = data / 2; ++ __x86_raw_data_cache_size = data; ++ /* Round data cache size to multiple of 256 bytes. */ ++ data = data & ~255L; ++ __x86_data_cache_size_half = data / 2; ++ __x86_data_cache_size = data; ++ } ++ ++ if (cpu_features->shared_cache_size != 0) ++ shared = cpu_features->shared_cache_size; ++ ++ if (shared > 0) ++ { ++ __x86_raw_shared_cache_size_half = shared / 2; ++ __x86_raw_shared_cache_size = shared; ++ /* Round shared cache size to multiple of 256 bytes. */ ++ shared = shared & ~255L; ++ __x86_shared_cache_size_half = shared / 2; ++ __x86_shared_cache_size = shared; ++ } ++ ++ /* The default setting for the non_temporal threshold is 3/4 of one ++ thread's share of the chip's cache. For most Intel and AMD processors ++ with an initial release date between 2017 and 2020, a thread's typical ++ share of the cache is from 500 KBytes to 2 MBytes. Using the 3/4 ++ threshold leaves 125 KBytes to 500 KBytes of the thread's data ++ in cache after a maximum temporal copy, which will maintain ++ in cache a reasonable portion of the thread's stack and other ++ active data. If the threshold is set higher than one thread's ++ share of the cache, it has a substantial risk of negatively ++ impacting the performance of other threads running on the chip. */ ++ __x86_shared_non_temporal_threshold ++ = (cpu_features->non_temporal_threshold != 0 ++ ? cpu_features->non_temporal_threshold ++ : __x86_shared_cache_size * 3 / 4); ++ ++ /* NB: The REP MOVSB threshold must be greater than VEC_SIZE * 8. */ ++ unsigned int minimum_rep_movsb_threshold; ++ /* NB: The default REP MOVSB threshold is 2048 * (VEC_SIZE / 16). */ ++ unsigned int rep_movsb_threshold; ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F) ++ && !CPU_FEATURE_PREFERRED_P (cpu_features, Prefer_No_AVX512)) ++ { ++ rep_movsb_threshold = 2048 * (64 / 16); ++ minimum_rep_movsb_threshold = 64 * 8; ++ } ++ else if (CPU_FEATURE_PREFERRED_P (cpu_features, ++ AVX_Fast_Unaligned_Load)) ++ { ++ rep_movsb_threshold = 2048 * (32 / 16); ++ minimum_rep_movsb_threshold = 32 * 8; ++ } ++ else ++ { ++ rep_movsb_threshold = 2048 * (16 / 16); ++ minimum_rep_movsb_threshold = 16 * 8; ++ } ++ if (cpu_features->rep_movsb_threshold > minimum_rep_movsb_threshold) ++ __x86_rep_movsb_threshold = cpu_features->rep_movsb_threshold; ++ else ++ __x86_rep_movsb_threshold = rep_movsb_threshold; ++ ++# if HAVE_TUNABLES ++ __x86_rep_stosb_threshold = cpu_features->rep_stosb_threshold; ++# endif ++} +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 5f0548fe08134236..4c9c15a44b618fed 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -17,9 +17,14 @@ + . */ + + #include +-#include + #include + #include ++#if IS_IN (libc) && !defined SHARED ++# include ++# include ++# include ++# include ++#endif + + #if HAVE_TUNABLES + # define TUNABLE_NAMESPACE cpu +@@ -752,4 +757,9 @@ no_cpuid: + # endif + } + #endif ++ ++#ifndef SHARED ++ /* NB: In libc.a, call init_cacheinfo. */ ++ init_cacheinfo (); ++#endif + } +diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h +new file mode 100644 +index 0000000000000000..b2b90074b0e98a60 +--- /dev/null ++++ b/sysdeps/x86/dl-cacheinfo.h +@@ -0,0 +1,478 @@ ++/* Initialize x86 cache info. ++ 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 ++ . */ ++ ++static const struct intel_02_cache_info ++{ ++ unsigned char idx; ++ unsigned char assoc; ++ unsigned char linesize; ++ unsigned char rel_name; ++ unsigned int size; ++} intel_02_known [] = ++ { ++#define M(sc) ((sc) - _SC_LEVEL1_ICACHE_SIZE) ++ { 0x06, 4, 32, M(_SC_LEVEL1_ICACHE_SIZE), 8192 }, ++ { 0x08, 4, 32, M(_SC_LEVEL1_ICACHE_SIZE), 16384 }, ++ { 0x09, 4, 32, M(_SC_LEVEL1_ICACHE_SIZE), 32768 }, ++ { 0x0a, 2, 32, M(_SC_LEVEL1_DCACHE_SIZE), 8192 }, ++ { 0x0c, 4, 32, M(_SC_LEVEL1_DCACHE_SIZE), 16384 }, ++ { 0x0d, 4, 64, M(_SC_LEVEL1_DCACHE_SIZE), 16384 }, ++ { 0x0e, 6, 64, M(_SC_LEVEL1_DCACHE_SIZE), 24576 }, ++ { 0x21, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, ++ { 0x22, 4, 64, M(_SC_LEVEL3_CACHE_SIZE), 524288 }, ++ { 0x23, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 1048576 }, ++ { 0x25, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 2097152 }, ++ { 0x29, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 4194304 }, ++ { 0x2c, 8, 64, M(_SC_LEVEL1_DCACHE_SIZE), 32768 }, ++ { 0x30, 8, 64, M(_SC_LEVEL1_ICACHE_SIZE), 32768 }, ++ { 0x39, 4, 64, M(_SC_LEVEL2_CACHE_SIZE), 131072 }, ++ { 0x3a, 6, 64, M(_SC_LEVEL2_CACHE_SIZE), 196608 }, ++ { 0x3b, 2, 64, M(_SC_LEVEL2_CACHE_SIZE), 131072 }, ++ { 0x3c, 4, 64, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, ++ { 0x3d, 6, 64, M(_SC_LEVEL2_CACHE_SIZE), 393216 }, ++ { 0x3e, 4, 64, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, ++ { 0x3f, 2, 64, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, ++ { 0x41, 4, 32, M(_SC_LEVEL2_CACHE_SIZE), 131072 }, ++ { 0x42, 4, 32, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, ++ { 0x43, 4, 32, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, ++ { 0x44, 4, 32, M(_SC_LEVEL2_CACHE_SIZE), 1048576 }, ++ { 0x45, 4, 32, M(_SC_LEVEL2_CACHE_SIZE), 2097152 }, ++ { 0x46, 4, 64, M(_SC_LEVEL3_CACHE_SIZE), 4194304 }, ++ { 0x47, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 8388608 }, ++ { 0x48, 12, 64, M(_SC_LEVEL2_CACHE_SIZE), 3145728 }, ++ { 0x49, 16, 64, M(_SC_LEVEL2_CACHE_SIZE), 4194304 }, ++ { 0x4a, 12, 64, M(_SC_LEVEL3_CACHE_SIZE), 6291456 }, ++ { 0x4b, 16, 64, M(_SC_LEVEL3_CACHE_SIZE), 8388608 }, ++ { 0x4c, 12, 64, M(_SC_LEVEL3_CACHE_SIZE), 12582912 }, ++ { 0x4d, 16, 64, M(_SC_LEVEL3_CACHE_SIZE), 16777216 }, ++ { 0x4e, 24, 64, M(_SC_LEVEL2_CACHE_SIZE), 6291456 }, ++ { 0x60, 8, 64, M(_SC_LEVEL1_DCACHE_SIZE), 16384 }, ++ { 0x66, 4, 64, M(_SC_LEVEL1_DCACHE_SIZE), 8192 }, ++ { 0x67, 4, 64, M(_SC_LEVEL1_DCACHE_SIZE), 16384 }, ++ { 0x68, 4, 64, M(_SC_LEVEL1_DCACHE_SIZE), 32768 }, ++ { 0x78, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 1048576 }, ++ { 0x79, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 131072 }, ++ { 0x7a, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, ++ { 0x7b, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, ++ { 0x7c, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 1048576 }, ++ { 0x7d, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 2097152 }, ++ { 0x7f, 2, 64, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, ++ { 0x80, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, ++ { 0x82, 8, 32, M(_SC_LEVEL2_CACHE_SIZE), 262144 }, ++ { 0x83, 8, 32, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, ++ { 0x84, 8, 32, M(_SC_LEVEL2_CACHE_SIZE), 1048576 }, ++ { 0x85, 8, 32, M(_SC_LEVEL2_CACHE_SIZE), 2097152 }, ++ { 0x86, 4, 64, M(_SC_LEVEL2_CACHE_SIZE), 524288 }, ++ { 0x87, 8, 64, M(_SC_LEVEL2_CACHE_SIZE), 1048576 }, ++ { 0xd0, 4, 64, M(_SC_LEVEL3_CACHE_SIZE), 524288 }, ++ { 0xd1, 4, 64, M(_SC_LEVEL3_CACHE_SIZE), 1048576 }, ++ { 0xd2, 4, 64, M(_SC_LEVEL3_CACHE_SIZE), 2097152 }, ++ { 0xd6, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 1048576 }, ++ { 0xd7, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 2097152 }, ++ { 0xd8, 8, 64, M(_SC_LEVEL3_CACHE_SIZE), 4194304 }, ++ { 0xdc, 12, 64, M(_SC_LEVEL3_CACHE_SIZE), 2097152 }, ++ { 0xdd, 12, 64, M(_SC_LEVEL3_CACHE_SIZE), 4194304 }, ++ { 0xde, 12, 64, M(_SC_LEVEL3_CACHE_SIZE), 8388608 }, ++ { 0xe2, 16, 64, M(_SC_LEVEL3_CACHE_SIZE), 2097152 }, ++ { 0xe3, 16, 64, M(_SC_LEVEL3_CACHE_SIZE), 4194304 }, ++ { 0xe4, 16, 64, M(_SC_LEVEL3_CACHE_SIZE), 8388608 }, ++ { 0xea, 24, 64, M(_SC_LEVEL3_CACHE_SIZE), 12582912 }, ++ { 0xeb, 24, 64, M(_SC_LEVEL3_CACHE_SIZE), 18874368 }, ++ { 0xec, 24, 64, M(_SC_LEVEL3_CACHE_SIZE), 25165824 }, ++ }; ++ ++#define nintel_02_known (sizeof (intel_02_known) / sizeof (intel_02_known [0])) ++ ++static int ++intel_02_known_compare (const void *p1, const void *p2) ++{ ++ const struct intel_02_cache_info *i1; ++ const struct intel_02_cache_info *i2; ++ ++ i1 = (const struct intel_02_cache_info *) p1; ++ i2 = (const struct intel_02_cache_info *) p2; ++ ++ if (i1->idx == i2->idx) ++ return 0; ++ ++ return i1->idx < i2->idx ? -1 : 1; ++} ++ ++ ++static long int ++__attribute__ ((noinline)) ++intel_check_word (int name, unsigned int value, bool *has_level_2, ++ bool *no_level_2_or_3, ++ const struct cpu_features *cpu_features) ++{ ++ if ((value & 0x80000000) != 0) ++ /* The register value is reserved. */ ++ return 0; ++ ++ /* Fold the name. The _SC_ constants are always in the order SIZE, ++ ASSOC, LINESIZE. */ ++ int folded_rel_name = (M(name) / 3) * 3; ++ ++ while (value != 0) ++ { ++ unsigned int byte = value & 0xff; ++ ++ if (byte == 0x40) ++ { ++ *no_level_2_or_3 = true; ++ ++ if (folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE)) ++ /* No need to look further. */ ++ break; ++ } ++ else if (byte == 0xff) ++ { ++ /* CPUID leaf 0x4 contains all the information. We need to ++ iterate over it. */ ++ unsigned int eax; ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++ ++ unsigned int round = 0; ++ while (1) ++ { ++ __cpuid_count (4, round, eax, ebx, ecx, edx); ++ ++ enum { null = 0, data = 1, inst = 2, uni = 3 } type = eax & 0x1f; ++ if (type == null) ++ /* That was the end. */ ++ break; ++ ++ unsigned int level = (eax >> 5) & 0x7; ++ ++ if ((level == 1 && type == data ++ && folded_rel_name == M(_SC_LEVEL1_DCACHE_SIZE)) ++ || (level == 1 && type == inst ++ && folded_rel_name == M(_SC_LEVEL1_ICACHE_SIZE)) ++ || (level == 2 && folded_rel_name == M(_SC_LEVEL2_CACHE_SIZE)) ++ || (level == 3 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE)) ++ || (level == 4 && folded_rel_name == M(_SC_LEVEL4_CACHE_SIZE))) ++ { ++ unsigned int offset = M(name) - folded_rel_name; ++ ++ if (offset == 0) ++ /* Cache size. */ ++ return (((ebx >> 22) + 1) ++ * (((ebx >> 12) & 0x3ff) + 1) ++ * ((ebx & 0xfff) + 1) ++ * (ecx + 1)); ++ if (offset == 1) ++ return (ebx >> 22) + 1; ++ ++ assert (offset == 2); ++ return (ebx & 0xfff) + 1; ++ } ++ ++ ++round; ++ } ++ /* There is no other cache information anywhere else. */ ++ break; ++ } ++ else ++ { ++ if (byte == 0x49 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE)) ++ { ++ /* Intel reused this value. For family 15, model 6 it ++ specifies the 3rd level cache. Otherwise the 2nd ++ level cache. */ ++ unsigned int family = cpu_features->basic.family; ++ unsigned int model = cpu_features->basic.model; ++ ++ if (family == 15 && model == 6) ++ { ++ /* The level 3 cache is encoded for this model like ++ the level 2 cache is for other models. Pretend ++ the caller asked for the level 2 cache. */ ++ name = (_SC_LEVEL2_CACHE_SIZE ++ + (name - _SC_LEVEL3_CACHE_SIZE)); ++ folded_rel_name = M(_SC_LEVEL2_CACHE_SIZE); ++ } ++ } ++ ++ struct intel_02_cache_info *found; ++ struct intel_02_cache_info search; ++ ++ search.idx = byte; ++ found = bsearch (&search, intel_02_known, nintel_02_known, ++ sizeof (intel_02_known[0]), intel_02_known_compare); ++ if (found != NULL) ++ { ++ if (found->rel_name == folded_rel_name) ++ { ++ unsigned int offset = M(name) - folded_rel_name; ++ ++ if (offset == 0) ++ /* Cache size. */ ++ return found->size; ++ if (offset == 1) ++ return found->assoc; ++ ++ assert (offset == 2); ++ return found->linesize; ++ } ++ ++ if (found->rel_name == M(_SC_LEVEL2_CACHE_SIZE)) ++ *has_level_2 = true; ++ } ++ } ++ ++ /* Next byte for the next round. */ ++ value >>= 8; ++ } ++ ++ /* Nothing found. */ ++ return 0; ++} ++ ++ ++static long int __attribute__ ((noinline)) ++handle_intel (int name, const struct cpu_features *cpu_features) ++{ ++ unsigned int maxidx = cpu_features->basic.max_cpuid; ++ ++ /* Return -1 for older CPUs. */ ++ if (maxidx < 2) ++ return -1; ++ ++ /* OK, we can use the CPUID instruction to get all info about the ++ caches. */ ++ unsigned int cnt = 0; ++ unsigned int max = 1; ++ long int result = 0; ++ bool no_level_2_or_3 = false; ++ bool has_level_2 = false; ++ ++ while (cnt++ < max) ++ { ++ unsigned int eax; ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++ __cpuid (2, eax, ebx, ecx, edx); ++ ++ /* The low byte of EAX in the first round contain the number of ++ rounds we have to make. At least one, the one we are already ++ doing. */ ++ if (cnt == 1) ++ { ++ max = eax & 0xff; ++ eax &= 0xffffff00; ++ } ++ ++ /* Process the individual registers' value. */ ++ result = intel_check_word (name, eax, &has_level_2, ++ &no_level_2_or_3, cpu_features); ++ if (result != 0) ++ return result; ++ ++ result = intel_check_word (name, ebx, &has_level_2, ++ &no_level_2_or_3, cpu_features); ++ if (result != 0) ++ return result; ++ ++ result = intel_check_word (name, ecx, &has_level_2, ++ &no_level_2_or_3, cpu_features); ++ if (result != 0) ++ return result; ++ ++ result = intel_check_word (name, edx, &has_level_2, ++ &no_level_2_or_3, cpu_features); ++ if (result != 0) ++ return result; ++ } ++ ++ if (name >= _SC_LEVEL2_CACHE_SIZE && name <= _SC_LEVEL3_CACHE_LINESIZE ++ && no_level_2_or_3) ++ return -1; ++ ++ return 0; ++} ++ ++ ++static long int __attribute__ ((noinline)) ++handle_amd (int name) ++{ ++ unsigned int eax; ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++ __cpuid (0x80000000, eax, ebx, ecx, edx); ++ ++ /* No level 4 cache (yet). */ ++ if (name > _SC_LEVEL3_CACHE_LINESIZE) ++ return 0; ++ ++ unsigned int fn = 0x80000005 + (name >= _SC_LEVEL2_CACHE_SIZE); ++ if (eax < fn) ++ return 0; ++ ++ __cpuid (fn, eax, ebx, ecx, edx); ++ ++ if (name < _SC_LEVEL1_DCACHE_SIZE) ++ { ++ name += _SC_LEVEL1_DCACHE_SIZE - _SC_LEVEL1_ICACHE_SIZE; ++ ecx = edx; ++ } ++ ++ switch (name) ++ { ++ case _SC_LEVEL1_DCACHE_SIZE: ++ return (ecx >> 14) & 0x3fc00; ++ ++ case _SC_LEVEL1_DCACHE_ASSOC: ++ ecx >>= 16; ++ if ((ecx & 0xff) == 0xff) ++ /* Fully associative. */ ++ return (ecx << 2) & 0x3fc00; ++ return ecx & 0xff; ++ ++ case _SC_LEVEL1_DCACHE_LINESIZE: ++ return ecx & 0xff; ++ ++ case _SC_LEVEL2_CACHE_SIZE: ++ return (ecx & 0xf000) == 0 ? 0 : (ecx >> 6) & 0x3fffc00; ++ ++ case _SC_LEVEL2_CACHE_ASSOC: ++ switch ((ecx >> 12) & 0xf) ++ { ++ case 0: ++ case 1: ++ case 2: ++ case 4: ++ return (ecx >> 12) & 0xf; ++ case 6: ++ return 8; ++ case 8: ++ return 16; ++ case 10: ++ return 32; ++ case 11: ++ return 48; ++ case 12: ++ return 64; ++ case 13: ++ return 96; ++ case 14: ++ return 128; ++ case 15: ++ return ((ecx >> 6) & 0x3fffc00) / (ecx & 0xff); ++ default: ++ return 0; ++ } ++ /* NOTREACHED */ ++ ++ case _SC_LEVEL2_CACHE_LINESIZE: ++ return (ecx & 0xf000) == 0 ? 0 : ecx & 0xff; ++ ++ case _SC_LEVEL3_CACHE_SIZE: ++ return (edx & 0xf000) == 0 ? 0 : (edx & 0x3ffc0000) << 1; ++ ++ case _SC_LEVEL3_CACHE_ASSOC: ++ switch ((edx >> 12) & 0xf) ++ { ++ case 0: ++ case 1: ++ case 2: ++ case 4: ++ return (edx >> 12) & 0xf; ++ case 6: ++ return 8; ++ case 8: ++ return 16; ++ case 10: ++ return 32; ++ case 11: ++ return 48; ++ case 12: ++ return 64; ++ case 13: ++ return 96; ++ case 14: ++ return 128; ++ case 15: ++ return ((edx & 0x3ffc0000) << 1) / (edx & 0xff); ++ default: ++ return 0; ++ } ++ /* NOTREACHED */ ++ ++ case _SC_LEVEL3_CACHE_LINESIZE: ++ return (edx & 0xf000) == 0 ? 0 : edx & 0xff; ++ ++ default: ++ assert (! "cannot happen"); ++ } ++ return -1; ++} ++ ++ ++static long int __attribute__ ((noinline)) ++handle_zhaoxin (int name) ++{ ++ unsigned int eax; ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++ ++ int folded_rel_name = (M(name) / 3) * 3; ++ ++ unsigned int round = 0; ++ while (1) ++ { ++ __cpuid_count (4, round, eax, ebx, ecx, edx); ++ ++ enum { null = 0, data = 1, inst = 2, uni = 3 } type = eax & 0x1f; ++ if (type == null) ++ break; ++ ++ unsigned int level = (eax >> 5) & 0x7; ++ ++ if ((level == 1 && type == data ++ && folded_rel_name == M(_SC_LEVEL1_DCACHE_SIZE)) ++ || (level == 1 && type == inst ++ && folded_rel_name == M(_SC_LEVEL1_ICACHE_SIZE)) ++ || (level == 2 && folded_rel_name == M(_SC_LEVEL2_CACHE_SIZE)) ++ || (level == 3 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE))) ++ { ++ unsigned int offset = M(name) - folded_rel_name; ++ ++ if (offset == 0) ++ /* Cache size. */ ++ return (((ebx >> 22) + 1) ++ * (((ebx >> 12) & 0x3ff) + 1) ++ * ((ebx & 0xfff) + 1) ++ * (ecx + 1)); ++ if (offset == 1) ++ return (ebx >> 22) + 1; ++ ++ assert (offset == 2); ++ return (ebx & 0xfff) + 1; ++ } ++ ++ ++round; ++ } ++ ++ /* Nothing found. */ ++ return 0; ++} +diff --git a/sysdeps/x86/dl-get-cpu-features.c b/sysdeps/x86/dl-get-cpu-features.c +index 2aba0d167129b336..82772cc12f0c7e54 100644 +--- a/sysdeps/x86/dl-get-cpu-features.c ++++ b/sysdeps/x86/dl-get-cpu-features.c +@@ -1,5 +1,5 @@ +-/* This file is part of the GNU C Library. +- Copyright (C) 2015-2018 Free Software Foundation, Inc. ++/* Initialize CPU feature data via IFUNC relocation. ++ Copyright (C) 2015-2020 Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -18,6 +18,31 @@ + + #include + ++#ifdef SHARED ++# include ++ ++/* NB: Normally, DL_PLATFORM_INIT calls init_cpu_features to initialize ++ CPU features in dynamic executable. But when loading ld.so inside of ++ static executable, DL_PLATFORM_INIT isn't called and IFUNC relocation ++ is used to call init_cpu_features. In static executable, it is called ++ once by IFUNC relocation. In dynamic executable, it is called twice ++ by DL_PLATFORM_INIT and by IFUNC relocation. */ ++extern void __x86_cpu_features (void) attribute_hidden; ++const void (*__x86_cpu_features_p) (void) attribute_hidden ++ = __x86_cpu_features; ++ ++void ++_dl_x86_init_cpu_features (void) ++{ ++ struct cpu_features *cpu_features = __get_cpu_features (); ++ if (cpu_features->basic.kind == arch_kind_unknown) ++ init_cpu_features (cpu_features); ++} ++ ++__ifunc (__x86_cpu_features, __x86_cpu_features, NULL, void, ++ _dl_x86_init_cpu_features); ++#endif ++ + #undef __x86_get_cpu_features + + const struct cpu_features * +diff --git a/sysdeps/x86/include/cpu-features.h b/sysdeps/x86/include/cpu-features.h +index dcf29b6fe8578078..f62be0b9b3746675 100644 +--- a/sysdeps/x86/include/cpu-features.h ++++ b/sysdeps/x86/include/cpu-features.h +@@ -159,6 +159,7 @@ struct cpu_features + /* Unused for x86. */ + # define INIT_ARCH() + # define __x86_get_cpu_features(max) (&GLRO(dl_x86_cpu_features)) ++extern void _dl_x86_init_cpu_features (void) attribute_hidden; + # endif + + # ifdef __x86_64__ +diff --git a/sysdeps/x86/libc-start.c b/sysdeps/x86/libc-start.c +index eb5335c154096384..60f2c34ab5511350 100644 +--- a/sysdeps/x86/libc-start.c ++++ b/sysdeps/x86/libc-start.c +@@ -20,7 +20,6 @@ + PIE. */ + # include + # include +-# include + # include + + extern struct cpu_features _dl_x86_cpu_features; +diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h +index d58298d787ef352c..e308b662d245cc63 100644 +--- a/sysdeps/x86_64/dl-machine.h ++++ b/sysdeps/x86_64/dl-machine.h +@@ -26,7 +26,6 @@ + #include + #include + #include +-#include + + /* Return nonzero iff ELF header is compatible with the running host. */ + static inline int __attribute__ ((unused)) +@@ -223,9 +222,9 @@ static inline void __attribute__ ((unused)) + dl_platform_init (void) + { + #if IS_IN (rtld) +- /* init_cpu_features has been called early from __libc_start_main in +- static executable. */ +- init_cpu_features (&GLRO(dl_x86_cpu_features)); ++ /* _dl_x86_init_cpu_features is a wrapper for init_cpu_features which ++ has been called early from __libc_start_main in static executable. */ ++ _dl_x86_init_cpu_features (); + #else + if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0') + /* Avoid an empty string which would disturb us. */ diff --git a/SOURCES/glibc-rh1817513-108.patch b/SOURCES/glibc-rh1817513-108.patch new file mode 100644 index 0000000..b6dabc9 --- /dev/null +++ b/SOURCES/glibc-rh1817513-108.patch @@ -0,0 +1,364 @@ +commit de1a9197af7f67a89f929dcadb8ceca8c3846b1c +Author: Florian Weimer +Date: Fri Oct 30 11:57:59 2020 +0100 + + elf: Unify old and new format cache handling code in ld.so + + struct file_entry_new starts with the fields of struct file_entry, + so the code can be shared if the size computation is made dynamic. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-cache.c b/elf/dl-cache.c +index ef37ca18fa9fb6e0..366a051dfcd26132 100644 +--- a/elf/dl-cache.c ++++ b/elf/dl-cache.c +@@ -35,103 +35,141 @@ static struct cache_file *cache; + static struct cache_file_new *cache_new; + static size_t cachesize; + +-/* 1 if cache_data + PTR points into the cache. */ +-#define _dl_cache_verify_ptr(ptr) (ptr < cache_data_size) +- +-#define SEARCH_CACHE(cache) \ +-/* We use binary search since the table is sorted in the cache file. \ +- The first matching entry in the table is returned. \ +- It is important to use the same algorithm as used while generating \ +- the cache file. */ \ +-do \ +- { \ +- left = 0; \ +- right = cache->nlibs - 1; \ +- \ +- while (left <= right) \ +- { \ +- __typeof__ (cache->libs[0].key) key; \ +- \ +- middle = (left + right) / 2; \ +- \ +- key = cache->libs[middle].key; \ +- \ +- /* Make sure string table indices are not bogus before using \ +- them. */ \ +- if (! _dl_cache_verify_ptr (key)) \ +- { \ +- cmpres = 1; \ +- break; \ +- } \ +- \ +- /* Actually compare the entry with the key. */ \ +- cmpres = _dl_cache_libcmp (name, cache_data + key); \ +- if (__glibc_unlikely (cmpres == 0)) \ +- { \ +- /* Found it. LEFT now marks the last entry for which we \ +- know the name is correct. */ \ +- left = middle; \ +- \ +- /* There might be entries with this name before the one we \ +- found. So we have to find the beginning. */ \ +- while (middle > 0) \ +- { \ +- __typeof__ (cache->libs[0].key) key; \ +- \ +- key = cache->libs[middle - 1].key; \ +- /* Make sure string table indices are not bogus before \ +- using them. */ \ +- if (! _dl_cache_verify_ptr (key) \ +- /* Actually compare the entry. */ \ +- || _dl_cache_libcmp (name, cache_data + key) != 0) \ +- break; \ +- --middle; \ +- } \ +- \ +- do \ +- { \ +- int flags; \ +- __typeof__ (cache->libs[0]) *lib = &cache->libs[middle]; \ +- \ +- /* Only perform the name test if necessary. */ \ +- if (middle > left \ +- /* We haven't seen this string so far. Test whether the \ +- index is ok and whether the name matches. Otherwise \ +- we are done. */ \ +- && (! _dl_cache_verify_ptr (lib->key) \ +- || (_dl_cache_libcmp (name, cache_data + lib->key) \ +- != 0))) \ +- break; \ +- \ +- flags = lib->flags; \ +- if (_dl_cache_check_flags (flags) \ +- && _dl_cache_verify_ptr (lib->value)) \ +- { \ +- if (best == NULL || flags == GLRO(dl_correct_cache_id)) \ +- { \ +- HWCAP_CHECK; \ +- best = cache_data + lib->value; \ +- \ +- if (flags == GLRO(dl_correct_cache_id)) \ +- /* We've found an exact match for the shared \ +- object and no general `ELF' release. Stop \ +- searching. */ \ +- break; \ +- } \ +- } \ +- } \ +- while (++middle <= right); \ +- break; \ +- } \ +- \ +- if (cmpres < 0) \ +- left = middle + 1; \ +- else \ +- right = middle - 1; \ +- } \ +- } \ +-while (0) ++/* True if PTR is a valid string table index. */ ++static inline bool ++_dl_cache_verify_ptr (uint32_t ptr, size_t string_table_size) ++{ ++ return ptr < string_table_size; ++} ++ ++/* Compute the address of the element INDEX of the array at LIBS. ++ Conceptually, this is &LIBS[INDEX], but use ENTRY_SIZE for the size ++ of *LIBS. */ ++static inline const struct file_entry * ++_dl_cache_file_entry (const struct file_entry *libs, size_t entry_size, ++ size_t index) ++{ ++ return (const void *) libs + index * entry_size; ++} ++ ++/* We use binary search since the table is sorted in the cache file. ++ The first matching entry in the table is returned. It is important ++ to use the same algorithm as used while generating the cache file. ++ STRING_TABLE_SIZE indicates the maximum offset in STRING_TABLE at ++ which data is mapped; it is not exact. */ ++static const char * ++search_cache (const char *string_table, uint32_t string_table_size, ++ struct file_entry *libs, uint32_t nlibs, uint32_t entry_size, ++ const char *name) ++{ ++ /* Used by the HWCAP check in the struct file_entry_new case. */ ++ uint64_t platform = _dl_string_platform (GLRO (dl_platform)); ++ if (platform != (uint64_t) -1) ++ platform = 1ULL << platform; ++ uint64_t hwcap_mask = GET_HWCAP_MASK (); ++#define _DL_HWCAP_TLS_MASK (1LL << 63) ++ uint64_t hwcap_exclude = ~((GLRO (dl_hwcap) & hwcap_mask) ++ | _DL_HWCAP_PLATFORM | _DL_HWCAP_TLS_MASK); ++ ++ int left = 0; ++ int right = nlibs - 1; ++ const char *best = NULL; ++ ++ while (left <= right) ++ { ++ int middle = (left + right) / 2; ++ uint32_t key = _dl_cache_file_entry (libs, entry_size, middle)->key; ++ ++ /* Make sure string table indices are not bogus before using ++ them. */ ++ if (!_dl_cache_verify_ptr (key, string_table_size)) ++ return NULL; ++ ++ /* Actually compare the entry with the key. */ ++ int cmpres = _dl_cache_libcmp (name, string_table + key); ++ if (__glibc_unlikely (cmpres == 0)) ++ { ++ /* Found it. LEFT now marks the last entry for which we ++ know the name is correct. */ ++ left = middle; ++ ++ /* There might be entries with this name before the one we ++ found. So we have to find the beginning. */ ++ while (middle > 0) ++ { ++ key = _dl_cache_file_entry (libs, entry_size, middle - 1)->key; ++ /* Make sure string table indices are not bogus before ++ using them. */ ++ if (!_dl_cache_verify_ptr (key, string_table_size) ++ /* Actually compare the entry. */ ++ || _dl_cache_libcmp (name, string_table + key) != 0) ++ break; ++ --middle; ++ } ++ ++ do ++ { ++ int flags; ++ const struct file_entry *lib ++ = _dl_cache_file_entry (libs, entry_size, middle); ++ ++ /* Only perform the name test if necessary. */ ++ if (middle > left ++ /* We haven't seen this string so far. Test whether the ++ index is ok and whether the name matches. Otherwise ++ we are done. */ ++ && (! _dl_cache_verify_ptr (lib->key, string_table_size) ++ || (_dl_cache_libcmp (name, string_table + lib->key) ++ != 0))) ++ break; ++ ++ flags = lib->flags; ++ if (_dl_cache_check_flags (flags) ++ && _dl_cache_verify_ptr (lib->value, string_table_size)) ++ { ++ if (best == NULL || flags == GLRO (dl_correct_cache_id)) ++ { ++ if (entry_size >= sizeof (struct file_entry_new)) ++ { ++ /* The entry is large enough to include ++ HWCAP data. Check it. */ ++ struct file_entry_new *libnew ++ = (struct file_entry_new *) lib; ++ ++ if (libnew->hwcap & hwcap_exclude) ++ continue; ++ if (GLRO (dl_osversion) ++ && libnew->osversion > GLRO (dl_osversion)) ++ continue; ++ if (_DL_PLATFORMS_COUNT ++ && (libnew->hwcap & _DL_HWCAP_PLATFORM) != 0 ++ && ((libnew->hwcap & _DL_HWCAP_PLATFORM) ++ != platform)) ++ continue; ++ } ++ ++ best = string_table + lib->value; ++ ++ if (flags == GLRO (dl_correct_cache_id)) ++ /* We've found an exact match for the shared ++ object and no general `ELF' release. Stop ++ searching. */ ++ break; ++ } ++ } ++ } ++ while (++middle <= right); ++ break; ++ } + ++ if (cmpres < 0) ++ left = middle + 1; ++ else ++ right = middle - 1; ++ } ++ ++ return best; ++} + + int + _dl_cache_libcmp (const char *p1, const char *p2) +@@ -182,12 +220,6 @@ _dl_cache_libcmp (const char *p1, const char *p2) + char * + _dl_load_cache_lookup (const char *name) + { +- int left, right, middle; +- int cmpres; +- const char *cache_data; +- uint32_t cache_data_size; +- const char *best; +- + /* Print a message if the loading of libs is traced. */ + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)) + _dl_debug_printf (" search cache=%s\n", LD_SO_CACHE); +@@ -247,51 +279,22 @@ _dl_load_cache_lookup (const char *name) + /* Previously looked for the cache file and didn't find it. */ + return NULL; + +- best = NULL; +- ++ const char *best; + if (cache_new != (void *) -1) + { +- uint64_t platform; +- +- /* This is where the strings start. */ +- cache_data = (const char *) cache_new; +- +- /* Now we can compute how large the string table is. */ +- cache_data_size = (const char *) cache + cachesize - cache_data; +- +- platform = _dl_string_platform (GLRO(dl_platform)); +- if (platform != (uint64_t) -1) +- platform = 1ULL << platform; +- +- uint64_t hwcap_mask = GET_HWCAP_MASK(); +- +-#define _DL_HWCAP_TLS_MASK (1LL << 63) +- uint64_t hwcap_exclude = ~((GLRO(dl_hwcap) & hwcap_mask) +- | _DL_HWCAP_PLATFORM | _DL_HWCAP_TLS_MASK); +- +- /* Only accept hwcap if it's for the right platform. */ +-#define HWCAP_CHECK \ +- if (lib->hwcap & hwcap_exclude) \ +- continue; \ +- if (GLRO(dl_osversion) && lib->osversion > GLRO(dl_osversion)) \ +- continue; \ +- if (_DL_PLATFORMS_COUNT \ +- && (lib->hwcap & _DL_HWCAP_PLATFORM) != 0 \ +- && (lib->hwcap & _DL_HWCAP_PLATFORM) != platform) \ +- continue +- SEARCH_CACHE (cache_new); ++ const char *string_table = (const char *) cache_new; ++ best = search_cache (string_table, cachesize, ++ &cache_new->libs[0].entry, cache_new->nlibs, ++ sizeof (cache_new->libs[0]), name); + } + else + { +- /* This is where the strings start. */ +- cache_data = (const char *) &cache->libs[cache->nlibs]; +- +- /* Now we can compute how large the string table is. */ +- cache_data_size = (const char *) cache + cachesize - cache_data; +- +-#undef HWCAP_CHECK +-#define HWCAP_CHECK do {} while (0) +- SEARCH_CACHE (cache); ++ const char *string_table = (const char *) &cache->libs[cache->nlibs]; ++ uint32_t string_table_size ++ = (const char *) cache + cachesize - string_table; ++ best = search_cache (string_table, string_table_size, ++ &cache->libs[0], cache->nlibs, ++ sizeof (cache->libs[0]), name); + } + + /* Print our result if wanted. */ +diff --git a/sysdeps/generic/dl-cache.h b/sysdeps/generic/dl-cache.h +index cf43f1cf3b441bc7..3c5730dfe42c7c88 100644 +--- a/sysdeps/generic/dl-cache.h ++++ b/sysdeps/generic/dl-cache.h +@@ -59,8 +59,8 @@ + */ + struct file_entry + { +- int flags; /* This is 1 for an ELF library. */ +- unsigned int key, value; /* String table indices. */ ++ int32_t flags; /* This is 1 for an ELF library. */ ++ uint32_t key, value; /* String table indices. */ + }; + + struct cache_file +@@ -77,8 +77,17 @@ struct cache_file + + struct file_entry_new + { +- int32_t flags; /* This is 1 for an ELF library. */ +- uint32_t key, value; /* String table indices. */ ++ union ++ { ++ /* Fields shared with struct file_entry. */ ++ struct file_entry entry; ++ /* Also expose these fields directly. */ ++ struct ++ { ++ int32_t flags; /* This is 1 for an ELF library. */ ++ uint32_t key, value; /* String table indices. */ ++ }; ++ }; + uint32_t osversion; /* Required OS version. */ + uint64_t hwcap; /* Hwcap entry. */ + }; diff --git a/SOURCES/glibc-rh1817513-109.patch b/SOURCES/glibc-rh1817513-109.patch new file mode 100644 index 0000000..f53c03b --- /dev/null +++ b/SOURCES/glibc-rh1817513-109.patch @@ -0,0 +1,67 @@ +commit 5e598c2bbf938eac0f4045f5143f9dd723646672 +Author: Florian Weimer +Date: Fri Oct 30 18:40:28 2020 +0100 + + elf: In ldconfig, extract the new_sub_entry function from search_dir + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/ldconfig.c b/elf/ldconfig.c +index 7c8fd29387463a8a..be730ceb075f6c1f 100644 +--- a/elf/ldconfig.c ++++ b/elf/ldconfig.c +@@ -328,6 +328,23 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ + "Andreas Jaeger"); + } + ++/* Allocate a new subdirectory with full path PATH under ENTRY, using ++ inode data from *ST. */ ++static struct dir_entry * ++new_sub_entry (const struct dir_entry *entry, const char *path, ++ const struct stat64 *st) ++{ ++ struct dir_entry *new_entry = xmalloc (sizeof (struct dir_entry)); ++ new_entry->from_file = entry->from_file; ++ new_entry->from_line = entry->from_line; ++ new_entry->path = xstrdup (path); ++ new_entry->flag = entry->flag; ++ new_entry->next = NULL; ++ new_entry->ino = st->st_ino; ++ new_entry->dev = st->st_dev; ++ return new_entry; ++} ++ + /* Add a single directory entry. */ + static void + add_single_dir (struct dir_entry *entry, int verbose) +@@ -823,26 +840,17 @@ search_dir (const struct dir_entry *entry) + + if (is_dir && is_hwcap_platform (direntry->d_name)) + { +- /* Handle subdirectory later. */ +- struct dir_entry *new_entry; +- +- new_entry = xmalloc (sizeof (struct dir_entry)); +- new_entry->from_file = entry->from_file; +- new_entry->from_line = entry->from_line; +- new_entry->path = xstrdup (file_name); +- new_entry->flag = entry->flag; +- new_entry->next = NULL; + if (!is_link + && direntry->d_type != DT_UNKNOWN + && __builtin_expect (lstat64 (real_file_name, &lstat_buf), 0)) + { + error (0, errno, _("Cannot lstat %s"), file_name); +- free (new_entry->path); +- free (new_entry); + continue; + } +- new_entry->ino = lstat_buf.st_ino; +- new_entry->dev = lstat_buf.st_dev; ++ ++ /* Handle subdirectory later. */ ++ struct dir_entry *new_entry = new_sub_entry (entry, file_name, ++ &lstat_buf); + add_single_dir (new_entry, 0); + continue; + } diff --git a/SOURCES/glibc-rh1817513-11.patch b/SOURCES/glibc-rh1817513-11.patch new file mode 100644 index 0000000..be54271 --- /dev/null +++ b/SOURCES/glibc-rh1817513-11.patch @@ -0,0 +1,79 @@ +commit 7cc65773f04e0f4252428c40dcbb784a39b58cd1 +Author: H.J. Lu +Date: Wed Oct 24 02:19:15 2018 -0700 + + x86: Support RDTSCP for benchtests + + RDTSCP waits until all previous instructions have executed and all + previous loads are globally visible before reading the counter. RDTSC + doesn't wait until all previous instructions have been executed before + reading the counter. All x86 processors since 2010 support RDTSCP + instruction. This patch adds RDTSCP support to benchtests. + + * benchtests/Makefile (CPPFLAGS-nonlib): Add -DUSE_RDTSCP if + USE_RDTSCP is defined. + * sysdeps/x86/hp-timing.h (HP_TIMING_NOW): Use RDTSCP if + USE_RDTSCP is defined. + +diff --git a/benchtests/Makefile b/benchtests/Makefile +index 28d6b0c43f5bd390..bde0caf140e8cf17 100644 +--- a/benchtests/Makefile ++++ b/benchtests/Makefile +@@ -131,6 +131,12 @@ CPPFLAGS-nonlib += -DDURATION=$(BENCH_DURATION) -D_ISOMAC + # HP_TIMING if it is available. + ifdef USE_CLOCK_GETTIME + CPPFLAGS-nonlib += -DUSE_CLOCK_GETTIME ++else ++# On x86 processors, use RDTSCP, instead of RDTSC, to measure performance ++# of functions. All x86 processors since 2010 support RDTSCP instruction. ++ifdef USE_RDTSCP ++CPPFLAGS-nonlib += -DUSE_RDTSCP ++endif + endif + + DETAILED_OPT := +diff --git a/benchtests/README b/benchtests/README +index 4ddff794d136f65f..aaf0b659e2b25627 100644 +--- a/benchtests/README ++++ b/benchtests/README +@@ -34,6 +34,15 @@ the benchmark to use clock_gettime by invoking make as follows: + + Again, one must run `make bench-clean' before changing the measurement method. + ++On x86 processors, RDTSCP instruction provides more precise timing data ++than RDTSC instruction. All x86 processors since 2010 support RDTSCP ++instruction. One can force the benchmark to use RDTSCP by invoking make ++as follows: ++ ++ $ make USE_RDTSCP=1 bench ++ ++One must run `make bench-clean' before changing the measurement method. ++ + Running benchmarks on another target: + ==================================== + +diff --git a/sysdeps/x86/hp-timing.h b/sysdeps/x86/hp-timing.h +index 77a1360748ca4535..0aa6f5e3f83e0d34 100644 +--- a/sysdeps/x86/hp-timing.h ++++ b/sysdeps/x86/hp-timing.h +@@ -40,7 +40,19 @@ typedef unsigned long long int hp_timing_t; + + NB: Use __builtin_ia32_rdtsc directly since including + makes building glibc very slow. */ +-# define HP_TIMING_NOW(Var) ((Var) = __builtin_ia32_rdtsc ()) ++# ifdef USE_RDTSCP ++/* RDTSCP waits until all previous instructions have executed and all ++ previous loads are globally visible before reading the counter. ++ RDTSC doesn't wait until all previous instructions have been executed ++ before reading the counter. */ ++# define HP_TIMING_NOW(Var) \ ++ (__extension__ ({ \ ++ unsigned int __aux; \ ++ (Var) = __builtin_ia32_rdtscp (&__aux); \ ++ })) ++# else ++# define HP_TIMING_NOW(Var) ((Var) = __builtin_ia32_rdtsc ()) ++# endif + + # include + #else diff --git a/SOURCES/glibc-rh1817513-110.patch b/SOURCES/glibc-rh1817513-110.patch new file mode 100644 index 0000000..57d0c15 --- /dev/null +++ b/SOURCES/glibc-rh1817513-110.patch @@ -0,0 +1,22 @@ +commit df5f473ed5ee95e3179fcb239e33e971619626cd +Author: Shuo Wang +Date: Tue Nov 24 16:42:18 2020 -0300 + + elf: Fix uninitialized variable for _dl_write + + Variable ret in elf/dl-write.c is uninitialized, which should get + return value from __writev. + +diff --git a/elf/dl-write.c b/elf/dl-write.c +index 7350aff0035d4fbc..9b741c8a8fe12f6c 100644 +--- a/elf/dl-write.c ++++ b/elf/dl-write.c +@@ -41,7 +41,7 @@ _dl_write (int fd, const void *buffer, size_t length) + else + { + __rtld_lock_lock_recursive (GL(dl_load_lock)); +- __writev (fd, &iov, 1); ++ ret = __writev (fd, &iov, 1); + if (ret < 0) + ret = -errno; + __rtld_lock_unlock_recursive (GL(dl_load_lock)); diff --git a/SOURCES/glibc-rh1817513-111.patch b/SOURCES/glibc-rh1817513-111.patch new file mode 100644 index 0000000..e194ff1 --- /dev/null +++ b/SOURCES/glibc-rh1817513-111.patch @@ -0,0 +1,85 @@ +commit 603ae243f6fe03208a3bb92adecf72403367bd95 +Author: Florian Weimer +Date: Thu Nov 26 16:59:44 2020 +0100 + + support: Add support_copy_file + + Reviewed-by: Adhemerval Zanella + +diff --git a/support/Makefile b/support/Makefile +index 895b83a426369b0c..35b21b19a248ba7f 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -46,6 +46,7 @@ libsupport-routines = \ + support_capture_subprocess \ + support_capture_subprocess_check \ + support_chroot \ ++ support_copy_file \ + support_copy_file_range \ + support_descriptor_supports_holes \ + support_descriptors \ +diff --git a/support/support.h b/support/support.h +index 3af87f85fe1b762d..6f7f804847f67600 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -115,6 +115,11 @@ extern const char support_install_rootsbindir[]; + /* Corresponds to the install's compiled locale directory. */ + extern const char support_complocaledir_prefix[]; + ++/* Copies the file at the path FROM to TO. If TO does not exist, it ++ is created. If TO is a regular file, it is truncated before ++ copying. The file mode is copied, but the permissions are not. */ ++extern void support_copy_file (const char *from, const char *to); ++ + extern ssize_t support_copy_file_range (int, off64_t *, int, off64_t *, + size_t, unsigned int); + +diff --git a/support/support_copy_file.c b/support/support_copy_file.c +new file mode 100644 +index 0000000000000000..c93e1e58c81b749d +--- /dev/null ++++ b/support/support_copy_file.c +@@ -0,0 +1,43 @@ ++/* Copy a file from one path to another. ++ 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 ++ ++void ++support_copy_file (const char *from, const char *to) ++{ ++ struct stat64 st; ++ xstat (from, &st); ++ int fd_from = xopen (from, O_RDONLY, 0); ++ mode_t mode = st.st_mode & 0777; ++ int fd_to = xopen (to, O_WRONLY | O_TRUNC | O_CREAT, mode); ++ ssize_t ret = support_copy_file_range (fd_from, NULL, fd_to, NULL, ++ st.st_size, 0); ++ if (ret < 0) ++ FAIL_EXIT1 ("copying from \"%s\" to \"%s\": %m", from, to); ++ if (ret != st.st_size) ++ FAIL_EXIT1 ("copying from \"%s\" to \"%s\": only %zd of %llu bytes copied", ++ from, to, ret, (unsigned long long int) st.st_size); ++ if (fchmod (fd_to, mode) < 0) ++ FAIL_EXIT1 ("fchmod on %s to 0%o: %m", to, mode); ++ xclose (fd_to); ++ xclose (fd_from); ++} diff --git a/SOURCES/glibc-rh1817513-112.patch b/SOURCES/glibc-rh1817513-112.patch new file mode 100644 index 0000000..80f1c38 --- /dev/null +++ b/SOURCES/glibc-rh1817513-112.patch @@ -0,0 +1,152 @@ +commit db07fae8250401adb2b97ab3e53d41da2a6bd767 +Author: Florian Weimer +Date: Thu Nov 26 16:59:44 2020 +0100 + + elf: Introduce enum opt_format in the ldconfig implementation + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/cache.c b/elf/cache.c +index c4cd825c30e00e8e..edcdd4b7cc1a6a0b 100644 +--- a/elf/cache.c ++++ b/elf/cache.c +@@ -321,13 +321,13 @@ save_cache (const char *cache_name) + struct cache_file *file_entries = NULL; + size_t file_entries_size = 0; + +- if (opt_format != 2) ++ if (opt_format != opt_format_new) + { + /* struct cache_file_new is 64-bit aligned on some arches while + only 32-bit aligned on other arches. Duplicate last old + cache entry so that new cache in ld.so.cache can be used by + both. */ +- if (opt_format != 0) ++ if (opt_format != opt_format_old) + cache_entry_old_count = (cache_entry_old_count + 1) & ~1; + + /* And the list of all entries in the old format. */ +@@ -345,7 +345,7 @@ save_cache (const char *cache_name) + struct cache_file_new *file_entries_new = NULL; + size_t file_entries_new_size = 0; + +- if (opt_format != 0) ++ if (opt_format != opt_format_old) + { + /* And the list of all entries in the new format. */ + file_entries_new_size = sizeof (struct cache_file_new) +@@ -370,7 +370,7 @@ save_cache (const char *cache_name) + table, we have to adjust all string indices for this so that + old libc5/glibc 2 dynamic linkers just ignore them. */ + unsigned int str_offset; +- if (opt_format != 0) ++ if (opt_format != opt_format_old) + str_offset = file_entries_new_size; + else + str_offset = 0; +@@ -385,13 +385,13 @@ save_cache (const char *cache_name) + entry = entry->next, ++idx_new) + { + /* First the library. */ +- if (opt_format != 2 && entry->hwcap == 0) ++ if (opt_format != opt_format_new && entry->hwcap == 0) + { + file_entries->libs[idx_old].flags = entry->flags; + /* XXX: Actually we can optimize here and remove duplicates. */ + file_entries->libs[idx_old].key = str_offset + pad; + } +- if (opt_format != 0) ++ if (opt_format != opt_format_old) + { + /* We could subtract file_entries_new_size from str_offset - + not doing so makes the code easier, the string table +@@ -407,9 +407,9 @@ save_cache (const char *cache_name) + str = mempcpy (str, entry->lib, len); + str_offset += len; + /* Then the path. */ +- if (opt_format != 2 && entry->hwcap == 0) ++ if (opt_format != opt_format_new && entry->hwcap == 0) + file_entries->libs[idx_old].value = str_offset + pad; +- if (opt_format != 0) ++ if (opt_format != opt_format_old) + file_entries_new->libs[idx_new].value = str_offset; + len = strlen (entry->path) + 1; + str = mempcpy (str, entry->path, len); +@@ -420,7 +420,7 @@ save_cache (const char *cache_name) + } + + /* Duplicate last old cache entry if needed. */ +- if (opt_format != 2 ++ if (opt_format != opt_format_new + && idx_old < cache_entry_old_count) + file_entries->libs[idx_old] = file_entries->libs[idx_old - 1]; + +@@ -438,16 +438,16 @@ save_cache (const char *cache_name) + temp_name); + + /* Write contents. */ +- if (opt_format != 2) ++ if (opt_format != opt_format_new) + { + if (write (fd, file_entries, file_entries_size) + != (ssize_t) file_entries_size) + error (EXIT_FAILURE, errno, _("Writing of cache data failed")); + } +- if (opt_format != 0) ++ if (opt_format != opt_format_old) + { + /* Align cache. */ +- if (opt_format != 2) ++ if (opt_format != opt_format_new) + { + char zero[pad]; + memset (zero, '\0', pad); +diff --git a/elf/ldconfig.c b/elf/ldconfig.c +index be730ceb075f6c1f..0fa5aef83f9cd86c 100644 +--- a/elf/ldconfig.c ++++ b/elf/ldconfig.c +@@ -100,8 +100,7 @@ static int opt_print_cache; + int opt_verbose; + + /* Format to support. */ +-/* 0: only libc5/glibc2; 1: both; 2: only glibc 2.2. */ +-int opt_format = 2; ++enum opt_format opt_format = opt_format_new; + + /* Build cache. */ + static int opt_build_cache = 1; +@@ -281,11 +280,11 @@ parse_opt (int key, char *arg, struct argp_state *state) + break; + case 'c': + if (strcmp (arg, "old") == 0) +- opt_format = 0; ++ opt_format = opt_format_old; + else if (strcmp (arg, "compat") == 0) +- opt_format = 1; ++ opt_format = opt_format_compat; + else if (strcmp (arg, "new") == 0) +- opt_format = 2; ++ opt_format = opt_format_new; + break; + default: + return ARGP_ERR_UNKNOWN; +diff --git a/sysdeps/generic/ldconfig.h b/sysdeps/generic/ldconfig.h +index 6774212110d23eae..b15b142511829436 100644 +--- a/sysdeps/generic/ldconfig.h ++++ b/sysdeps/generic/ldconfig.h +@@ -90,7 +90,14 @@ extern char *chroot_canon (const char *chroot, const char *name); + /* Declared in ldconfig.c. */ + extern int opt_verbose; + +-extern int opt_format; ++enum opt_format ++ { ++ opt_format_old = 0, /* Use struct cache_file. */ ++ opt_format_compat = 1, /* Use both, old format followed by new. */ ++ opt_format_new = 2, /* Use struct cache_file_new. */ ++ }; ++ ++extern enum opt_format opt_format; + + /* Prototypes for a few program-wide used functions. */ + #include diff --git a/SOURCES/glibc-rh1817513-113.patch b/SOURCES/glibc-rh1817513-113.patch new file mode 100644 index 0000000..c37d4df --- /dev/null +++ b/SOURCES/glibc-rh1817513-113.patch @@ -0,0 +1,1111 @@ +commit dad90d528259b669342757c37dedefa8577e2636 +Author: Florian Weimer +Date: Fri Dec 4 09:13:43 2020 +0100 + + elf: Add glibc-hwcaps support for LD_LIBRARY_PATH + + 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. + + ld.so supports two new arguments, --glibc-hwcaps-prepend and + --glibc-hwcaps-mask. Each accepts a colon-separated list of + glibc-hwcaps subdirectory names. The prepend option adds additional + subdirectories that are searched first, in the specified order. The + mask option restricts the automatically selected subdirectories to + those listed in the option argument. For example, on systems where + /usr/lib64 is on the library search path, + --glibc-hwcaps-prepend=valgrind:debug causes the dynamic loader to + search the directories /usr/lib64/glibc-hwcaps/valgrind and + /usr/lib64/glibc-hwcaps/debug just before /usr/lib64 is searched. + + Reviewed-by: Adhemerval Zanella + +Conflicts: + elf/Makefile + (Test backport differences.) + +diff --git a/elf/Makefile b/elf/Makefile +index bc96b8fd65e376cc..f795617780b393ec 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 +@@ -199,13 +200,14 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-filterobj tst-filterobj-dlopen tst-auxobj tst-auxobj-dlopen \ + tst-audit14 tst-audit15 tst-audit16 \ + tst-tls-ie tst-tls-ie-dlmopen \ +- argv0test ++ argv0test \ ++ tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask + # reldep9 + 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 + ifeq ($(build-hardcoded-path-in-tests),yes) + tests += tst-dlopen-aout +@@ -318,7 +320,10 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-auditlogmod-1 tst-auditlogmod-2 tst-auditlogmod-3 \ + tst-tls-ie-mod0 tst-tls-ie-mod1 tst-tls-ie-mod2 \ + tst-tls-ie-mod3 tst-tls-ie-mod4 tst-tls-ie-mod5 \ +- tst-tls-ie-mod6 ++ tst-tls-ie-mod6 libmarkermod1-1 libmarkermod1-2 libmarkermod1-3 \ ++ libmarkermod2-1 libmarkermod2-2 \ ++ libmarkermod3-1 libmarkermod3-2 libmarkermod3-3 \ ++ libmarkermod4-1 libmarkermod4-2 libmarkermod4-3 libmarkermod4-4 \ + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +@@ -1732,3 +1737,60 @@ $(objpfx)argv0test.out: tst-rtld-argv0.sh $(objpfx)ld.so \ + '$(test-wrapper-env)' '$(run_program_env)' \ + '$(rpath-link)' 'test-argv0' > $@; \ + $(evaluate-test) ++ ++# A list containing the name of the most likely searched subdirectory ++# of the glibc-hwcaps directory, for each supported architecture (in ++# other words, the oldest hardware level recognized by the ++# glibc-hwcaps mechanism for this architecture). Used to obtain test ++# coverage for some glibc-hwcaps tests for the widest possible range ++# of systems. ++glibc-hwcaps-first-subdirs-for-tests = ++ ++# The test modules are parameterized by preprocessor macros. ++LDFLAGS-libmarkermod1-1.so += -Wl,-soname,libmarkermod1.so ++LDFLAGS-libmarkermod2-1.so += -Wl,-soname,libmarkermod2.so ++LDFLAGS-libmarkermod3-1.so += -Wl,-soname,libmarkermod3.so ++LDFLAGS-libmarkermod4-1.so += -Wl,-soname,libmarkermod4.so ++$(objpfx)libmarkermod%.os : markermodMARKER-VALUE.c ++ $(compile-command.c) \ ++ -DMARKER=marker$(firstword $(subst -, ,$*)) \ ++ -DVALUE=$(lastword $(subst -, ,$*)) ++$(objpfx)libmarkermod1.so: $(objpfx)libmarkermod1-1.so ++ cp $< $@ ++$(objpfx)libmarkermod2.so: $(objpfx)libmarkermod2-1.so ++ cp $< $@ ++$(objpfx)libmarkermod3.so: $(objpfx)libmarkermod3-1.so ++ cp $< $@ ++$(objpfx)libmarkermod4.so: $(objpfx)libmarkermod4-1.so ++ cp $< $@ ++ ++# tst-glibc-hwcaps-prepend checks that --glibc-hwcaps-prepend is ++# preferred over auto-detected subdirectories. ++$(objpfx)tst-glibc-hwcaps-prepend: $(objpfx)libmarkermod1-1.so ++$(objpfx)glibc-hwcaps/prepend-markermod1/libmarkermod1.so: \ ++ $(objpfx)libmarkermod1-2.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/%/libmarkermod1.so: $(objpfx)libmarkermod1-3.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)tst-glibc-hwcaps-prepend.out: \ ++ $(objpfx)tst-glibc-hwcaps-prepend $(objpfx)libmarkermod1.so \ ++ $(patsubst %,$(objpfx)glibc-hwcaps/%/libmarkermod1.so,prepend-markermod1 \ ++ $(glibc-hwcaps-first-subdirs-for-tests)) ++ $(test-wrapper) $(rtld-prefix) \ ++ --glibc-hwcaps-prepend prepend-markermod1 \ ++ $< > $@; \ ++ $(evaluate-test) ++ ++# tst-glibc-hwcaps-mask checks that --glibc-hwcaps-mask can be used to ++# suppress all auto-detected subdirectories. ++$(objpfx)tst-glibc-hwcaps-mask: $(objpfx)libmarkermod1-1.so ++$(objpfx)tst-glibc-hwcaps-mask.out: \ ++ $(objpfx)tst-glibc-hwcaps-mask $(objpfx)libmarkermod1.so \ ++ $(patsubst %,$(objpfx)glibc-hwcaps/%/libmarkermod1.so,\ ++ $(glibc-hwcaps-first-subdirs-for-tests)) ++ $(test-wrapper) $(rtld-prefix) \ ++ --glibc-hwcaps-mask does-not-exist \ ++ $< > $@; \ ++ $(evaluate-test) +diff --git a/elf/dl-hwcaps-subdirs.c b/elf/dl-hwcaps-subdirs.c +new file mode 100644 +index 0000000000000000..60c6d59731ee3188 +--- /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[] = ""; ++ ++uint32_t ++_dl_hwcaps_subdirs_active (void) ++{ ++ return 0; ++} +diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c +index 82ee89c36a1eb4ab..e57d0d2d41741021 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 hwcaps_counts ++{ ++ /* Number of substrings. */ ++ size_t count; ++ ++ /* Sum of the individual substring lengths (without separators 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 ++update_hwcaps_counts (struct hwcaps_counts *counts, const char *hwcaps, ++ uint32_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; ++ } ++} ++ ++/* 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, ++ uint32_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; ++ } ++} ++ + /* 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. */ ++ uint32_t hwcaps_subdirs_active = _dl_hwcaps_subdirs_active (); ++ struct hwcaps_counts hwcaps_counts = { 0, }; ++ update_hwcaps_counts (&hwcaps_counts, glibc_hwcaps_prepend, -1, NULL); ++ update_hwcaps_counts (&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) +@@ -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; ++ } ++ ++ ++ /* 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 +@@ -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; + } +diff --git a/elf/dl-hwcaps.h b/elf/dl-hwcaps.h +index d69ee11dc27bb5e5..3fcfbceb1a8fc1c8 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,103 @@ + # 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; ++} ++ ++/* 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; ++ uint32_t bitmask; ++}; ++ ++/* Prepare *S for iteration with _dl_hwcaps_split_masked. Only HWCAP ++ names in SUBJECT whose bit is set in BITMASK and whose name is in ++ 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, ++ uint32_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. Up to 32 subdirectories are supported, limited by ++ the width of the uint32_t mask. */ ++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. */ ++uint32_t _dl_hwcaps_subdirs_active (void) attribute_hidden; ++ ++/* Returns a bitmask that marks the last ACTIVE subdirectories in a ++ _dl_hwcaps_subdirs_active string (containing SUBDIRS directories in ++ total) as active. Intended for use in _dl_hwcaps_subdirs_active ++ implementations (if a contiguous tail of the list in ++ _dl_hwcaps_subdirs is selected). */ ++static inline uint32_t ++_dl_hwcaps_subdirs_build_bitmask (int subdirs, int active) ++{ ++ /* Leading subdirectories that are not active. */ ++ int inactive = subdirs - active; ++ if (inactive == 32) ++ return 0; ++ ++ uint32_t mask; ++ if (subdirs != 32) ++ mask = (1U << subdirs) - 1; ++ else ++ mask = -1; ++ return mask ^ ((1U << inactive) - 1); ++} ++ ++#endif /* _DL_HWCAPS_H */ +diff --git a/elf/dl-hwcaps_split.c b/elf/dl-hwcaps_split.c +new file mode 100644 +index 0000000000000000..95225e9f409ca229 +--- /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; ++} ++ ++_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; ++} +diff --git a/elf/dl-load.c b/elf/dl-load.c +index d2be21ea7d1545fe..fee08d7816714178 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. */ +diff --git a/elf/dl-main.h b/elf/dl-main.h +index b51256d3b48230b0..566713a0d10cfdb7 100644 +--- a/elf/dl-main.h ++++ b/elf/dl-main.h +@@ -84,6 +84,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 rtld_mode mode; + + /* True if any of the debugging options is enabled. */ +@@ -98,7 +106,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. */ +diff --git a/elf/dl-support.c b/elf/dl-support.c +index fb9672367f8d6abd..34be8e5babfb6af3 100644 +--- a/elf/dl-support.c ++++ b/elf/dl-support.c +@@ -315,7 +315,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); +diff --git a/elf/dl-usage.c b/elf/dl-usage.c +index 796ad38b43c2211b..e22a9c39427187d1 100644 +--- a/elf/dl-usage.c ++++ b/elf/dl-usage.c +@@ -83,7 +83,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"); + +@@ -132,6 +132,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); ++ _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. */ ++ uint32_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; ++ } ++ ++ if (nothing_printed) ++ _dl_printf ("\n\ ++No subdirectories of glibc-hwcaps directories are searched.\n"); ++} ++ + /* Write a list of hwcap subdirectories to standard output. See + _dl_important_hwcaps in dl-hwcaps.c. */ + static void +@@ -186,6 +247,10 @@ setting environment variables (which would be inherited 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\ +@@ -198,6 +263,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 (EXIT_SUCCESS); + } +diff --git a/elf/markermodMARKER-VALUE.c b/elf/markermodMARKER-VALUE.c +new file mode 100644 +index 0000000000000000..99bdcf71a4e219c6 +--- /dev/null ++++ b/elf/markermodMARKER-VALUE.c +@@ -0,0 +1,29 @@ ++/* Source file template for building shared objects with marker functions. ++ 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 ++ . */ ++ ++/* MARKER and VALUE must be set on the compiler command line. */ ++ ++#ifndef MARKER ++# error MARKER not defined ++#endif ++ ++int ++MARKER (void) ++{ ++ return VALUE; ++} +diff --git a/elf/rtld.c b/elf/rtld.c +index da1eef108508b95f..fde5a6a4a485207e 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -287,6 +287,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 = rtld_mode_normal; + state->any_debug = false; + state->version_info = false; +@@ -1238,6 +1240,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; +diff --git a/elf/tst-dl-hwcaps_split.c b/elf/tst-dl-hwcaps_split.c +new file mode 100644 +index 0000000000000000..364159427074bd1c +--- /dev/null ++++ b/elf/tst-dl-hwcaps_split.c +@@ -0,0 +1,148 @@ ++/* 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); ++} ++ ++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); ++} ++ ++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"))); ++ 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", "second", i)); ++ TEST_VERIFY (!_dl_hwcaps_contains ("first:second:", "second", i)); ++ TEST_VERIFY (!_dl_hwcaps_contains ("first:second::", "second", i)); ++ TEST_VERIFY (!_dl_hwcaps_contains ("first::second", "second", 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" +diff --git a/elf/tst-glibc-hwcaps-mask.c b/elf/tst-glibc-hwcaps-mask.c +new file mode 100644 +index 0000000000000000..27b09b358caf7853 +--- /dev/null ++++ b/elf/tst-glibc-hwcaps-mask.c +@@ -0,0 +1,31 @@ ++/* Test that --glibc-hwcaps-mask works. ++ 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 ++ ++extern int marker1 (void); ++ ++static int ++do_test (void) ++{ ++ /* The marker1 function in elf/markermod1.so returns 1. */ ++ TEST_COMPARE (marker1 (), 1); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-glibc-hwcaps-prepend.c b/elf/tst-glibc-hwcaps-prepend.c +new file mode 100644 +index 0000000000000000..57d7319f1484ca4b +--- /dev/null ++++ b/elf/tst-glibc-hwcaps-prepend.c +@@ -0,0 +1,32 @@ ++/* Test that --glibc-hwcaps-prepend works. ++ 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 ++ ++extern int marker1 (void); ++ ++static int ++do_test (void) ++{ ++ /* The marker1 function in ++ glibc-hwcaps/prepend-markermod1/markermod1.so returns 2. */ ++ TEST_COMPARE (marker1 (), 2); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-glibc-hwcaps.c b/elf/tst-glibc-hwcaps.c +new file mode 100644 +index 0000000000000000..28f47cf8914a1f2a +--- /dev/null ++++ b/elf/tst-glibc-hwcaps.c +@@ -0,0 +1,28 @@ ++/* Stub test for glibc-hwcaps. ++ 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 ++ ++static int ++do_test (void) ++{ ++ puts ("info: generic tst-glibc-hwcaps (tests nothing)"); ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 2c9fdeb286bdaadf..77923499d3de4366 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1045,8 +1045,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; + + /* Gather the information needed to install the profiling tables and start +@@ -1070,9 +1075,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; + diff --git a/SOURCES/glibc-rh1817513-114.patch b/SOURCES/glibc-rh1817513-114.patch new file mode 100644 index 0000000..26cd1b6 --- /dev/null +++ b/SOURCES/glibc-rh1817513-114.patch @@ -0,0 +1,190 @@ +commit 84ba719b260551918965d0a433914de683087645 +Author: Florian Weimer +Date: Fri Dec 4 09:13:43 2020 +0100 + + elf: Add endianness markup to ld.so.cache (bug 27008) + + Use a reserved byte in the new format cache header to indicate whether + the file is in little endian or big endian format. Eventually, this + information could be used to provide a unified cache for qemu-user + and similiar scenarios. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/cache.c b/elf/cache.c +index edcdd4b7cc1a6a0b..28e4889d006d2f0b 100644 +--- a/elf/cache.c ++++ b/elf/cache.c +@@ -152,6 +152,14 @@ print_entry (const char *lib, int flag, unsigned int osversion, + printf (") => %s\n", key); + } + ++/* Print an error and exit if the new-file cache is internally ++ inconsistent. */ ++static void ++check_new_cache (struct cache_file_new *cache) ++{ ++ if (! cache_file_new_matches_endian (cache)) ++ error (EXIT_FAILURE, 0, _("Cache file has wrong endianness.\n")); ++} + + /* Print the whole cache file, if a file contains the new cache format + hidden in the old one, print the contents of the new format. */ +@@ -193,6 +201,7 @@ print_cache (const char *cache_name) + || memcmp (cache_new->version, CACHE_VERSION, + sizeof CACHE_VERSION - 1)) + error (EXIT_FAILURE, 0, _("File is not a cache file.\n")); ++ check_new_cache (cache_new); + format = 1; + /* This is where the strings start. */ + cache_data = (const char *) cache_new; +@@ -222,6 +231,7 @@ print_cache (const char *cache_name) + && memcmp (cache_new->version, CACHE_VERSION, + sizeof CACHE_VERSION - 1) == 0) + { ++ check_new_cache (cache_new); + cache_data = (const char *) cache_new; + format = 1; + } +@@ -361,6 +371,7 @@ save_cache (const char *cache_name) + + file_entries_new->nlibs = cache_entry_count; + file_entries_new->len_strings = total_strlen; ++ file_entries_new->flags = cache_file_new_flags_endian_current; + } + + /* Pad for alignment of cache_file_new. */ +diff --git a/elf/dl-cache.c b/elf/dl-cache.c +index 366a051dfcd26132..de063faa8b2c88ae 100644 +--- a/elf/dl-cache.c ++++ b/elf/dl-cache.c +@@ -242,6 +242,11 @@ _dl_load_cache_lookup (const char *name) + && ((cachesize - sizeof *cache_new) / sizeof (struct file_entry_new) + >= ((struct cache_file_new *) file)->nlibs)) + { ++ if (! cache_file_new_matches_endian (file)) ++ { ++ __munmap (file, cachesize); ++ file = (void *) -1; ++ } + cache_new = file; + cache = file; + } +@@ -263,7 +268,20 @@ _dl_load_cache_lookup (const char *name) + if (cachesize < (offset + sizeof (struct cache_file_new)) + || memcmp (cache_new->magic, CACHEMAGIC_VERSION_NEW, + sizeof CACHEMAGIC_VERSION_NEW - 1) != 0) +- cache_new = (void *) -1; ++ cache_new = (void *) -1; ++ else ++ { ++ if (! cache_file_new_matches_endian (cache_new)) ++ { ++ /* The old-format part of the cache is bogus as well ++ if the endianness does not match. (But it is ++ unclear how the new header can be located if the ++ endianess does not match.) */ ++ cache = (void *) -1; ++ cache_new = (void *) -1; ++ __munmap (file, cachesize); ++ } ++ } + } + else + { +diff --git a/sysdeps/generic/dl-cache.h b/sysdeps/generic/dl-cache.h +index 3c5730dfe42c7c88..6ecfd6da0e59329c 100644 +--- a/sysdeps/generic/dl-cache.h ++++ b/sysdeps/generic/dl-cache.h +@@ -16,6 +16,11 @@ + License along with the GNU C Library; if not, see + . */ + ++#ifndef _DL_CACHE_H ++#define _DL_CACHE_H ++ ++#include ++#include + #include + + #ifndef _DL_CACHE_DEFAULT_ID +@@ -92,17 +97,72 @@ struct file_entry_new + uint64_t hwcap; /* Hwcap entry. */ + }; + ++/* See flags member of struct cache_file_new below. */ ++enum ++ { ++ /* No endianness information available. An old ldconfig version ++ without endianness support wrote the file. */ ++ cache_file_new_flags_endian_unset = 0, ++ ++ /* Cache is invalid and should be ignored. */ ++ cache_file_new_flags_endian_invalid = 1, ++ ++ /* Cache format is little endian. */ ++ cache_file_new_flags_endian_little = 2, ++ ++ /* Cache format is big endian. */ ++ cache_file_new_flags_endian_big = 3, ++ ++ /* Bit mask to extract the cache_file_new_flags_endian_* ++ values. */ ++ cache_file_new_flags_endian_mask = 3, ++ ++ /* Expected value of the endian bits in the flags member for the ++ current architecture. */ ++ cache_file_new_flags_endian_current ++ = (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ ++ ? cache_file_new_flags_endian_little ++ : cache_file_new_flags_endian_big), ++ }; ++ + struct cache_file_new + { + char magic[sizeof CACHEMAGIC_NEW - 1]; + char version[sizeof CACHE_VERSION - 1]; + uint32_t nlibs; /* Number of entries. */ + uint32_t len_strings; /* Size of string table. */ +- uint32_t unused[5]; /* Leave space for future extensions ++ ++ /* flags & cache_file_new_flags_endian_mask is one of the values ++ cache_file_new_flags_endian_unset, cache_file_new_flags_endian_invalid, ++ cache_file_new_flags_endian_little, cache_file_new_flags_endian_big. ++ ++ The remaining bits are unused and should be generated as zero and ++ ignored by readers. */ ++ uint8_t flags; ++ ++ uint8_t padding_unsed[3]; /* Not used, for future extensions. */ ++ ++ uint32_t unused[4]; /* Leave space for future extensions + and align to 8 byte boundary. */ + struct file_entry_new libs[0]; /* Entries describing libraries. */ + /* After this the string table of size len_strings is found. */ + }; ++_Static_assert (sizeof (struct cache_file_new) == 48, ++ "size of struct cache_file_new"); ++ ++/* Returns false if *CACHE has the wrong endianness for this ++ architecture, and true if the endianness matches (or is ++ unknown). */ ++static inline bool ++cache_file_new_matches_endian (const struct cache_file_new *cache) ++{ ++ /* A zero value for cache->flags means that no endianness ++ information is available. */ ++ return cache->flags == 0 ++ || ((cache->flags & cache_file_new_flags_endian_big) ++ == cache_file_new_flags_endian_current); ++} ++ + + /* Used to align cache_file_new. */ + #define ALIGN_CACHE(addr) \ +@@ -110,3 +170,5 @@ struct cache_file_new + & (~(__alignof__ (struct cache_file_new) - 1))) + + extern int _dl_cache_libcmp (const char *p1, const char *p2) attribute_hidden; ++ ++#endif /* _DL_CACHE_H */ diff --git a/SOURCES/glibc-rh1817513-115.patch b/SOURCES/glibc-rh1817513-115.patch new file mode 100644 index 0000000..3b0db56 --- /dev/null +++ b/SOURCES/glibc-rh1817513-115.patch @@ -0,0 +1,312 @@ +commit dfb3f101c5ef23adf60d389058a2b33e23303d04 +Author: Florian Weimer +Date: Fri Dec 4 09:13:43 2020 +0100 + + elf: Add extension mechanism to ld.so.cache + + A previously unused new-format header field is used to record + the address of an extension directory. + + This change adds a demo extension which records the version of + ldconfig which builds a file. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/cache.c b/elf/cache.c +index 28e4889d006d2f0b..5a8f1ad70cc3fead 100644 +--- a/elf/cache.c ++++ b/elf/cache.c +@@ -15,6 +15,7 @@ + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + ++#include + #include + #include + #include +@@ -33,6 +34,7 @@ + + #include + #include ++#include + + struct cache_entry + { +@@ -161,6 +163,21 @@ check_new_cache (struct cache_file_new *cache) + error (EXIT_FAILURE, 0, _("Cache file has wrong endianness.\n")); + } + ++/* Print the extension information at the cache at start address ++ FILE_BASE, of length FILE_SIZE bytes. The new-format cache header ++ is at CACHE, and the file name for diagnostics is CACHE_NAME. */ ++static void ++print_extensions (struct cache_extension_all_loaded *ext) ++{ ++ if (ext->sections[cache_extension_tag_generator].base != NULL) ++ { ++ fputs (_("Cache generated by: "), stdout); ++ fwrite (ext->sections[cache_extension_tag_generator].base, 1, ++ ext->sections[cache_extension_tag_generator].size, stdout); ++ putchar ('\n'); ++ } ++} ++ + /* Print the whole cache file, if a file contains the new cache format + hidden in the old one, print the contents of the new format. */ + void +@@ -250,6 +267,11 @@ print_cache (const char *cache_name) + } + else if (format == 1) + { ++ struct cache_extension_all_loaded ext; ++ if (!cache_extension_load (cache_new, cache, cache_size, &ext)) ++ error (EXIT_FAILURE, 0, ++ _("Malformed extension data in cache file %s\n"), cache_name); ++ + printf (_("%d libs found in cache `%s'\n"), + cache_new->nlibs, cache_name); + +@@ -260,6 +282,7 @@ print_cache (const char *cache_name) + cache_new->libs[i].osversion, + cache_new->libs[i].hwcap, + cache_data + cache_new->libs[i].value); ++ print_extensions (&ext); + } + /* Cleanup. */ + munmap (cache, cache_size); +@@ -301,6 +324,45 @@ compare (const struct cache_entry *e1, const struct cache_entry *e2) + return res; + } + ++/* Size of the cache extension directory. All tags are assumed to be ++ present. */ ++enum ++ { ++ cache_extension_size = (offsetof (struct cache_extension, sections) ++ + (cache_extension_count ++ * sizeof (struct cache_extension_section))) ++ }; ++ ++/* Write the cache extensions to FD. The extension directory is ++ assumed to be located at CACHE_EXTENSION_OFFSET. */ ++static void ++write_extensions (int fd, uint32_t cache_extension_offset) ++{ ++ assert ((cache_extension_offset % 4) == 0); ++ ++ struct cache_extension *ext = xmalloc (cache_extension_size); ++ ext->magic = cache_extension_magic; ++ ext->count = cache_extension_count; ++ ++ for (int i = 0; i < cache_extension_count; ++i) ++ { ++ ext->sections[i].tag = i; ++ ext->sections[i].flags = 0; ++ } ++ ++ const char *generator ++ = "ldconfig " PKGVERSION RELEASE " release version " VERSION; ++ ext->sections[cache_extension_tag_generator].offset ++ = cache_extension_offset + cache_extension_size; ++ ext->sections[cache_extension_tag_generator].size = strlen (generator); ++ ++ if (write (fd, ext, cache_extension_size) != cache_extension_size ++ || write (fd, generator, strlen (generator)) != strlen (generator)) ++ error (EXIT_FAILURE, errno, _("Writing of cache extension data failed")); ++ ++ free (ext); ++} ++ + /* Save the contents of the cache. */ + void + save_cache (const char *cache_name) +@@ -435,6 +497,25 @@ save_cache (const char *cache_name) + && idx_old < cache_entry_old_count) + file_entries->libs[idx_old] = file_entries->libs[idx_old - 1]; + ++ /* Compute the location of the extension directory. This ++ implementation puts the directory after the string table. The ++ size computation matches the write calls below. The extension ++ directory does not exist with format 0, so the value does not ++ matter. */ ++ uint32_t extension_offset = 0; ++ if (opt_format != opt_format_new) ++ extension_offset += file_entries_size; ++ if (opt_format != opt_format_old) ++ { ++ if (opt_format != opt_format_new) ++ extension_offset += pad; ++ extension_offset += file_entries_new_size; ++ } ++ extension_offset += total_strlen; ++ extension_offset = roundup (extension_offset, 4); /* Provide alignment. */ ++ if (opt_format != opt_format_old) ++ file_entries_new->extension_offset = extension_offset; ++ + /* Write out the cache. */ + + /* Write cache first to a temporary file and rename it later. */ +@@ -473,6 +554,14 @@ save_cache (const char *cache_name) + if (write (fd, strings, total_strlen) != (ssize_t) total_strlen) + error (EXIT_FAILURE, errno, _("Writing of cache data failed")); + ++ if (opt_format != opt_format_old) ++ { ++ /* Align file position to 4. */ ++ off64_t old_offset = lseek64 (fd, extension_offset, SEEK_SET); ++ assert ((unsigned long long int) (extension_offset - old_offset) < 4); ++ write_extensions (fd, extension_offset); ++ } ++ + /* Make sure user can always read cache file */ + if (chmod (temp_name, S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR)) + error (EXIT_FAILURE, errno, +diff --git a/sysdeps/generic/dl-cache.h b/sysdeps/generic/dl-cache.h +index 6ecfd6da0e59329c..259e843724531630 100644 +--- a/sysdeps/generic/dl-cache.h ++++ b/sysdeps/generic/dl-cache.h +@@ -21,7 +21,9 @@ + + #include + #include ++#include + #include ++#include + + #ifndef _DL_CACHE_DEFAULT_ID + # define _DL_CACHE_DEFAULT_ID 3 +@@ -142,7 +144,11 @@ struct cache_file_new + + uint8_t padding_unsed[3]; /* Not used, for future extensions. */ + +- uint32_t unused[4]; /* Leave space for future extensions ++ /* File offset of the extension directory. See struct ++ cache_extension below. Must be a multiple of four. */ ++ uint32_t extension_offset; ++ ++ uint32_t unused[3]; /* Leave space for future extensions + and align to 8 byte boundary. */ + struct file_entry_new libs[0]; /* Entries describing libraries. */ + /* After this the string table of size len_strings is found. */ +@@ -164,6 +170,121 @@ cache_file_new_matches_endian (const struct cache_file_new *cache) + } + + ++/* Randomly chosen magic value, which allows for additional ++ consistency verification. */ ++enum { cache_extension_magic = (uint32_t) -358342284 }; ++ ++/* Tag values for different kinds of extension sections. Similar to ++ SHT_* constants. */ ++enum cache_extension_tag ++ { ++ /* Array of bytes containing the glibc version that generated this ++ cache file. */ ++ cache_extension_tag_generator, ++ ++ /* Total number of known cache extension tags. */ ++ cache_extension_count ++ }; ++ ++/* Element in the array following struct cache_extension. Similar to ++ an ELF section header. */ ++struct cache_extension_section ++{ ++ /* Type of the extension section. A enum cache_extension_tag value. */ ++ uint32_t tag; ++ ++ /* Extension-specific flags. Currently generated as zero. */ ++ uint32_t flags; ++ ++ /* Offset from the start of the file for the data in this extension ++ section. Specific extensions can have alignment constraints. */ ++ uint32_t offset; ++ ++ /* Length in bytes of the extension data. Specific extensions may ++ have size requirements. */ ++ uint32_t size; ++}; ++ ++/* The extension directory in the cache. An array of struct ++ cache_extension_section entries. */ ++struct cache_extension ++{ ++ uint32_t magic; /* Always cache_extension_magic. */ ++ uint32_t count; /* Number of following entries. */ ++ ++ /* count section descriptors of type struct cache_extension_section ++ follow. */ ++ struct cache_extension_section sections[]; ++}; ++ ++/* A relocated version of struct cache_extension_section. */ ++struct cache_extension_loaded ++{ ++ /* Address and size of this extension section. base is NULL if the ++ section is missing from the file. */ ++ const void *base; ++ size_t size; ++ ++ /* Flags from struct cache_extension_section. */ ++ uint32_t flags; ++}; ++ ++/* All supported extension sections, relocated. Filled in by ++ cache_extension_load below. */ ++struct cache_extension_all_loaded ++{ ++ struct cache_extension_loaded sections[cache_extension_count]; ++}; ++ ++static bool __attribute__ ((unused)) ++cache_extension_load (const struct cache_file_new *cache, ++ const void *file_base, size_t file_size, ++ struct cache_extension_all_loaded *loaded) ++{ ++ memset (loaded, 0, sizeof (*loaded)); ++ if (cache->extension_offset == 0) ++ /* No extensions present. This is not a format error. */ ++ return true; ++ if ((cache->extension_offset % 4) != 0) ++ /* Extension offset is misaligned. */ ++ return false; ++ size_t size_tmp; ++ if (__builtin_add_overflow (cache->extension_offset, ++ sizeof (struct cache_extension), &size_tmp) ++ || size_tmp > file_size) ++ /* Extension extends beyond the end of the file. */ ++ return false; ++ const struct cache_extension *ext = file_base + cache->extension_offset; ++ if (ext->magic != cache_extension_magic) ++ return false; ++ if (__builtin_mul_overflow (ext->count, ++ sizeof (struct cache_extension_section), ++ &size_tmp) ++ || __builtin_add_overflow (cache->extension_offset ++ + sizeof (struct cache_extension), size_tmp, ++ &size_tmp) ++ || size_tmp > file_size) ++ /* Extension array extends beyond the end of the file. */ ++ return false; ++ for (uint32_t i = 0; i < ext->count; ++i) ++ { ++ if (__builtin_add_overflow (ext->sections[i].offset, ++ ext->sections[i].size, &size_tmp) ++ || size_tmp > file_size) ++ /* Extension data extends beyond the end of the file. */ ++ return false; ++ ++ uint32_t tag = ext->sections[i].tag; ++ if (tag >= cache_extension_count) ++ /* Tag is out of range and unrecognized. */ ++ continue; ++ loaded->sections[tag].base = file_base + ext->sections[i].offset; ++ loaded->sections[tag].size = ext->sections[i].size; ++ loaded->sections[tag].flags = ext->sections[i].flags; ++ } ++ return true; ++} ++ + /* Used to align cache_file_new. */ + #define ALIGN_CACHE(addr) \ + (((addr) + __alignof__ (struct cache_file_new) -1) \ diff --git a/SOURCES/glibc-rh1817513-116.patch b/SOURCES/glibc-rh1817513-116.patch new file mode 100644 index 0000000..e5f927f --- /dev/null +++ b/SOURCES/glibc-rh1817513-116.patch @@ -0,0 +1,544 @@ +commit 785969a047ad2f23f758901c6816422573544453 +Author: Florian Weimer +Date: Fri Dec 4 09:13:43 2020 +0100 + + elf: Implement a string table for ldconfig, with tail merging + + This will be used in ldconfig to reduce the ld.so.cache size slightly. + + Tail merging is an optimization where a pointer points into another + string if the first string is a suffix of the second string. + + The hash function FNV-1a was chosen because it is simple and achieves + good dispersion even for short strings (so that the hash table bucket + count can be a power of two). It is clearly superior to the hsearch + hash and the ELF hash in this regard. + + The hash table uses chaining for collision resolution. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/Makefile b/elf/Makefile +index f795617780b393ec..abb3e9d1179ef5cd 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -163,7 +163,7 @@ tests-container = \ + + tests := tst-tls9 tst-leaks1 \ + tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 \ +- tst-auxv ++ tst-auxv tst-stringtable + tests-internal := tst-tls1 tst-tls2 $(tests-static-internal) + tests-static := $(tests-static-normal) $(tests-static-internal) + +diff --git a/elf/stringtable.c b/elf/stringtable.c +new file mode 100644 +index 0000000000000000..099347d73ee70b8f +--- /dev/null ++++ b/elf/stringtable.c +@@ -0,0 +1,209 @@ ++/* String tables for ld.so.cache construction. Implementation. ++ Copyright (C) 2020 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published ++ by the Free Software Foundation; version 2 of the License, or ++ (at your option) any later version. ++ ++ This program 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 General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, see . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++stringtable_init (struct stringtable *table) ++{ ++ table->count = 0; ++ ++ /* This needs to be a power of two. 128 is sufficient to keep track ++ of 42 DSOs without resizing (assuming two strings per DSOs). ++ glibc itself comes with more than 20 DSOs, so 64 would likely to ++ be too small. */ ++ table->allocated = 128; ++ ++ table->entries = xcalloc (table->allocated, sizeof (table->entries[0])); ++} ++ ++/* 32-bit FNV-1a hash function. */ ++static uint32_t ++fnv1a (const char *string, size_t length) ++{ ++ const unsigned char *p = (const unsigned char *) string; ++ uint32_t hash = 2166136261U; ++ for (size_t i = 0; i < length; ++i) ++ { ++ hash ^= p[i]; ++ hash *= 16777619U; ++ } ++ return hash; ++} ++ ++/* Double the capacity of the hash table. */ ++static void ++stringtable_rehash (struct stringtable *table) ++{ ++ /* This computation cannot overflow because the old total in-memory ++ size of the hash table is larger than the computed value. */ ++ uint32_t new_allocated = table->allocated * 2; ++ struct stringtable_entry **new_entries ++ = xcalloc (new_allocated, sizeof (table->entries[0])); ++ ++ uint32_t mask = new_allocated - 1; ++ for (uint32_t i = 0; i < table->allocated; ++i) ++ for (struct stringtable_entry *e = table->entries[i]; e != NULL; ) ++ { ++ struct stringtable_entry *next = e->next; ++ uint32_t hash = fnv1a (e->string, e->length); ++ uint32_t new_index = hash & mask; ++ e->next = new_entries[new_index]; ++ new_entries[new_index] = e; ++ e = next; ++ } ++ ++ free (table->entries); ++ table->entries = new_entries; ++ table->allocated = new_allocated; ++} ++ ++struct stringtable_entry * ++stringtable_add (struct stringtable *table, const char *string) ++{ ++ /* Check for a zero-initialized table. */ ++ if (table->allocated == 0) ++ stringtable_init (table); ++ ++ size_t length = strlen (string); ++ if (length > (1U << 30)) ++ error (EXIT_FAILURE, 0, _("String table string is too long")); ++ uint32_t hash = fnv1a (string, length); ++ ++ /* Return a previously-existing entry. */ ++ for (struct stringtable_entry *e ++ = table->entries[hash & (table->allocated - 1)]; ++ e != NULL; e = e->next) ++ if (e->length == length && memcmp (e->string, string, length) == 0) ++ return e; ++ ++ /* Increase the size of the table if necessary. Keep utilization ++ below two thirds. */ ++ if (table->count >= (1U << 30)) ++ error (EXIT_FAILURE, 0, _("String table has too many entries")); ++ if (table->count * 3 > table->allocated * 2) ++ stringtable_rehash (table); ++ ++ /* Add the new table entry. */ ++ ++table->count; ++ struct stringtable_entry *e ++ = xmalloc (offsetof (struct stringtable_entry, string) + length + 1); ++ uint32_t index = hash & (table->allocated - 1); ++ e->next = table->entries[index]; ++ table->entries[index] = e; ++ e->length = length; ++ e->offset = 0; ++ memcpy (e->string, string, length + 1); ++ return e; ++} ++ ++/* Sort reversed strings in reverse lexicographic order. This is used ++ for tail merging. */ ++static int ++finalize_compare (const void *l, const void *r) ++{ ++ struct stringtable_entry *left = *(struct stringtable_entry **) l; ++ struct stringtable_entry *right = *(struct stringtable_entry **) r; ++ size_t to_compare; ++ if (left->length < right->length) ++ to_compare = left->length; ++ else ++ to_compare = right->length; ++ for (size_t i = 1; i <= to_compare; ++i) ++ { ++ unsigned char lch = left->string[left->length - i]; ++ unsigned char rch = right->string[right->length - i]; ++ if (lch != rch) ++ return rch - lch; ++ } ++ if (left->length == right->length) ++ return 0; ++ else if (left->length < right->length) ++ /* Longer strings should come first. */ ++ return 1; ++ else ++ return -1; ++} ++ ++void ++stringtable_finalize (struct stringtable *table, ++ struct stringtable_finalized *result) ++{ ++ if (table->count == 0) ++ { ++ result->strings = xstrdup (""); ++ result->size = 0; ++ return; ++ } ++ ++ /* Optimize the order of the strings. */ ++ struct stringtable_entry **array = xcalloc (table->count, sizeof (*array)); ++ { ++ size_t j = 0; ++ for (uint32_t i = 0; i < table->allocated; ++i) ++ for (struct stringtable_entry *e = table->entries[i]; e != NULL; ++ e = e->next) ++ { ++ array[j] = e; ++ ++j; ++ } ++ assert (j == table->count); ++ } ++ qsort (array, table->count, sizeof (*array), finalize_compare); ++ ++ /* Assign offsets, using tail merging (sharing suffixes) if possible. */ ++ array[0]->offset = 0; ++ for (uint32_t j = 1; j < table->count; ++j) ++ { ++ struct stringtable_entry *previous = array[j - 1]; ++ struct stringtable_entry *current = array[j]; ++ if (previous->length >= current->length ++ && memcmp (&previous->string[previous->length - current->length], ++ current->string, current->length) == 0) ++ current->offset = (previous->offset + previous->length ++ - current->length); ++ else if (__builtin_add_overflow (previous->offset, ++ previous->length + 1, ++ ¤t->offset)) ++ error (EXIT_FAILURE, 0, _("String table is too large")); ++ } ++ ++ /* Allocate the result string. */ ++ { ++ struct stringtable_entry *last = array[table->count - 1]; ++ if (__builtin_add_overflow (last->offset, last->length + 1, ++ &result->size)) ++ error (EXIT_FAILURE, 0, _("String table is too large")); ++ } ++ /* The strings are copied from the hash table, so the array is no ++ longer needed. */ ++ free (array); ++ result->strings = xcalloc (result->size, 1); ++ ++ /* Copy the strings. */ ++ for (uint32_t i = 0; i < table->allocated; ++i) ++ for (struct stringtable_entry *e = table->entries[i]; e != NULL; ++ e = e->next) ++ if (result->strings[e->offset] == '\0') ++ memcpy (&result->strings[e->offset], e->string, e->length + 1); ++} +diff --git a/elf/stringtable.h b/elf/stringtable.h +new file mode 100644 +index 0000000000000000..7d57d1bda9602947 +--- /dev/null ++++ b/elf/stringtable.h +@@ -0,0 +1,64 @@ ++/* String tables for ld.so.cache construction. ++ Copyright (C) 2020 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published ++ by the Free Software Foundation; version 2 of the License, or ++ (at your option) any later version. ++ ++ This program 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 General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, see . */ ++ ++#ifndef _STRINGTABLE_H ++#define _STRINGTABLE_H ++ ++#include ++#include ++ ++/* An entry in the string table. Only the length and string fields are ++ expected to be used outside the string table code. */ ++struct stringtable_entry ++{ ++ struct stringtable_entry *next; /* For collision resolution. */ ++ uint32_t length; /* Length of then string. */ ++ uint32_t offset; /* From start of finalized table. */ ++ char string[]; /* Null-terminated string. */ ++}; ++ ++/* A string table. Zero-initialization produces a valid atable. */ ++struct stringtable ++{ ++ struct stringtable_entry **entries; /* Array of hash table buckets. */ ++ uint32_t count; /* Number of elements in the table. */ ++ uint32_t allocated; /* Length of the entries array. */ ++}; ++ ++/* Adds STRING to TABLE. May return the address of an existing entry. */ ++struct stringtable_entry *stringtable_add (struct stringtable *table, ++ const char *string); ++ ++/* Result of stringtable_finalize. SIZE bytes at STRINGS should be ++ written to the file. */ ++struct stringtable_finalized ++{ ++ char *strings; ++ size_t size; ++}; ++ ++/* Assigns offsets to string table entries and computes the serialized ++ form of the string table. */ ++void stringtable_finalize (struct stringtable *table, ++ struct stringtable_finalized *result); ++ ++/* Deallocate the string table (but not the TABLE pointer itself). ++ (The table can be re-used for adding more strings without ++ initialization.) */ ++void stringtable_free (struct stringtable *table); ++ ++#endif /* _STRINGTABLE_H */ +diff --git a/elf/stringtable_free.c b/elf/stringtable_free.c +new file mode 100644 +index 0000000000000000..8588a254705d4df8 +--- /dev/null ++++ b/elf/stringtable_free.c +@@ -0,0 +1,33 @@ ++/* String tables for ld.so.cache construction. Deallocation (for tests only). ++ Copyright (C) 2020 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published ++ by the Free Software Foundation; version 2 of the License, or ++ (at your option) any later version. ++ ++ This program 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 General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, see . */ ++ ++#include ++#include ++ ++void ++stringtable_free (struct stringtable *table) ++{ ++ for (uint32_t i = 0; i < table->allocated; ++i) ++ for (struct stringtable_entry *e = table->entries[i]; e != NULL; ) ++ { ++ struct stringtable_entry *next = e->next; ++ free (e); ++ e = next; ++ } ++ free (table->entries); ++ *table = (struct stringtable) { 0, }; ++} +diff --git a/elf/tst-stringtable.c b/elf/tst-stringtable.c +new file mode 100644 +index 0000000000000000..3731086037567d57 +--- /dev/null ++++ b/elf/tst-stringtable.c +@@ -0,0 +1,181 @@ ++/* Unit test for ldconfig string tables. ++ Copyright (C) 2020 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published ++ by the Free Software Foundation; version 2 of the License, or ++ (at your option) any later version. ++ ++ This program 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 General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, see . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ /* Empty string table. */ ++ { ++ struct stringtable s = { 0, }; ++ struct stringtable_finalized f; ++ stringtable_finalize (&s, &f); ++ TEST_COMPARE_STRING (f.strings, ""); ++ TEST_COMPARE (f.size, 0); ++ free (f.strings); ++ stringtable_free (&s); ++ } ++ ++ /* String table with one empty string. */ ++ { ++ struct stringtable s = { 0, }; ++ struct stringtable_entry *e = stringtable_add (&s, ""); ++ TEST_COMPARE_STRING (e->string, ""); ++ TEST_COMPARE (e->length, 0); ++ TEST_COMPARE (s.count, 1); ++ ++ struct stringtable_finalized f; ++ stringtable_finalize (&s, &f); ++ TEST_COMPARE (e->offset, 0); ++ TEST_COMPARE_STRING (f.strings, ""); ++ TEST_COMPARE (f.size, 1); ++ free (f.strings); ++ stringtable_free (&s); ++ } ++ ++ /* String table with one non-empty string. */ ++ { ++ struct stringtable s = { 0, }; ++ struct stringtable_entry *e = stringtable_add (&s, "name"); ++ TEST_COMPARE_STRING (e->string, "name"); ++ TEST_COMPARE (e->length, 4); ++ TEST_COMPARE (s.count, 1); ++ ++ struct stringtable_finalized f; ++ stringtable_finalize (&s, &f); ++ TEST_COMPARE (e->offset, 0); ++ TEST_COMPARE_STRING (f.strings, "name"); ++ TEST_COMPARE (f.size, 5); ++ free (f.strings); ++ stringtable_free (&s); ++ } ++ ++ /* Two strings, one is a prefix of the other. Tail-merging can only ++ happen in one way in this case. */ ++ { ++ struct stringtable s = { 0, }; ++ struct stringtable_entry *suffix = stringtable_add (&s, "suffix"); ++ TEST_COMPARE_STRING (suffix->string, "suffix"); ++ TEST_COMPARE (suffix->length, 6); ++ TEST_COMPARE (s.count, 1); ++ ++ struct stringtable_entry *prefix ++ = stringtable_add (&s, "prefix-suffix"); ++ TEST_COMPARE_STRING (prefix->string, "prefix-suffix"); ++ TEST_COMPARE (prefix->length, strlen ("prefix-suffix")); ++ TEST_COMPARE (s.count, 2); ++ ++ struct stringtable_finalized f; ++ stringtable_finalize (&s, &f); ++ TEST_COMPARE (prefix->offset, 0); ++ TEST_COMPARE (suffix->offset, strlen ("prefix-")); ++ TEST_COMPARE_STRING (f.strings, "prefix-suffix"); ++ TEST_COMPARE (f.size, sizeof ("prefix-suffix")); ++ free (f.strings); ++ stringtable_free (&s); ++ } ++ ++ /* String table with various shared prefixes. Triggers hash ++ resizing. */ ++ { ++ enum { count = 1500 }; ++ char *strings[2 * count]; ++ struct stringtable_entry *entries[2 * count]; ++ struct stringtable s = { 0, }; ++ for (int i = 0; i < count; ++i) ++ { ++ strings[i] = xasprintf ("%d", i); ++ entries[i] = stringtable_add (&s, strings[i]); ++ TEST_COMPARE (entries[i]->length, strlen (strings[i])); ++ TEST_COMPARE_STRING (entries[i]->string, strings[i]); ++ strings[i + count] = xasprintf ("prefix/%d", i); ++ entries[i + count] = stringtable_add (&s, strings[i + count]); ++ TEST_COMPARE (entries[i + count]->length, strlen (strings[i + count])); ++ TEST_COMPARE_STRING (entries[i + count]->string, strings[i + count]); ++ } ++ ++ struct stringtable_finalized f; ++ stringtable_finalize (&s, &f); ++ ++ for (int i = 0; i < 2 * count; ++i) ++ { ++ TEST_COMPARE (entries[i]->length, strlen (strings[i])); ++ TEST_COMPARE_STRING (entries[i]->string, strings[i]); ++ TEST_COMPARE_STRING (f.strings + entries[i]->offset, strings[i]); ++ free (strings[i]); ++ } ++ ++ free (f.strings); ++ stringtable_free (&s); ++ } ++ ++ /* Verify that maximum tail merging happens. */ ++ { ++ struct stringtable s = { 0, }; ++ const char *strings[] = { ++ "", ++ "a", ++ "b", ++ "aa", ++ "aaa", ++ "aa", ++ "bb", ++ "b", ++ "a", ++ "ba", ++ "baa", ++ }; ++ struct stringtable_entry *entries[array_length (strings)]; ++ for (int i = 0; i < array_length (strings); ++i) ++ entries[i] = stringtable_add (&s, strings[i]); ++ for (int i = 0; i < array_length (strings); ++i) ++ TEST_COMPARE_STRING (entries[i]->string, strings[i]); ++ ++ struct stringtable_finalized f; ++ stringtable_finalize (&s, &f); ++ ++ /* There are only four different strings, "aaa", "ba", "baa", ++ "bb". The rest is shared in an unspecified fashion. */ ++ TEST_COMPARE (f.size, 4 + 3 + 4 + 3); ++ ++ for (int i = 0; i < array_length (strings); ++i) ++ { ++ TEST_COMPARE_STRING (entries[i]->string, strings[i]); ++ TEST_COMPARE_STRING (f.strings + entries[i]->offset, strings[i]); ++ } ++ ++ free (f.strings); ++ stringtable_free (&s); ++ } ++ ++ return 0; ++} ++ ++#include ++ ++/* Re-compile the string table implementation here. It is not ++ possible to link against the actual build because it was built for ++ use in ldconfig. */ ++#define _(arg) arg ++#include "stringtable.c" ++#include "stringtable_free.c" diff --git a/SOURCES/glibc-rh1817513-117.patch b/SOURCES/glibc-rh1817513-117.patch new file mode 100644 index 0000000..65516f4 --- /dev/null +++ b/SOURCES/glibc-rh1817513-117.patch @@ -0,0 +1,209 @@ +commit 73b6e50a22dea9ae6144beaaa675d2ac62c281ca +Author: Florian Weimer +Date: Fri Dec 4 09:13:43 2020 +0100 + + elf: Implement tail merging of strings in ldconfig + + This simplifies the string table construction in elf/cache.c + because there is no more need to keep track of offsets explicitly; + the string table implementation does this internally. + + This change slightly reduces the size of the cache on disk. The + file format does not change as a result. The strings are + null-terminated, without explicit length, so tail merging is + transparent to readers. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/Makefile b/elf/Makefile +index abb3e9d1179ef5cd..a3e802a9a99b759c 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -112,7 +112,8 @@ others-static += ldconfig + others += ldconfig + install-rootsbin += ldconfig + +-ldconfig-modules := cache readlib xmalloc xstrdup chroot_canon static-stubs ++ldconfig-modules := cache readlib xmalloc xstrdup chroot_canon static-stubs \ ++ stringtable + extra-objs += $(ldconfig-modules:=.o) + others-extras = $(ldconfig-modules) + endif +diff --git a/elf/cache.c b/elf/cache.c +index 5a8f1ad70cc3fead..f773cacacf26db1c 100644 +--- a/elf/cache.c ++++ b/elf/cache.c +@@ -35,11 +35,15 @@ + #include + #include + #include ++#include ++ ++/* Used to store library names, paths, and other strings. */ ++static struct stringtable strings; + + struct cache_entry + { +- char *lib; /* Library name. */ +- char *path; /* Path to find library. */ ++ struct stringtable_entry *lib; /* Library name. */ ++ struct stringtable_entry *path; /* Path to find library. */ + int flags; /* Flags to indicate kind of library. */ + unsigned int osversion; /* Required OS version. */ + uint64_t hwcap; /* Important hardware capabilities. */ +@@ -300,7 +304,7 @@ static int + compare (const struct cache_entry *e1, const struct cache_entry *e2) + { + /* We need to swap entries here to get the correct sort order. */ +- int res = _dl_cache_libcmp (e2->lib, e1->lib); ++ int res = _dl_cache_libcmp (e2->lib->string, e1->lib->string); + if (res == 0) + { + if (e1->flags < e2->flags) +@@ -369,26 +373,24 @@ save_cache (const char *cache_name) + { + /* The cache entries are sorted already, save them in this order. */ + +- /* Count the length of all strings. */ +- /* The old format doesn't contain hwcap entries and doesn't contain +- libraries in subdirectories with hwcaps entries. Count therefore +- also all entries with hwcap == 0. */ +- size_t total_strlen = 0; + struct cache_entry *entry; + /* Number of cache entries. */ + int cache_entry_count = 0; +- /* Number of normal cache entries. */ ++ /* The old format doesn't contain hwcap entries and doesn't contain ++ libraries in subdirectories with hwcaps entries. Count therefore ++ also all entries with hwcap == 0. */ + int cache_entry_old_count = 0; + + for (entry = entries; entry != NULL; entry = entry->next) + { +- /* Account the final NULs. */ +- total_strlen += strlen (entry->lib) + strlen (entry->path) + 2; + ++cache_entry_count; + if (entry->hwcap == 0) + ++cache_entry_old_count; + } + ++ struct stringtable_finalized strings_finalized; ++ stringtable_finalize (&strings, &strings_finalized); ++ + /* Create the on disk cache structure. */ + struct cache_file *file_entries = NULL; + size_t file_entries_size = 0; +@@ -432,7 +434,7 @@ save_cache (const char *cache_name) + sizeof CACHE_VERSION - 1); + + file_entries_new->nlibs = cache_entry_count; +- file_entries_new->len_strings = total_strlen; ++ file_entries_new->len_strings = strings_finalized.size; + file_entries_new->flags = cache_file_new_flags_endian_current; + } + +@@ -449,20 +451,20 @@ save_cache (const char *cache_name) + str_offset = 0; + + /* An array for all strings. */ +- char *strings = xmalloc (total_strlen); +- char *str = strings; + int idx_old; + int idx_new; + + for (idx_old = 0, idx_new = 0, entry = entries; entry != NULL; + entry = entry->next, ++idx_new) + { +- /* First the library. */ + if (opt_format != opt_format_new && entry->hwcap == 0) + { + file_entries->libs[idx_old].flags = entry->flags; + /* XXX: Actually we can optimize here and remove duplicates. */ + file_entries->libs[idx_old].key = str_offset + pad; ++ file_entries->libs[idx_new].key = str_offset + entry->lib->offset; ++ file_entries->libs[idx_new].value ++ = str_offset + entry->path->offset; + } + if (opt_format != opt_format_old) + { +@@ -473,20 +475,12 @@ save_cache (const char *cache_name) + file_entries_new->libs[idx_new].flags = entry->flags; + file_entries_new->libs[idx_new].osversion = entry->osversion; + file_entries_new->libs[idx_new].hwcap = entry->hwcap; +- file_entries_new->libs[idx_new].key = str_offset; ++ file_entries_new->libs[idx_new].key ++ = str_offset + entry->lib->offset; ++ file_entries_new->libs[idx_new].value ++ = str_offset + entry->path->offset; + } + +- size_t len = strlen (entry->lib) + 1; +- str = mempcpy (str, entry->lib, len); +- str_offset += len; +- /* Then the path. */ +- if (opt_format != opt_format_new && entry->hwcap == 0) +- file_entries->libs[idx_old].value = str_offset + pad; +- if (opt_format != opt_format_old) +- file_entries_new->libs[idx_new].value = str_offset; +- len = strlen (entry->path) + 1; +- str = mempcpy (str, entry->path, len); +- str_offset += len; + /* Ignore entries with hwcap for old format. */ + if (entry->hwcap == 0) + ++idx_old; +@@ -511,7 +505,7 @@ save_cache (const char *cache_name) + extension_offset += pad; + extension_offset += file_entries_new_size; + } +- extension_offset += total_strlen; ++ extension_offset += strings_finalized.size; + extension_offset = roundup (extension_offset, 4); /* Provide alignment. */ + if (opt_format != opt_format_old) + file_entries_new->extension_offset = extension_offset; +@@ -551,7 +545,8 @@ save_cache (const char *cache_name) + error (EXIT_FAILURE, errno, _("Writing of cache data failed")); + } + +- if (write (fd, strings, total_strlen) != (ssize_t) total_strlen) ++ if (write (fd, strings_finalized.strings, strings_finalized.size) ++ != (ssize_t) strings_finalized.size) + error (EXIT_FAILURE, errno, _("Writing of cache data failed")); + + if (opt_format != opt_format_old) +@@ -580,7 +575,7 @@ save_cache (const char *cache_name) + /* Free all allocated memory. */ + free (file_entries_new); + free (file_entries); +- free (strings); ++ free (strings_finalized.strings); + + while (entries) + { +@@ -596,14 +591,19 @@ void + add_to_cache (const char *path, const char *lib, int flags, + unsigned int osversion, uint64_t hwcap) + { +- size_t liblen = strlen (lib) + 1; +- size_t len = liblen + strlen (path) + 1; +- struct cache_entry *new_entry +- = xmalloc (sizeof (struct cache_entry) + liblen + len); +- +- new_entry->lib = memcpy ((char *) (new_entry + 1), lib, liblen); +- new_entry->path = new_entry->lib + liblen; +- snprintf (new_entry->path, len, "%s/%s", path, lib); ++ struct cache_entry *new_entry = xmalloc (sizeof (*new_entry)); ++ ++ struct stringtable_entry *path_interned; ++ { ++ char *p; ++ if (asprintf (&p, "%s/%s", path, lib) < 0) ++ error (EXIT_FAILURE, errno, _("Could not create library path")); ++ path_interned = stringtable_add (&strings, p); ++ free (p); ++ } ++ ++ new_entry->lib = stringtable_add (&strings, lib); ++ new_entry->path = path_interned; + new_entry->flags = flags; + new_entry->osversion = osversion; + new_entry->hwcap = hwcap; diff --git a/SOURCES/glibc-rh1817513-118.patch b/SOURCES/glibc-rh1817513-118.patch new file mode 100644 index 0000000..92620f5 --- /dev/null +++ b/SOURCES/glibc-rh1817513-118.patch @@ -0,0 +1,778 @@ +commit b44ac4f4c7a8bbe5eaa2701aa9452eaf2c96e1dd +Author: Florian Weimer +Date: Fri Dec 4 09:13:43 2020 +0100 + + elf: Process glibc-hwcaps subdirectories in ldconfig + + Libraries from these subdirectories are added to the cache + with a special hwcap bit DL_CACHE_HWCAP_EXTENSION, so that + they are ignored by older dynamic loaders. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/cache.c b/elf/cache.c +index f773cacacf26db1c..dde3d7fefa4105f9 100644 +--- a/elf/cache.c ++++ b/elf/cache.c +@@ -40,6 +40,105 @@ + /* Used to store library names, paths, and other strings. */ + static struct stringtable strings; + ++/* Keeping track of "glibc-hwcaps" subdirectories. During cache ++ construction, a linear search by name is performed to deduplicate ++ entries. */ ++struct glibc_hwcaps_subdirectory ++{ ++ struct glibc_hwcaps_subdirectory *next; ++ ++ /* Interned string with the subdirectory name. */ ++ struct stringtable_entry *name; ++ ++ /* Array index in the cache_extension_tag_glibc_hwcaps section in ++ the stored cached file. This is computed after all the ++ subdirectories have been processed, so that subdirectory names in ++ the extension section can be sorted. */ ++ uint32_t section_index; ++ ++ /* True if the subdirectory is actually used for anything. */ ++ bool used; ++}; ++ ++const char * ++glibc_hwcaps_subdirectory_name (const struct glibc_hwcaps_subdirectory *dir) ++{ ++ return dir->name->string; ++} ++ ++/* Linked list of known hwcaps subdirecty names. */ ++static struct glibc_hwcaps_subdirectory *hwcaps; ++ ++struct glibc_hwcaps_subdirectory * ++new_glibc_hwcaps_subdirectory (const char *name) ++{ ++ struct stringtable_entry *name_interned = stringtable_add (&strings, name); ++ for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next) ++ if (p->name == name_interned) ++ return p; ++ struct glibc_hwcaps_subdirectory *p = xmalloc (sizeof (*p)); ++ p->next = hwcaps; ++ p->name = name_interned; ++ p->section_index = 0; ++ p->used = false; ++ hwcaps = p; ++ return p; ++} ++ ++/* Helper for sorting struct glibc_hwcaps_subdirectory elements by ++ name. */ ++static int ++assign_glibc_hwcaps_indices_compare (const void *l, const void *r) ++{ ++ const struct glibc_hwcaps_subdirectory *left ++ = *(struct glibc_hwcaps_subdirectory **)l; ++ const struct glibc_hwcaps_subdirectory *right ++ = *(struct glibc_hwcaps_subdirectory **)r; ++ return strcmp (glibc_hwcaps_subdirectory_name (left), ++ glibc_hwcaps_subdirectory_name (right)); ++} ++ ++/* Count the number of hwcaps subdirectories which are actually ++ used. */ ++static size_t ++glibc_hwcaps_count (void) ++{ ++ size_t count = 0; ++ for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next) ++ if (p->used) ++ ++count; ++ return count; ++} ++ ++/* Compute the section_index fields for all */ ++static void ++assign_glibc_hwcaps_indices (void) ++{ ++ /* Convert the linked list into an array, so that we can use qsort. ++ Only copy the subdirectories which are actually used. */ ++ size_t count = glibc_hwcaps_count (); ++ struct glibc_hwcaps_subdirectory **array ++ = xmalloc (sizeof (*array) * count); ++ { ++ size_t i = 0; ++ for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next) ++ if (p->used) ++ { ++ array[i] = p; ++ ++i; ++ } ++ assert (i == count); ++ } ++ ++ qsort (array, count, sizeof (*array), assign_glibc_hwcaps_indices_compare); ++ ++ /* Assign the array indices. */ ++ for (size_t i = 0; i < count; ++i) ++ array[i]->section_index = i; ++ ++ free (array); ++} ++ + struct cache_entry + { + struct stringtable_entry *lib; /* Library name. */ +@@ -48,6 +147,10 @@ struct cache_entry + unsigned int osversion; /* Required OS version. */ + uint64_t hwcap; /* Important hardware capabilities. */ + int bits_hwcap; /* Number of bits set in hwcap. */ ++ ++ /* glibc-hwcaps subdirectory. If not NULL, hwcap must be zero. */ ++ struct glibc_hwcaps_subdirectory *hwcaps; ++ + struct cache_entry *next; /* Next entry in list. */ + }; + +@@ -60,7 +163,7 @@ static const char *flag_descr[] = + /* Print a single entry. */ + static void + print_entry (const char *lib, int flag, unsigned int osversion, +- uint64_t hwcap, const char *key) ++ uint64_t hwcap, const char *hwcap_string, const char *key) + { + printf ("\t%s (", lib); + switch (flag & FLAG_TYPE_MASK) +@@ -132,7 +235,9 @@ print_entry (const char *lib, int flag, unsigned int osversion, + printf (",%d", flag & FLAG_REQUIRED_MASK); + break; + } +- if (hwcap != 0) ++ if (hwcap_string != NULL) ++ printf (", hwcap: \"%s\"", hwcap_string); ++ else if (hwcap != 0) + printf (", hwcap: %#.16" PRIx64, hwcap); + if (osversion != 0) + { +@@ -158,6 +263,29 @@ print_entry (const char *lib, int flag, unsigned int osversion, + printf (") => %s\n", key); + } + ++/* Returns the string with the name of the glibcs-hwcaps subdirectory ++ associated with ENTRY->hwcap. file_base must be the base address ++ for string table indices. */ ++static const char * ++glibc_hwcaps_string (struct cache_extension_all_loaded *ext, ++ const void *file_base, size_t file_size, ++ struct file_entry_new *entry) ++{ ++ const uint32_t *hwcaps_array ++ = ext->sections[cache_extension_tag_glibc_hwcaps].base; ++ if (dl_cache_hwcap_extension (entry) && hwcaps_array != NULL) ++ { ++ uint32_t index = (uint32_t) entry->hwcap; ++ if (index < ext->sections[cache_extension_tag_glibc_hwcaps].size / 4) ++ { ++ uint32_t string_table_index = hwcaps_array[index]; ++ if (string_table_index < file_size) ++ return file_base + string_table_index; ++ } ++ } ++ return NULL; ++} ++ + /* Print an error and exit if the new-file cache is internally + inconsistent. */ + static void +@@ -167,9 +295,7 @@ check_new_cache (struct cache_file_new *cache) + error (EXIT_FAILURE, 0, _("Cache file has wrong endianness.\n")); + } + +-/* Print the extension information at the cache at start address +- FILE_BASE, of length FILE_SIZE bytes. The new-format cache header +- is at CACHE, and the file name for diagnostics is CACHE_NAME. */ ++/* Print the extension information in *EXT. */ + static void + print_extensions (struct cache_extension_all_loaded *ext) + { +@@ -266,7 +392,7 @@ print_cache (const char *cache_name) + /* Print everything. */ + for (unsigned int i = 0; i < cache->nlibs; i++) + print_entry (cache_data + cache->libs[i].key, +- cache->libs[i].flags, 0, 0, ++ cache->libs[i].flags, 0, 0, NULL, + cache_data + cache->libs[i].value); + } + else if (format == 1) +@@ -281,11 +407,16 @@ print_cache (const char *cache_name) + + /* Print everything. */ + for (unsigned int i = 0; i < cache_new->nlibs; i++) +- print_entry (cache_data + cache_new->libs[i].key, +- cache_new->libs[i].flags, +- cache_new->libs[i].osversion, +- cache_new->libs[i].hwcap, +- cache_data + cache_new->libs[i].value); ++ { ++ const char *hwcaps_string ++ = glibc_hwcaps_string (&ext, cache, cache_size, ++ &cache_new->libs[i]); ++ print_entry (cache_data + cache_new->libs[i].key, ++ cache_new->libs[i].flags, ++ cache_new->libs[i].osversion, ++ cache_new->libs[i].hwcap, hwcaps_string, ++ cache_data + cache_new->libs[i].value); ++ } + print_extensions (&ext); + } + /* Cleanup. */ +@@ -311,8 +442,23 @@ compare (const struct cache_entry *e1, const struct cache_entry *e2) + return 1; + else if (e1->flags > e2->flags) + return -1; ++ /* Keep the glibc-hwcaps extension entries before the regular ++ entries, and sort them by their names. search_cache in ++ dl-cache.c stops searching once the first non-extension entry ++ is found, so the extension entries need to come first. */ ++ else if (e1->hwcaps != NULL && e2->hwcaps == NULL) ++ return -1; ++ else if (e1->hwcaps == NULL && e2->hwcaps != NULL) ++ return 1; ++ else if (e1->hwcaps != NULL && e2->hwcaps != NULL) ++ { ++ res = strcmp (glibc_hwcaps_subdirectory_name (e1->hwcaps), ++ glibc_hwcaps_subdirectory_name (e2->hwcaps)); ++ if (res != 0) ++ return res; ++ } + /* Sort by most specific hwcap. */ +- else if (e2->bits_hwcap > e1->bits_hwcap) ++ if (e2->bits_hwcap > e1->bits_hwcap) + return 1; + else if (e2->bits_hwcap < e1->bits_hwcap) + return -1; +@@ -337,30 +483,65 @@ enum + * sizeof (struct cache_extension_section))) + }; + +-/* Write the cache extensions to FD. The extension directory is +- assumed to be located at CACHE_EXTENSION_OFFSET. */ ++/* Write the cache extensions to FD. The string table is shifted by ++ STRING_TABLE_OFFSET. The extension directory is assumed to be ++ located at CACHE_EXTENSION_OFFSET. assign_glibc_hwcaps_indices ++ must have been called. */ + static void +-write_extensions (int fd, uint32_t cache_extension_offset) ++write_extensions (int fd, uint32_t str_offset, ++ uint32_t cache_extension_offset) + { + assert ((cache_extension_offset % 4) == 0); + ++ /* The length and contents of the glibc-hwcaps section. */ ++ uint32_t hwcaps_count = glibc_hwcaps_count (); ++ uint32_t hwcaps_offset = cache_extension_offset + cache_extension_size; ++ uint32_t hwcaps_size = hwcaps_count * sizeof (uint32_t); ++ uint32_t *hwcaps_array = xmalloc (hwcaps_size); ++ for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next) ++ if (p->used) ++ hwcaps_array[p->section_index] = str_offset + p->name->offset; ++ ++ /* This is the offset of the generator string. */ ++ uint32_t generator_offset = hwcaps_offset; ++ if (hwcaps_count == 0) ++ /* There is no section for the hwcaps subdirectories. */ ++ generator_offset -= sizeof (struct cache_extension_section); ++ else ++ /* The string table indices for the hwcaps subdirectories shift ++ the generator string backwards. */ ++ generator_offset += hwcaps_size; ++ + struct cache_extension *ext = xmalloc (cache_extension_size); + ext->magic = cache_extension_magic; +- ext->count = cache_extension_count; + +- for (int i = 0; i < cache_extension_count; ++i) +- { +- ext->sections[i].tag = i; +- ext->sections[i].flags = 0; +- } ++ /* Extension index current being filled. */ ++ size_t xid = 0; + + const char *generator + = "ldconfig " PKGVERSION RELEASE " release version " VERSION; +- ext->sections[cache_extension_tag_generator].offset +- = cache_extension_offset + cache_extension_size; +- ext->sections[cache_extension_tag_generator].size = strlen (generator); ++ ext->sections[xid].tag = cache_extension_tag_generator; ++ ext->sections[xid].flags = 0; ++ ext->sections[xid].offset = generator_offset; ++ ext->sections[xid].size = strlen (generator); ++ ++ if (hwcaps_count > 0) ++ { ++ ++xid; ++ ext->sections[xid].tag = cache_extension_tag_glibc_hwcaps; ++ ext->sections[xid].flags = 0; ++ ext->sections[xid].offset = hwcaps_offset; ++ ext->sections[xid].size = hwcaps_size; ++ } ++ ++ ++xid; ++ ext->count = xid; ++ assert (xid <= cache_extension_count); + +- if (write (fd, ext, cache_extension_size) != cache_extension_size ++ size_t ext_size = (offsetof (struct cache_extension, sections) ++ + xid * sizeof (struct cache_extension_section)); ++ if (write (fd, ext, ext_size) != ext_size ++ || write (fd, hwcaps_array, hwcaps_size) != hwcaps_size + || write (fd, generator, strlen (generator)) != strlen (generator)) + error (EXIT_FAILURE, errno, _("Writing of cache extension data failed")); + +@@ -373,6 +554,8 @@ save_cache (const char *cache_name) + { + /* The cache entries are sorted already, save them in this order. */ + ++ assign_glibc_hwcaps_indices (); ++ + struct cache_entry *entry; + /* Number of cache entries. */ + int cache_entry_count = 0; +@@ -474,7 +657,11 @@ save_cache (const char *cache_name) + struct. */ + file_entries_new->libs[idx_new].flags = entry->flags; + file_entries_new->libs[idx_new].osversion = entry->osversion; +- file_entries_new->libs[idx_new].hwcap = entry->hwcap; ++ 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; + file_entries_new->libs[idx_new].key + = str_offset + entry->lib->offset; + file_entries_new->libs[idx_new].value +@@ -554,7 +741,7 @@ save_cache (const char *cache_name) + /* Align file position to 4. */ + off64_t old_offset = lseek64 (fd, extension_offset, SEEK_SET); + assert ((unsigned long long int) (extension_offset - old_offset) < 4); +- write_extensions (fd, extension_offset); ++ write_extensions (fd, str_offset, extension_offset); + } + + /* Make sure user can always read cache file */ +@@ -588,27 +775,35 @@ save_cache (const char *cache_name) + + /* Add one library to the cache. */ + void +-add_to_cache (const char *path, const char *lib, int flags, +- unsigned int osversion, uint64_t hwcap) ++add_to_cache (const char *path, const char *filename, const char *soname, ++ int flags, unsigned int osversion, uint64_t hwcap, ++ struct glibc_hwcaps_subdirectory *hwcaps) + { + struct cache_entry *new_entry = xmalloc (sizeof (*new_entry)); + + struct stringtable_entry *path_interned; + { + char *p; +- if (asprintf (&p, "%s/%s", path, lib) < 0) ++ if (asprintf (&p, "%s/%s", path, filename) < 0) + error (EXIT_FAILURE, errno, _("Could not create library path")); + path_interned = stringtable_add (&strings, p); + free (p); + } + +- new_entry->lib = stringtable_add (&strings, lib); ++ new_entry->lib = stringtable_add (&strings, soname); + new_entry->path = path_interned; + new_entry->flags = flags; + new_entry->osversion = osversion; + new_entry->hwcap = hwcap; ++ new_entry->hwcaps = hwcaps; + new_entry->bits_hwcap = 0; + ++ if (hwcaps != NULL) ++ { ++ assert (hwcap == 0); ++ hwcaps->used = true; ++ } ++ + /* Count the number of bits set in the masked value. */ + for (size_t i = 0; + (~((1ULL << i) - 1) & hwcap) != 0 && i < 8 * sizeof (hwcap); ++i) +diff --git a/elf/ldconfig.c b/elf/ldconfig.c +index 0fa5aef83f9cd86c..8c66d7e5426d8cc4 100644 +--- a/elf/ldconfig.c ++++ b/elf/ldconfig.c +@@ -16,6 +16,7 @@ + along with this program; if not, see . */ + + #define PROCINFO_CLASS static ++#include + #include + #include + #include +@@ -41,6 +42,7 @@ + + #include + #include ++#include + + #include + +@@ -85,6 +87,10 @@ struct dir_entry + dev_t dev; + const char *from_file; + int from_line; ++ ++ /* Non-NULL for subdirectories under a glibc-hwcaps subdirectory. */ ++ struct glibc_hwcaps_subdirectory *hwcaps; ++ + struct dir_entry *next; + }; + +@@ -338,17 +344,20 @@ new_sub_entry (const struct dir_entry *entry, const char *path, + new_entry->from_line = entry->from_line; + new_entry->path = xstrdup (path); + new_entry->flag = entry->flag; ++ new_entry->hwcaps = NULL; + new_entry->next = NULL; + new_entry->ino = st->st_ino; + new_entry->dev = st->st_dev; + return new_entry; + } + +-/* Add a single directory entry. */ +-static void ++/* Add a single directory entry. Return true if the directory is ++ actually added (because it is not a duplicate). */ ++static bool + add_single_dir (struct dir_entry *entry, int verbose) + { + struct dir_entry *ptr, *prev; ++ bool added = true; + + ptr = dir_entries; + prev = ptr; +@@ -368,6 +377,7 @@ add_single_dir (struct dir_entry *entry, int verbose) + ptr->flag = entry->flag; + free (entry->path); + free (entry); ++ added = false; + break; + } + prev = ptr; +@@ -378,6 +388,73 @@ add_single_dir (struct dir_entry *entry, int verbose) + dir_entries = entry; + else if (ptr == NULL) + prev->next = entry; ++ return added; ++} ++ ++/* Check if PATH contains a "glibc-hwcaps" subdirectory. If so, queue ++ its subdirectories for glibc-hwcaps processing. */ ++static void ++add_glibc_hwcaps_subdirectories (struct dir_entry *entry, const char *path) ++{ ++ /* glibc-hwcaps subdirectories do not nest. */ ++ assert (entry->hwcaps == NULL); ++ ++ char *glibc_hwcaps; ++ if (asprintf (&glibc_hwcaps, "%s/" GLIBC_HWCAPS_SUBDIRECTORY, path) < 0) ++ error (EXIT_FAILURE, errno, _("Could not form glibc-hwcaps path")); ++ ++ DIR *dir = opendir (glibc_hwcaps); ++ if (dir != NULL) ++ { ++ while (true) ++ { ++ errno = 0; ++ struct dirent64 *e = readdir64 (dir); ++ if (e == NULL) ++ { ++ if (errno == 0) ++ break; ++ else ++ error (EXIT_FAILURE, errno, _("Listing directory %s"), path); ++ } ++ ++ /* Ignore hidden subdirectories, including "." and "..", and ++ regular files. File names containing a ':' cannot be ++ looked up by the dynamic loader, so skip those as ++ well. */ ++ if (e->d_name[0] == '.' || e->d_type == DT_REG ++ || strchr (e->d_name, ':') != NULL) ++ continue; ++ ++ /* See if this entry eventually resolves to a directory. */ ++ struct stat64 st; ++ if (fstatat64 (dirfd (dir), e->d_name, &st, 0) < 0) ++ /* Ignore unreadable entries. */ ++ continue; ++ ++ if (S_ISDIR (st.st_mode)) ++ { ++ /* This is a directory, so it needs to be scanned for ++ libraries, associated with the hwcaps implied by the ++ subdirectory name. */ ++ char *new_path; ++ if (asprintf (&new_path, "%s/" GLIBC_HWCAPS_SUBDIRECTORY "/%s", ++ /* Use non-canonicalized path here. */ ++ entry->path, e->d_name) < 0) ++ error (EXIT_FAILURE, errno, ++ _("Could not form glibc-hwcaps path")); ++ struct dir_entry *new_entry = new_sub_entry (entry, new_path, ++ &st); ++ free (new_path); ++ new_entry->hwcaps = new_glibc_hwcaps_subdirectory (e->d_name); ++ add_single_dir (new_entry, 0); ++ } ++ } ++ ++ closedir (dir); ++ } ++ ++ free (glibc_hwcaps); + } + + /* Add one directory to the list of directories to process. */ +@@ -386,6 +463,7 @@ add_dir_1 (const char *line, const char *from_file, int from_line) + { + unsigned int i; + struct dir_entry *entry = xmalloc (sizeof (struct dir_entry)); ++ entry->hwcaps = NULL; + entry->next = NULL; + + entry->from_file = strdup (from_file); +@@ -443,7 +521,9 @@ add_dir_1 (const char *line, const char *from_file, int from_line) + entry->ino = stat_buf.st_ino; + entry->dev = stat_buf.st_dev; + +- add_single_dir (entry, 1); ++ if (add_single_dir (entry, 1)) ++ /* Add glibc-hwcaps subdirectories if present. */ ++ add_glibc_hwcaps_subdirectories (entry, path); + } + + if (opt_chroot) +@@ -695,15 +775,27 @@ struct dlib_entry + static void + search_dir (const struct dir_entry *entry) + { +- uint64_t hwcap = path_hwcap (entry->path); +- if (opt_verbose) ++ uint64_t hwcap; ++ if (entry->hwcaps == NULL) + { +- if (hwcap != 0) +- printf ("%s: (hwcap: %#.16" PRIx64 ")", entry->path, hwcap); +- else +- printf ("%s:", entry->path); +- printf (_(" (from %s:%d)\n"), entry->from_file, entry->from_line); ++ hwcap = path_hwcap (entry->path); ++ if (opt_verbose) ++ { ++ if (hwcap != 0) ++ printf ("%s: (hwcap: %#.16" PRIx64 ")", entry->path, hwcap); ++ else ++ printf ("%s:", entry->path); ++ } + } ++ else ++ { ++ hwcap = 0; ++ if (opt_verbose) ++ printf ("%s: (hwcap: \"%s\")", entry->path, ++ glibc_hwcaps_subdirectory_name (entry->hwcaps)); ++ } ++ if (opt_verbose) ++ printf (_(" (from %s:%d)\n"), entry->from_file, entry->from_line); + + char *dir_name; + char *real_file_name; +@@ -745,13 +837,15 @@ search_dir (const struct dir_entry *entry) + && direntry->d_type != DT_DIR) + continue; + /* Does this file look like a shared library or is it a hwcap +- subdirectory? The dynamic linker is also considered as ++ subdirectory (if not already processing a glibc-hwcaps ++ subdirectory)? The dynamic linker is also considered as + shared library. */ + if (((strncmp (direntry->d_name, "lib", 3) != 0 + && strncmp (direntry->d_name, "ld-", 3) != 0) + || strstr (direntry->d_name, ".so") == NULL) + && (direntry->d_type == DT_REG +- || !is_hwcap_platform (direntry->d_name))) ++ || (entry->hwcaps == NULL ++ && !is_hwcap_platform (direntry->d_name)))) + continue; + + size_t len = strlen (direntry->d_name); +@@ -799,7 +893,7 @@ search_dir (const struct dir_entry *entry) + } + + struct stat64 stat_buf; +- int is_dir; ++ bool is_dir; + int is_link = S_ISLNK (lstat_buf.st_mode); + if (is_link) + { +@@ -837,7 +931,10 @@ search_dir (const struct dir_entry *entry) + else + is_dir = S_ISDIR (lstat_buf.st_mode); + +- if (is_dir && is_hwcap_platform (direntry->d_name)) ++ /* No descending into subdirectories if this directory is a ++ glibc-hwcaps subdirectory (which are not recursive). */ ++ if (entry->hwcaps == NULL ++ && is_dir && is_hwcap_platform (direntry->d_name)) + { + if (!is_link + && direntry->d_type != DT_UNKNOWN +@@ -1028,13 +1125,31 @@ search_dir (const struct dir_entry *entry) + struct dlib_entry *dlib_ptr; + for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next) + { +- /* Don't create links to links. */ +- if (dlib_ptr->is_link == 0) +- create_links (dir_name, entry->path, dlib_ptr->name, +- dlib_ptr->soname); ++ /* The cached file name is the soname for non-glibc-hwcaps ++ subdirectories (relying on symbolic links; this helps with ++ library updates that change the file name), and the actual ++ file for glibc-hwcaps subdirectories. */ ++ const char *filename; ++ if (entry->hwcaps == NULL) ++ { ++ /* Don't create links to links. */ ++ if (dlib_ptr->is_link == 0) ++ create_links (dir_name, entry->path, dlib_ptr->name, ++ dlib_ptr->soname); ++ filename = dlib_ptr->soname; ++ } ++ else ++ { ++ /* Do not create links in glibc-hwcaps subdirectories, but ++ still log the cache addition. */ ++ if (opt_verbose) ++ printf ("\t%s -> %s\n", dlib_ptr->soname, dlib_ptr->name); ++ filename = dlib_ptr->name; ++ } + if (opt_build_cache) +- add_to_cache (entry->path, dlib_ptr->soname, dlib_ptr->flag, +- dlib_ptr->osversion, hwcap); ++ add_to_cache (entry->path, filename, dlib_ptr->soname, ++ dlib_ptr->flag, dlib_ptr->osversion, ++ hwcap, entry->hwcaps); + } + + /* Free all resources. */ +diff --git a/sysdeps/generic/dl-cache.h b/sysdeps/generic/dl-cache.h +index 259e843724531630..6adbe3c79a32a4ec 100644 +--- a/sysdeps/generic/dl-cache.h ++++ b/sysdeps/generic/dl-cache.h +@@ -99,6 +99,23 @@ struct file_entry_new + uint64_t hwcap; /* Hwcap entry. */ + }; + ++/* 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); ++} ++ + /* See flags member of struct cache_file_new below. */ + enum + { +@@ -182,6 +199,17 @@ enum cache_extension_tag + cache file. */ + cache_extension_tag_generator, + ++ /* glibc-hwcaps subdirectory information. An array of uint32_t ++ values, which are indices into the string table. The strings ++ are sorted lexicographically (according to strcmp). The extra ++ level of indirection (instead of using string table indices ++ directly) allows the dynamic loader to compute the preference ++ order of the hwcaps names more efficiently. ++ ++ For this section, 4-byte alignment is required, and the section ++ size must be a multiple of 4. */ ++ cache_extension_tag_glibc_hwcaps, ++ + /* Total number of known cache extension tags. */ + cache_extension_count + }; +@@ -236,6 +264,27 @@ struct cache_extension_all_loaded + struct cache_extension_loaded sections[cache_extension_count]; + }; + ++/* Performs basic data validation based on section tag, and removes ++ the sections which are invalid. */ ++static void ++cache_extension_verify (struct cache_extension_all_loaded *loaded) ++{ ++ { ++ /* Section must not be empty, it must be aligned at 4 bytes, and ++ the size must be a multiple of 4. */ ++ struct cache_extension_loaded *hwcaps ++ = &loaded->sections[cache_extension_tag_glibc_hwcaps]; ++ if (hwcaps->size == 0 ++ || ((uintptr_t) hwcaps->base % 4) != 0 ++ || (hwcaps->size % 4) != 0) ++ { ++ hwcaps->base = NULL; ++ hwcaps->size = 0; ++ hwcaps->flags = 0; ++ } ++ } ++} ++ + static bool __attribute__ ((unused)) + cache_extension_load (const struct cache_file_new *cache, + const void *file_base, size_t file_size, +@@ -282,6 +331,7 @@ cache_extension_load (const struct cache_file_new *cache, + loaded->sections[tag].size = ext->sections[i].size; + loaded->sections[tag].flags = ext->sections[i].flags; + } ++ cache_extension_verify (loaded); + return true; + } + +diff --git a/sysdeps/generic/ldconfig.h b/sysdeps/generic/ldconfig.h +index b15b142511829436..a8d22f143f867a3e 100644 +--- a/sysdeps/generic/ldconfig.h ++++ b/sysdeps/generic/ldconfig.h +@@ -57,8 +57,22 @@ extern void init_cache (void); + + extern void save_cache (const char *cache_name); + +-extern void add_to_cache (const char *path, const char *lib, int flags, +- unsigned int osversion, uint64_t hwcap); ++struct glibc_hwcaps_subdirectory; ++ ++/* Return a struct describing the subdirectory for NAME. Reuse an ++ existing struct if it exists. */ ++struct glibc_hwcaps_subdirectory *new_glibc_hwcaps_subdirectory ++ (const char *name); ++ ++/* Returns the name that was specified when ++ add_glibc_hwcaps_subdirectory was called. */ ++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, ++ struct glibc_hwcaps_subdirectory *); + + extern void init_aux_cache (void); + diff --git a/SOURCES/glibc-rh1817513-119.patch b/SOURCES/glibc-rh1817513-119.patch new file mode 100644 index 0000000..adb64de --- /dev/null +++ b/SOURCES/glibc-rh1817513-119.patch @@ -0,0 +1,659 @@ +commit 600d9e0c87940da9b0fdeff492bf888df852d40c +Author: Florian Weimer +Date: Fri Dec 4 09:13:43 2020 +0100 + + elf: Add glibc-hwcaps subdirectory support to ld.so cache processing + + This recognizes the DL_CACHE_HWCAP_EXTENSION flag in cache entries, + and picks the supported cache entry with the highest priority. + + The elf/tst-glibc-hwcaps-prepend-cache test documents a non-desired + aspect of the current cache implementation: If the cache selects a DSO + that does not exist on disk, _dl_map_object falls back to open_path, + which may or may not find an alternative implementation. This is an + existing limitation that also applies to the legacy hwcaps processing + for ld.so.cache. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/Makefile b/elf/Makefile +index a3e802a9a99b759c..f67b231c0f8e3aff 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -162,6 +162,12 @@ tst-tls1-static-non-pie-no-pie = yes + tests-container = \ + tst-ldconfig-bad-aux-cache + ++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-prepend-cache ++endif ++ + tests := tst-tls9 tst-leaks1 \ + tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 \ + tst-auxv tst-stringtable +@@ -1784,6 +1790,14 @@ $(objpfx)tst-glibc-hwcaps-prepend.out: \ + $< > $@; \ + $(evaluate-test) + ++# Like tst-glibc-hwcaps-prepend, but uses a container and loads the ++# library via ld.so.cache. Test setup is contained in the test ++# itself. ++$(objpfx)tst-glibc-hwcaps-prepend-cache: $(libdl) ++$(objpfx)tst-glibc-hwcaps-prepend-cache.out: \ ++ $(objpfx)tst-glibc-hwcaps-prepend-cache $(objpfx)libmarkermod1-1.so \ ++ $(objpfx)libmarkermod1-2.so $(objpfx)libmarkermod1-3.so ++ + # tst-glibc-hwcaps-mask checks that --glibc-hwcaps-mask can be used to + # suppress all auto-detected subdirectories. + $(objpfx)tst-glibc-hwcaps-mask: $(objpfx)libmarkermod1-1.so +@@ -1795,3 +1809,7 @@ $(objpfx)tst-glibc-hwcaps-mask.out: \ + --glibc-hwcaps-mask does-not-exist \ + $< > $@; \ + $(evaluate-test) ++ ++# Generic dependency for sysdeps implementation of ++# tst-glibc-hwcaps-cache. ++$(objpfx)tst-glibc-hwcaps-cache.out: $(objpfx)tst-glibc-hwcaps +diff --git a/elf/dl-cache.c b/elf/dl-cache.c +index de063faa8b2c88ae..e75afdaee23226e6 100644 +--- a/elf/dl-cache.c ++++ b/elf/dl-cache.c +@@ -35,6 +35,144 @@ static struct cache_file *cache; + static struct cache_file_new *cache_new; + static size_t cachesize; + ++#ifdef SHARED ++/* This is used to cache the priorities of glibc-hwcaps ++ subdirectories. The elements of _dl_cache_priorities correspond to ++ the strings in the cache_extension_tag_glibc_hwcaps section. */ ++static uint32_t *glibc_hwcaps_priorities; ++static uint32_t glibc_hwcaps_priorities_length; ++static uint32_t glibc_hwcaps_priorities_allocated; ++ ++/* True if the full malloc was used to allocated the array. */ ++static bool glibc_hwcaps_priorities_malloced; ++ ++/* Deallocate the glibc_hwcaps_priorities array. */ ++static void ++glibc_hwcaps_priorities_free (void) ++{ ++ /* When the minimal malloc is in use, free does not do anything, ++ so it does not make sense to call it. */ ++ if (glibc_hwcaps_priorities_malloced) ++ free (glibc_hwcaps_priorities); ++ glibc_hwcaps_priorities = NULL; ++ glibc_hwcaps_priorities_allocated = 0; ++} ++ ++/* Ordered comparison of a hwcaps string from the cache on the left ++ (identified by its string table index) and a _dl_hwcaps_priorities ++ element on the right. */ ++static int ++glibc_hwcaps_compare (uint32_t left_index, struct dl_hwcaps_priority *right) ++{ ++ const char *left_name = (const char *) cache + left_index; ++ uint32_t left_name_length = strlen (left_name); ++ uint32_t to_compare; ++ if (left_name_length < right->name_length) ++ to_compare = left_name_length; ++ else ++ to_compare = right->name_length; ++ int cmp = memcmp (left_name, right->name, to_compare); ++ if (cmp != 0) ++ return cmp; ++ if (left_name_length < right->name_length) ++ return -1; ++ else if (left_name_length > right->name_length) ++ return 1; ++ else ++ return 0; ++} ++ ++/* Initialize the glibc_hwcaps_priorities array and its length, ++ glibc_hwcaps_priorities_length. */ ++static void ++glibc_hwcaps_priorities_init (void) ++{ ++ struct cache_extension_all_loaded ext; ++ if (!cache_extension_load (cache_new, cache, cachesize, &ext)) ++ return; ++ ++ uint32_t length = (ext.sections[cache_extension_tag_glibc_hwcaps].size ++ / sizeof (uint32_t)); ++ if (length > glibc_hwcaps_priorities_allocated) ++ { ++ glibc_hwcaps_priorities_free (); ++ ++ uint32_t *new_allocation = malloc (length * sizeof (uint32_t)); ++ if (new_allocation == NULL) ++ /* This effectively disables hwcaps on memory allocation ++ errors. */ ++ return; ++ ++ glibc_hwcaps_priorities = new_allocation; ++ glibc_hwcaps_priorities_allocated = length; ++ glibc_hwcaps_priorities_malloced = __rtld_malloc_is_complete (); ++ } ++ ++ /* Compute the priorities for the subdirectories by merging the ++ array in the cache with the dl_hwcaps_priorities array. */ ++ const uint32_t *left = ext.sections[cache_extension_tag_glibc_hwcaps].base; ++ const uint32_t *left_end = left + length; ++ struct dl_hwcaps_priority *right = _dl_hwcaps_priorities; ++ struct dl_hwcaps_priority *right_end = right + _dl_hwcaps_priorities_length; ++ uint32_t *result = glibc_hwcaps_priorities; ++ ++ while (left < left_end && right < right_end) ++ { ++ if (*left < cachesize) ++ { ++ int cmp = glibc_hwcaps_compare (*left, right); ++ if (cmp == 0) ++ { ++ *result = right->priority; ++ ++result; ++ ++left; ++ ++right; ++ } ++ else if (cmp < 0) ++ { ++ *result = 0; ++ ++result; ++ ++left; ++ } ++ else ++ ++right; ++ } ++ else ++ { ++ *result = 0; ++ ++result; ++ } ++ } ++ while (left < left_end) ++ { ++ *result = 0; ++ ++result; ++ ++left; ++ } ++ ++ glibc_hwcaps_priorities_length = length; ++} ++ ++/* Return the priority of the cache_extension_tag_glibc_hwcaps section ++ entry at INDEX. Zero means do not use. Otherwise, lower values ++ indicate greater preference. */ ++static uint32_t ++glibc_hwcaps_priority (uint32_t index) ++{ ++ /* This does not need to repeated initialization attempts because ++ this function is only called if there is glibc-hwcaps data in the ++ cache, so the first call initializes the glibc_hwcaps_priorities ++ array. */ ++ if (glibc_hwcaps_priorities_length == 0) ++ glibc_hwcaps_priorities_init (); ++ ++ if (index < glibc_hwcaps_priorities_length) ++ return glibc_hwcaps_priorities[index]; ++ else ++ return 0; ++} ++#endif /* SHARED */ ++ + /* True if PTR is a valid string table index. */ + static inline bool + _dl_cache_verify_ptr (uint32_t ptr, size_t string_table_size) +@@ -74,6 +212,9 @@ search_cache (const char *string_table, uint32_t string_table_size, + int left = 0; + int right = nlibs - 1; + const char *best = NULL; ++#ifdef SHARED ++ uint32_t best_priority = 0; ++#endif + + while (left <= right) + { +@@ -129,6 +270,11 @@ search_cache (const char *string_table, uint32_t string_table_size, + { + if (best == NULL || flags == GLRO (dl_correct_cache_id)) + { ++ /* Named/extension hwcaps get slightly different ++ treatment: We keep searching for a better ++ match. */ ++ bool named_hwcap = false; ++ + if (entry_size >= sizeof (struct file_entry_new)) + { + /* The entry is large enough to include +@@ -136,7 +282,18 @@ search_cache (const char *string_table, uint32_t string_table_size, + struct file_entry_new *libnew + = (struct file_entry_new *) lib; + +- if (libnew->hwcap & hwcap_exclude) ++#ifdef SHARED ++ named_hwcap = dl_cache_hwcap_extension (libnew); ++#endif ++ ++ /* The entries with named/extension hwcaps ++ have been exhausted. Return the best ++ match encountered so far if there is ++ one. */ ++ if (!named_hwcap && best != NULL) ++ break; ++ ++ if ((libnew->hwcap & hwcap_exclude) && !named_hwcap) + continue; + if (GLRO (dl_osversion) + && libnew->osversion > GLRO (dl_osversion)) +@@ -146,14 +303,41 @@ search_cache (const char *string_table, uint32_t string_table_size, + && ((libnew->hwcap & _DL_HWCAP_PLATFORM) + != platform)) + continue; ++ ++#ifdef SHARED ++ /* For named hwcaps, determine the priority ++ and see if beats what has been found so ++ far. */ ++ if (named_hwcap) ++ { ++ uint32_t entry_priority ++ = glibc_hwcaps_priority (libnew->hwcap); ++ if (entry_priority == 0) ++ /* Not usable at all. Skip. */ ++ continue; ++ else if (best == NULL ++ || entry_priority < best_priority) ++ /* This entry is of higher priority ++ than the previous one, or it is the ++ first entry. */ ++ best_priority = entry_priority; ++ else ++ /* An entry has already been found, ++ but it is a better match. */ ++ continue; ++ } ++#endif /* SHARED */ + } + + best = string_table + lib->value; + +- if (flags == GLRO (dl_correct_cache_id)) ++ if (flags == GLRO (dl_correct_cache_id) ++ && !named_hwcap) + /* We've found an exact match for the shared + object and no general `ELF' release. Stop +- searching. */ ++ searching, but not if a named (extension) ++ hwcap is used. In this case, an entry with ++ a higher priority may come up later. */ + break; + } + } +@@ -346,5 +530,9 @@ _dl_unload_cache (void) + __munmap (cache, cachesize); + cache = NULL; + } ++#ifdef SHARED ++ /* This marks the glibc_hwcaps_priorities array as out-of-date. */ ++ glibc_hwcaps_priorities_length = 0; ++#endif + } + #endif +diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c +index e57d0d2d41741021..098173a84c43c1fd 100644 +--- a/elf/dl-hwcaps.c ++++ b/elf/dl-hwcaps.c +@@ -89,6 +89,81 @@ copy_hwcaps (struct copy_hwcaps *target, const char *hwcaps, + } + } + ++struct dl_hwcaps_priority *_dl_hwcaps_priorities; ++uint32_t _dl_hwcaps_priorities_length; ++ ++/* Allocate _dl_hwcaps_priorities and fill it with data. */ ++static void ++compute_priorities (size_t total_count, const char *prepend, ++ uint32_t bitmask, const char *mask) ++{ ++ _dl_hwcaps_priorities = malloc (total_count ++ * sizeof (*_dl_hwcaps_priorities)); ++ if (_dl_hwcaps_priorities == NULL) ++ _dl_signal_error (ENOMEM, NULL, NULL, ++ N_("cannot create HWCAP priorities")); ++ _dl_hwcaps_priorities_length = total_count; ++ ++ /* First the prepended subdirectories. */ ++ size_t i = 0; ++ { ++ struct dl_hwcaps_split sp; ++ _dl_hwcaps_split_init (&sp, prepend); ++ while (_dl_hwcaps_split (&sp)) ++ { ++ _dl_hwcaps_priorities[i].name = sp.segment; ++ _dl_hwcaps_priorities[i].name_length = sp.length; ++ _dl_hwcaps_priorities[i].priority = i + 1; ++ ++i; ++ } ++ } ++ ++ /* Then the built-in subdirectories that are actually active. */ ++ { ++ struct dl_hwcaps_split_masked sp; ++ _dl_hwcaps_split_masked_init (&sp, _dl_hwcaps_subdirs, bitmask, mask); ++ while (_dl_hwcaps_split_masked (&sp)) ++ { ++ _dl_hwcaps_priorities[i].name = sp.split.segment; ++ _dl_hwcaps_priorities[i].name_length = sp.split.length; ++ _dl_hwcaps_priorities[i].priority = i + 1; ++ ++i; ++ } ++ } ++ assert (i == total_count); ++} ++ ++/* Sort the _dl_hwcaps_priorities array by name. */ ++static void ++sort_priorities_by_name (void) ++{ ++ /* Insertion sort. There is no need to link qsort into the dynamic ++ loader for such a short array. */ ++ for (size_t i = 1; i < _dl_hwcaps_priorities_length; ++i) ++ for (size_t j = i; j > 0; --j) ++ { ++ struct dl_hwcaps_priority *previous = _dl_hwcaps_priorities + j - 1; ++ struct dl_hwcaps_priority *current = _dl_hwcaps_priorities + j; ++ ++ /* Bail out if current is greater or equal to the previous ++ value. */ ++ uint32_t to_compare; ++ if (current->name_length < previous->name_length) ++ to_compare = current->name_length; ++ else ++ to_compare = previous->name_length; ++ int cmp = memcmp (current->name, previous->name, to_compare); ++ if (cmp >= 0 ++ || (cmp == 0 && current->name_length >= previous->name_length)) ++ break; ++ ++ /* Swap *previous and *current. */ ++ struct dl_hwcaps_priority tmp = *previous; ++ *previous = *current; ++ *current = tmp; ++ } ++} ++ + /* Return an array of useful/necessary hardware capability names. */ + const struct r_strlenpair * + _dl_important_hwcaps (const char *glibc_hwcaps_prepend, +@@ -111,6 +186,9 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend, + update_hwcaps_counts (&hwcaps_counts, glibc_hwcaps_prepend, -1, NULL); + update_hwcaps_counts (&hwcaps_counts, _dl_hwcaps_subdirs, + hwcaps_subdirs_active, glibc_hwcaps_mask); ++ compute_priorities (hwcaps_counts.count, glibc_hwcaps_prepend, ++ hwcaps_subdirs_active, glibc_hwcaps_mask); ++ sort_priorities_by_name (); + + /* Each hwcaps subdirectory has a GLIBC_HWCAPS_PREFIX string prefix + and a "/" suffix once stored in the result. */ +diff --git a/elf/dl-hwcaps.h b/elf/dl-hwcaps.h +index 3fcfbceb1a8fc1c8..769ecab3f886c6c4 100644 +--- a/elf/dl-hwcaps.h ++++ b/elf/dl-hwcaps.h +@@ -132,4 +132,23 @@ _dl_hwcaps_subdirs_build_bitmask (int subdirs, int active) + return mask ^ ((1U << inactive) - 1); + } + ++/* Pre-computed glibc-hwcaps subdirectory priorities. Used in ++ dl-cache.c to quickly find the proprieties for the stored HWCAP ++ names. */ ++struct dl_hwcaps_priority ++{ ++ /* The name consists of name_length bytes at name (not necessarily ++ null-terminated). */ ++ const char *name; ++ uint32_t name_length; ++ ++ /* Priority of this name. A positive number. */ ++ uint32_t priority; ++}; ++ ++/* Pre-computed hwcaps priorities. Set up by ++ _dl_important_hwcaps. */ ++extern struct dl_hwcaps_priority *_dl_hwcaps_priorities attribute_hidden; ++extern uint32_t _dl_hwcaps_priorities_length attribute_hidden; ++ + #endif /* _DL_HWCAPS_H */ +diff --git a/elf/tst-glibc-hwcaps-cache.c b/elf/tst-glibc-hwcaps-cache.c +new file mode 100644 +index 0000000000000000..4bad56afc03451fc +--- /dev/null ++++ b/elf/tst-glibc-hwcaps-cache.c +@@ -0,0 +1,45 @@ ++/* Wrapper to invoke tst-glibc-hwcaps in a container, to test ld.so.cache. ++ 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. 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", support_objdir_root); ++ execv (path, argv); ++ printf ("error: execv of %s failed: %m\n", path); ++ return 1; ++} +diff --git a/elf/tst-glibc-hwcaps-cache.root/etc/ld.so.conf b/elf/tst-glibc-hwcaps-cache.root/etc/ld.so.conf +new file mode 100644 +index 0000000000000000..e1e74dbda2bf3dfa +--- /dev/null ++++ b/elf/tst-glibc-hwcaps-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-cache.root/postclean.req b/elf/tst-glibc-hwcaps-cache.root/postclean.req +new file mode 100644 +index 0000000000000000..e69de29bb2d1d643 +diff --git a/elf/tst-glibc-hwcaps-cache.script b/elf/tst-glibc-hwcaps-cache.script +new file mode 100644 +index 0000000000000000..6356d152089cdd9a +--- /dev/null ++++ b/elf/tst-glibc-hwcaps-cache.script +@@ -0,0 +1,6 @@ ++# test-container does not support scripts in sysdeps directories, so ++# collect everything in one file. ++ ++cp $B/elf/libmarkermod2-1.so $L/libmarkermod2.so ++cp $B/elf/libmarkermod3-1.so $L/libmarkermod3.so ++cp $B/elf/libmarkermod4-1.so $L/libmarkermod4.so +diff --git a/elf/tst-glibc-hwcaps-prepend-cache.c b/elf/tst-glibc-hwcaps-prepend-cache.c +new file mode 100644 +index 0000000000000000..40509cebe2b5ba27 +--- /dev/null ++++ b/elf/tst-glibc-hwcaps-prepend-cache.c +@@ -0,0 +1,149 @@ ++/* Test that --glibc-hwcaps-prepend works, using dlopen and /etc/ld.so.cache. ++ 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 ++#include ++#include ++#include ++ ++/* Invoke /sbin/ldconfig with some error checking. */ ++static void ++run_ldconfig (void) ++{ ++ char *command = xasprintf ("%s/ldconfig", support_install_rootsbindir); ++ TEST_COMPARE (system (command), 0); ++ free (command); ++} ++ ++/* The library under test. */ ++#define SONAME "libmarkermod1.so" ++ ++static int ++do_test (void) ++{ ++ if (dlopen (SONAME, RTLD_NOW) != NULL) ++ FAIL_EXIT1 (SONAME " is already on the search path"); ++ ++ /* Install the default implementation of libmarkermod1.so. */ ++ xmkdirp ("/etc", 0777); ++ support_write_file_string ("/etc/ld.so.conf", "/glibc-test/lib\n"); ++ xmkdirp ("/glibc-test/lib/glibc-hwcaps/prepend2", 0777); ++ xmkdirp ("/glibc-test/lib/glibc-hwcaps/prepend3", 0777); ++ { ++ char *src = xasprintf ("%s/elf/libmarkermod1-1.so", support_objdir_root); ++ support_copy_file (src, "/glibc-test/lib/" SONAME); ++ free (src); ++ } ++ run_ldconfig (); ++ { ++ /* The default implementation can now be loaded. */ ++ void *handle = xdlopen (SONAME, RTLD_NOW); ++ int (*marker1) (void) = xdlsym (handle, "marker1"); ++ TEST_COMPARE (marker1 (), 1); ++ xdlclose (handle); ++ } ++ ++ /* Add the first override to the directory that is searched last. */ ++ { ++ char *src = xasprintf ("%s/elf/libmarkermod1-2.so", support_objdir_root); ++ support_copy_file (src, "/glibc-test/lib/glibc-hwcaps/prepend2/" ++ SONAME); ++ free (src); ++ } ++ { ++ /* This is still the first implementation. The cache has not been ++ updated. */ ++ void *handle = xdlopen (SONAME, RTLD_NOW); ++ int (*marker1) (void) = xdlsym (handle, "marker1"); ++ TEST_COMPARE (marker1 (), 1); ++ xdlclose (handle); ++ } ++ run_ldconfig (); ++ { ++ /* After running ldconfig, it is the second implementation. */ ++ void *handle = xdlopen (SONAME, RTLD_NOW); ++ int (*marker1) (void) = xdlsym (handle, "marker1"); ++ TEST_COMPARE (marker1 (), 2); ++ xdlclose (handle); ++ } ++ ++ /* Add the second override to the directory that is searched first. */ ++ { ++ char *src = xasprintf ("%s/elf/libmarkermod1-3.so", support_objdir_root); ++ support_copy_file (src, "/glibc-test/lib/glibc-hwcaps/prepend3/" ++ SONAME); ++ free (src); ++ } ++ { ++ /* This is still the second implementation. */ ++ void *handle = xdlopen (SONAME, RTLD_NOW); ++ int (*marker1) (void) = xdlsym (handle, "marker1"); ++ TEST_COMPARE (marker1 (), 2); ++ xdlclose (handle); ++ } ++ run_ldconfig (); ++ { ++ /* After running ldconfig, it is the third implementation. */ ++ void *handle = xdlopen (SONAME, RTLD_NOW); ++ int (*marker1) (void) = xdlsym (handle, "marker1"); ++ TEST_COMPARE (marker1 (), 3); ++ xdlclose (handle); ++ } ++ ++ /* Remove the second override again, without running ldconfig. ++ Ideally, this would revert to implementation 2. However, in the ++ current implementation, the cache returns exactly one file name ++ which does not exist after unlinking, so the dlopen fails. */ ++ xunlink ("/glibc-test/lib/glibc-hwcaps/prepend3/" SONAME); ++ TEST_VERIFY (dlopen (SONAME, RTLD_NOW) == NULL); ++ run_ldconfig (); ++ { ++ /* After running ldconfig, the second implementation is available ++ once more. */ ++ void *handle = xdlopen (SONAME, RTLD_NOW); ++ int (*marker1) (void) = xdlsym (handle, "marker1"); ++ TEST_COMPARE (marker1 (), 2); ++ xdlclose (handle); ++ } ++ ++ return 0; ++} ++ ++static void ++prepare (int argc, char **argv) ++{ ++ const char *no_restart = "no-restart"; ++ if (argc == 2 && strcmp (argv[1], no_restart) == 0) ++ return; ++ /* Re-execute the test with an explicit loader invocation. */ ++ execl (support_objdir_elf_ldso, ++ support_objdir_elf_ldso, ++ "--glibc-hwcaps-prepend", "prepend3:prepend2", ++ argv[0], no_restart, ++ NULL); ++ printf ("error: execv of %s failed: %m\n", argv[0]); ++ _exit (1); ++} ++ ++#define PREPARE prepare ++#include +diff --git a/elf/tst-glibc-hwcaps-prepend-cache.root/postclean.req b/elf/tst-glibc-hwcaps-prepend-cache.root/postclean.req +new file mode 100644 +index 0000000000000000..e69de29bb2d1d643 diff --git a/SOURCES/glibc-rh1817513-12.patch b/SOURCES/glibc-rh1817513-12.patch new file mode 100644 index 0000000..b755c39 --- /dev/null +++ b/SOURCES/glibc-rh1817513-12.patch @@ -0,0 +1,38 @@ +commit 2954daf00bb4dc27c69a48e6798d5960ea320741 +Author: Andreas Schwab +Date: Tue Oct 23 09:40:14 2018 +0200 + + Add more checks for valid ld.so.cache file (bug 18093) + +diff --git a/elf/cache.c b/elf/cache.c +index e63979da7d25560c..c4cd825c30e00e8e 100644 +--- a/elf/cache.c ++++ b/elf/cache.c +@@ -199,6 +199,11 @@ print_cache (const char *cache_name) + } + else + { ++ /* Check for corruption, avoiding overflow. */ ++ if ((cache_size - sizeof (struct cache_file)) / sizeof (struct file_entry) ++ < cache->nlibs) ++ error (EXIT_FAILURE, 0, _("File is not a cache file.\n")); ++ + size_t offset = ALIGN_CACHE (sizeof (struct cache_file) + + (cache->nlibs + * sizeof (struct file_entry))); +diff --git a/elf/dl-cache.c b/elf/dl-cache.c +index 6ee5153ff9514872..6dd99a35b9f97cfb 100644 +--- a/elf/dl-cache.c ++++ b/elf/dl-cache.c +@@ -204,7 +204,10 @@ _dl_load_cache_lookup (const char *name) + - only the new format + The following checks if the cache contains any of these formats. */ + if (file != MAP_FAILED && cachesize > sizeof *cache +- && memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0) ++ && memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0 ++ /* Check for corruption, avoiding overflow. */ ++ && ((cachesize - sizeof *cache) / sizeof (struct file_entry) ++ >= ((struct cache_file *) file)->nlibs)) + { + size_t offset; + /* Looks ok. */ diff --git a/SOURCES/glibc-rh1817513-120.patch b/SOURCES/glibc-rh1817513-120.patch new file mode 100644 index 0000000..6c5d566 --- /dev/null +++ b/SOURCES/glibc-rh1817513-120.patch @@ -0,0 +1,249 @@ +commit f267e1c9dd7fb8852cc32d6eafd96bbcfd5cbb2b +Author: Florian Weimer +Date: Fri Dec 4 09:13:43 2020 +0100 + + x86_64: Add glibc-hwcaps support + + The subdirectories match those in the x86-64 psABI: + + https://gitlab.com/x86-psABIs/x86-64-ABI/-/commit/77566eb03bc6a326811cb7e9a6b9396884b67c7c + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/Makefile b/elf/Makefile +index f67b231c0f8e3aff..7f2fc73877f0a4c8 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -1751,7 +1751,7 @@ $(objpfx)argv0test.out: tst-rtld-argv0.sh $(objpfx)ld.so \ + # glibc-hwcaps mechanism for this architecture). Used to obtain test + # coverage for some glibc-hwcaps tests for the widest possible range + # of systems. +-glibc-hwcaps-first-subdirs-for-tests = ++glibc-hwcaps-first-subdirs-for-tests = x86-64-v2 + + # The test modules are parameterized by preprocessor macros. + LDFLAGS-libmarkermod1-1.so += -Wl,-soname,libmarkermod1.so +diff --git a/elf/tst-glibc-hwcaps-cache.script b/elf/tst-glibc-hwcaps-cache.script +index 6356d152089cdd9a..66d6942402b7233b 100644 +--- a/elf/tst-glibc-hwcaps-cache.script ++++ b/elf/tst-glibc-hwcaps-cache.script +@@ -4,3 +4,13 @@ + cp $B/elf/libmarkermod2-1.so $L/libmarkermod2.so + cp $B/elf/libmarkermod3-1.so $L/libmarkermod3.so + cp $B/elf/libmarkermod4-1.so $L/libmarkermod4.so ++ ++mkdirp 0770 $L/glibc-hwcaps/x86-64-v2 ++cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/x86-64-v2/libmarkermod2.so ++mkdirp 0770 $L/glibc-hwcaps/x86-64-v3 ++cp $B/elf/libmarkermod3-2.so $L/glibc-hwcaps/x86-64-v2/libmarkermod3.so ++cp $B/elf/libmarkermod3-3.so $L/glibc-hwcaps/x86-64-v3/libmarkermod3.so ++mkdirp 0770 $L/glibc-hwcaps/x86-64-v4 ++cp $B/elf/libmarkermod4-2.so $L/glibc-hwcaps/x86-64-v2/libmarkermod4.so ++cp $B/elf/libmarkermod4-3.so $L/glibc-hwcaps/x86-64-v3/libmarkermod4.so ++cp $B/elf/libmarkermod4-4.so $L/glibc-hwcaps/x86-64-v4/libmarkermod4.so +diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile +index 42b97c5cc73892cc..d1d7cb9d2eeca9c5 100644 +--- a/sysdeps/x86_64/Makefile ++++ b/sysdeps/x86_64/Makefile +@@ -144,8 +144,47 @@ CFLAGS-tst-auditmod10b.c += $(AVX512-CFLAGS) + CFLAGS-tst-avx512-aux.c += $(AVX512-CFLAGS) + CFLAGS-tst-avx512mod.c += $(AVX512-CFLAGS) + endif ++ ++$(objpfx)tst-glibc-hwcaps: $(objpfx)libmarkermod2-1.so \ ++ $(objpfx)libmarkermod3-1.so $(objpfx)libmarkermod4-1.so ++$(objpfx)tst-glibc-hwcaps.out: \ ++ $(objpfx)libmarkermod2.so \ ++ $(objpfx)glibc-hwcaps/x86-64-v2/libmarkermod2.so \ ++ $(objpfx)libmarkermod3.so \ ++ $(objpfx)glibc-hwcaps/x86-64-v2/libmarkermod3.so \ ++ $(objpfx)glibc-hwcaps/x86-64-v3/libmarkermod3.so \ ++ $(objpfx)libmarkermod4.so \ ++ $(objpfx)glibc-hwcaps/x86-64-v2/libmarkermod4.so \ ++ $(objpfx)glibc-hwcaps/x86-64-v3/libmarkermod4.so \ ++ $(objpfx)glibc-hwcaps/x86-64-v4/libmarkermod4.so \ ++ ++$(objpfx)glibc-hwcaps/x86-64-v2/libmarkermod2.so: $(objpfx)libmarkermod2-2.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/x86-64-v2/libmarkermod3.so: $(objpfx)libmarkermod3-2.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/x86-64-v3/libmarkermod3.so: $(objpfx)libmarkermod3-3.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/x86-64-v2/libmarkermod4.so: $(objpfx)libmarkermod4-2.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/x86-64-v3/libmarkermod4.so: $(objpfx)libmarkermod4-3.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/x86-64-v4/libmarkermod4.so: $(objpfx)libmarkermod4-4.so ++ $(make-target-directory) ++ cp $< $@ ++ ++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-cache + endif + ++endif # $(subdir) == elf ++ + ifeq ($(subdir),csu) + gen-as-const-headers += tlsdesc.sym rtld-offsets.sym + endif +diff --git a/sysdeps/x86_64/dl-hwcaps-subdirs.c b/sysdeps/x86_64/dl-hwcaps-subdirs.c +new file mode 100644 +index 0000000000000000..8810a822efe36962 +--- /dev/null ++++ b/sysdeps/x86_64/dl-hwcaps-subdirs.c +@@ -0,0 +1,66 @@ ++/* Architecture-specific glibc-hwcaps subdirectories. 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 ++#include ++ ++const char _dl_hwcaps_subdirs[] = "x86-64-v4:x86-64-v3:x86-64-v2"; ++enum { subdirs_count = 3 }; /* Number of components in _dl_hwcaps_subdirs. */ ++ ++uint32_t ++_dl_hwcaps_subdirs_active (void) ++{ ++ int active = 0; ++ ++ /* Test in reverse preference order. */ ++ ++ /* x86-64-v2. */ ++ if (!(CPU_FEATURE_USABLE (CMPXCHG16B) ++ && CPU_FEATURE_USABLE (LAHF64_SAHF64) ++ && CPU_FEATURE_USABLE (POPCNT) ++ && CPU_FEATURE_USABLE (SSE3) ++ && CPU_FEATURE_USABLE (SSE4_1) ++ && CPU_FEATURE_USABLE (SSE4_2) ++ && CPU_FEATURE_USABLE (SSSE3))) ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++ ++active; ++ ++ /* x86-64-v3. */ ++ if (!(CPU_FEATURE_USABLE (AVX) ++ && CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI1) ++ && CPU_FEATURE_USABLE (BMI2) ++ && CPU_FEATURE_USABLE (F16C) ++ && CPU_FEATURE_USABLE (FMA) ++ && CPU_FEATURE_USABLE (LZCNT) ++ && CPU_FEATURE_USABLE (MOVBE) ++ && CPU_FEATURE_USABLE (OSXSAVE))) ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++ ++active; ++ ++ /* x86-64-v4. */ ++ if (!(CPU_FEATURE_USABLE (AVX512F) ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (AVX512CD) ++ && CPU_FEATURE_USABLE (AVX512DQ) ++ && CPU_FEATURE_USABLE (AVX512VL))) ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++ ++active; ++ ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++} +diff --git a/sysdeps/x86_64/tst-glibc-hwcaps.c b/sysdeps/x86_64/tst-glibc-hwcaps.c +new file mode 100644 +index 0000000000000000..3075a8286dc30768 +--- /dev/null ++++ b/sysdeps/x86_64/tst-glibc-hwcaps.c +@@ -0,0 +1,76 @@ ++/* glibc-hwcaps subdirectory test. x86_64 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 ++#include ++#include ++#include ++ ++extern int marker2 (void); ++extern int marker3 (void); ++extern int marker4 (void); ++ ++/* Return the x86-64-vN level, 1 for the baseline. */ ++static int ++compute_level (void) ++{ ++ const struct cpu_features *cpu_features ++ = __x86_get_cpu_features (COMMON_CPUID_INDEX_MAX); ++ ++ if (!(CPU_FEATURE_USABLE_P (cpu_features, CMPXCHG16B) ++ && CPU_FEATURE_USABLE_P (cpu_features, LAHF64_SAHF64) ++ && CPU_FEATURE_USABLE_P (cpu_features, POPCNT) ++ && CPU_FEATURE_USABLE_P (cpu_features, MMX) ++ && CPU_FEATURE_USABLE_P (cpu_features, SSE) ++ && CPU_FEATURE_USABLE_P (cpu_features, SSE2) ++ && CPU_FEATURE_USABLE_P (cpu_features, SSE3) ++ && CPU_FEATURE_USABLE_P (cpu_features, SSSE3) ++ && CPU_FEATURE_USABLE_P (cpu_features, SSE4_1) ++ && CPU_FEATURE_USABLE_P (cpu_features, SSE4_2))) ++ return 1; ++ if (!(CPU_FEATURE_USABLE_P (cpu_features, AVX) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI1) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2) ++ && CPU_FEATURE_USABLE_P (cpu_features, F16C) ++ && CPU_FEATURE_USABLE_P (cpu_features, FMA) ++ && CPU_FEATURE_USABLE_P (cpu_features, LZCNT) ++ && CPU_FEATURE_USABLE_P (cpu_features, MOVBE) ++ && CPU_FEATURE_USABLE_P (cpu_features, OSXSAVE))) ++ return 2; ++ if (!(CPU_FEATURE_USABLE_P (cpu_features, AVX512F) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512CD) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512DQ) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512VL))) ++ return 3; ++ return 4; ++} ++ ++static int ++do_test (void) ++{ ++ int level = compute_level (); ++ printf ("info: detected x86-64 micro-architecture level: %d\n", level); ++ TEST_COMPARE (marker2 (), MIN (level, 2)); ++ TEST_COMPARE (marker3 (), MIN (level, 3)); ++ TEST_COMPARE (marker4 (), MIN (level, 4)); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1817513-121.patch b/SOURCES/glibc-rh1817513-121.patch new file mode 100644 index 0000000..5280b4b --- /dev/null +++ b/SOURCES/glibc-rh1817513-121.patch @@ -0,0 +1,21 @@ +commit 4f4bd9e47ba98ccfeeaa8c600c0b0c8bbabcebb3 +Author: Matheus Castanho +Date: Fri Dec 4 09:48:56 2020 -0300 + + elf: Add missing header to elf/dl-hwcaps.h + + The lack of this header makes size_t unavailable on builds configured + with --disable-tunables, causing compilation errors. + +diff --git a/elf/dl-hwcaps.h b/elf/dl-hwcaps.h +index 769ecab3f886c6c4..9a34088c17e97d7f 100644 +--- a/elf/dl-hwcaps.h ++++ b/elf/dl-hwcaps.h +@@ -20,6 +20,7 @@ + #define _DL_HWCAPS_H + + #include ++#include + + #include + diff --git a/SOURCES/glibc-rh1817513-122.patch b/SOURCES/glibc-rh1817513-122.patch new file mode 100644 index 0000000..bc3388d --- /dev/null +++ b/SOURCES/glibc-rh1817513-122.patch @@ -0,0 +1,20 @@ +commit 2976082a385a7fb3d0294c6acf745b4f93e834ee +Author: H.J. Lu +Date: Thu Dec 3 15:02:44 2020 -0800 + + x86: Set RDRAND usable if CPU supports RDRAND + + Set RDRAND usable if CPU supports RDRAND. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 4c9c15a44b618fed..805d00a43309fc23 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -85,6 +85,7 @@ update_usable (struct cpu_features *cpu_features) + CPU_FEATURE_SET_USABLE (cpu_features, WAITPKG); + CPU_FEATURE_SET_USABLE (cpu_features, GFNI); + CPU_FEATURE_SET_USABLE (cpu_features, RDPID); ++ CPU_FEATURE_SET_USABLE (cpu_features, RDRAND); + CPU_FEATURE_SET_USABLE (cpu_features, CLDEMOTE); + CPU_FEATURE_SET_USABLE (cpu_features, MOVDIRI); + CPU_FEATURE_SET_USABLE (cpu_features, MOVDIR64B); diff --git a/SOURCES/glibc-rh1817513-123.patch b/SOURCES/glibc-rh1817513-123.patch new file mode 100644 index 0000000..1aa9cb7 --- /dev/null +++ b/SOURCES/glibc-rh1817513-123.patch @@ -0,0 +1,65 @@ +commit 93fda28693f0d9060b0aa71eeacaacfe9f16896e +Author: H.J. Lu +Date: Thu Dec 3 15:02:44 2020 -0800 + + x86: Adjust tst-cpu-features-supports.c for GCC 11 + + Check HAS_CPU_FEATURE instead of CPU_FEATURE_USABLE for FSGSBASE, IBT, + LM, SHSTK and XSAVES since FSGSBASE requires kernel support, IBT/SHSTK/LM + require OS support and XSAVES is supervisor-mode only. + +diff --git a/sysdeps/x86/tst-cpu-features-supports.c b/sysdeps/x86/tst-cpu-features-supports.c +index bf881b531f4bc2ed..287cf01fbdfaeda1 100644 +--- a/sysdeps/x86/tst-cpu-features-supports.c ++++ b/sysdeps/x86/tst-cpu-features-supports.c +@@ -40,6 +40,11 @@ check_supports (int supports, int usable, const char *supports_name, + #define CHECK_SUPPORTS(str, name) \ + check_supports (__builtin_cpu_supports (#str), \ + CPU_FEATURE_USABLE (name), \ ++ #str, "CPU_FEATURE_USABLE (" #name ")"); ++ ++#define CHECK_CPU_SUPPORTS(str, name) \ ++ check_supports (__builtin_cpu_supports (#str), \ ++ HAS_CPU_FEATURE (name), \ + #str, "HAS_CPU_FEATURE (" #name ")"); + + static int +@@ -118,7 +123,7 @@ do_test (int argc, char **argv) + fails += CHECK_SUPPORTS (fma4, FMA4); + #endif + #if __GNUC_PREREQ (11, 0) +- fails += CHECK_SUPPORTS (fsgsbase, FSGSBASE); ++ fails += CHECK_CPU_SUPPORTS (fsgsbase, FSGSBASE); + fails += CHECK_SUPPORTS (fxsave, FXSR); + #endif + #if __GNUC_PREREQ (8, 0) +@@ -126,9 +131,9 @@ do_test (int argc, char **argv) + #endif + #if __GNUC_PREREQ (11, 0) + fails += CHECK_SUPPORTS (hle, HLE); +- fails += CHECK_SUPPORTS (ibt, IBT); ++ fails += CHECK_CPU_SUPPORTS (ibt, IBT); + fails += CHECK_SUPPORTS (lahf_lm, LAHF64_SAHF64); +- fails += CHECK_SUPPORTS (lm, LM); ++ fails += CHECK_CPU_SUPPORTS (lm, LM); + fails += CHECK_SUPPORTS (lwp, LWP); + fails += CHECK_SUPPORTS (lzcnt, LZCNT); + #endif +@@ -150,7 +155,7 @@ do_test (int argc, char **argv) + fails += CHECK_SUPPORTS (rtm, RTM); + fails += CHECK_SUPPORTS (serialize, SERIALIZE); + fails += CHECK_SUPPORTS (sha, SHA); +- fails += CHECK_SUPPORTS (shstk, SHSTK); ++ fails += CHECK_CPU_SUPPORTS (shstk, SHSTK); + #endif + fails += CHECK_SUPPORTS (sse, SSE); + fails += CHECK_SUPPORTS (sse2, SSE2); +@@ -180,7 +185,7 @@ do_test (int argc, char **argv) + fails += CHECK_SUPPORTS (xsave, XSAVE); + fails += CHECK_SUPPORTS (xsavec, XSAVEC); + fails += CHECK_SUPPORTS (xsaveopt, XSAVEOPT); +- fails += CHECK_SUPPORTS (xsaves, XSAVES); ++ fails += CHECK_CPU_SUPPORTS (xsaves, XSAVES); + #endif + + printf ("%d differences between __builtin_cpu_supports and glibc code.\n", diff --git a/SOURCES/glibc-rh1817513-124.patch b/SOURCES/glibc-rh1817513-124.patch new file mode 100644 index 0000000..ec9e96d --- /dev/null +++ b/SOURCES/glibc-rh1817513-124.patch @@ -0,0 +1,187 @@ +commit 4c38c1a229bc3628269ad98bd7e8d31d118d91f6 +Author: Florian Weimer +Date: Fri Dec 4 09:13:43 2020 +0100 + + powerpc64le: Add glibc-hwcaps support + + The "power10" and "power9" subdirectories are selected in a way + that matches the -mcpu=power10 and -mcpu=power9 options of GCC. + +diff --git a/elf/Makefile b/elf/Makefile +index 7f2fc73877f0a4c8..57e3a8982297f79a 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -1751,7 +1751,7 @@ $(objpfx)argv0test.out: tst-rtld-argv0.sh $(objpfx)ld.so \ + # glibc-hwcaps mechanism for this architecture). Used to obtain test + # coverage for some glibc-hwcaps tests for the widest possible range + # of systems. +-glibc-hwcaps-first-subdirs-for-tests = x86-64-v2 ++glibc-hwcaps-first-subdirs-for-tests = power9 x86-64-v2 + + # The test modules are parameterized by preprocessor macros. + LDFLAGS-libmarkermod1-1.so += -Wl,-soname,libmarkermod1.so +diff --git a/elf/tst-glibc-hwcaps-cache.script b/elf/tst-glibc-hwcaps-cache.script +index 66d6942402b7233b..6a4675f9bd30e02f 100644 +--- a/elf/tst-glibc-hwcaps-cache.script ++++ b/elf/tst-glibc-hwcaps-cache.script +@@ -5,6 +5,12 @@ cp $B/elf/libmarkermod2-1.so $L/libmarkermod2.so + cp $B/elf/libmarkermod3-1.so $L/libmarkermod3.so + cp $B/elf/libmarkermod4-1.so $L/libmarkermod4.so + ++mkdirp 0770 $L/glibc-hwcaps/power9 ++cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/power9/libmarkermod2.so ++mkdirp 0770 $L/glibc-hwcaps/power10 ++cp $B/elf/libmarkermod3-2.so $L/glibc-hwcaps/power9/libmarkermod3.so ++cp $B/elf/libmarkermod3-3.so $L/glibc-hwcaps/power10/libmarkermod3.so ++ + mkdirp 0770 $L/glibc-hwcaps/x86-64-v2 + cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/x86-64-v2/libmarkermod2.so + mkdirp 0770 $L/glibc-hwcaps/x86-64-v3 +diff --git a/sysdeps/powerpc/powerpc64/le/Makefile b/sysdeps/powerpc/powerpc64/le/Makefile +index f59db1ca3c8ed454..7a4be6bfef729914 100644 +--- a/sysdeps/powerpc/powerpc64/le/Makefile ++++ b/sysdeps/powerpc/powerpc64/le/Makefile +@@ -82,3 +82,31 @@ CFLAGS-printf_fp.c = -mfloat128 + CFLAGS-printf_fphex.c = -mfloat128 + CFLAGS-printf_size.c = -mfloat128 + endif ++ ++ifeq ($(subdir),elf) ++$(objpfx)tst-glibc-hwcaps: \ ++ $(objpfx)libmarkermod2-1.so $(objpfx)libmarkermod3-1.so ++$(objpfx)tst-glibc-hwcaps.out: \ ++ $(objpfx)libmarkermod2.so \ ++ $(objpfx)glibc-hwcaps/power9/libmarkermod2.so \ ++ $(objpfx)libmarkermod3.so \ ++ $(objpfx)glibc-hwcaps/power9/libmarkermod3.so \ ++ $(objpfx)glibc-hwcaps/power10/libmarkermod3.so \ ++ ++$(objpfx)glibc-hwcaps/power9/libmarkermod2.so: $(objpfx)libmarkermod2-2.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/power9/libmarkermod3.so: $(objpfx)libmarkermod3-2.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/power10/libmarkermod3.so: $(objpfx)libmarkermod3-3.so ++ $(make-target-directory) ++ cp $< $@ ++ ++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-cache ++endif ++ ++endif # $(subdir) == elf +diff --git a/sysdeps/powerpc/powerpc64/le/dl-hwcaps-subdirs.c b/sysdeps/powerpc/powerpc64/le/dl-hwcaps-subdirs.c +new file mode 100644 +index 0000000000000000..6a21d77649f44dd4 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/le/dl-hwcaps-subdirs.c +@@ -0,0 +1,46 @@ ++/* Architecture-specific glibc-hwcaps subdirectories. powerpc64le 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 ++#include ++ ++const char _dl_hwcaps_subdirs[] = "power10:power9"; ++enum { subdirs_count = 2 }; /* Number of components in _dl_hwcaps_subdirs. */ ++ ++uint32_t ++_dl_hwcaps_subdirs_active (void) ++{ ++ int active = 0; ++ ++ /* Test in reverse preference order. Altivec and VSX are implied by ++ the powerpc64le ABI definition. */ ++ ++ /* POWER9. GCC enables float128 hardware support for -mcpu=power9. */ ++ if ((GLRO (dl_hwcap2) & PPC_FEATURE2_ARCH_3_00) == 0 ++ || (GLRO (dl_hwcap2) & PPC_FEATURE2_HAS_IEEE128) == 0) ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++ ++active; ++ ++ /* POWER10. GCC defines __MMA__ for -mcpu=power10. */ ++ if ((GLRO (dl_hwcap2) & PPC_FEATURE2_ARCH_3_1) == 0 ++ || (GLRO (dl_hwcap2) & PPC_FEATURE2_MMA) == 0) ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++ ++active; ++ ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++} +diff --git a/sysdeps/powerpc/powerpc64/le/tst-glibc-hwcaps.c b/sysdeps/powerpc/powerpc64/le/tst-glibc-hwcaps.c +new file mode 100644 +index 0000000000000000..e510fca80a22aaeb +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/le/tst-glibc-hwcaps.c +@@ -0,0 +1,54 @@ ++/* glibc-hwcaps subdirectory test. powerpc64le 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 ++#include ++#include ++#include ++#include ++ ++extern int marker2 (void); ++extern int marker3 (void); ++ ++/* Return the POWER level, 8 for the baseline. */ ++static int ++compute_level (void) ++{ ++ const char *platform = (const char *) getauxval (AT_PLATFORM); ++ if (strcmp (platform, "power8") == 0) ++ return 8; ++ if (strcmp (platform, "power9") == 0) ++ return 9; ++ if (strcmp (platform, "power10") == 0) ++ return 10; ++ printf ("warning: unrecognized AT_PLATFORM value: %s\n", platform); ++ /* Assume that the new platform supports POWER10. */ ++ return 10; ++} ++ ++static int ++do_test (void) ++{ ++ int level = compute_level (); ++ printf ("info: detected POWER level: %d\n", level); ++ TEST_COMPARE (marker2 (), MIN (level - 7, 2)); ++ TEST_COMPARE (marker3 (), MIN (level - 7, 3)); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1817513-125.patch b/SOURCES/glibc-rh1817513-125.patch new file mode 100644 index 0000000..648b205 --- /dev/null +++ b/SOURCES/glibc-rh1817513-125.patch @@ -0,0 +1,21 @@ +commit 0d4ed9d40efa84e8dc88e64cf337c8e95af7b045 +Author: Florian Weimer +Date: Wed Dec 9 18:56:14 2020 +0100 + + elf: Fix incorrect comparison in sort_priorities_by_name + + Reported-By: Stefan Liebler + +diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c +index 098173a84c43c1fd..50d764ae8707f46d 100644 +--- a/elf/dl-hwcaps.c ++++ b/elf/dl-hwcaps.c +@@ -153,7 +153,7 @@ sort_priorities_by_name (void) + else + to_compare = previous->name_length; + int cmp = memcmp (current->name, previous->name, to_compare); +- if (cmp >= 0 ++ if (cmp > 0 + || (cmp == 0 && current->name_length >= previous->name_length)) + break; + diff --git a/SOURCES/glibc-rh1817513-126.patch b/SOURCES/glibc-rh1817513-126.patch new file mode 100644 index 0000000..6d04ee2 --- /dev/null +++ b/SOURCES/glibc-rh1817513-126.patch @@ -0,0 +1,25 @@ +commit 1bb8d05b9c751f6909e85ee96f6c78d536987bfd +Author: Florian Weimer +Date: Thu Dec 10 12:24:53 2020 +0100 + + elf: Fix run-time dependencies of tst-dlopen-fail-2 + + The misattributed dependencies can cause failures in parallel testing + if the dependencies have not been built yet. + + Fixes commit a332bd1518af518c984fad73eba6f46dc5b2b2d4 + ("elf: Add elf/tst-dlopenfail-2 [BZ #25396]"). + +diff --git a/elf/Makefile b/elf/Makefile +index 57e3a8982297f79a..63c61ad63677ec63 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -1655,7 +1655,7 @@ $(objpfx)tst-dlopenfailmod1.so: \ + LDFLAGS-tst-dlopenfaillinkmod.so = -Wl,-soname,tst-dlopenfail-missingmod.so + $(objpfx)tst-dlopenfailmod2.so: $(shared-thread-library) + $(objpfx)tst-dlopenfail-2: $(libdl) +-$(objpfx)tst-dlopenfail.out: \ ++$(objpfx)tst-dlopenfail-2.out: \ + $(objpfx)tst-dlopenfailmod1.so $(objpfx)tst-dlopenfailmod2.so \ + $(objpfx)tst-dlopenfailmod3.so + diff --git a/SOURCES/glibc-rh1817513-127.patch b/SOURCES/glibc-rh1817513-127.patch new file mode 100644 index 0000000..892276f --- /dev/null +++ b/SOURCES/glibc-rh1817513-127.patch @@ -0,0 +1,241 @@ +commit fdf8fbca455ca3ef57235bde907bcc6a624ac5aa +Author: Florian Weimer +Date: Thu Dec 10 13:51:18 2020 +0100 + + s390x: Add glibc-hwcaps support + + Subdirectories z13, z14, z15 can be selected, mostly based on the + level of support for vector instructions. + + Co-Authored-By: Stefan Liebler + +diff --git a/elf/Makefile b/elf/Makefile +index 63c61ad63677ec63..67029930dd2cb461 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -1751,7 +1751,7 @@ $(objpfx)argv0test.out: tst-rtld-argv0.sh $(objpfx)ld.so \ + # glibc-hwcaps mechanism for this architecture). Used to obtain test + # coverage for some glibc-hwcaps tests for the widest possible range + # of systems. +-glibc-hwcaps-first-subdirs-for-tests = power9 x86-64-v2 ++glibc-hwcaps-first-subdirs-for-tests = power9 x86-64-v2 z13 + + # The test modules are parameterized by preprocessor macros. + LDFLAGS-libmarkermod1-1.so += -Wl,-soname,libmarkermod1.so +diff --git a/elf/tst-glibc-hwcaps-cache.script b/elf/tst-glibc-hwcaps-cache.script +index 6a4675f9bd30e02f..c3271f61f9e50f2e 100644 +--- a/elf/tst-glibc-hwcaps-cache.script ++++ b/elf/tst-glibc-hwcaps-cache.script +@@ -11,6 +11,16 @@ mkdirp 0770 $L/glibc-hwcaps/power10 + cp $B/elf/libmarkermod3-2.so $L/glibc-hwcaps/power9/libmarkermod3.so + cp $B/elf/libmarkermod3-3.so $L/glibc-hwcaps/power10/libmarkermod3.so + ++mkdirp 0770 $L/glibc-hwcaps/z13 ++cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/z13/libmarkermod2.so ++mkdirp 0770 $L/glibc-hwcaps/z14 ++cp $B/elf/libmarkermod3-2.so $L/glibc-hwcaps/z13/libmarkermod3.so ++cp $B/elf/libmarkermod3-3.so $L/glibc-hwcaps/z14/libmarkermod3.so ++mkdirp 0770 $L/glibc-hwcaps/z15 ++cp $B/elf/libmarkermod4-2.so $L/glibc-hwcaps/z13/libmarkermod4.so ++cp $B/elf/libmarkermod4-3.so $L/glibc-hwcaps/z14/libmarkermod4.so ++cp $B/elf/libmarkermod4-4.so $L/glibc-hwcaps/z15/libmarkermod4.so ++ + mkdirp 0770 $L/glibc-hwcaps/x86-64-v2 + cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/x86-64-v2/libmarkermod2.so + mkdirp 0770 $L/glibc-hwcaps/x86-64-v3 +diff --git a/sysdeps/s390/s390-64/Makefile b/sysdeps/s390/s390-64/Makefile +index b4d793bb3dd1f703..e5da26871c862e63 100644 +--- a/sysdeps/s390/s390-64/Makefile ++++ b/sysdeps/s390/s390-64/Makefile +@@ -6,4 +6,43 @@ ifeq ($(subdir),elf) + CFLAGS-rtld.c += -Wno-uninitialized -Wno-unused + CFLAGS-dl-load.c += -Wno-unused + CFLAGS-dl-reloc.c += -Wno-unused ++ ++$(objpfx)tst-glibc-hwcaps: $(objpfx)libmarkermod2-1.so \ ++ $(objpfx)libmarkermod3-1.so $(objpfx)libmarkermod4-1.so ++$(objpfx)tst-glibc-hwcaps.out: \ ++ $(objpfx)libmarkermod2.so \ ++ $(objpfx)glibc-hwcaps/z13/libmarkermod2.so \ ++ $(objpfx)libmarkermod3.so \ ++ $(objpfx)glibc-hwcaps/z13/libmarkermod3.so \ ++ $(objpfx)glibc-hwcaps/z14/libmarkermod3.so \ ++ $(objpfx)libmarkermod4.so \ ++ $(objpfx)glibc-hwcaps/z13/libmarkermod4.so \ ++ $(objpfx)glibc-hwcaps/z14/libmarkermod4.so \ ++ $(objpfx)glibc-hwcaps/z15/libmarkermod4.so \ ++ ++$(objpfx)glibc-hwcaps/z13/libmarkermod2.so: $(objpfx)libmarkermod2-2.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z13/libmarkermod3.so: $(objpfx)libmarkermod3-2.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z14/libmarkermod3.so: $(objpfx)libmarkermod3-3.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z13/libmarkermod4.so: $(objpfx)libmarkermod4-2.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z14/libmarkermod4.so: $(objpfx)libmarkermod4-3.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z15/libmarkermod4.so: $(objpfx)libmarkermod4-4.so ++ $(make-target-directory) ++ cp $< $@ ++ ++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-cache + endif ++ ++endif # $(subdir) == elf +diff --git a/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c b/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c +new file mode 100644 +index 0000000000000000..3673808a458350ad +--- /dev/null ++++ b/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c +@@ -0,0 +1,54 @@ ++/* Architecture-specific glibc-hwcaps subdirectories. s390x 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 ++#include ++ ++const char _dl_hwcaps_subdirs[] = "z15:z14:z13"; ++enum { subdirs_count = 3 }; /* Number of components in _dl_hwcaps_subdirs. */ ++ ++uint32_t ++_dl_hwcaps_subdirs_active (void) ++{ ++ int active = 0; ++ ++ /* Test in reverse preference order. */ ++ ++ /* z13. */ ++ if (!(GLRO (dl_hwcap) & HWCAP_S390_VX)) ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++ ++active; ++ ++ /* z14. */ ++ if (!((GLRO (dl_hwcap) & HWCAP_S390_VXD) ++ && (GLRO (dl_hwcap) & HWCAP_S390_VXE) ++ && (GLRO (dl_hwcap) & HWCAP_S390_GS))) ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++ ++active; ++ ++ /* z15. ++ Note: We do not list HWCAP_S390_SORT and HWCAP_S390_DFLT here as, ++ according to the Principles of Operation, those may be replaced or removed ++ in future. */ ++ if (!((GLRO (dl_hwcap) & HWCAP_S390_VXRS_EXT2) ++ && (GLRO (dl_hwcap) & HWCAP_S390_VXRS_PDE))) ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++ ++active; ++ ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++} +diff --git a/sysdeps/s390/s390-64/tst-glibc-hwcaps.c b/sysdeps/s390/s390-64/tst-glibc-hwcaps.c +new file mode 100644 +index 0000000000000000..690f0d5fab36eb59 +--- /dev/null ++++ b/sysdeps/s390/s390-64/tst-glibc-hwcaps.c +@@ -0,0 +1,82 @@ ++/* glibc-hwcaps subdirectory test. s390x 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 ++#include ++#include ++#include ++#include ++ ++extern int marker2 (void); ++extern int marker3 (void); ++extern int marker4 (void); ++ ++/* Return the arch level, 10 for the baseline libmarkermod*.so's. */ ++static int ++compute_level (void) ++{ ++ const char *platform = (const char *) getauxval (AT_PLATFORM); ++ ++ /* The arch* versions refer to the edition of the Principles of ++ Operation, and they are off by two when compared with the recent ++ product names. (The code below should not be considered an ++ accurate mapping to Principles of Operation editions for earlier ++ AT_PLATFORM strings). */ ++ if (strcmp (platform, "z900") == 0) ++ return 10; ++ if (strcmp (platform, "z990") == 0) ++ return 10; ++ if (strcmp (platform, "z9-109") == 0) ++ return 10; ++ if (strcmp (platform, "z10") == 0) ++ return 10; ++ if (strcmp (platform, "z196") == 0) ++ return 10; ++ if (strcmp (platform, "zEC12") == 0) ++ return 10; ++ ++ /* If we are running on z13 or newer and the kernel was booted with novx, ++ then AT_PLATFORM is z13 or newer, but _dl_hwcaps_subdirs_active will ++ return zero and the _dl_hwcaps_subdirs are not searched. */ ++ const unsigned long int hwcap = getauxval (AT_HWCAP); ++ if ((hwcap & HWCAP_S390_VX) == 0) ++ return 10; ++ ++ if (strcmp (platform, "z13") == 0) ++ return 11; ++ if (strcmp (platform, "z14") == 0) ++ return 12; ++ if (strcmp (platform, "z15") == 0) ++ return 13; ++ printf ("warning: unrecognized AT_PLATFORM value: %s\n", platform); ++ /* Assume that the new platform supports z15. */ ++ return 13; ++} ++ ++static int ++do_test (void) ++{ ++ int level = compute_level (); ++ printf ("info: detected architecture level: arch%d\n", level); ++ TEST_COMPARE (marker2 (), MIN (level - 9, 2)); ++ TEST_COMPARE (marker3 (), MIN (level - 9, 3)); ++ TEST_COMPARE (marker4 (), MIN (level - 9, 4)); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1817513-128.patch b/SOURCES/glibc-rh1817513-128.patch new file mode 100644 index 0000000..a6a4106 --- /dev/null +++ b/SOURCES/glibc-rh1817513-128.patch @@ -0,0 +1,83 @@ +commit 97476447edff96e526daa1a22d6ed3665181ff93 +Author: DJ Delorie +Date: Wed Oct 23 17:52:26 2019 -0400 + + Install charmaps uncompressed in testroot + + The testroot does not have a gunzip command, so the charmap files + should not be installed gzipped else they cannot be used (and thus + tested). With this patch, installing with INSTALL_UNCOMPRESSED=yes + installs uncompressed charmaps instead. + + Note that we must purge the $(symbolic_link_list) as it contains + references to $(DESTDIR), which we change during the testroot + installation. + + Reviewed-by: Carlos O'Donell + +diff --git a/Makefile b/Makefile +index 3748d6f7cfb6223b..6d73241bbc811c13 100644 +--- a/Makefile ++++ b/Makefile +@@ -398,8 +398,15 @@ ifeq ($(run-built-tests),yes) + $(test-wrapper) cp $$dso $(objpfx)testroot.pristine$$dso ;\ + done + endif ++ # $(symbolic-link-list) is a file that encodes $(DESTDIR) so we ++ # have to purge it ++ rm -f $(symbolic-link-list) ++ # Setting INSTALL_UNCOMPRESSED causes localedata/Makefile to ++ # install the charmaps uncompressed, as the testroot does not ++ # provide a gunzip program. + $(MAKE) install DESTDIR=$(objpfx)testroot.pristine \ +- subdirs='$(sorted-subdirs)' ++ INSTALL_UNCOMPRESSED=yes subdirs='$(sorted-subdirs)' ++ rm -f $(symbolic-link-list) + touch $(objpfx)testroot.pristine/install.stamp + + tests-special-notdir = $(patsubst $(objpfx)%, %, $(tests-special)) +diff --git a/localedata/Makefile b/localedata/Makefile +index 0fed95dcae6a9183..14fcc37fed21e740 100644 +--- a/localedata/Makefile ++++ b/localedata/Makefile +@@ -167,9 +167,17 @@ endif + endif + + # Files to install. ++ifeq ($(INSTALL_UNCOMPRESSED),yes) ++# This option is for testing inside the testroot container, as the ++# container does not include a working gunzip program. ++install-others := $(addprefix $(inst_i18ndir)/, \ ++ $(charmaps) \ ++ $(locales)) ++else + install-others := $(addprefix $(inst_i18ndir)/, \ + $(addsuffix .gz, $(charmaps)) \ + $(locales)) ++endif + + tests: $(objdir)/iconvdata/gconv-modules + +@@ -282,12 +290,22 @@ endif + + include ../Rules + ++ifeq ($(INSTALL_UNCOMPRESSED),yes) ++# Install the charmap files as-is. This option is for testing inside ++# the testroot container, as the container does not include a working ++# gunzip program. ++$(inst_i18ndir)/charmaps/%: charmaps/% $(+force) ++ $(make-target-directory) ++ rm -f $@ ++ $(INSTALL_DATA) $< $@ ++else + # Install the charmap files in gzipped format. + $(inst_i18ndir)/charmaps/%.gz: charmaps/% $(+force) + $(make-target-directory) + rm -f $(@:.gz=) $@ + $(INSTALL_DATA) $< $(@:.gz=) + gzip -9n $(@:.gz=) ++endif + + # Install the locale source files in the appropriate directory. + $(inst_i18ndir)/locales/%: locales/% $(+force); $(do-install) diff --git a/SOURCES/glibc-rh1817513-129.patch b/SOURCES/glibc-rh1817513-129.patch new file mode 100644 index 0000000..b34711e --- /dev/null +++ b/SOURCES/glibc-rh1817513-129.patch @@ -0,0 +1,121 @@ +commit de42613540de8d3d70b5f14a14923cab7bd694d0 +Author: Florian Weimer +Date: Mon May 25 18:17:27 2020 +0200 + + elf: Turn _dl_printf, _dl_error_printf, _dl_fatal_printf into functions + + This change makes it easier to set a breakpoint on these calls. + + This also addresses the issue that including without + does not result usable _dl_*printf macros because of the + use of the STD*_FILENO macros there. + + (The private symbol for _dl_fatal_printf will go away again + once the exception handling implementation is unified between + libc and ld.so.) + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/Versions b/elf/Versions +index 3be879c4adfa74c7..be88c48e6d45a937 100644 +--- a/elf/Versions ++++ b/elf/Versions +@@ -58,7 +58,7 @@ ld { + _dl_allocate_tls; _dl_allocate_tls_init; + _dl_argv; _dl_find_dso_for_object; _dl_get_tls_static_info; + _dl_deallocate_tls; _dl_make_stack_executable; +- _dl_rtld_di_serinfo; _dl_starting_up; ++ _dl_rtld_di_serinfo; _dl_starting_up; _dl_fatal_printf; + _rtld_global; _rtld_global_ro; + + # Only here for gdb while a better method is developed. +diff --git a/elf/dl-misc.c b/elf/dl-misc.c +index 3f28de3ee9d68368..508630e444d2a00c 100644 +--- a/elf/dl-misc.c ++++ b/elf/dl-misc.c +@@ -302,6 +302,37 @@ _dl_dprintf (int fd, const char *fmt, ...) + va_end (arg); + } + ++void ++_dl_printf (const char *fmt, ...) ++{ ++ va_list arg; ++ ++ va_start (arg, fmt); ++ _dl_debug_vdprintf (STDOUT_FILENO, 0, fmt, arg); ++ va_end (arg); ++} ++ ++void ++_dl_error_printf (const char *fmt, ...) ++{ ++ va_list arg; ++ ++ va_start (arg, fmt); ++ _dl_debug_vdprintf (STDERR_FILENO, 0, fmt, arg); ++ va_end (arg); ++} ++ ++void ++_dl_fatal_printf (const char *fmt, ...) ++{ ++ va_list arg; ++ ++ va_start (arg, fmt); ++ _dl_debug_vdprintf (STDERR_FILENO, 0, fmt, arg); ++ va_end (arg); ++ _exit (127); ++} ++rtld_hidden_def (_dl_fatal_printf) + + /* Test whether given NAME matches any of the names of the given object. */ + int +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 77923499d3de4366..6cbbaa808a596f77 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -762,24 +762,19 @@ ssize_t _dl_write (int fd, const void *buffer, size_t length) + + /* Write a message on the specified descriptor standard output. The + parameters are interpreted as for a `printf' call. */ +-#define _dl_printf(fmt, args...) \ +- _dl_dprintf (STDOUT_FILENO, fmt, ##args) ++void _dl_printf (const char *fmt, ...) ++ attribute_hidden __attribute__ ((__format__ (__printf__, 1, 2))); + + /* Write a message on the specified descriptor standard error. The + parameters are interpreted as for a `printf' call. */ +-#define _dl_error_printf(fmt, args...) \ +- _dl_dprintf (STDERR_FILENO, fmt, ##args) ++void _dl_error_printf (const char *fmt, ...) ++ attribute_hidden __attribute__ ((__format__ (__printf__, 1, 2))); + + /* Write a message on the specified descriptor standard error and exit + the program. The parameters are interpreted as for a `printf' call. */ +-#define _dl_fatal_printf(fmt, args...) \ +- do \ +- { \ +- _dl_dprintf (STDERR_FILENO, fmt, ##args); \ +- _exit (127); \ +- } \ +- while (1) +- ++void _dl_fatal_printf (const char *fmt, ...) ++ __attribute__ ((__format__ (__printf__, 1, 2), __noreturn__)); ++rtld_hidden_proto (_dl_fatal_printf) + + /* An exception raised by the _dl_signal_error function family and + caught by _dl_catch_error function family. Exceptions themselves +diff --git a/sysdeps/mach/hurd/i386/localplt.data b/sysdeps/mach/hurd/i386/localplt.data +index 4b9dbf5acc088cff..eb79216e3b494486 100644 +--- a/sysdeps/mach/hurd/i386/localplt.data ++++ b/sysdeps/mach/hurd/i386/localplt.data +@@ -43,6 +43,7 @@ ld.so: _dl_allocate_tls_init + ld.so: _dl_exception_create + ld.so: _dl_exception_create_format + ld.so: _dl_exception_free ++ld.so: _dl_fatal_printf + ld.so: _dl_find_dso_for_object + ld.so: _dl_init_first + ld.so: _dl_mcount diff --git a/SOURCES/glibc-rh1817513-13.patch b/SOURCES/glibc-rh1817513-13.patch new file mode 100644 index 0000000..6267bb6 --- /dev/null +++ b/SOURCES/glibc-rh1817513-13.patch @@ -0,0 +1,199 @@ +commit a5275ba5378c9256d18e582572b4315e8edfcbfb +Author: H.J. Lu +Date: Thu Nov 29 14:15:01 2018 -0800 + + _dl_exception_create_format: Support %x/%lx/%zx + + Add support for %x, %lx and %zx to _dl_exception_create_format and pad + to the full width with 0. + + * elf/Makefile (tests-internal): Add tst-create_format1. + * elf/dl-exception.c (_dl_exception_create_format): Support + %x, %lx and %zx. + * elf/tst-create_format1.c: New file. + +Conflicts: + elf/Makefile + (Different backport order of tests.) + +diff --git a/elf/Makefile b/elf/Makefile +index 89dff92adfc417f5..6d1962b2e4deb871 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -198,7 +198,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + 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-ptrguard1 tst-stackguard1 tst-libc_dlvsym \ ++ tst-create_format1 + tests-container += tst-pldd + ifeq ($(build-hardcoded-path-in-tests),yes) + tests += tst-dlopen-aout +diff --git a/elf/dl-exception.c b/elf/dl-exception.c +index 1c63e4a3a65b6d55..1e41d89a7db52683 100644 +--- a/elf/dl-exception.c ++++ b/elf/dl-exception.c +@@ -111,6 +111,20 @@ _dl_exception_create_format (struct dl_exception *exception, const char *objname + case 's': + length += strlen (va_arg (ap, const char *)); + break; ++ /* Recognize the l modifier. It is only important on some ++ platforms where long and int have a different size. We ++ can use the same code for size_t. */ ++ case 'l': ++ case 'z': ++ if (p[1] == 'x') ++ { ++ length += LONG_WIDTH / 4; ++ ++p; ++ break; ++ } ++ case 'x': ++ length += INT_WIDTH / 4; ++ break; + default: + /* Assumed to be '%'. */ + ++length; +@@ -167,6 +181,32 @@ _dl_exception_create_format (struct dl_exception *exception, const char *objname + *wptr = '%'; + ++wptr; + break; ++ case 'x': ++ { ++ unsigned long int num = va_arg (ap, unsigned int); ++ char *start = wptr; ++ wptr += INT_WIDTH / 4; ++ char *cp = _itoa (num, wptr, 16, 0); ++ /* Pad to the full width with 0. */ ++ while (cp != start) ++ *--cp = '0'; ++ } ++ break; ++ case 'l': ++ case 'z': ++ if (p[1] == 'x') ++ { ++ unsigned long int num = va_arg (ap, unsigned long int); ++ char *start = wptr; ++ wptr += LONG_WIDTH / 4; ++ char *cp = _itoa (num, wptr, 16, 0); ++ /* Pad to the full width with 0. */ ++ while (cp != start) ++ *--cp = '0'; ++ ++p; ++ break; ++ } ++ /* FALLTHROUGH */ + default: + _dl_fatal_printf ("Fatal error:" + " invalid format in exception string\n"); +diff --git a/elf/tst-create_format1.c b/elf/tst-create_format1.c +new file mode 100644 +index 0000000000000000..8b9edfdc69ea4ced +--- /dev/null ++++ b/elf/tst-create_format1.c +@@ -0,0 +1,103 @@ ++/* Check _dl_exception_create_format. ++ Copyright (C) 2018 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 ++ ++#define TEST(es, objn, fmt, ...) \ ++ ({ \ ++ struct dl_exception exception; \ ++ _dl_exception_create_format (&exception, objn, fmt, __VA_ARGS__); \ ++ TEST_COMPARE_STRING (exception.objname, objn == NULL ? "" : objn); \ ++ TEST_COMPARE_STRING (exception.errstring, es); \ ++ _dl_exception_free (&exception); \ ++ }) ++ ++static void ++do_test_invalid_conversion (void *closure) ++{ ++ TEST ("(null)", NULL, "%p", NULL); ++} ++ ++/* Exit status after abnormal termination. */ ++static int invalid_status; ++ ++static void ++init_invalid_status (void) ++{ ++ pid_t pid = xfork (); ++ if (pid == 0) ++ _exit (127); ++ xwaitpid (pid, &invalid_status, 0); ++ if (WIFEXITED (invalid_status)) ++ invalid_status = WEXITSTATUS (invalid_status); ++} ++ ++static int ++do_test (void) ++{ ++ init_invalid_status (); ++ ++ TEST ("test", NULL, "%s", "test"); ++ TEST ("test-test", NULL, "%s-test", "test"); ++ TEST ("test", "test", "%s", "test"); ++ TEST ("test-test", "test", "%s-test", "test"); ++ ++ TEST ("test%", NULL, "%s%%", "test"); ++ TEST ("test%-test", NULL, "%s%%-test", "test"); ++ TEST ("test%", "test", "%s%%", "test"); ++ TEST ("test%-test", "test", "%s%%-test", "test"); ++ ++ TEST ("0000007b", NULL, "%x", 123); ++ TEST ("0000007b-test", NULL, "%x-test", 123); ++ TEST ("0000007b", "test", "%x", 123); ++ TEST ("0000007b-test", "test", "%x-test", 123); ++ ++#define TEST_LONG(es, objn, fmt, ...) \ ++ ({ \ ++ if (sizeof (int) == sizeof (long int)) \ ++ TEST (es, objn, fmt, __VA_ARGS__); \ ++ else \ ++ TEST ("ffffffff" es, objn, fmt, __VA_ARGS__); \ ++ }) ++ ++ TEST_LONG ("fffffffd", NULL, "%lx", (long int)~2ul); ++ TEST_LONG ("fffffffd-test", NULL, "%lx-test", (long int)~2ul); ++ TEST_LONG ("fffffffd", "test", "%lx", (long int)~2ul); ++ TEST_LONG ("fffffffd-test", "test", "%lx-test", (long int)~2ul); ++ ++ TEST_LONG ("fffffffe", NULL, "%zx", (size_t)~1ul); ++ TEST_LONG ("fffffffe-test", NULL, "%zx-test", (size_t)~1ul); ++ TEST_LONG ("fffffffe", "test", "%zx", (size_t)~1ul); ++ TEST_LONG ("fffffffe-test", "test", "%zx-test", (size_t)~1ul); ++ ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (do_test_invalid_conversion, NULL); ++ support_capture_subprocess_check (&result, "dl-exception", ++ invalid_status, sc_allow_stderr); ++ TEST_COMPARE_STRING (result.err.buffer, ++ "Fatal error: invalid format in exception string\n"); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1817513-130.patch b/SOURCES/glibc-rh1817513-130.patch new file mode 100644 index 0000000..d06b247 --- /dev/null +++ b/SOURCES/glibc-rh1817513-130.patch @@ -0,0 +1,22 @@ +commit 8dddf0bd5a3d57fba8da27e93f3d1a7032fce184 +Author: Florian Weimer +Date: Wed Oct 30 17:44:09 2019 +0100 + + resolv/tst-idna_name_classify: Isolate from system libraries + + Loading NSS modules from static binaries uses installed system + libraries if LD_LIBRARY_PATH is not set. + +diff --git a/inet/Makefile b/inet/Makefile +index 7782913b4c06f057..62d25f853538bb08 100644 +--- a/inet/Makefile ++++ b/inet/Makefile +@@ -112,4 +112,8 @@ ifeq ($(build-static-nss),yes) + CFLAGS += -DSTATIC_NSS + endif + ++# The test uses dlopen indirectly and would otherwise load system ++# objects. ++tst-idna_name_classify-ENV = \ ++ LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)elf + $(objpfx)tst-idna_name_classify.out: $(gen-locales) diff --git a/SOURCES/glibc-rh1817513-131.patch b/SOURCES/glibc-rh1817513-131.patch new file mode 100644 index 0000000..7f650e5 --- /dev/null +++ b/SOURCES/glibc-rh1817513-131.patch @@ -0,0 +1,21 @@ +commit 880433de13fa31e52587720f81b762a6c7797e4e +Author: Florian Weimer +Date: Thu Dec 10 15:47:26 2020 +0100 + + elf: Include in cache.c + + The roundup macro is defined there. Relying on an indirect + definition is brittle. + +diff --git a/elf/cache.c b/elf/cache.c +index dde3d7fefa4105f9..fdfedb0964bcd217 100644 +--- a/elf/cache.c ++++ b/elf/cache.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + #include + #include + diff --git a/SOURCES/glibc-rh1817513-132.patch b/SOURCES/glibc-rh1817513-132.patch new file mode 100644 index 0000000..914292e --- /dev/null +++ b/SOURCES/glibc-rh1817513-132.patch @@ -0,0 +1,33 @@ +commit 2ee7711bdd7de9dd30073b223ce29d5cd50320f6 +Author: H.J. Lu +Date: Sun Dec 13 04:56:41 2020 -0800 + + x86: Remove the default REP MOVSB threshold tunable value [BZ #27061] + + Since we can't tell if the tunable value is set by user or not: + + https://sourceware.org/bugzilla/show_bug.cgi?id=27069 + + remove the default REP MOVSB threshold tunable value so that the correct + default value will be set correctly by init_cacheinfo (). + + Reviewed-by: Carlos O'Donell + +diff --git a/sysdeps/x86/dl-tunables.list b/sysdeps/x86/dl-tunables.list +index e066313a1d1dd009..89bf296626658900 100644 +--- a/sysdeps/x86/dl-tunables.list ++++ b/sysdeps/x86/dl-tunables.list +@@ -39,9 +39,11 @@ glibc { + # REP MOVSB. Since larger register size can move more data with a + # single load and store, the threshold is higher with larger register + # size. Note: Since the REP MOVSB threshold must be greater than 8 +- # times of vector size, the minium value must be updated at run-time. ++ # times of vector size and the default value is 2048 * (vector size ++ # / 16), the default value and the minimum value must be updated at ++ # run-time. NB: Don't set the default value since we can't tell if ++ # the tunable value is set by user or not [BZ #27069]. + minval: 1 +- default: 2048 + } + x86_rep_stosb_threshold { + type: SIZE_T diff --git a/SOURCES/glibc-rh1817513-133.patch b/SOURCES/glibc-rh1817513-133.patch new file mode 100644 index 0000000..a714822 --- /dev/null +++ b/SOURCES/glibc-rh1817513-133.patch @@ -0,0 +1,18 @@ +commit 8a30bb4e0604aefcf28f20360fc8ba8ef8604b9c +Author: Florian Weimer +Date: Wed Dec 23 12:07:20 2020 +0100 + + elf: Account for glibc-hwcaps/ prefix in _dl_important_hwcaps + +diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c +index 50d764ae8707f46d..2fc4ae67a0f5d051 100644 +--- a/elf/dl-hwcaps.c ++++ b/elf/dl-hwcaps.c +@@ -192,6 +192,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend, + + /* Each hwcaps subdirectory has a GLIBC_HWCAPS_PREFIX string prefix + and a "/" suffix once stored in the result. */ ++ hwcaps_counts.maximum_length += strlen (GLIBC_HWCAPS_PREFIX) + 1; + size_t total = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1) + + hwcaps_counts.total_length); + diff --git a/SOURCES/glibc-rh1817513-14.patch b/SOURCES/glibc-rh1817513-14.patch new file mode 100644 index 0000000..0186fde --- /dev/null +++ b/SOURCES/glibc-rh1817513-14.patch @@ -0,0 +1,22 @@ +commit ce7387cc250a408d3fbb7a6fff7ad4d977166b00 +Author: H.J. Lu +Date: Thu Nov 29 20:03:46 2018 -0800 + + elf/dl-exception.c: Include <_itoa.h> for _itoa prototype + + Tested with build-many-glibcs.py. + + * elf/dl-exception.c: Include <_itoa.h>. + +diff --git a/elf/dl-exception.c b/elf/dl-exception.c +index 1e41d89a7db52683..3e8e0ba3f1442005 100644 +--- a/elf/dl-exception.c ++++ b/elf/dl-exception.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include <_itoa.h> + + /* This message we return as a last resort. We define the string in a + variable since we have to avoid freeing it and so have to enable diff --git a/SOURCES/glibc-rh1817513-15.patch b/SOURCES/glibc-rh1817513-15.patch new file mode 100644 index 0000000..d9ef9ef --- /dev/null +++ b/SOURCES/glibc-rh1817513-15.patch @@ -0,0 +1,1820 @@ +commit c22e4c2a1431c5e77bf4288d35bf7629f2f093aa +Author: H.J. Lu +Date: Mon Dec 3 05:54:43 2018 -0800 + + x86: Extend CPUID support in struct cpu_features + + Extend CPUID support for all feature bits from CPUID. Add a new macro, + CPU_FEATURE_USABLE, which can be used to check if a feature is usable at + run-time, instead of HAS_CPU_FEATURE and HAS_ARCH_FEATURE. + + Add COMMON_CPUID_INDEX_D_ECX_1, COMMON_CPUID_INDEX_80000007 and + COMMON_CPUID_INDEX_80000008 to check CPU feature bits in them. + + Tested on i686 and x86-64 as well as using build-many-glibcs.py with + x86 targets. + + * sysdeps/x86/cacheinfo.c (intel_check_word): Updated for + cpu_features_basic. + (__cache_sysconf): Likewise. + (init_cacheinfo): Likewise. + * sysdeps/x86/cpu-features.c (get_extended_indeces): Also + populate COMMON_CPUID_INDEX_80000007 and + COMMON_CPUID_INDEX_80000008. + (get_common_indices): Also populate COMMON_CPUID_INDEX_D_ECX_1. + Use CPU_FEATURES_CPU_P (cpu_features, XSAVEC) to check if + XSAVEC is available. Set the bit_arch_XXX_Usable bits. + (init_cpu_features): Use _Static_assert on + index_arch_Fast_Unaligned_Load. + __get_cpuid_registers and __get_arch_feature. Updated for + cpu_features_basic. Set stepping in cpu_features. + * sysdeps/x86/cpu-features.h: (FEATURE_INDEX_1): Changed to enum. + (FEATURE_INDEX_2): New. + (FEATURE_INDEX_MAX): Changed to enum. + (COMMON_CPUID_INDEX_D_ECX_1): New. + (COMMON_CPUID_INDEX_80000007): Likewise. + (COMMON_CPUID_INDEX_80000008): Likewise. + (cpuid_registers): Likewise. + (cpu_features_basic): Likewise. + (CPU_FEATURE_USABLE): Likewise. + (bit_arch_XXX_Usable): Likewise. + (cpu_features): Use cpuid_registers and cpu_features_basic. + (bit_arch_XXX): Reweritten. + (bit_cpu_XXX): Likewise. + (index_cpu_XXX): Likewise. + (reg_XXX): Likewise. + * sysdeps/x86/tst-get-cpu-features.c: Include and + . + (CHECK_CPU_FEATURE): New. + (CHECK_CPU_FEATURE_USABLE): Likewise. + (cpu_kinds): Likewise. + (do_test): Print vendor, family, model and stepping. Check + HAS_CPU_FEATURE and CPU_FEATURE_USABLE. + (TEST_FUNCTION): Removed. + Include instead of + "../../test-skeleton.c". + * sysdeps/x86_64/multiarch/sched_cpucount.c (__sched_cpucount): + Check POPCNT instead of POPCOUNT. + * sysdeps/x86_64/multiarch/test-multiarch.c (do_test): Likewise. + +Backport difference: Adjustments to previous cache sizing +backports (which happened later upstream). + +diff --git a/sysdeps/x86/cacheinfo.c b/sysdeps/x86/cacheinfo.c +index 57c36d030a76c8b2..f1125f30223f5ca3 100644 +--- a/sysdeps/x86/cacheinfo.c ++++ b/sysdeps/x86/cacheinfo.c +@@ -205,8 +205,8 @@ intel_check_word (int name, unsigned int value, bool *has_level_2, + /* Intel reused this value. For family 15, model 6 it + specifies the 3rd level cache. Otherwise the 2nd + level cache. */ +- unsigned int family = cpu_features->family; +- unsigned int model = cpu_features->model; ++ unsigned int family = cpu_features->basic.family; ++ unsigned int model = cpu_features->basic.model; + + if (family == 15 && model == 6) + { +@@ -258,7 +258,7 @@ intel_check_word (int name, unsigned int value, bool *has_level_2, + static long int __attribute__ ((noinline)) + handle_intel (int name, const struct cpu_features *cpu_features) + { +- unsigned int maxidx = cpu_features->max_cpuid; ++ unsigned int maxidx = cpu_features->basic.max_cpuid; + + /* Return -1 for older CPUs. */ + if (maxidx < 2) +@@ -443,10 +443,10 @@ __cache_sysconf (int name) + { + const struct cpu_features *cpu_features = __get_cpu_features (); + +- if (cpu_features->kind == arch_kind_intel) ++ if (cpu_features->basic.kind == arch_kind_intel) + return handle_intel (name, cpu_features); + +- if (cpu_features->kind == arch_kind_amd) ++ if (cpu_features->basic.kind == arch_kind_amd) + return handle_amd (name); + + // XXX Fill in more vendors. +@@ -497,9 +497,9 @@ init_cacheinfo (void) + unsigned int level; + unsigned int threads = 0; + const struct cpu_features *cpu_features = __get_cpu_features (); +- int max_cpuid = cpu_features->max_cpuid; ++ int max_cpuid = cpu_features->basic.max_cpuid; + +- if (cpu_features->kind == arch_kind_intel) ++ if (cpu_features->basic.kind == arch_kind_intel) + { + data = handle_intel (_SC_LEVEL1_DCACHE_SIZE, cpu_features); + +@@ -538,8 +538,8 @@ init_cacheinfo (void) + highest cache level. */ + if (max_cpuid >= 4) + { +- unsigned int family = cpu_features->family; +- unsigned int model = cpu_features->model; ++ unsigned int family = cpu_features->basic.family; ++ unsigned int model = cpu_features->basic.model; + + int i = 0; + +@@ -700,7 +700,7 @@ intel_bug_no_cache_info: + shared += core; + } + } +- else if (cpu_features->kind == arch_kind_amd) ++ else if (cpu_features->basic.kind == arch_kind_amd) + { + data = handle_amd (_SC_LEVEL1_DCACHE_SIZE); + long int core = handle_amd (_SC_LEVEL2_CACHE_SIZE); +@@ -722,7 +722,7 @@ intel_bug_no_cache_info: + threads = 1 << ((ecx >> 12) & 0x0f); + } + +- if (threads == 0 || cpu_features->family >= 0x17) ++ if (threads == 0 || cpu_features->basic.family >= 0x17) + { + /* If APIC ID width is not available, use logical + processor count. */ +@@ -738,7 +738,7 @@ intel_bug_no_cache_info: + shared /= threads; + + /* Get shared cache per ccx for Zen architectures. */ +- if (cpu_features->family >= 0x17) ++ if (cpu_features->basic.family >= 0x17) + { + unsigned int eax; + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 3b268efbce627e6c..3a02a9c7d08f9603 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -52,7 +52,18 @@ get_extended_indices (struct cpu_features *cpu_features) + cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].ebx, + cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].ecx, + cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].edx); +- ++ if (eax >= 0x80000007) ++ __cpuid (0x80000007, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_80000007].eax, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_80000007].ebx, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_80000007].ecx, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_80000007].edx); ++ if (eax >= 0x80000008) ++ __cpuid (0x80000008, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_80000008].eax, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_80000008].ebx, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_80000008].ecx, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_80000008].edx); + } + + static void +@@ -78,13 +89,20 @@ get_common_indices (struct cpu_features *cpu_features, + } + } + +- if (cpu_features->max_cpuid >= 7) ++ if (cpu_features->basic.max_cpuid >= 7) + __cpuid_count (7, 0, + cpu_features->cpuid[COMMON_CPUID_INDEX_7].eax, + cpu_features->cpuid[COMMON_CPUID_INDEX_7].ebx, + cpu_features->cpuid[COMMON_CPUID_INDEX_7].ecx, + cpu_features->cpuid[COMMON_CPUID_INDEX_7].edx); + ++ if (cpu_features->basic.max_cpuid >= 0xd) ++ __cpuid_count (0xd, 1, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_D_ECX_1].eax, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_D_ECX_1].ebx, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_D_ECX_1].ecx, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_D_ECX_1].edx); ++ + /* Can we call xgetbv? */ + if (CPU_FEATURES_CPU_P (cpu_features, OSXSAVE)) + { +@@ -116,6 +134,18 @@ get_common_indices (struct cpu_features *cpu_features, + if (CPU_FEATURES_CPU_P (cpu_features, FMA)) + cpu_features->feature[index_arch_FMA_Usable] + |= bit_arch_FMA_Usable; ++ /* Determine if VAES is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, VAES)) ++ cpu_features->feature[index_arch_VAES_Usable] ++ |= bit_arch_VAES_Usable; ++ /* Determine if VPCLMULQDQ is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, VPCLMULQDQ)) ++ cpu_features->feature[index_arch_VPCLMULQDQ_Usable] ++ |= bit_arch_VPCLMULQDQ_Usable; ++ /* Determine if XOP is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, XOP)) ++ cpu_features->feature[index_arch_XOP_Usable] ++ |= bit_arch_XOP_Usable; + } + + /* Check if OPMASK state, upper 256-bit of ZMM0-ZMM15 and +@@ -129,17 +159,69 @@ get_common_indices (struct cpu_features *cpu_features, + { + cpu_features->feature[index_arch_AVX512F_Usable] + |= bit_arch_AVX512F_Usable; ++ /* Determine if AVX512CD is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512CD)) ++ cpu_features->feature[index_arch_AVX512CD_Usable] ++ |= bit_arch_AVX512CD_Usable; ++ /* Determine if AVX512ER is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512ER)) ++ cpu_features->feature[index_arch_AVX512ER_Usable] ++ |= bit_arch_AVX512ER_Usable; ++ /* Determine if AVX512PF is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512PF)) ++ cpu_features->feature[index_arch_AVX512PF_Usable] ++ |= bit_arch_AVX512PF_Usable; ++ /* Determine if AVX512VL is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512VL)) ++ cpu_features->feature[index_arch_AVX512VL_Usable] ++ |= bit_arch_AVX512VL_Usable; + /* Determine if AVX512DQ is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512DQ)) + cpu_features->feature[index_arch_AVX512DQ_Usable] + |= bit_arch_AVX512DQ_Usable; ++ /* Determine if AVX512BW is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512BW)) ++ cpu_features->feature[index_arch_AVX512BW_Usable] ++ |= bit_arch_AVX512BW_Usable; ++ /* Determine if AVX512_4FMAPS is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512_4FMAPS)) ++ cpu_features->feature[index_arch_AVX512_4FMAPS_Usable] ++ |= bit_arch_AVX512_4FMAPS_Usable; ++ /* Determine if AVX512_4VNNIW is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512_4VNNIW)) ++ cpu_features->feature[index_arch_AVX512_4VNNIW_Usable] ++ |= bit_arch_AVX512_4VNNIW_Usable; ++ /* Determine if AVX512_BITALG is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512_BITALG)) ++ cpu_features->feature[index_arch_AVX512_BITALG_Usable] ++ |= bit_arch_AVX512_BITALG_Usable; ++ /* Determine if AVX512_IFMA is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512_IFMA)) ++ cpu_features->feature[index_arch_AVX512_IFMA_Usable] ++ |= bit_arch_AVX512_IFMA_Usable; ++ /* Determine if AVX512_VBMI is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VBMI)) ++ cpu_features->feature[index_arch_AVX512_VBMI_Usable] ++ |= bit_arch_AVX512_VBMI_Usable; ++ /* Determine if AVX512_VBMI2 is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VBMI2)) ++ cpu_features->feature[index_arch_AVX512_VBMI2_Usable] ++ |= bit_arch_AVX512_VBMI2_Usable; ++ /* Determine if is AVX512_VNNI usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VNNI)) ++ cpu_features->feature[index_arch_AVX512_VNNI_Usable] ++ |= bit_arch_AVX512_VNNI_Usable; ++ /* Determine if AVX512_VPOPCNTDQ is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VPOPCNTDQ)) ++ cpu_features->feature[index_arch_AVX512_VPOPCNTDQ_Usable] ++ |= bit_arch_AVX512_VPOPCNTDQ_Usable; + } + } + } + + /* For _dl_runtime_resolve, set xsave_state_size to xsave area + size + integer register save size and align it to 64 bytes. */ +- if (cpu_features->max_cpuid >= 0xd) ++ if (cpu_features->basic.max_cpuid >= 0xd) + { + unsigned int eax, ebx, ecx, edx; + +@@ -154,10 +236,8 @@ get_common_indices (struct cpu_features *cpu_features, + cpu_features->xsave_state_full_size + = xsave_state_full_size; + +- __cpuid_count (0xd, 1, eax, ebx, ecx, edx); +- + /* Check if XSAVEC is available. */ +- if ((eax & (1 << 1)) != 0) ++ if (CPU_FEATURES_CPU_P (cpu_features, XSAVEC)) + { + unsigned int xstate_comp_offsets[32]; + unsigned int xstate_comp_sizes[32]; +@@ -209,12 +289,25 @@ get_common_indices (struct cpu_features *cpu_features, + } + } + ++_Static_assert (((index_arch_Fast_Unaligned_Load ++ == index_arch_Fast_Unaligned_Copy) ++ && (index_arch_Fast_Unaligned_Load ++ == index_arch_Prefer_PMINUB_for_stringop) ++ && (index_arch_Fast_Unaligned_Load ++ == index_arch_Slow_SSE4_2) ++ && (index_arch_Fast_Unaligned_Load ++ == index_arch_Fast_Rep_String) ++ && (index_arch_Fast_Unaligned_Load ++ == index_arch_Fast_Copy_Backward)), ++ "Incorrect index_arch_Fast_Unaligned_Load"); ++ + static inline void + init_cpu_features (struct cpu_features *cpu_features) + { + unsigned int ebx, ecx, edx; + unsigned int family = 0; + unsigned int model = 0; ++ unsigned int stepping = 0; + enum cpu_features_kind kind; + + #if !HAS_CPUID +@@ -225,12 +318,12 @@ init_cpu_features (struct cpu_features *cpu_features) + } + #endif + +- __cpuid (0, cpu_features->max_cpuid, ebx, ecx, edx); ++ __cpuid (0, cpu_features->basic.max_cpuid, ebx, ecx, edx); + + /* This spells out "GenuineIntel". */ + if (ebx == 0x756e6547 && ecx == 0x6c65746e && edx == 0x49656e69) + { +- unsigned int extended_model, stepping; ++ unsigned int extended_model; + + kind = arch_kind_intel; + +@@ -269,15 +362,6 @@ init_cpu_features (struct cpu_features *cpu_features) + case 0x5d: + /* Unaligned load versions are faster than SSSE3 + on Silvermont. */ +-#if index_arch_Fast_Unaligned_Load != index_arch_Prefer_PMINUB_for_stringop +-# error index_arch_Fast_Unaligned_Load != index_arch_Prefer_PMINUB_for_stringop +-#endif +-#if index_arch_Fast_Unaligned_Load != index_arch_Slow_SSE4_2 +-# error index_arch_Fast_Unaligned_Load != index_arch_Slow_SSE4_2 +-#endif +-#if index_arch_Fast_Unaligned_Load != index_arch_Fast_Unaligned_Copy +-# error index_arch_Fast_Unaligned_Load != index_arch_Fast_Unaligned_Copy +-#endif + cpu_features->feature[index_arch_Fast_Unaligned_Load] + |= (bit_arch_Fast_Unaligned_Load + | bit_arch_Fast_Unaligned_Copy +@@ -300,15 +384,6 @@ init_cpu_features (struct cpu_features *cpu_features) + case 0x2f: + /* Rep string instructions, unaligned load, unaligned copy, + and pminub are fast on Intel Core i3, i5 and i7. */ +-#if index_arch_Fast_Rep_String != index_arch_Fast_Unaligned_Load +-# error index_arch_Fast_Rep_String != index_arch_Fast_Unaligned_Load +-#endif +-#if index_arch_Fast_Rep_String != index_arch_Prefer_PMINUB_for_stringop +-# error index_arch_Fast_Rep_String != index_arch_Prefer_PMINUB_for_stringop +-#endif +-#if index_arch_Fast_Rep_String != index_arch_Fast_Unaligned_Copy +-# error index_arch_Fast_Rep_String != index_arch_Fast_Unaligned_Copy +-#endif + cpu_features->feature[index_arch_Fast_Rep_String] + |= (bit_arch_Fast_Rep_String + | bit_arch_Fast_Unaligned_Load +@@ -352,7 +427,7 @@ init_cpu_features (struct cpu_features *cpu_features) + /* This spells out "AuthenticAMD". */ + else if (ebx == 0x68747541 && ecx == 0x444d4163 && edx == 0x69746e65) + { +- unsigned int extended_model, stepping; ++ unsigned int extended_model; + + kind = arch_kind_amd; + +@@ -374,9 +449,6 @@ init_cpu_features (struct cpu_features *cpu_features) + + if (family == 0x15) + { +-#if index_arch_Fast_Unaligned_Load != index_arch_Fast_Copy_Backward +-# error index_arch_Fast_Unaligned_Load != index_arch_Fast_Copy_Backward +-#endif + /* "Excavator" */ + if (model >= 0x60 && model <= 0x7f) + { +@@ -408,9 +480,10 @@ init_cpu_features (struct cpu_features *cpu_features) + no_cpuid: + #endif + +- cpu_features->family = family; +- cpu_features->model = model; +- cpu_features->kind = kind; ++ cpu_features->basic.kind = kind; ++ cpu_features->basic.family = family; ++ cpu_features->basic.model = model; ++ cpu_features->basic.stepping = stepping; + + #if HAVE_TUNABLES + TUNABLE_GET (hwcaps, tunable_val_t *, TUNABLE_CALLBACK (set_hwcaps)); +@@ -431,7 +504,7 @@ no_cpuid: + + #ifdef __x86_64__ + GLRO(dl_hwcap) = HWCAP_X86_64; +- if (cpu_features->kind == arch_kind_intel) ++ if (cpu_features->basic.kind == arch_kind_intel) + { + const char *platform = NULL; + +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index fb22d7b9d6226a92..4917182e99a8ee90 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -18,108 +18,58 @@ + #ifndef cpu_features_h + #define cpu_features_h + +-#define bit_arch_Fast_Rep_String (1 << 0) +-#define bit_arch_Fast_Copy_Backward (1 << 1) +-#define bit_arch_Slow_BSF (1 << 2) +-#define bit_arch_Fast_Unaligned_Load (1 << 4) +-#define bit_arch_Prefer_PMINUB_for_stringop (1 << 5) +-#define bit_arch_AVX_Usable (1 << 6) +-#define bit_arch_FMA_Usable (1 << 7) +-#define bit_arch_FMA4_Usable (1 << 8) +-#define bit_arch_Slow_SSE4_2 (1 << 9) +-#define bit_arch_AVX2_Usable (1 << 10) +-#define bit_arch_AVX_Fast_Unaligned_Load (1 << 11) +-#define bit_arch_AVX512F_Usable (1 << 12) +-#define bit_arch_AVX512DQ_Usable (1 << 13) +-#define bit_arch_I586 (1 << 14) +-#define bit_arch_I686 (1 << 15) +-#define bit_arch_Prefer_MAP_32BIT_EXEC (1 << 16) +-#define bit_arch_Prefer_No_VZEROUPPER (1 << 17) +-#define bit_arch_Fast_Unaligned_Copy (1 << 18) +-#define bit_arch_Prefer_ERMS (1 << 19) +-#define bit_arch_Prefer_No_AVX512 (1 << 20) +-#define bit_arch_MathVec_Prefer_No_AVX512 (1 << 21) +-#define bit_arch_XSAVEC_Usable (1 << 22) +-#define bit_arch_Prefer_FSRM (1 << 23) +- +-/* CPUID Feature flags. */ +- +-/* COMMON_CPUID_INDEX_1. */ +-#define bit_cpu_CX8 (1 << 8) +-#define bit_cpu_CMOV (1 << 15) +-#define bit_cpu_SSE (1 << 25) +-#define bit_cpu_SSE2 (1 << 26) +-#define bit_cpu_SSSE3 (1 << 9) +-#define bit_cpu_SSE4_1 (1 << 19) +-#define bit_cpu_SSE4_2 (1 << 20) +-#define bit_cpu_OSXSAVE (1 << 27) +-#define bit_cpu_AVX (1 << 28) +-#define bit_cpu_POPCOUNT (1 << 23) +-#define bit_cpu_FMA (1 << 12) +-#define bit_cpu_FMA4 (1 << 16) +-#define bit_cpu_HTT (1 << 28) +-#define bit_cpu_LZCNT (1 << 5) +-#define bit_cpu_MOVBE (1 << 22) +-#define bit_cpu_POPCNT (1 << 23) +- +-/* COMMON_CPUID_INDEX_7. */ +-#define bit_cpu_BMI1 (1 << 3) +-#define bit_cpu_BMI2 (1 << 8) +-#define bit_cpu_ERMS (1 << 9) +-#define bit_cpu_RTM (1 << 11) +-#define bit_cpu_AVX2 (1 << 5) +-#define bit_cpu_AVX512F (1 << 16) +-#define bit_cpu_AVX512DQ (1 << 17) +-#define bit_cpu_AVX512PF (1 << 26) +-#define bit_cpu_AVX512ER (1 << 27) +-#define bit_cpu_AVX512CD (1 << 28) +-#define bit_cpu_AVX512BW (1 << 30) +-#define bit_cpu_AVX512VL (1u << 31) +-#define bit_cpu_IBT (1u << 20) +-#define bit_cpu_SHSTK (1u << 7) +-#define bit_cpu_FSRM (1 << 4) +- +-/* XCR0 Feature flags. */ +-#define bit_XMM_state (1 << 1) +-#define bit_YMM_state (1 << 2) +-#define bit_Opmask_state (1 << 5) +-#define bit_ZMM0_15_state (1 << 6) +-#define bit_ZMM16_31_state (1 << 7) ++enum ++{ ++ /* The integer bit array index for the first set of internal feature ++ bits. */ ++ FEATURE_INDEX_1 = 0, ++ FEATURE_INDEX_2, ++ /* The current maximum size of the feature integer bit array. */ ++ FEATURE_INDEX_MAX ++}; + +-/* The integer bit array index for the first set of internal feature bits. */ +-#define FEATURE_INDEX_1 0 ++enum ++{ ++ COMMON_CPUID_INDEX_1 = 0, ++ COMMON_CPUID_INDEX_7, ++ COMMON_CPUID_INDEX_80000001, ++ COMMON_CPUID_INDEX_D_ECX_1, ++ COMMON_CPUID_INDEX_80000007, ++ COMMON_CPUID_INDEX_80000008, ++ /* Keep the following line at the end. */ ++ COMMON_CPUID_INDEX_MAX ++}; + +-/* The current maximum size of the feature integer bit array. */ +-#define FEATURE_INDEX_MAX 1 ++struct cpuid_registers ++{ ++ unsigned int eax; ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++}; + +-enum +- { +- COMMON_CPUID_INDEX_1 = 0, +- COMMON_CPUID_INDEX_7, +- COMMON_CPUID_INDEX_80000001, +- /* Keep the following line at the end. */ +- COMMON_CPUID_INDEX_MAX +- }; ++enum cpu_features_kind ++{ ++ arch_kind_unknown = 0, ++ arch_kind_intel, ++ arch_kind_amd, ++ arch_kind_other ++}; + +-struct cpu_features ++struct cpu_features_basic + { +- enum cpu_features_kind +- { +- arch_kind_unknown = 0, +- arch_kind_intel, +- arch_kind_amd, +- arch_kind_other +- } kind; ++ enum cpu_features_kind kind; + int max_cpuid; +- struct cpuid_registers +- { +- unsigned int eax; +- unsigned int ebx; +- unsigned int ecx; +- unsigned int edx; +- } cpuid[COMMON_CPUID_INDEX_MAX]; + unsigned int family; + unsigned int model; ++ unsigned int stepping; ++}; ++ ++struct cpu_features ++{ ++ struct cpuid_registers cpuid[COMMON_CPUID_INDEX_MAX]; ++ unsigned int feature[FEATURE_INDEX_MAX]; ++ struct cpu_features_basic basic; + /* The state size for XSAVEC or XSAVE. The type must be unsigned long + int so that we use + +@@ -132,7 +82,6 @@ struct cpu_features + GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC_Usable + */ + unsigned int xsave_state_full_size; +- unsigned int feature[FEATURE_INDEX_MAX]; + /* Data cache size for use in memory and string routines, typically + L1 size. */ + unsigned long int data_cache_size; +@@ -148,112 +97,838 @@ struct cpu_features + extern const struct cpu_features *__get_cpu_features (void) + __attribute__ ((const)); + +-# if defined (_LIBC) && !IS_IN (nonlib) +-/* Unused for x86. */ +-# define INIT_ARCH() +-# define __get_cpu_features() (&GLRO(dl_x86_cpu_features)) +-# endif +- +- + /* Only used directly in cpu-features.c. */ + # define CPU_FEATURES_CPU_P(ptr, name) \ + ((ptr->cpuid[index_cpu_##name].reg_##name & (bit_cpu_##name)) != 0) + # define CPU_FEATURES_ARCH_P(ptr, name) \ + ((ptr->feature[index_arch_##name] & (bit_arch_##name)) != 0) + +-/* HAS_* evaluates to true if we may use the feature at runtime. */ +-# define HAS_CPU_FEATURE(name) \ +- CPU_FEATURES_CPU_P (__get_cpu_features (), name) ++/* HAS_CPU_FEATURE evaluates to true if CPU supports the feature. */ ++#define HAS_CPU_FEATURE(name) \ ++ CPU_FEATURES_CPU_P (__get_cpu_features (), name) ++/* HAS_ARCH_FEATURE evaluates to true if we may use the feature at ++ runtime. */ + # define HAS_ARCH_FEATURE(name) \ +- CPU_FEATURES_ARCH_P (__get_cpu_features (), name) +- +-# define index_cpu_CX8 COMMON_CPUID_INDEX_1 +-# define index_cpu_CMOV COMMON_CPUID_INDEX_1 +-# define index_cpu_SSE COMMON_CPUID_INDEX_1 +-# define index_cpu_SSE2 COMMON_CPUID_INDEX_1 +-# define index_cpu_SSSE3 COMMON_CPUID_INDEX_1 +-# define index_cpu_SSE4_1 COMMON_CPUID_INDEX_1 +-# define index_cpu_SSE4_2 COMMON_CPUID_INDEX_1 +-# define index_cpu_AVX COMMON_CPUID_INDEX_1 +-# define index_cpu_AVX2 COMMON_CPUID_INDEX_7 +-# define index_cpu_AVX512F COMMON_CPUID_INDEX_7 +-# define index_cpu_AVX512DQ COMMON_CPUID_INDEX_7 +-# define index_cpu_AVX512PF COMMON_CPUID_INDEX_7 +-# define index_cpu_AVX512ER COMMON_CPUID_INDEX_7 +-# define index_cpu_AVX512CD COMMON_CPUID_INDEX_7 +-# define index_cpu_AVX512BW COMMON_CPUID_INDEX_7 +-# define index_cpu_AVX512VL COMMON_CPUID_INDEX_7 +-# define index_cpu_ERMS COMMON_CPUID_INDEX_7 +-# define index_cpu_RTM COMMON_CPUID_INDEX_7 +-# define index_cpu_FMA COMMON_CPUID_INDEX_1 +-# define index_cpu_FMA4 COMMON_CPUID_INDEX_80000001 +-# define index_cpu_POPCOUNT COMMON_CPUID_INDEX_1 +-# define index_cpu_OSXSAVE COMMON_CPUID_INDEX_1 +-# define index_cpu_HTT COMMON_CPUID_INDEX_1 +-# define index_cpu_BMI1 COMMON_CPUID_INDEX_7 +-# define index_cpu_BMI2 COMMON_CPUID_INDEX_7 +-# define index_cpu_LZCNT COMMON_CPUID_INDEX_80000001 +-# define index_cpu_MOVBE COMMON_CPUID_INDEX_1 +-# define index_cpu_POPCNT COMMON_CPUID_INDEX_1 +-# define index_cpu_IBT COMMON_CPUID_INDEX_7 +-# define index_cpu_SHSTK COMMON_CPUID_INDEX_7 +-# define index_cpu_FSRM COMMON_CPUID_INDEX_7 +- +-# define reg_CX8 edx +-# define reg_CMOV edx +-# define reg_SSE edx +-# define reg_SSE2 edx +-# define reg_SSSE3 ecx +-# define reg_SSE4_1 ecx +-# define reg_SSE4_2 ecx +-# define reg_AVX ecx +-# define reg_AVX2 ebx +-# define reg_AVX512F ebx +-# define reg_AVX512DQ ebx +-# define reg_AVX512PF ebx +-# define reg_AVX512ER ebx +-# define reg_AVX512CD ebx +-# define reg_AVX512BW ebx +-# define reg_AVX512VL ebx +-# define reg_ERMS ebx +-# define reg_RTM ebx +-# define reg_FMA ecx +-# define reg_FMA4 ecx +-# define reg_POPCOUNT ecx +-# define reg_OSXSAVE ecx +-# define reg_HTT edx +-# define reg_BMI1 ebx +-# define reg_BMI2 ebx +-# define reg_LZCNT ecx +-# define reg_MOVBE ecx +-# define reg_POPCNT ecx +-# define reg_IBT edx +-# define reg_SHSTK ecx +-# define reg_FSRM edx +- +-# define index_arch_Fast_Rep_String FEATURE_INDEX_1 +-# define index_arch_Fast_Copy_Backward FEATURE_INDEX_1 +-# define index_arch_Slow_BSF FEATURE_INDEX_1 +-# define index_arch_Fast_Unaligned_Load FEATURE_INDEX_1 +-# define index_arch_Prefer_PMINUB_for_stringop FEATURE_INDEX_1 +-# define index_arch_AVX_Usable FEATURE_INDEX_1 +-# define index_arch_FMA_Usable FEATURE_INDEX_1 +-# define index_arch_FMA4_Usable FEATURE_INDEX_1 +-# define index_arch_Slow_SSE4_2 FEATURE_INDEX_1 +-# define index_arch_AVX2_Usable FEATURE_INDEX_1 +-# define index_arch_AVX_Fast_Unaligned_Load FEATURE_INDEX_1 +-# define index_arch_AVX512F_Usable FEATURE_INDEX_1 +-# define index_arch_AVX512DQ_Usable FEATURE_INDEX_1 +-# define index_arch_I586 FEATURE_INDEX_1 +-# define index_arch_I686 FEATURE_INDEX_1 +-# define index_arch_Prefer_MAP_32BIT_EXEC FEATURE_INDEX_1 +-# define index_arch_Prefer_No_VZEROUPPER FEATURE_INDEX_1 +-# define index_arch_Fast_Unaligned_Copy FEATURE_INDEX_1 +-# define index_arch_Prefer_ERMS FEATURE_INDEX_1 +-# define index_arch_Prefer_No_AVX512 FEATURE_INDEX_1 +-# define index_arch_MathVec_Prefer_No_AVX512 FEATURE_INDEX_1 +-# define index_arch_XSAVEC_Usable FEATURE_INDEX_1 +-# define index_arch_Prefer_FSRM FEATURE_INDEX_1 ++ CPU_FEATURES_ARCH_P (__get_cpu_features (), name) ++/* CPU_FEATURE_USABLE evaluates to true if the feature is usable. */ ++#define CPU_FEATURE_USABLE(name) \ ++ ((need_arch_feature_##name && HAS_ARCH_FEATURE (name##_Usable)) \ ++ || (!need_arch_feature_##name && HAS_CPU_FEATURE(name))) ++ ++/* Architecture features. */ ++ ++/* FEATURE_INDEX_1. */ ++#define bit_arch_AVX_Usable (1u << 0) ++#define bit_arch_AVX2_Usable (1u << 1) ++#define bit_arch_AVX512F_Usable (1u << 2) ++#define bit_arch_AVX512CD_Usable (1u << 3) ++#define bit_arch_AVX512ER_Usable (1u << 4) ++#define bit_arch_AVX512PF_Usable (1u << 5) ++#define bit_arch_AVX512VL_Usable (1u << 6) ++#define bit_arch_AVX512DQ_Usable (1u << 7) ++#define bit_arch_AVX512BW_Usable (1u << 8) ++#define bit_arch_AVX512_4FMAPS_Usable (1u << 9) ++#define bit_arch_AVX512_4VNNIW_Usable (1u << 10) ++#define bit_arch_AVX512_BITALG_Usable (1u << 11) ++#define bit_arch_AVX512_IFMA_Usable (1u << 12) ++#define bit_arch_AVX512_VBMI_Usable (1u << 13) ++#define bit_arch_AVX512_VBMI2_Usable (1u << 14) ++#define bit_arch_AVX512_VNNI_Usable (1u << 15) ++#define bit_arch_AVX512_VPOPCNTDQ_Usable (1u << 16) ++#define bit_arch_FMA_Usable (1u << 17) ++#define bit_arch_FMA4_Usable (1u << 18) ++#define bit_arch_VAES_Usable (1u << 19) ++#define bit_arch_VPCLMULQDQ_Usable (1u << 20) ++#define bit_arch_XOP_Usable (1u << 21) ++#define bit_arch_XSAVEC_Usable (1u << 22) ++ ++#define index_arch_AVX_Usable FEATURE_INDEX_1 ++#define index_arch_AVX2_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512F_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512CD_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512ER_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512PF_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512VL_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512BW_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512DQ_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512_4FMAPS_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512_4VNNIW_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512_BITALG_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512_IFMA_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512_VBMI_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512_VBMI2_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512_VNNI_Usable FEATURE_INDEX_1 ++#define index_arch_AVX512_VPOPCNTDQ_Usable FEATURE_INDEX_1 ++#define index_arch_FMA_Usable FEATURE_INDEX_1 ++#define index_arch_FMA4_Usable FEATURE_INDEX_1 ++#define index_arch_VAES_Usable FEATURE_INDEX_1 ++#define index_arch_VPCLMULQDQ_Usable FEATURE_INDEX_1 ++#define index_arch_XOP_Usable FEATURE_INDEX_1 ++#define index_arch_XSAVEC_Usable FEATURE_INDEX_1 ++ ++/* Unused. Compiler will optimize them out. */ ++#define bit_arch_SSE3_Usable (1u << 0) ++#define bit_arch_PCLMULQDQ_Usable (1u << 0) ++#define bit_arch_SSSE3_Usable (1u << 0) ++#define bit_arch_CMPXCHG16B_Usable (1u << 0) ++#define bit_arch_SSE4_1_Usable (1u << 0) ++#define bit_arch_SSE4_2_Usable (1u << 0) ++#define bit_arch_MOVBE_Usable (1u << 0) ++#define bit_arch_POPCNT_Usable (1u << 0) ++#define bit_arch_AES_Usable (1u << 0) ++#define bit_arch_XSAVE_Usable (1u << 0) ++#define bit_arch_OSXSAVE_Usable (1u << 0) ++#define bit_arch_F16C_Usable (1u << 0) ++#define bit_arch_RDRAND_Usable (1u << 0) ++#define bit_arch_FPU_Usable (1u << 0) ++#define bit_arch_TSC_Usable (1u << 0) ++#define bit_arch_MSR_Usable (1u << 0) ++#define bit_arch_CX8_Usable (1u << 0) ++#define bit_arch_SEP_Usable (1u << 0) ++#define bit_arch_CMOV_Usable (1u << 0) ++#define bit_arch_CLFSH_Usable (1u << 0) ++#define bit_arch_MMX_Usable (1u << 0) ++#define bit_arch_FXSR_Usable (1u << 0) ++#define bit_arch_SSE_Usable (1u << 0) ++#define bit_arch_SSE2_Usable (1u << 0) ++#define bit_arch_FSGSBASE_Usable (1u << 0) ++#define bit_arch_BMI1_Usable (1u << 0) ++#define bit_arch_HLE_Usable (1u << 0) ++#define bit_arch_BMI2_Usable (1u << 0) ++#define bit_arch_ERMS_Usable (1u << 0) ++#define bit_arch_RTM_Usable (1u << 0) ++#define bit_arch_RDSEED_Usable (1u << 0) ++#define bit_arch_ADX_Usable (1u << 0) ++#define bit_arch_CLFLUSHOPT_Usable (1u << 0) ++#define bit_arch_CLWB_Usable (1u << 0) ++#define bit_arch_SHA_Usable (1u << 0) ++#define bit_arch_PREFETCHWT1_Usable (1u << 0) ++#define bit_arch_GFNI_Usable (1u << 0) ++#define bit_arch_RDPID_Usable (1u << 0) ++#define bit_arch_CLDEMOTE_Usable (1u << 0) ++#define bit_arch_MOVDIRI_Usable (1u << 0) ++#define bit_arch_MOVDIR64B_Usable (1u << 0) ++#define bit_arch_FSRM_Usable (1u << 0) ++#define bit_arch_LAHF64_SAHF64_Usable (1u << 0) ++#define bit_arch_SVM_Usable (1u << 0) ++#define bit_arch_LZCNT_Usable (1u << 0) ++#define bit_arch_SSE4A_Usable (1u << 0) ++#define bit_arch_PREFETCHW_Usable (1u << 0) ++#define bit_arch_TBM_Usable (1u << 0) ++#define bit_arch_SYSCALL_SYSRET_Usable (1u << 0) ++#define bit_arch_RDTSCP_Usable (1u << 0) ++#define bit_arch_XSAVEOPT_Usable (1u << 0) ++#define bit_arch_XGETBV_ECX_1_Usable (1u << 0) ++#define bit_arch_XSAVES_Usable (1u << 0) ++#define bit_arch_INVARIANT_TSC_Usable (1u << 0) ++#define bit_arch_WBNOINVD_Usable (1u << 0) ++ ++/* Unused. Compiler will optimize them out. */ ++#define index_arch_SSE3_Usable FEATURE_INDEX_1 ++#define index_arch_PCLMULQDQ_Usable FEATURE_INDEX_1 ++#define index_arch_SSSE3_Usable FEATURE_INDEX_1 ++#define index_arch_CMPXCHG16B_Usable FEATURE_INDEX_1 ++#define index_arch_SSE4_1_Usable FEATURE_INDEX_1 ++#define index_arch_SSE4_2_Usable FEATURE_INDEX_1 ++#define index_arch_MOVBE_Usable FEATURE_INDEX_1 ++#define index_arch_POPCNT_Usable FEATURE_INDEX_1 ++#define index_arch_AES_Usable FEATURE_INDEX_1 ++#define index_arch_XSAVE_Usable FEATURE_INDEX_1 ++#define index_arch_OSXSAVE_Usable FEATURE_INDEX_1 ++#define index_arch_F16C_Usable FEATURE_INDEX_1 ++#define index_arch_RDRAND_Usable FEATURE_INDEX_1 ++#define index_arch_FPU_Usable FEATURE_INDEX_1 ++#define index_arch_TSC_Usable FEATURE_INDEX_1 ++#define index_arch_MSR_Usable FEATURE_INDEX_1 ++#define index_arch_CX8_Usable FEATURE_INDEX_1 ++#define index_arch_SEP_Usable FEATURE_INDEX_1 ++#define index_arch_CMOV_Usable FEATURE_INDEX_1 ++#define index_arch_CLFSH_Usable FEATURE_INDEX_1 ++#define index_arch_MMX_Usable FEATURE_INDEX_1 ++#define index_arch_FXSR_Usable FEATURE_INDEX_1 ++#define index_arch_SSE_Usable FEATURE_INDEX_1 ++#define index_arch_SSE2_Usable FEATURE_INDEX_1 ++#define index_arch_FSGSBASE_Usable FEATURE_INDEX_1 ++#define index_arch_BMI1_Usable FEATURE_INDEX_1 ++#define index_arch_HLE_Usable FEATURE_INDEX_1 ++#define index_arch_BMI2_Usable FEATURE_INDEX_1 ++#define index_arch_ERMS_Usable FEATURE_INDEX_1 ++#define index_arch_RTM_Usable FEATURE_INDEX_1 ++#define index_arch_RDSEED_Usable FEATURE_INDEX_1 ++#define index_arch_ADX_Usable FEATURE_INDEX_1 ++#define index_arch_CLFLUSHOPT_Usable FEATURE_INDEX_1 ++#define index_arch_CLWB_Usable FEATURE_INDEX_1 ++#define index_arch_SHA_Usable FEATURE_INDEX_1 ++#define index_arch_PREFETCHWT1_Usable FEATURE_INDEX_1 ++#define index_arch_GFNI_Usable FEATURE_INDEX_1 ++#define index_arch_RDPID_Usable FEATURE_INDEX_1 ++#define index_arch_CLDEMOTE_Usable FEATURE_INDEX_1 ++#define index_arch_MOVDIRI_Usable FEATURE_INDEX_1 ++#define index_arch_MOVDIR64B_Usable FEATURE_INDEX_1 ++#define index_arch_FSRM_Usable FEATURE_INDEX_1 ++#define index_arch_LAHF64_SAHF64_Usable FEATURE_INDEX_1 ++#define index_arch_LZCNT_Usable FEATURE_INDEX_1 ++#define index_arch_SSE4A_Usable FEATURE_INDEX_1 ++#define index_arch_PREFETCHW_Usable FEATURE_INDEX_1 ++#define index_arch_TBM_Usable FEATURE_INDEX_1 ++#define index_arch_SYSCALL_SYSRET_Usable FEATURE_INDEX_1 ++#define index_arch_RDTSCP_Usable FEATURE_INDEX_1 ++#define index_arch_XSAVEOPT_Usable FEATURE_INDEX_1 ++#define index_arch_XGETBV_ECX_1_Usable FEATURE_INDEX_1 ++#define index_arch_XSAVES_Usable FEATURE_INDEX_1 ++#define index_arch_INVARIANT_TSC_Usable FEATURE_INDEX_1 ++#define index_arch_WBNOINVD_Usable FEATURE_INDEX_1 ++ ++/* COMMON_CPUID_INDEX_1. */ ++ ++/* ECX. */ ++#define need_arch_feature_SSE3 0 ++#define need_arch_feature_PCLMULQDQ 0 ++#define need_arch_feature_SSSE3 0 ++#define need_arch_feature_FMA 1 ++#define need_arch_feature_CMPXCHG16B 0 ++#define need_arch_feature_SSE4_1 0 ++#define need_arch_feature_SSE4_2 0 ++#define need_arch_feature_MOVBE 0 ++#define need_arch_feature_POPCNT 0 ++#define need_arch_feature_AES 0 ++#define need_arch_feature_XSAVE 0 ++#define need_arch_feature_OSXSAVE 0 ++#define need_arch_feature_AVX 1 ++#define need_arch_feature_F16C 0 ++#define need_arch_feature_RDRAND 0 ++ ++/* EDX. */ ++#define need_arch_feature_FPU 0 ++#define need_arch_feature_TSC 0 ++#define need_arch_feature_MSR 0 ++#define need_arch_feature_CX8 0 ++#define need_arch_feature_SEP 0 ++#define need_arch_feature_CMOV 0 ++#define need_arch_feature_CLFSH 0 ++#define need_arch_feature_MMX 0 ++#define need_arch_feature_FXSR 0 ++#define need_arch_feature_SSE 0 ++#define need_arch_feature_SSE2 0 ++ ++/* COMMON_CPUID_INDEX_7. */ ++ ++/* EBX. */ ++#define need_arch_feature_FSGSBASE 0 ++#define need_arch_feature_BMI1 0 ++#define need_arch_feature_HLE 0 ++#define need_arch_feature_AVX2 1 ++#define need_arch_feature_BMI2 0 ++#define need_arch_feature_ERMS 0 ++#define need_arch_feature_RTM 0 ++#define need_arch_feature_AVX512F 1 ++#define need_arch_feature_AVX512DQ 1 ++#define need_arch_feature_RDSEED 0 ++#define need_arch_feature_ADX 0 ++#define need_arch_feature_AVX512_IFMA 1 ++#define need_arch_feature_CLFLUSHOPT 0 ++#define need_arch_feature_CLWB 0 ++#define need_arch_feature_AVX512PF 1 ++#define need_arch_feature_AVX512ER 1 ++#define need_arch_feature_AVX512CD 1 ++#define need_arch_feature_SHA 0 ++#define need_arch_feature_AVX512BW 1 ++#define need_arch_feature_AVX512VL 1 ++ ++/* ECX. */ ++#define need_arch_feature_PREFETCHWT1 0 ++#define need_arch_feature_AVX512_VBMI 1 ++#define need_arch_feature_AVX512_VBMI2 1 ++#define need_arch_feature_GFNI 0 ++#define need_arch_feature_VAES 1 ++#define need_arch_feature_VPCLMULQDQ 1 ++#define need_arch_feature_AVX512_VNNI 1 ++#define need_arch_feature_AVX512_BITALG 1 ++#define need_arch_feature_AVX512_VPOPCNTDQ 1 ++#define need_arch_feature_RDPID 0 ++#define need_arch_feature_CLDEMOTE 0 ++#define need_arch_feature_MOVDIRI 0 ++#define need_arch_feature_MOVDIR64B 0 ++ ++/* EDX. */ ++#define need_arch_feature_AVX512_4VNNIW 1 ++#define need_arch_feature_AVX512_4FMAPS 1 ++#define need_arch_feature_FSRM 0 ++ ++/* COMMON_CPUID_INDEX_80000001. */ ++ ++/* ECX. */ ++#define need_arch_feature_LAHF64_SAHF64 0 ++#define need_arch_feature_LZCNT 0 ++#define need_arch_feature_SSE4A 0 ++#define need_arch_feature_PREFETCHW 0 ++#define need_arch_feature_XOP 1 ++#define need_arch_feature_FMA4 1 ++#define need_arch_feature_TBM 0 ++#define need_arch_feature_SYSCALL_SYSRET 0 ++#define need_arch_feature_RDTSCP 0 ++#define need_arch_feature_XSAVEOPT 0 ++#define need_arch_feature_XSAVEC 1 ++#define need_arch_feature_XGETBV_ECX_1 0 ++#define need_arch_feature_XSAVES 0 ++#define need_arch_feature_INVARIANT_TSC 0 ++#define need_arch_feature_WBNOINVD 0 ++ ++/* CPU features. */ ++ ++/* COMMON_CPUID_INDEX_1. */ ++ ++/* ECX. */ ++#define bit_cpu_SSE3 (1u << 0) ++#define bit_cpu_PCLMULQDQ (1u << 1) ++#define bit_cpu_DTES64 (1u << 2) ++#define bit_cpu_MONITOR (1u << 3) ++#define bit_cpu_DS_CPL (1u << 4) ++#define bit_cpu_VMX (1u << 5) ++#define bit_cpu_SMX (1u << 6) ++#define bit_cpu_EST (1u << 7) ++#define bit_cpu_TM2 (1u << 8) ++#define bit_cpu_SSSE3 (1u << 9) ++#define bit_cpu_CNXT_ID (1u << 10) ++#define bit_cpu_SDBG (1u << 11) ++#define bit_cpu_FMA (1u << 12) ++#define bit_cpu_CMPXCHG16B (1u << 13) ++#define bit_cpu_XTPRUPDCTRL (1u << 14) ++#define bit_cpu_PDCM (1u << 15) ++#define bit_cpu_PCID (1u << 17) ++#define bit_cpu_DCA (1u << 18) ++#define bit_cpu_SSE4_1 (1u << 19) ++#define bit_cpu_SSE4_2 (1u << 20) ++#define bit_cpu_X2APIC (1u << 21) ++#define bit_cpu_MOVBE (1u << 22) ++#define bit_cpu_POPCNT (1u << 23) ++#define bit_cpu_TSC_DEADLINE (1u << 24) ++#define bit_cpu_AES (1u << 25) ++#define bit_cpu_XSAVE (1u << 26) ++#define bit_cpu_OSXSAVE (1u << 27) ++#define bit_cpu_AVX (1u << 28) ++#define bit_cpu_F16C (1u << 29) ++#define bit_cpu_RDRAND (1u << 30) ++ ++/* EDX. */ ++#define bit_cpu_FPU (1u << 0) ++#define bit_cpu_VME (1u << 1) ++#define bit_cpu_DE (1u << 2) ++#define bit_cpu_PSE (1u << 3) ++#define bit_cpu_TSC (1u << 4) ++#define bit_cpu_MSR (1u << 5) ++#define bit_cpu_PAE (1u << 6) ++#define bit_cpu_MCE (1u << 7) ++#define bit_cpu_CX8 (1u << 8) ++#define bit_cpu_APIC (1u << 9) ++#define bit_cpu_SEP (1u << 11) ++#define bit_cpu_MTRR (1u << 12) ++#define bit_cpu_PGE (1u << 13) ++#define bit_cpu_MCA (1u << 14) ++#define bit_cpu_CMOV (1u << 15) ++#define bit_cpu_PAT (1u << 16) ++#define bit_cpu_PSE_36 (1u << 17) ++#define bit_cpu_PSN (1u << 18) ++#define bit_cpu_CLFSH (1u << 20) ++#define bit_cpu_DS (1u << 21) ++#define bit_cpu_ACPI (1u << 22) ++#define bit_cpu_MMX (1u << 23) ++#define bit_cpu_FXSR (1u << 24) ++#define bit_cpu_SSE (1u << 25) ++#define bit_cpu_SSE2 (1u << 26) ++#define bit_cpu_SS (1u << 27) ++#define bit_cpu_HTT (1u << 28) ++#define bit_cpu_TM (1u << 29) ++#define bit_cpu_PBE (1u << 31) ++ ++/* COMMON_CPUID_INDEX_7. */ ++ ++/* EBX. */ ++#define bit_cpu_FSGSBASE (1u << 0) ++#define bit_cpu_TSC_ADJUST (1u << 1) ++#define bit_cpu_SGX (1u << 2) ++#define bit_cpu_BMI1 (1u << 3) ++#define bit_cpu_HLE (1u << 4) ++#define bit_cpu_AVX2 (1u << 5) ++#define bit_cpu_SMEP (1u << 7) ++#define bit_cpu_BMI2 (1u << 8) ++#define bit_cpu_ERMS (1u << 9) ++#define bit_cpu_INVPCID (1u << 10) ++#define bit_cpu_RTM (1u << 11) ++#define bit_cpu_PQM (1u << 12) ++#define bit_cpu_MPX (1u << 14) ++#define bit_cpu_PQE (1u << 15) ++#define bit_cpu_AVX512F (1u << 16) ++#define bit_cpu_AVX512DQ (1u << 17) ++#define bit_cpu_RDSEED (1u << 18) ++#define bit_cpu_ADX (1u << 19) ++#define bit_cpu_SMAP (1u << 20) ++#define bit_cpu_AVX512_IFMA (1u << 21) ++#define bit_cpu_CLFLUSHOPT (1u << 22) ++#define bit_cpu_CLWB (1u << 24) ++#define bit_cpu_TRACE (1u << 25) ++#define bit_cpu_AVX512PF (1u << 26) ++#define bit_cpu_AVX512ER (1u << 27) ++#define bit_cpu_AVX512CD (1u << 28) ++#define bit_cpu_SHA (1u << 29) ++#define bit_cpu_AVX512BW (1u << 30) ++#define bit_cpu_AVX512VL (1u << 31) ++ ++/* ECX. */ ++#define bit_cpu_PREFETCHWT1 (1u << 0) ++#define bit_cpu_AVX512_VBMI (1u << 1) ++#define bit_cpu_UMIP (1u << 2) ++#define bit_cpu_PKU (1u << 3) ++#define bit_cpu_OSPKE (1u << 4) ++#define bit_cpu_WAITPKG (1u << 5) ++#define bit_cpu_AVX512_VBMI2 (1u << 6) ++#define bit_cpu_SHSTK (1u << 7) ++#define bit_cpu_GFNI (1u << 8) ++#define bit_cpu_VAES (1u << 9) ++#define bit_cpu_VPCLMULQDQ (1u << 10) ++#define bit_cpu_AVX512_VNNI (1u << 11) ++#define bit_cpu_AVX512_BITALG (1u << 12) ++#define bit_cpu_AVX512_VPOPCNTDQ (1u << 14) ++#define bit_cpu_RDPID (1u << 22) ++#define bit_cpu_CLDEMOTE (1u << 25) ++#define bit_cpu_MOVDIRI (1u << 27) ++#define bit_cpu_MOVDIR64B (1u << 28) ++#define bit_cpu_SGX_LC (1u << 30) ++ ++/* EDX. */ ++#define bit_cpu_AVX512_4VNNIW (1u << 2) ++#define bit_cpu_AVX512_4FMAPS (1u << 3) ++#define bit_cpu_FSRM (1u << 4) ++#define bit_cpu_PCONFIG (1u << 18) ++#define bit_cpu_IBT (1u << 20) ++#define bit_cpu_IBRS_IBPB (1u << 26) ++#define bit_cpu_STIBP (1u << 27) ++#define bit_cpu_CAPABILITIES (1u << 29) ++#define bit_cpu_SSBD (1u << 31) ++ ++/* COMMON_CPUID_INDEX_80000001. */ ++ ++/* ECX. */ ++#define bit_cpu_LAHF64_SAHF64 (1u << 0) ++#define bit_cpu_SVM (1u << 2) ++#define bit_cpu_LZCNT (1u << 5) ++#define bit_cpu_SSE4A (1u << 6) ++#define bit_cpu_PREFETCHW (1u << 8) ++#define bit_cpu_XOP (1u << 11) ++#define bit_cpu_LWP (1u << 15) ++#define bit_cpu_FMA4 (1u << 16) ++#define bit_cpu_TBM (1u << 21) ++ ++/* EDX. */ ++#define bit_cpu_SYSCALL_SYSRET (1u << 11) ++#define bit_cpu_NX (1u << 20) ++#define bit_cpu_PAGE1GB (1u << 26) ++#define bit_cpu_RDTSCP (1u << 27) ++#define bit_cpu_LM (1u << 29) ++ ++/* COMMON_CPUID_INDEX_D_ECX_1. */ ++ ++/* EAX. */ ++#define bit_cpu_XSAVEOPT (1u << 0) ++#define bit_cpu_XSAVEC (1u << 1) ++#define bit_cpu_XGETBV_ECX_1 (1u << 2) ++#define bit_cpu_XSAVES (1u << 3) ++ ++/* COMMON_CPUID_INDEX_80000007. */ ++ ++/* EDX. */ ++#define bit_cpu_INVARIANT_TSC (1u << 8) ++ ++/* COMMON_CPUID_INDEX_80000008. */ ++ ++/* EBX. */ ++#define bit_cpu_WBNOINVD (1u << 9) ++ ++/* COMMON_CPUID_INDEX_1. */ ++ ++/* ECX. */ ++#define index_cpu_SSE3 COMMON_CPUID_INDEX_1 ++#define index_cpu_PCLMULQDQ COMMON_CPUID_INDEX_1 ++#define index_cpu_DTES64 COMMON_CPUID_INDEX_1 ++#define index_cpu_MONITOR COMMON_CPUID_INDEX_1 ++#define index_cpu_DS_CPL COMMON_CPUID_INDEX_1 ++#define index_cpu_VMX COMMON_CPUID_INDEX_1 ++#define index_cpu_SMX COMMON_CPUID_INDEX_1 ++#define index_cpu_EST COMMON_CPUID_INDEX_1 ++#define index_cpu_TM2 COMMON_CPUID_INDEX_1 ++#define index_cpu_SSSE3 COMMON_CPUID_INDEX_1 ++#define index_cpu_CNXT_ID COMMON_CPUID_INDEX_1 ++#define index_cpu_SDBG COMMON_CPUID_INDEX_1 ++#define index_cpu_FMA COMMON_CPUID_INDEX_1 ++#define index_cpu_CMPXCHG16B COMMON_CPUID_INDEX_1 ++#define index_cpu_XTPRUPDCTRL COMMON_CPUID_INDEX_1 ++#define index_cpu_PDCM COMMON_CPUID_INDEX_1 ++#define index_cpu_PCID COMMON_CPUID_INDEX_1 ++#define index_cpu_DCA COMMON_CPUID_INDEX_1 ++#define index_cpu_SSE4_1 COMMON_CPUID_INDEX_1 ++#define index_cpu_SSE4_2 COMMON_CPUID_INDEX_1 ++#define index_cpu_X2APIC COMMON_CPUID_INDEX_1 ++#define index_cpu_MOVBE COMMON_CPUID_INDEX_1 ++#define index_cpu_POPCNT COMMON_CPUID_INDEX_1 ++#define index_cpu_TSC_DEADLINE COMMON_CPUID_INDEX_1 ++#define index_cpu_AES COMMON_CPUID_INDEX_1 ++#define index_cpu_XSAVE COMMON_CPUID_INDEX_1 ++#define index_cpu_OSXSAVE COMMON_CPUID_INDEX_1 ++#define index_cpu_AVX COMMON_CPUID_INDEX_1 ++#define index_cpu_F16C COMMON_CPUID_INDEX_1 ++#define index_cpu_RDRAND COMMON_CPUID_INDEX_1 ++ ++/* ECX. */ ++#define index_cpu_FPU COMMON_CPUID_INDEX_1 ++#define index_cpu_VME COMMON_CPUID_INDEX_1 ++#define index_cpu_DE COMMON_CPUID_INDEX_1 ++#define index_cpu_PSE COMMON_CPUID_INDEX_1 ++#define index_cpu_TSC COMMON_CPUID_INDEX_1 ++#define index_cpu_MSR COMMON_CPUID_INDEX_1 ++#define index_cpu_PAE COMMON_CPUID_INDEX_1 ++#define index_cpu_MCE COMMON_CPUID_INDEX_1 ++#define index_cpu_CX8 COMMON_CPUID_INDEX_1 ++#define index_cpu_APIC COMMON_CPUID_INDEX_1 ++#define index_cpu_SEP COMMON_CPUID_INDEX_1 ++#define index_cpu_MTRR COMMON_CPUID_INDEX_1 ++#define index_cpu_PGE COMMON_CPUID_INDEX_1 ++#define index_cpu_MCA COMMON_CPUID_INDEX_1 ++#define index_cpu_CMOV COMMON_CPUID_INDEX_1 ++#define index_cpu_PAT COMMON_CPUID_INDEX_1 ++#define index_cpu_PSE_36 COMMON_CPUID_INDEX_1 ++#define index_cpu_PSN COMMON_CPUID_INDEX_1 ++#define index_cpu_CLFSH COMMON_CPUID_INDEX_1 ++#define index_cpu_DS COMMON_CPUID_INDEX_1 ++#define index_cpu_ACPI COMMON_CPUID_INDEX_1 ++#define index_cpu_MMX COMMON_CPUID_INDEX_1 ++#define index_cpu_FXSR COMMON_CPUID_INDEX_1 ++#define index_cpu_SSE COMMON_CPUID_INDEX_1 ++#define index_cpu_SSE2 COMMON_CPUID_INDEX_1 ++#define index_cpu_SS COMMON_CPUID_INDEX_1 ++#define index_cpu_HTT COMMON_CPUID_INDEX_1 ++#define index_cpu_TM COMMON_CPUID_INDEX_1 ++#define index_cpu_PBE COMMON_CPUID_INDEX_1 ++ ++/* COMMON_CPUID_INDEX_7. */ ++ ++/* EBX. */ ++#define index_cpu_FSGSBASE COMMON_CPUID_INDEX_7 ++#define index_cpu_TSC_ADJUST COMMON_CPUID_INDEX_7 ++#define index_cpu_SGX COMMON_CPUID_INDEX_7 ++#define index_cpu_BMI1 COMMON_CPUID_INDEX_7 ++#define index_cpu_HLE COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX2 COMMON_CPUID_INDEX_7 ++#define index_cpu_SMEP COMMON_CPUID_INDEX_7 ++#define index_cpu_BMI2 COMMON_CPUID_INDEX_7 ++#define index_cpu_ERMS COMMON_CPUID_INDEX_7 ++#define index_cpu_INVPCID COMMON_CPUID_INDEX_7 ++#define index_cpu_RTM COMMON_CPUID_INDEX_7 ++#define index_cpu_PQM COMMON_CPUID_INDEX_7 ++#define index_cpu_MPX COMMON_CPUID_INDEX_7 ++#define index_cpu_PQE COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512F COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512DQ COMMON_CPUID_INDEX_7 ++#define index_cpu_RDSEED COMMON_CPUID_INDEX_7 ++#define index_cpu_ADX COMMON_CPUID_INDEX_7 ++#define index_cpu_SMAP COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512_IFMA COMMON_CPUID_INDEX_7 ++#define index_cpu_CLFLUSHOPT COMMON_CPUID_INDEX_7 ++#define index_cpu_CLWB COMMON_CPUID_INDEX_7 ++#define index_cpu_TRACE COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512PF COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512ER COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512CD COMMON_CPUID_INDEX_7 ++#define index_cpu_SHA COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512BW COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512VL COMMON_CPUID_INDEX_7 ++ ++/* ECX. */ ++#define index_cpu_PREFETCHWT1 COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512_VBMI COMMON_CPUID_INDEX_7 ++#define index_cpu_UMIP COMMON_CPUID_INDEX_7 ++#define index_cpu_PKU COMMON_CPUID_INDEX_7 ++#define index_cpu_OSPKE COMMON_CPUID_INDEX_7 ++#define index_cpu_WAITPKG COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512_VBMI2 COMMON_CPUID_INDEX_7 ++#define index_cpu_SHSTK COMMON_CPUID_INDEX_7 ++#define index_cpu_GFNI COMMON_CPUID_INDEX_7 ++#define index_cpu_VAES COMMON_CPUID_INDEX_7 ++#define index_cpu_VPCLMULQDQ COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512_VNNI COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512_BITALG COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512_VPOPCNTDQ COMMON_CPUID_INDEX_7 ++#define index_cpu_RDPID COMMON_CPUID_INDEX_7 ++#define index_cpu_CLDEMOTE COMMON_CPUID_INDEX_7 ++#define index_cpu_MOVDIRI COMMON_CPUID_INDEX_7 ++#define index_cpu_MOVDIR64B COMMON_CPUID_INDEX_7 ++#define index_cpu_SGX_LC COMMON_CPUID_INDEX_7 ++ ++/* EDX. */ ++#define index_cpu_AVX512_4VNNIW COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512_4FMAPS COMMON_CPUID_INDEX_7 ++#define index_cpu_FSRM COMMON_CPUID_INDEX_7 ++#define index_cpu_PCONFIG COMMON_CPUID_INDEX_7 ++#define index_cpu_IBT COMMON_CPUID_INDEX_7 ++#define index_cpu_IBRS_IBPB COMMON_CPUID_INDEX_7 ++#define index_cpu_STIBP COMMON_CPUID_INDEX_7 ++#define index_cpu_CAPABILITIES COMMON_CPUID_INDEX_7 ++#define index_cpu_SSBD COMMON_CPUID_INDEX_7 ++ ++/* COMMON_CPUID_INDEX_80000001. */ ++ ++/* ECX. */ ++#define index_cpu_LAHF64_SAHF64 COMMON_CPUID_INDEX_80000001 ++#define index_cpu_SVM COMMON_CPUID_INDEX_80000001 ++#define index_cpu_LZCNT COMMON_CPUID_INDEX_80000001 ++#define index_cpu_SSE4A COMMON_CPUID_INDEX_80000001 ++#define index_cpu_PREFETCHW COMMON_CPUID_INDEX_80000001 ++#define index_cpu_XOP COMMON_CPUID_INDEX_80000001 ++#define index_cpu_LWP COMMON_CPUID_INDEX_80000001 ++#define index_cpu_FMA4 COMMON_CPUID_INDEX_80000001 ++#define index_cpu_TBM COMMON_CPUID_INDEX_80000001 ++ ++/* EDX. */ ++#define index_cpu_SYSCALL_SYSRET COMMON_CPUID_INDEX_80000001 ++#define index_cpu_NX COMMON_CPUID_INDEX_80000001 ++#define index_cpu_PAGE1GB COMMON_CPUID_INDEX_80000001 ++#define index_cpu_RDTSCP COMMON_CPUID_INDEX_80000001 ++#define index_cpu_LM COMMON_CPUID_INDEX_80000001 ++ ++/* COMMON_CPUID_INDEX_D_ECX_1. */ ++ ++/* EAX. */ ++#define index_cpu_XSAVEOPT COMMON_CPUID_INDEX_D_ECX_1 ++#define index_cpu_XSAVEC COMMON_CPUID_INDEX_D_ECX_1 ++#define index_cpu_XGETBV_ECX_1 COMMON_CPUID_INDEX_D_ECX_1 ++#define index_cpu_XSAVES COMMON_CPUID_INDEX_D_ECX_1 ++ ++/* COMMON_CPUID_INDEX_80000007. */ ++ ++/* EDX. */ ++#define index_cpu_INVARIANT_TSC COMMON_CPUID_INDEX_80000007 ++ ++/* COMMON_CPUID_INDEX_80000008. */ ++ ++/* EBX. */ ++#define index_cpu_WBNOINVD COMMON_CPUID_INDEX_80000008 ++ ++/* COMMON_CPUID_INDEX_1. */ ++ ++/* ECX. */ ++#define reg_SSE3 ecx ++#define reg_PCLMULQDQ ecx ++#define reg_DTES64 ecx ++#define reg_MONITOR ecx ++#define reg_DS_CPL ecx ++#define reg_VMX ecx ++#define reg_SMX ecx ++#define reg_EST ecx ++#define reg_TM2 ecx ++#define reg_SSSE3 ecx ++#define reg_CNXT_ID ecx ++#define reg_SDBG ecx ++#define reg_FMA ecx ++#define reg_CMPXCHG16B ecx ++#define reg_XTPRUPDCTRL ecx ++#define reg_PDCM ecx ++#define reg_PCID ecx ++#define reg_DCA ecx ++#define reg_SSE4_1 ecx ++#define reg_SSE4_2 ecx ++#define reg_X2APIC ecx ++#define reg_MOVBE ecx ++#define reg_POPCNT ecx ++#define reg_TSC_DEADLINE ecx ++#define reg_AES ecx ++#define reg_XSAVE ecx ++#define reg_OSXSAVE ecx ++#define reg_AVX ecx ++#define reg_F16C ecx ++#define reg_RDRAND ecx ++ ++/* EDX. */ ++#define reg_FPU edx ++#define reg_VME edx ++#define reg_DE edx ++#define reg_PSE edx ++#define reg_TSC edx ++#define reg_MSR edx ++#define reg_PAE edx ++#define reg_MCE edx ++#define reg_CX8 edx ++#define reg_APIC edx ++#define reg_SEP edx ++#define reg_MTRR edx ++#define reg_PGE edx ++#define reg_MCA edx ++#define reg_CMOV edx ++#define reg_PAT edx ++#define reg_PSE_36 edx ++#define reg_PSN edx ++#define reg_CLFSH edx ++#define reg_DS edx ++#define reg_ACPI edx ++#define reg_MMX edx ++#define reg_FXSR edx ++#define reg_SSE edx ++#define reg_SSE2 edx ++#define reg_SS edx ++#define reg_HTT edx ++#define reg_TM edx ++#define reg_PBE edx ++ ++/* COMMON_CPUID_INDEX_7. */ ++ ++/* EBX. */ ++#define reg_FSGSBASE ebx ++#define reg_TSC_ADJUST ebx ++#define reg_SGX ebx ++#define reg_BMI1 ebx ++#define reg_HLE ebx ++#define reg_BMI2 ebx ++#define reg_AVX2 ebx ++#define reg_SMEP ebx ++#define reg_ERMS ebx ++#define reg_INVPCID ebx ++#define reg_RTM ebx ++#define reg_PQM ebx ++#define reg_MPX ebx ++#define reg_PQE ebx ++#define reg_AVX512F ebx ++#define reg_AVX512DQ ebx ++#define reg_RDSEED ebx ++#define reg_ADX ebx ++#define reg_SMAP ebx ++#define reg_AVX512_IFMA ebx ++#define reg_CLFLUSHOPT ebx ++#define reg_CLWB ebx ++#define reg_TRACE ebx ++#define reg_AVX512PF ebx ++#define reg_AVX512ER ebx ++#define reg_AVX512CD ebx ++#define reg_SHA ebx ++#define reg_AVX512BW ebx ++#define reg_AVX512VL ebx ++ ++/* ECX. */ ++#define reg_PREFETCHWT1 ecx ++#define reg_AVX512_VBMI ecx ++#define reg_UMIP ecx ++#define reg_PKU ecx ++#define reg_OSPKE ecx ++#define reg_WAITPKG ecx ++#define reg_AVX512_VBMI2 ecx ++#define reg_SHSTK ecx ++#define reg_GFNI ecx ++#define reg_VAES ecx ++#define reg_VPCLMULQDQ ecx ++#define reg_AVX512_VNNI ecx ++#define reg_AVX512_BITALG ecx ++#define reg_AVX512_VPOPCNTDQ ecx ++#define reg_RDPID ecx ++#define reg_CLDEMOTE ecx ++#define reg_MOVDIRI ecx ++#define reg_MOVDIR64B ecx ++#define reg_SGX_LC ecx ++ ++/* EDX. */ ++#define reg_AVX512_4VNNIW edx ++#define reg_AVX512_4FMAPS edx ++#define reg_FSRM edx ++#define reg_PCONFIG edx ++#define reg_IBT edx ++#define reg_IBRS_IBPB edx ++#define reg_STIBP edx ++#define reg_CAPABILITIES edx ++#define reg_SSBD edx ++ ++/* COMMON_CPUID_INDEX_80000001. */ ++ ++/* ECX. */ ++#define reg_LAHF64_SAHF64 ecx ++#define reg_SVM ecx ++#define reg_LZCNT ecx ++#define reg_SSE4A ecx ++#define reg_PREFETCHW ecx ++#define reg_XOP ecx ++#define reg_LWP ecx ++#define reg_FMA4 ecx ++#define reg_TBM ecx ++ ++/* EDX. */ ++#define reg_SYSCALL_SYSRET edx ++#define reg_NX edx ++#define reg_PAGE1GB edx ++#define reg_RDTSCP edx ++#define reg_LM edx ++ ++/* COMMON_CPUID_INDEX_D_ECX_1. */ ++ ++/* EAX. */ ++#define reg_XSAVEOPT eax ++#define reg_XSAVEC eax ++#define reg_XGETBV_ECX_1 eax ++#define reg_XSAVES eax ++ ++/* COMMON_CPUID_INDEX_80000007. */ ++ ++/* EDX. */ ++#define reg_INVARIANT_TSC edx ++ ++/* COMMON_CPUID_INDEX_80000008. */ ++ ++/* EBX. */ ++#define reg_WBNOINVD ebx ++ ++/* FEATURE_INDEX_2. */ ++#define bit_arch_I586 (1u << 0) ++#define bit_arch_I686 (1u << 1) ++#define bit_arch_Fast_Rep_String (1u << 2) ++#define bit_arch_Fast_Copy_Backward (1u << 3) ++#define bit_arch_Fast_Unaligned_Load (1u << 4) ++#define bit_arch_Fast_Unaligned_Copy (1u << 5) ++#define bit_arch_Slow_BSF (1u << 6) ++#define bit_arch_Slow_SSE4_2 (1u << 7) ++#define bit_arch_AVX_Fast_Unaligned_Load (1u << 8) ++#define bit_arch_Prefer_MAP_32BIT_EXEC (1u << 9) ++#define bit_arch_Prefer_PMINUB_for_stringop (1u << 10) ++#define bit_arch_Prefer_No_VZEROUPPER (1u << 11) ++#define bit_arch_Prefer_ERMS (1u << 12) ++#define bit_arch_Prefer_FSRM (1u << 13) ++#define bit_arch_Prefer_No_AVX512 (1u << 14) ++#define bit_arch_MathVec_Prefer_No_AVX512 (1u << 15) ++ ++#define index_arch_Fast_Rep_String FEATURE_INDEX_2 ++#define index_arch_Fast_Copy_Backward FEATURE_INDEX_2 ++#define index_arch_Slow_BSF FEATURE_INDEX_2 ++#define index_arch_Fast_Unaligned_Load FEATURE_INDEX_2 ++#define index_arch_Prefer_PMINUB_for_stringop FEATURE_INDEX_2 ++#define index_arch_Fast_Unaligned_Copy FEATURE_INDEX_2 ++#define index_arch_I586 FEATURE_INDEX_2 ++#define index_arch_I686 FEATURE_INDEX_2 ++#define index_arch_Slow_SSE4_2 FEATURE_INDEX_2 ++#define index_arch_AVX_Fast_Unaligned_Load FEATURE_INDEX_2 ++#define index_arch_Prefer_MAP_32BIT_EXEC FEATURE_INDEX_2 ++#define index_arch_Prefer_No_VZEROUPPER FEATURE_INDEX_2 ++#define index_arch_Prefer_ERMS FEATURE_INDEX_2 ++#define index_arch_Prefer_No_AVX512 FEATURE_INDEX_2 ++#define index_arch_MathVec_Prefer_No_AVX512 FEATURE_INDEX_2 ++#define index_arch_Prefer_FSRM FEATURE_INDEX_2 ++ ++/* XCR0 Feature flags. */ ++#define bit_XMM_state (1u << 1) ++#define bit_YMM_state (1u << 2) ++#define bit_Opmask_state (1u << 5) ++#define bit_ZMM0_15_state (1u << 6) ++#define bit_ZMM16_31_state (1u << 7) ++ ++# if defined (_LIBC) && !IS_IN (nonlib) ++/* Unused for x86. */ ++# define INIT_ARCH() ++# define __get_cpu_features() (&GLRO(dl_x86_cpu_features)) ++# define x86_get_cpuid_registers(i) \ ++ (&(GLRO(dl_x86_cpu_features).cpuid[i])) ++# endif + + #ifdef __x86_64__ + # define HAS_CPUID 1 +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index b2fac197dac7708e..64a7fd6157242bdd 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -17,15 +17,271 @@ + . */ + + #include ++#include + #include ++#include ++ ++#define CHECK_CPU_FEATURE(name) \ ++ { \ ++ if (HAS_CPU_FEATURE (name)) \ ++ printf (" " #name "\n"); \ ++ } ++ ++#define CHECK_CPU_FEATURE_USABLE(name) \ ++ { \ ++ if (CPU_FEATURE_USABLE(name)) \ ++ printf (" " #name "\n"); \ ++ } ++ ++static const char * const cpu_kinds[] = ++{ ++ "Unknown", ++ "Intel", ++ "AMD", ++ "Other", ++}; + + static int + do_test (void) + { +- if (__get_cpu_features ()->kind == arch_kind_unknown) +- abort (); ++ const struct cpu_features *cpu_features = __get_cpu_features (); ++ ++ switch (cpu_features->basic.kind) ++ { ++ case arch_kind_intel: ++ case arch_kind_amd: ++ case arch_kind_other: ++ printf ("Vendor: %s\n", cpu_kinds[cpu_features->basic.kind]); ++ printf ("Family: 0x%x\n", cpu_features->basic.family); ++ printf ("Model: 0x%x\n", cpu_features->basic.model); ++ printf ("Stepping: 0x%x\n", cpu_features->basic.stepping); ++ break; ++ ++ default: ++ abort (); ++ } ++ ++#ifdef __SSE2__ ++ TEST_VERIFY_EXIT (HAS_CPU_FEATURE (SSE2)); ++#endif ++ ++ printf ("CPU features:\n"); ++ CHECK_CPU_FEATURE (SSE3); ++ CHECK_CPU_FEATURE (PCLMULQDQ); ++ CHECK_CPU_FEATURE (DTES64); ++ CHECK_CPU_FEATURE (MONITOR); ++ CHECK_CPU_FEATURE (DS_CPL); ++ CHECK_CPU_FEATURE (VMX); ++ CHECK_CPU_FEATURE (SMX); ++ CHECK_CPU_FEATURE (EST); ++ CHECK_CPU_FEATURE (TM2); ++ CHECK_CPU_FEATURE (SSSE3); ++ CHECK_CPU_FEATURE (CNXT_ID); ++ CHECK_CPU_FEATURE (SDBG); ++ CHECK_CPU_FEATURE (FMA); ++ CHECK_CPU_FEATURE (CMPXCHG16B); ++ CHECK_CPU_FEATURE (XTPRUPDCTRL); ++ CHECK_CPU_FEATURE (PDCM); ++ CHECK_CPU_FEATURE (PCID); ++ CHECK_CPU_FEATURE (DCA); ++ CHECK_CPU_FEATURE (SSE4_1); ++ CHECK_CPU_FEATURE (SSE4_2); ++ CHECK_CPU_FEATURE (X2APIC); ++ CHECK_CPU_FEATURE (MOVBE); ++ CHECK_CPU_FEATURE (POPCNT); ++ CHECK_CPU_FEATURE (TSC_DEADLINE); ++ CHECK_CPU_FEATURE (AES); ++ CHECK_CPU_FEATURE (XSAVE); ++ CHECK_CPU_FEATURE (OSXSAVE); ++ CHECK_CPU_FEATURE (AVX); ++ CHECK_CPU_FEATURE (F16C); ++ CHECK_CPU_FEATURE (RDRAND); ++ CHECK_CPU_FEATURE (FPU); ++ CHECK_CPU_FEATURE (VME); ++ CHECK_CPU_FEATURE (DE); ++ CHECK_CPU_FEATURE (PSE); ++ CHECK_CPU_FEATURE (TSC); ++ CHECK_CPU_FEATURE (MSR); ++ CHECK_CPU_FEATURE (PAE); ++ CHECK_CPU_FEATURE (MCE); ++ CHECK_CPU_FEATURE (CX8); ++ CHECK_CPU_FEATURE (APIC); ++ CHECK_CPU_FEATURE (SEP); ++ CHECK_CPU_FEATURE (MTRR); ++ CHECK_CPU_FEATURE (PGE); ++ CHECK_CPU_FEATURE (MCA); ++ CHECK_CPU_FEATURE (CMOV); ++ CHECK_CPU_FEATURE (PAT); ++ CHECK_CPU_FEATURE (PSE_36); ++ CHECK_CPU_FEATURE (PSN); ++ CHECK_CPU_FEATURE (CLFSH); ++ CHECK_CPU_FEATURE (DS); ++ CHECK_CPU_FEATURE (ACPI); ++ CHECK_CPU_FEATURE (MMX); ++ CHECK_CPU_FEATURE (FXSR); ++ CHECK_CPU_FEATURE (SSE); ++ CHECK_CPU_FEATURE (SSE2); ++ CHECK_CPU_FEATURE (SS); ++ CHECK_CPU_FEATURE (HTT); ++ CHECK_CPU_FEATURE (TM); ++ CHECK_CPU_FEATURE (PBE); ++ CHECK_CPU_FEATURE (FSGSBASE); ++ CHECK_CPU_FEATURE (TSC_ADJUST); ++ CHECK_CPU_FEATURE (SGX); ++ CHECK_CPU_FEATURE (BMI1); ++ CHECK_CPU_FEATURE (HLE); ++ CHECK_CPU_FEATURE (AVX2); ++ CHECK_CPU_FEATURE (SMEP); ++ CHECK_CPU_FEATURE (BMI2); ++ CHECK_CPU_FEATURE (ERMS); ++ CHECK_CPU_FEATURE (INVPCID); ++ CHECK_CPU_FEATURE (RTM); ++ CHECK_CPU_FEATURE (PQM); ++ CHECK_CPU_FEATURE (MPX); ++ CHECK_CPU_FEATURE (PQE); ++ CHECK_CPU_FEATURE (AVX512F); ++ CHECK_CPU_FEATURE (AVX512DQ); ++ CHECK_CPU_FEATURE (RDSEED); ++ CHECK_CPU_FEATURE (ADX); ++ CHECK_CPU_FEATURE (SMAP); ++ CHECK_CPU_FEATURE (AVX512_IFMA); ++ CHECK_CPU_FEATURE (CLFLUSHOPT); ++ CHECK_CPU_FEATURE (CLWB); ++ CHECK_CPU_FEATURE (TRACE); ++ CHECK_CPU_FEATURE (AVX512PF); ++ CHECK_CPU_FEATURE (AVX512ER); ++ CHECK_CPU_FEATURE (AVX512CD); ++ CHECK_CPU_FEATURE (SHA); ++ CHECK_CPU_FEATURE (AVX512BW); ++ CHECK_CPU_FEATURE (AVX512VL); ++ CHECK_CPU_FEATURE (PREFETCHWT1); ++ CHECK_CPU_FEATURE (AVX512_VBMI); ++ CHECK_CPU_FEATURE (UMIP); ++ CHECK_CPU_FEATURE (PKU); ++ CHECK_CPU_FEATURE (OSPKE); ++ CHECK_CPU_FEATURE (WAITPKG); ++ CHECK_CPU_FEATURE (AVX512_VBMI2); ++ CHECK_CPU_FEATURE (SHSTK); ++ CHECK_CPU_FEATURE (GFNI); ++ CHECK_CPU_FEATURE (VAES); ++ CHECK_CPU_FEATURE (VPCLMULQDQ); ++ CHECK_CPU_FEATURE (AVX512_VNNI); ++ CHECK_CPU_FEATURE (AVX512_BITALG); ++ CHECK_CPU_FEATURE (AVX512_VPOPCNTDQ); ++ CHECK_CPU_FEATURE (RDPID); ++ CHECK_CPU_FEATURE (CLDEMOTE); ++ CHECK_CPU_FEATURE (MOVDIRI); ++ CHECK_CPU_FEATURE (MOVDIR64B); ++ CHECK_CPU_FEATURE (SGX_LC); ++ CHECK_CPU_FEATURE (AVX512_4VNNIW); ++ CHECK_CPU_FEATURE (AVX512_4FMAPS); ++ CHECK_CPU_FEATURE (FSRM); ++ CHECK_CPU_FEATURE (PCONFIG); ++ CHECK_CPU_FEATURE (IBT); ++ CHECK_CPU_FEATURE (IBRS_IBPB); ++ CHECK_CPU_FEATURE (STIBP); ++ CHECK_CPU_FEATURE (CAPABILITIES); ++ CHECK_CPU_FEATURE (SSBD); ++ CHECK_CPU_FEATURE (LAHF64_SAHF64); ++ CHECK_CPU_FEATURE (SVM); ++ CHECK_CPU_FEATURE (LZCNT); ++ CHECK_CPU_FEATURE (SSE4A); ++ CHECK_CPU_FEATURE (PREFETCHW); ++ CHECK_CPU_FEATURE (XOP); ++ CHECK_CPU_FEATURE (LWP); ++ CHECK_CPU_FEATURE (FMA4); ++ CHECK_CPU_FEATURE (TBM); ++ CHECK_CPU_FEATURE (SYSCALL_SYSRET); ++ CHECK_CPU_FEATURE (NX); ++ CHECK_CPU_FEATURE (PAGE1GB); ++ CHECK_CPU_FEATURE (RDTSCP); ++ CHECK_CPU_FEATURE (LM); ++ CHECK_CPU_FEATURE (XSAVEOPT); ++ CHECK_CPU_FEATURE (XSAVEC); ++ CHECK_CPU_FEATURE (XGETBV_ECX_1); ++ CHECK_CPU_FEATURE (XSAVES); ++ CHECK_CPU_FEATURE (INVARIANT_TSC); ++ CHECK_CPU_FEATURE (WBNOINVD); ++ ++ printf ("Usable CPU features:\n"); ++ CHECK_CPU_FEATURE_USABLE (SSE3); ++ CHECK_CPU_FEATURE_USABLE (PCLMULQDQ); ++ CHECK_CPU_FEATURE_USABLE (SSSE3); ++ CHECK_CPU_FEATURE_USABLE (FMA); ++ CHECK_CPU_FEATURE_USABLE (CMPXCHG16B); ++ CHECK_CPU_FEATURE_USABLE (SSE4_1); ++ CHECK_CPU_FEATURE_USABLE (SSE4_2); ++ CHECK_CPU_FEATURE_USABLE (MOVBE); ++ CHECK_CPU_FEATURE_USABLE (POPCNT); ++ CHECK_CPU_FEATURE_USABLE (AES); ++ CHECK_CPU_FEATURE_USABLE (XSAVE); ++ CHECK_CPU_FEATURE_USABLE (OSXSAVE); ++ CHECK_CPU_FEATURE_USABLE (AVX); ++ CHECK_CPU_FEATURE_USABLE (F16C); ++ CHECK_CPU_FEATURE_USABLE (RDRAND); ++ CHECK_CPU_FEATURE_USABLE (FPU); ++ CHECK_CPU_FEATURE_USABLE (TSC); ++ CHECK_CPU_FEATURE_USABLE (MSR); ++ CHECK_CPU_FEATURE_USABLE (CX8); ++ CHECK_CPU_FEATURE_USABLE (SEP); ++ CHECK_CPU_FEATURE_USABLE (CMOV); ++ CHECK_CPU_FEATURE_USABLE (CLFSH); ++ CHECK_CPU_FEATURE_USABLE (MMX); ++ CHECK_CPU_FEATURE_USABLE (FXSR); ++ CHECK_CPU_FEATURE_USABLE (SSE); ++ CHECK_CPU_FEATURE_USABLE (SSE2); ++ CHECK_CPU_FEATURE_USABLE (FSGSBASE); ++ CHECK_CPU_FEATURE_USABLE (BMI1); ++ CHECK_CPU_FEATURE_USABLE (HLE); ++ CHECK_CPU_FEATURE_USABLE (AVX2); ++ CHECK_CPU_FEATURE_USABLE (BMI2); ++ CHECK_CPU_FEATURE_USABLE (ERMS); ++ CHECK_CPU_FEATURE_USABLE (AVX512F); ++ CHECK_CPU_FEATURE_USABLE (AVX512DQ); ++ CHECK_CPU_FEATURE_USABLE (RDSEED); ++ CHECK_CPU_FEATURE_USABLE (ADX); ++ CHECK_CPU_FEATURE_USABLE (AVX512_IFMA); ++ CHECK_CPU_FEATURE_USABLE (CLFLUSHOPT); ++ CHECK_CPU_FEATURE_USABLE (CLWB); ++ CHECK_CPU_FEATURE_USABLE (AVX512PF); ++ CHECK_CPU_FEATURE_USABLE (AVX512ER); ++ CHECK_CPU_FEATURE_USABLE (AVX512CD); ++ CHECK_CPU_FEATURE_USABLE (SHA); ++ CHECK_CPU_FEATURE_USABLE (AVX512BW); ++ CHECK_CPU_FEATURE_USABLE (AVX512VL); ++ CHECK_CPU_FEATURE_USABLE (PREFETCHWT1); ++ CHECK_CPU_FEATURE_USABLE (AVX512_VBMI); ++ CHECK_CPU_FEATURE_USABLE (AVX512_VBMI2); ++ CHECK_CPU_FEATURE_USABLE (GFNI); ++ CHECK_CPU_FEATURE_USABLE (VAES); ++ CHECK_CPU_FEATURE_USABLE (VPCLMULQDQ); ++ CHECK_CPU_FEATURE_USABLE (AVX512_VNNI); ++ CHECK_CPU_FEATURE_USABLE (AVX512_BITALG); ++ CHECK_CPU_FEATURE_USABLE (AVX512_VPOPCNTDQ); ++ CHECK_CPU_FEATURE_USABLE (RDPID); ++ CHECK_CPU_FEATURE_USABLE (CLDEMOTE); ++ CHECK_CPU_FEATURE_USABLE (MOVDIRI); ++ CHECK_CPU_FEATURE_USABLE (MOVDIR64B); ++ CHECK_CPU_FEATURE_USABLE (AVX512_4VNNIW); ++ CHECK_CPU_FEATURE_USABLE (AVX512_4FMAPS); ++ CHECK_CPU_FEATURE_USABLE (FSRM); ++ CHECK_CPU_FEATURE_USABLE (LAHF64_SAHF64); ++ CHECK_CPU_FEATURE_USABLE (LZCNT); ++ CHECK_CPU_FEATURE_USABLE (SSE4A); ++ CHECK_CPU_FEATURE_USABLE (PREFETCHW); ++ CHECK_CPU_FEATURE_USABLE (XOP); ++ CHECK_CPU_FEATURE_USABLE (FMA4); ++ CHECK_CPU_FEATURE_USABLE (TBM); ++ CHECK_CPU_FEATURE_USABLE (SYSCALL_SYSRET); ++ CHECK_CPU_FEATURE_USABLE (RDTSCP); ++ CHECK_CPU_FEATURE_USABLE (XSAVEOPT); ++ CHECK_CPU_FEATURE_USABLE (XSAVEC); ++ CHECK_CPU_FEATURE_USABLE (XGETBV_ECX_1); ++ CHECK_CPU_FEATURE_USABLE (XSAVES); ++ CHECK_CPU_FEATURE_USABLE (INVARIANT_TSC); ++ CHECK_CPU_FEATURE_USABLE (WBNOINVD); ++ + return 0; + } + +-#define TEST_FUNCTION do_test () +-#include "../../test-skeleton.c" ++#include +diff --git a/sysdeps/x86_64/multiarch/sched_cpucount.c b/sysdeps/x86_64/multiarch/sched_cpucount.c +index d10d74ae21e05d47..7949119dcdb5a94b 100644 +--- a/sysdeps/x86_64/multiarch/sched_cpucount.c ++++ b/sysdeps/x86_64/multiarch/sched_cpucount.c +@@ -33,4 +33,4 @@ + #undef __sched_cpucount + + libc_ifunc (__sched_cpucount, +- HAS_CPU_FEATURE (POPCOUNT) ? popcount_cpucount : generic_cpucount); ++ HAS_CPU_FEATURE (POPCNT) ? popcount_cpucount : generic_cpucount); +diff --git a/sysdeps/x86_64/multiarch/test-multiarch.c b/sysdeps/x86_64/multiarch/test-multiarch.c +index aa872f27dbe7ea2f..417147c3d5f325a5 100644 +--- a/sysdeps/x86_64/multiarch/test-multiarch.c ++++ b/sysdeps/x86_64/multiarch/test-multiarch.c +@@ -85,8 +85,8 @@ do_test (int argc, char **argv) + , "HAS_CPU_FEATURE (SSE4_1)"); + fails += check_proc ("ssse3", HAS_CPU_FEATURE (SSSE3), + "HAS_CPU_FEATURE (SSSE3)"); +- fails += check_proc ("popcnt", HAS_CPU_FEATURE (POPCOUNT), +- "HAS_CPU_FEATURE (POPCOUNT)"); ++ fails += check_proc ("popcnt", HAS_CPU_FEATURE (POPCNT), ++ "HAS_CPU_FEATURE (POPCNT)"); + + printf ("%d differences between /proc/cpuinfo and glibc code.\n", fails); + diff --git a/SOURCES/glibc-rh1817513-16.patch b/SOURCES/glibc-rh1817513-16.patch new file mode 100644 index 0000000..2698a30 --- /dev/null +++ b/SOURCES/glibc-rh1817513-16.patch @@ -0,0 +1,146 @@ +commit b2e93de0ffedcfe2cfba100d47a4d4f6f85cea0b +Author: DJ Delorie +Date: Tue Dec 4 00:03:12 2018 -0500 + + test-container: add "su" command to run test as root, add unshare hints + + * support/test-container.c (check_for_unshare_hints): New. + (main): Call it if unshare fails. Add support for "su" scriptlet + command. + +diff --git a/support/test-container.c b/support/test-container.c +index fe0ebbd07df83da7..1d1aebeaf3412573 100644 +--- a/support/test-container.c ++++ b/support/test-container.c +@@ -88,15 +88,22 @@ int verbose = 0; + * mytest.root/ is rsync'd into container + * mytest.root/preclean.req causes fresh rsync (with delete) before + test if present +- * mytest.root/mytset.script has a list of "commands" to run: ++ * mytest.root/mytest.script has a list of "commands" to run: + syntax: + # comment ++ su + mv FILE FILE + cp FILE FILE + rm FILE + FILE must start with $B/, $S/, $I/, $L/, or / + (expands to build dir, source dir, install dir, library dir + (in container), or container's root) ++ details: ++ - '#': A comment. ++ - 'su': Enables running test as root in the container. ++ - 'mv': A minimal move files command. ++ - 'cp': A minimal copy files command. ++ - 'rm': A minimal remove files command. + * mytest.root/postclean.req causes fresh rsync (with delete) after + test if present + +@@ -349,6 +356,7 @@ recursive_remove (char *path) + + switch (child) { + case -1: ++ perror("fork"); + FAIL_EXIT1 ("Unable to fork"); + case 0: + /* Child. */ +@@ -610,6 +618,47 @@ rsync (char *src, char *dest, int and_delete) + } + + ++ ++/* See if we can detect what the user needs to do to get unshare ++ support working for us. */ ++void ++check_for_unshare_hints (void) ++{ ++ FILE *f; ++ int i; ++ ++ /* Default Debian Linux disables user namespaces, but allows a way ++ to enable them. */ ++ f = fopen ("/proc/sys/kernel/unprivileged_userns_clone", "r"); ++ if (f != NULL) ++ { ++ i = 99; /* Sentinel. */ ++ fscanf (f, "%d", &i); ++ if (i == 0) ++ { ++ printf ("To enable test-container, please run this as root:\n"); ++ printf (" echo 1 > /proc/sys/kernel/unprivileged_userns_clone\n"); ++ } ++ fclose (f); ++ return; ++ } ++ ++ /* ALT Linux has an alternate way of doing the same. */ ++ f = fopen ("/proc/sys/kernel/userns_restrict", "r"); ++ if (f != NULL) ++ { ++ i = 99; /* Sentinel. */ ++ fscanf (f, "%d", &i); ++ if (i == 1) ++ { ++ printf ("To enable test-container, please run this as root:\n"); ++ printf (" echo 0 > /proc/sys/kernel/userns_restrict\n"); ++ } ++ fclose (f); ++ return; ++ } ++} ++ + int + main (int argc, char **argv) + { +@@ -628,6 +677,8 @@ main (int argc, char **argv) + + uid_t original_uid; + gid_t original_gid; ++ /* If set, the test runs as root instead of the user running the testsuite. */ ++ int be_su = 0; + int UMAP; + int GMAP; + /* Used for "%lld %lld 1" so need not be large. */ +@@ -857,6 +908,10 @@ main (int argc, char **argv) + { + maybe_xunlink (the_words[1]); + } ++ else if (nt == 1 && strcmp (the_words[0], "su") == 0) ++ { ++ be_su = 1; ++ } + else if (nt > 0 && the_words[0][0] != '#') + { + printf ("\033[31minvalid [%s]\033[0m\n", the_words[0]); +@@ -910,7 +965,12 @@ main (int argc, char **argv) + /* Older kernels may not support all the options, or security + policy may block this call. */ + if (errno == EINVAL || errno == EPERM) +- FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (errno)); ++ { ++ int saved_errno = errno; ++ if (errno == EPERM) ++ check_for_unshare_hints (); ++ FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (saved_errno)); ++ } + else + FAIL_EXIT1 ("unable to unshare user/fs: %s", strerror (errno)); + } +@@ -981,7 +1041,7 @@ main (int argc, char **argv) + FAIL_EXIT1 ("can't write to /proc/self/uid_map\n"); + + sprintf (tmp, "%lld %lld 1\n", +- (long long) original_uid, (long long) original_uid); ++ (long long) (be_su ? 0 : original_uid), (long long) original_uid); + write (UMAP, tmp, strlen (tmp)); + xclose (UMAP); + +@@ -1002,7 +1062,7 @@ main (int argc, char **argv) + FAIL_EXIT1 ("can't write to /proc/self/gid_map\n"); + + sprintf (tmp, "%lld %lld 1\n", +- (long long) original_gid, (long long) original_gid); ++ (long long) (be_su ? 0 : original_gid), (long long) original_gid); + write (GMAP, tmp, strlen (tmp)); + xclose (GMAP); + diff --git a/SOURCES/glibc-rh1817513-17.patch b/SOURCES/glibc-rh1817513-17.patch new file mode 100644 index 0000000..faeb2bd --- /dev/null +++ b/SOURCES/glibc-rh1817513-17.patch @@ -0,0 +1,1559 @@ +commit 1a153e47fcc9401d8ea424ad86569a57ed0f8c52 +Author: Leonardo Sandoval +Date: Mon Oct 8 08:59:50 2018 -0500 + + x86-64: Optimize strcat/strncat, strcpy/strncpy and stpcpy/stpncpy with AVX2 + + Optimize x86-64 strcat/strncat, strcpy/strncpy and stpcpy/stpncpy with AVX2. + It uses vector comparison as much as possible. In general, the larger the + source string, the greater performance gain observed, reaching speedups of + 1.6x compared to SSE2 unaligned routines. Select AVX2 strcat/strncat, + strcpy/strncpy and stpcpy/stpncpy on AVX2 machines where vzeroupper is + preferred and AVX unaligned load is fast. + + * sysdeps/x86_64/multiarch/Makefile (sysdep_routines): Add + strcat-avx2, strncat-avx2, strcpy-avx2, strncpy-avx2, + stpcpy-avx2 and stpncpy-avx2. + * sysdeps/x86_64/multiarch/ifunc-impl-list.c: + (__libc_ifunc_impl_list): Add tests for __strcat_avx2, + __strncat_avx2, __strcpy_avx2, __strncpy_avx2, __stpcpy_avx2 + and __stpncpy_avx2. + * sysdeps/x86_64/multiarch/{ifunc-unaligned-ssse3.h => + ifunc-strcpy.h}: rename header for a more generic name. + * sysdeps/x86_64/multiarch/ifunc-strcpy.h: + (IFUNC_SELECTOR): Return OPTIMIZE (avx2) on AVX 2 machines if + AVX unaligned load is fast and vzeroupper is preferred. + * sysdeps/x86_64/multiarch/stpcpy-avx2.S: New file + * sysdeps/x86_64/multiarch/stpncpy-avx2.S: Likewise + * sysdeps/x86_64/multiarch/strcat-avx2.S: Likewise + * sysdeps/x86_64/multiarch/strcpy-avx2.S: Likewise + * sysdeps/x86_64/multiarch/strncat-avx2.S: Likewise + * sysdeps/x86_64/multiarch/strncpy-avx2.S: Likewise + +diff --git a/sysdeps/x86_64/multiarch/Makefile b/sysdeps/x86_64/multiarch/Makefile +index bb5e97073520ee51..395e432c092ca17c 100644 +--- a/sysdeps/x86_64/multiarch/Makefile ++++ b/sysdeps/x86_64/multiarch/Makefile +@@ -24,11 +24,14 @@ sysdep_routines += strncat-c stpncpy-c strncpy-c \ + strchr-sse2 strchrnul-sse2 strchr-avx2 strchrnul-avx2 \ + strrchr-sse2 strrchr-avx2 \ + strlen-sse2 strnlen-sse2 strlen-avx2 strnlen-avx2 \ ++ strcat-avx2 strncat-avx2 \ + strcat-ssse3 strncat-ssse3\ ++ strcpy-avx2 strncpy-avx2 \ + strcpy-sse2 stpcpy-sse2 \ + strcpy-ssse3 strncpy-ssse3 stpcpy-ssse3 stpncpy-ssse3 \ + strcpy-sse2-unaligned strncpy-sse2-unaligned \ + stpcpy-sse2-unaligned stpncpy-sse2-unaligned \ ++ stpcpy-avx2 stpncpy-avx2 \ + strcat-sse2 \ + strcat-sse2-unaligned strncat-sse2-unaligned \ + strchr-sse2-no-bsf memcmp-ssse3 strstr-sse2-unaligned \ +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index 9aaaef7251b8edfe..8b55bb6954000cc2 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -199,6 +199,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, stpncpy, + IFUNC_IMPL_ADD (array, i, stpncpy, HAS_CPU_FEATURE (SSSE3), + __stpncpy_ssse3) ++ IFUNC_IMPL_ADD (array, i, stpncpy, HAS_ARCH_FEATURE (AVX2_Usable), ++ __stpncpy_avx2) + IFUNC_IMPL_ADD (array, i, stpncpy, 1, + __stpncpy_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, stpncpy, 1, __stpncpy_sse2)) +@@ -207,6 +209,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, stpcpy, + IFUNC_IMPL_ADD (array, i, stpcpy, HAS_CPU_FEATURE (SSSE3), + __stpcpy_ssse3) ++ IFUNC_IMPL_ADD (array, i, stpcpy, HAS_ARCH_FEATURE (AVX2_Usable), ++ __stpcpy_avx2) + IFUNC_IMPL_ADD (array, i, stpcpy, 1, __stpcpy_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, stpcpy, 1, __stpcpy_sse2)) + +@@ -239,6 +243,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/x86_64/multiarch/strcat.c. */ + IFUNC_IMPL (i, name, strcat, ++ IFUNC_IMPL_ADD (array, i, strcat, HAS_ARCH_FEATURE (AVX2_Usable), ++ __strcat_avx2) + IFUNC_IMPL_ADD (array, i, strcat, HAS_CPU_FEATURE (SSSE3), + __strcat_ssse3) + IFUNC_IMPL_ADD (array, i, strcat, 1, __strcat_sse2_unaligned) +@@ -280,6 +286,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/x86_64/multiarch/strcpy.c. */ + IFUNC_IMPL (i, name, strcpy, ++ IFUNC_IMPL_ADD (array, i, strcpy, HAS_ARCH_FEATURE (AVX2_Usable), ++ __strcpy_avx2) + IFUNC_IMPL_ADD (array, i, strcpy, HAS_CPU_FEATURE (SSSE3), + __strcpy_ssse3) + IFUNC_IMPL_ADD (array, i, strcpy, 1, __strcpy_sse2_unaligned) +@@ -321,6 +329,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/x86_64/multiarch/strncat.c. */ + IFUNC_IMPL (i, name, strncat, ++ IFUNC_IMPL_ADD (array, i, strncat, HAS_ARCH_FEATURE (AVX2_Usable), ++ __strncat_avx2) + IFUNC_IMPL_ADD (array, i, strncat, HAS_CPU_FEATURE (SSSE3), + __strncat_ssse3) + IFUNC_IMPL_ADD (array, i, strncat, 1, +@@ -329,6 +339,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/x86_64/multiarch/strncpy.c. */ + IFUNC_IMPL (i, name, strncpy, ++ IFUNC_IMPL_ADD (array, i, strncpy, HAS_ARCH_FEATURE (AVX2_Usable), ++ __strncpy_avx2) + IFUNC_IMPL_ADD (array, i, strncpy, HAS_CPU_FEATURE (SSSE3), + __strncpy_ssse3) + IFUNC_IMPL_ADD (array, i, strncpy, 1, +diff --git a/sysdeps/x86_64/multiarch/ifunc-unaligned-ssse3.h b/sysdeps/x86_64/multiarch/ifunc-strcpy.h +similarity index 83% +rename from sysdeps/x86_64/multiarch/ifunc-unaligned-ssse3.h +rename to sysdeps/x86_64/multiarch/ifunc-strcpy.h +index 81805f9832345923..4f2286fefccda069 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-unaligned-ssse3.h ++++ b/sysdeps/x86_64/multiarch/ifunc-strcpy.h +@@ -24,12 +24,18 @@ extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2) attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2_unaligned) + attribute_hidden; + extern __typeof (REDIRECT_NAME) OPTIMIZE (ssse3) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden; + + static inline void * + IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + ++ if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) ++ && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable) ++ && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) ++ return OPTIMIZE (avx2); ++ + if (CPU_FEATURES_ARCH_P (cpu_features, Fast_Unaligned_Load)) + return OPTIMIZE (sse2_unaligned); + +diff --git a/sysdeps/x86_64/multiarch/stpcpy-avx2.S b/sysdeps/x86_64/multiarch/stpcpy-avx2.S +new file mode 100644 +index 0000000000000000..f0bd3029fe3047ed +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/stpcpy-avx2.S +@@ -0,0 +1,3 @@ ++#define USE_AS_STPCPY ++#define STRCPY __stpcpy_avx2 ++#include "strcpy-avx2.S" +diff --git a/sysdeps/x86_64/multiarch/stpcpy.c b/sysdeps/x86_64/multiarch/stpcpy.c +index 1e340fca991a021c..8ffd13b48c83ca8e 100644 +--- a/sysdeps/x86_64/multiarch/stpcpy.c ++++ b/sysdeps/x86_64/multiarch/stpcpy.c +@@ -28,7 +28,7 @@ + # undef __stpcpy + + # define SYMBOL_NAME stpcpy +-# include "ifunc-unaligned-ssse3.h" ++# include "ifunc-strcpy.h" + + libc_ifunc_redirected (__redirect_stpcpy, __stpcpy, IFUNC_SELECTOR ()); + +diff --git a/sysdeps/x86_64/multiarch/stpncpy-avx2.S b/sysdeps/x86_64/multiarch/stpncpy-avx2.S +new file mode 100644 +index 0000000000000000..032b0407d08c6a9d +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/stpncpy-avx2.S +@@ -0,0 +1,4 @@ ++#define USE_AS_STPCPY ++#define USE_AS_STRNCPY ++#define STRCPY __stpncpy_avx2 ++#include "strcpy-avx2.S" +diff --git a/sysdeps/x86_64/multiarch/stpncpy.c b/sysdeps/x86_64/multiarch/stpncpy.c +index 28842ece2b0998e3..f3e203f78cca2e61 100644 +--- a/sysdeps/x86_64/multiarch/stpncpy.c ++++ b/sysdeps/x86_64/multiarch/stpncpy.c +@@ -26,7 +26,7 @@ + # undef __stpncpy + + # define SYMBOL_NAME stpncpy +-# include "ifunc-unaligned-ssse3.h" ++# include "ifunc-strcpy.h" + + libc_ifunc_redirected (__redirect_stpncpy, __stpncpy, IFUNC_SELECTOR ()); + +diff --git a/sysdeps/x86_64/multiarch/strcat-avx2.S b/sysdeps/x86_64/multiarch/strcat-avx2.S +new file mode 100644 +index 0000000000000000..b062356427677ca6 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strcat-avx2.S +@@ -0,0 +1,275 @@ ++/* strcat with AVX2 ++ Copyright (C) 2011-2018 Free Software Foundation, Inc. ++ Contributed by Intel Corporation. ++ 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 ++ . */ ++ ++#if IS_IN (libc) ++ ++# include ++ ++# ifndef STRCAT ++# define STRCAT __strcat_avx2 ++# endif ++ ++# define USE_AS_STRCAT ++ ++/* Number of bytes in a vector register */ ++# define VEC_SIZE 32 ++ ++ .section .text.avx,"ax",@progbits ++ENTRY (STRCAT) ++ mov %rdi, %r9 ++# ifdef USE_AS_STRNCAT ++ mov %rdx, %r8 ++# endif ++ ++ xor %eax, %eax ++ mov %edi, %ecx ++ and $((VEC_SIZE * 4) - 1), %ecx ++ vpxor %xmm6, %xmm6, %xmm6 ++ cmp $(VEC_SIZE * 3), %ecx ++ ja L(fourth_vector_boundary) ++ vpcmpeqb (%rdi), %ymm6, %ymm0 ++ vpmovmskb %ymm0, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_first_vector) ++ mov %rdi, %rax ++ and $-VEC_SIZE, %rax ++ jmp L(align_vec_size_start) ++L(fourth_vector_boundary): ++ mov %rdi, %rax ++ and $-VEC_SIZE, %rax ++ vpcmpeqb (%rax), %ymm6, %ymm0 ++ mov $-1, %r10d ++ sub %rax, %rcx ++ shl %cl, %r10d ++ vpmovmskb %ymm0, %edx ++ and %r10d, %edx ++ jnz L(exit) ++ ++L(align_vec_size_start): ++ vpcmpeqb VEC_SIZE(%rax), %ymm6, %ymm0 ++ vpmovmskb %ymm0, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_second_vector) ++ ++ vpcmpeqb (VEC_SIZE * 2)(%rax), %ymm6, %ymm1 ++ vpmovmskb %ymm1, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_third_vector) ++ ++ vpcmpeqb (VEC_SIZE * 3)(%rax), %ymm6, %ymm2 ++ vpmovmskb %ymm2, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fourth_vector) ++ ++ vpcmpeqb (VEC_SIZE * 4)(%rax), %ymm6, %ymm3 ++ vpmovmskb %ymm3, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fifth_vector) ++ ++ vpcmpeqb (VEC_SIZE * 5)(%rax), %ymm6, %ymm0 ++ add $(VEC_SIZE * 4), %rax ++ vpmovmskb %ymm0, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_second_vector) ++ ++ vpcmpeqb (VEC_SIZE * 2)(%rax), %ymm6, %ymm1 ++ vpmovmskb %ymm1, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_third_vector) ++ ++ vpcmpeqb (VEC_SIZE * 3)(%rax), %ymm6, %ymm2 ++ vpmovmskb %ymm2, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fourth_vector) ++ ++ vpcmpeqb (VEC_SIZE * 4)(%rax), %ymm6, %ymm3 ++ vpmovmskb %ymm3, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fifth_vector) ++ ++ vpcmpeqb (VEC_SIZE * 5)(%rax), %ymm6, %ymm0 ++ add $(VEC_SIZE * 4), %rax ++ vpmovmskb %ymm0, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_second_vector) ++ ++ vpcmpeqb (VEC_SIZE * 2)(%rax), %ymm6, %ymm1 ++ vpmovmskb %ymm1, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_third_vector) ++ ++ vpcmpeqb (VEC_SIZE * 3)(%rax), %ymm6, %ymm2 ++ vpmovmskb %ymm2, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fourth_vector) ++ ++ vpcmpeqb (VEC_SIZE * 4)(%rax), %ymm6, %ymm3 ++ vpmovmskb %ymm3, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fifth_vector) ++ ++ vpcmpeqb (VEC_SIZE * 5)(%rax), %ymm6, %ymm0 ++ add $(VEC_SIZE * 4), %rax ++ vpmovmskb %ymm0, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_second_vector) ++ ++ vpcmpeqb (VEC_SIZE * 2)(%rax), %ymm6, %ymm1 ++ vpmovmskb %ymm1, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_third_vector) ++ ++ vpcmpeqb (VEC_SIZE * 3)(%rax), %ymm6, %ymm2 ++ vpmovmskb %ymm2, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fourth_vector) ++ ++ vpcmpeqb (VEC_SIZE * 4)(%rax), %ymm6, %ymm3 ++ vpmovmskb %ymm3, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fifth_vector) ++ ++ test $((VEC_SIZE * 4) - 1), %rax ++ jz L(align_four_vec_loop) ++ ++ vpcmpeqb (VEC_SIZE * 5)(%rax), %ymm6, %ymm0 ++ add $(VEC_SIZE * 5), %rax ++ vpmovmskb %ymm0, %edx ++ test %edx, %edx ++ jnz L(exit) ++ ++ test $((VEC_SIZE * 4) - 1), %rax ++ jz L(align_four_vec_loop) ++ ++ vpcmpeqb VEC_SIZE(%rax), %ymm6, %ymm1 ++ add $VEC_SIZE, %rax ++ vpmovmskb %ymm1, %edx ++ test %edx, %edx ++ jnz L(exit) ++ ++ test $((VEC_SIZE * 4) - 1), %rax ++ jz L(align_four_vec_loop) ++ ++ vpcmpeqb VEC_SIZE(%rax), %ymm6, %ymm2 ++ add $VEC_SIZE, %rax ++ vpmovmskb %ymm2, %edx ++ test %edx, %edx ++ jnz L(exit) ++ ++ test $((VEC_SIZE * 4) - 1), %rax ++ jz L(align_four_vec_loop) ++ ++ vpcmpeqb VEC_SIZE(%rax), %ymm6, %ymm3 ++ add $VEC_SIZE, %rax ++ vpmovmskb %ymm3, %edx ++ test %edx, %edx ++ jnz L(exit) ++ ++ add $VEC_SIZE, %rax ++ ++ .p2align 4 ++L(align_four_vec_loop): ++ vmovaps (%rax), %ymm4 ++ vpminub VEC_SIZE(%rax), %ymm4, %ymm4 ++ vmovaps (VEC_SIZE * 2)(%rax), %ymm5 ++ vpminub (VEC_SIZE * 3)(%rax), %ymm5, %ymm5 ++ add $(VEC_SIZE * 4), %rax ++ vpminub %ymm4, %ymm5, %ymm5 ++ vpcmpeqb %ymm5, %ymm6, %ymm5 ++ vpmovmskb %ymm5, %edx ++ test %edx, %edx ++ jz L(align_four_vec_loop) ++ ++ vpcmpeqb -(VEC_SIZE * 4)(%rax), %ymm6, %ymm0 ++ sub $(VEC_SIZE * 5), %rax ++ vpmovmskb %ymm0, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_second_vector) ++ ++ vpcmpeqb (VEC_SIZE * 2)(%rax), %ymm6, %ymm1 ++ vpmovmskb %ymm1, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_third_vector) ++ ++ vpcmpeqb (VEC_SIZE * 3)(%rax), %ymm6, %ymm2 ++ vpmovmskb %ymm2, %edx ++ test %edx, %edx ++ jnz L(exit_null_on_fourth_vector) ++ ++ vpcmpeqb (VEC_SIZE * 4)(%rax), %ymm6, %ymm3 ++ vpmovmskb %ymm3, %edx ++ sub %rdi, %rax ++ bsf %rdx, %rdx ++ add %rdx, %rax ++ add $(VEC_SIZE * 4), %rax ++ jmp L(StartStrcpyPart) ++ ++ .p2align 4 ++L(exit): ++ sub %rdi, %rax ++L(exit_null_on_first_vector): ++ bsf %rdx, %rdx ++ add %rdx, %rax ++ jmp L(StartStrcpyPart) ++ ++ .p2align 4 ++L(exit_null_on_second_vector): ++ sub %rdi, %rax ++ bsf %rdx, %rdx ++ add %rdx, %rax ++ add $VEC_SIZE, %rax ++ jmp L(StartStrcpyPart) ++ ++ .p2align 4 ++L(exit_null_on_third_vector): ++ sub %rdi, %rax ++ bsf %rdx, %rdx ++ add %rdx, %rax ++ add $(VEC_SIZE * 2), %rax ++ jmp L(StartStrcpyPart) ++ ++ .p2align 4 ++L(exit_null_on_fourth_vector): ++ sub %rdi, %rax ++ bsf %rdx, %rdx ++ add %rdx, %rax ++ add $(VEC_SIZE * 3), %rax ++ jmp L(StartStrcpyPart) ++ ++ .p2align 4 ++L(exit_null_on_fifth_vector): ++ sub %rdi, %rax ++ bsf %rdx, %rdx ++ add %rdx, %rax ++ add $(VEC_SIZE * 4), %rax ++ ++ .p2align 4 ++L(StartStrcpyPart): ++ lea (%r9, %rax), %rdi ++ mov %rsi, %rcx ++ mov %r9, %rax /* save result */ ++ ++# ifdef USE_AS_STRNCAT ++ test %r8, %r8 ++ jz L(ExitZero) ++# define USE_AS_STRNCPY ++# endif ++ ++# include "strcpy-avx2.S" ++#endif +diff --git a/sysdeps/x86_64/multiarch/strcat.c b/sysdeps/x86_64/multiarch/strcat.c +index 1f7f6263f35ba402..694b9b2405827bd4 100644 +--- a/sysdeps/x86_64/multiarch/strcat.c ++++ b/sysdeps/x86_64/multiarch/strcat.c +@@ -24,7 +24,7 @@ + # undef strcat + + # define SYMBOL_NAME strcat +-# include "ifunc-unaligned-ssse3.h" ++# include "ifunc-strcpy.h" + + libc_ifunc_redirected (__redirect_strcat, strcat, IFUNC_SELECTOR ()); + +diff --git a/sysdeps/x86_64/multiarch/strcpy-avx2.S b/sysdeps/x86_64/multiarch/strcpy-avx2.S +new file mode 100644 +index 0000000000000000..81677f9060773a49 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strcpy-avx2.S +@@ -0,0 +1,1022 @@ ++/* strcpy with AVX2 ++ Copyright (C) 2011-2018 Free Software Foundation, Inc. ++ Contributed by Intel Corporation. ++ 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 ++ . */ ++ ++#if IS_IN (libc) ++ ++# ifndef USE_AS_STRCAT ++# include ++ ++# ifndef STRCPY ++# define STRCPY __strcpy_avx2 ++# endif ++ ++# endif ++ ++/* Number of bytes in a vector register */ ++# ifndef VEC_SIZE ++# define VEC_SIZE 32 ++# endif ++ ++# ifndef VZEROUPPER ++# define VZEROUPPER vzeroupper ++# endif ++ ++/* zero register */ ++#define xmmZ xmm0 ++#define ymmZ ymm0 ++ ++/* mask register */ ++#define ymmM ymm1 ++ ++# ifndef USE_AS_STRCAT ++ ++ .section .text.avx,"ax",@progbits ++ENTRY (STRCPY) ++# ifdef USE_AS_STRNCPY ++ mov %rdx, %r8 ++ test %r8, %r8 ++ jz L(ExitZero) ++# endif ++ mov %rsi, %rcx ++# ifndef USE_AS_STPCPY ++ mov %rdi, %rax /* save result */ ++# endif ++ ++# endif ++ ++ vpxor %xmmZ, %xmmZ, %xmmZ ++ ++ and $((VEC_SIZE * 4) - 1), %ecx ++ cmp $(VEC_SIZE * 2), %ecx ++ jbe L(SourceStringAlignmentLessTwoVecSize) ++ ++ and $-VEC_SIZE, %rsi ++ and $(VEC_SIZE - 1), %ecx ++ ++ vpcmpeqb (%rsi), %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ shr %cl, %rdx ++ ++# ifdef USE_AS_STRNCPY ++# if defined USE_AS_STPCPY || defined USE_AS_STRCAT ++ mov $VEC_SIZE, %r10 ++ sub %rcx, %r10 ++ cmp %r10, %r8 ++# else ++ mov $(VEC_SIZE + 1), %r10 ++ sub %rcx, %r10 ++ cmp %r10, %r8 ++# endif ++ jbe L(CopyVecSizeTailCase2OrCase3) ++# endif ++ test %edx, %edx ++ jnz L(CopyVecSizeTail) ++ ++ vpcmpeqb VEC_SIZE(%rsi), %ymmZ, %ymm2 ++ vpmovmskb %ymm2, %edx ++ ++# ifdef USE_AS_STRNCPY ++ add $VEC_SIZE, %r10 ++ cmp %r10, %r8 ++ jbe L(CopyTwoVecSizeCase2OrCase3) ++# endif ++ test %edx, %edx ++ jnz L(CopyTwoVecSize) ++ ++ vmovdqu (%rsi, %rcx), %ymm2 /* copy VEC_SIZE bytes */ ++ vmovdqu %ymm2, (%rdi) ++ ++/* If source address alignment != destination address alignment */ ++ .p2align 4 ++L(UnalignVecSizeBoth): ++ sub %rcx, %rdi ++# ifdef USE_AS_STRNCPY ++ add %rcx, %r8 ++ sbb %rcx, %rcx ++ or %rcx, %r8 ++# endif ++ mov $VEC_SIZE, %rcx ++ vmovdqa (%rsi, %rcx), %ymm2 ++ vmovdqu %ymm2, (%rdi, %rcx) ++ vmovdqa VEC_SIZE(%rsi, %rcx), %ymm2 ++ vpcmpeqb %ymm2, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ add $VEC_SIZE, %rcx ++# ifdef USE_AS_STRNCPY ++ sub $(VEC_SIZE * 3), %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++# endif ++ test %edx, %edx ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec2) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ vmovdqu %ymm2, (%rdi, %rcx) ++ vmovdqa VEC_SIZE(%rsi, %rcx), %ymm3 ++ vpcmpeqb %ymm3, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ add $VEC_SIZE, %rcx ++# ifdef USE_AS_STRNCPY ++ sub $VEC_SIZE, %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++# endif ++ test %edx, %edx ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec3) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ vmovdqu %ymm3, (%rdi, %rcx) ++ vmovdqa VEC_SIZE(%rsi, %rcx), %ymm4 ++ vpcmpeqb %ymm4, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ add $VEC_SIZE, %rcx ++# ifdef USE_AS_STRNCPY ++ sub $VEC_SIZE, %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++# endif ++ test %edx, %edx ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec4) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ vmovdqu %ymm4, (%rdi, %rcx) ++ vmovdqa VEC_SIZE(%rsi, %rcx), %ymm2 ++ vpcmpeqb %ymm2, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ add $VEC_SIZE, %rcx ++# ifdef USE_AS_STRNCPY ++ sub $VEC_SIZE, %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++# endif ++ test %edx, %edx ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec2) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ vmovdqu %ymm2, (%rdi, %rcx) ++ vmovdqa VEC_SIZE(%rsi, %rcx), %ymm2 ++ vpcmpeqb %ymm2, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ add $VEC_SIZE, %rcx ++# ifdef USE_AS_STRNCPY ++ sub $VEC_SIZE, %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++# endif ++ test %edx, %edx ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec2) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ vmovdqa VEC_SIZE(%rsi, %rcx), %ymm3 ++ vmovdqu %ymm2, (%rdi, %rcx) ++ vpcmpeqb %ymm3, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ add $VEC_SIZE, %rcx ++# ifdef USE_AS_STRNCPY ++ sub $VEC_SIZE, %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++# endif ++ test %edx, %edx ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec3) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ vmovdqu %ymm3, (%rdi, %rcx) ++ mov %rsi, %rdx ++ lea VEC_SIZE(%rsi, %rcx), %rsi ++ and $-(VEC_SIZE * 4), %rsi ++ sub %rsi, %rdx ++ sub %rdx, %rdi ++# ifdef USE_AS_STRNCPY ++ lea (VEC_SIZE * 8)(%r8, %rdx), %r8 ++# endif ++L(UnalignedFourVecSizeLoop): ++ vmovdqa (%rsi), %ymm4 ++ vmovdqa VEC_SIZE(%rsi), %ymm5 ++ vmovdqa (VEC_SIZE * 2)(%rsi), %ymm6 ++ vmovdqa (VEC_SIZE * 3)(%rsi), %ymm7 ++ vpminub %ymm5, %ymm4, %ymm2 ++ vpminub %ymm7, %ymm6, %ymm3 ++ vpminub %ymm2, %ymm3, %ymm3 ++ vpcmpeqb %ymmM, %ymm3, %ymm3 ++ vpmovmskb %ymm3, %edx ++# ifdef USE_AS_STRNCPY ++ sub $(VEC_SIZE * 4), %r8 ++ jbe L(UnalignedLeaveCase2OrCase3) ++# endif ++ test %edx, %edx ++ jnz L(UnalignedFourVecSizeLeave) ++ ++L(UnalignedFourVecSizeLoop_start): ++ add $(VEC_SIZE * 4), %rdi ++ add $(VEC_SIZE * 4), %rsi ++ vmovdqu %ymm4, -(VEC_SIZE * 4)(%rdi) ++ vmovdqa (%rsi), %ymm4 ++ vmovdqu %ymm5, -(VEC_SIZE * 3)(%rdi) ++ vmovdqa VEC_SIZE(%rsi), %ymm5 ++ vpminub %ymm5, %ymm4, %ymm2 ++ vmovdqu %ymm6, -(VEC_SIZE * 2)(%rdi) ++ vmovdqa (VEC_SIZE * 2)(%rsi), %ymm6 ++ vmovdqu %ymm7, -VEC_SIZE(%rdi) ++ vmovdqa (VEC_SIZE * 3)(%rsi), %ymm7 ++ vpminub %ymm7, %ymm6, %ymm3 ++ vpminub %ymm2, %ymm3, %ymm3 ++ vpcmpeqb %ymmM, %ymm3, %ymm3 ++ vpmovmskb %ymm3, %edx ++# ifdef USE_AS_STRNCPY ++ sub $(VEC_SIZE * 4), %r8 ++ jbe L(UnalignedLeaveCase2OrCase3) ++# endif ++ test %edx, %edx ++ jz L(UnalignedFourVecSizeLoop_start) ++ ++L(UnalignedFourVecSizeLeave): ++ vpcmpeqb %ymm4, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ test %edx, %edx ++ jnz L(CopyVecSizeUnaligned_0) ++ ++ vpcmpeqb %ymm5, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %ecx ++ test %ecx, %ecx ++ jnz L(CopyVecSizeUnaligned_16) ++ ++ vpcmpeqb %ymm6, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ test %edx, %edx ++ jnz L(CopyVecSizeUnaligned_32) ++ ++ vpcmpeqb %ymm7, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %ecx ++ bsf %ecx, %edx ++ vmovdqu %ymm4, (%rdi) ++ vmovdqu %ymm5, VEC_SIZE(%rdi) ++ vmovdqu %ymm6, (VEC_SIZE * 2)(%rdi) ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++# ifdef USE_AS_STPCPY ++ lea (VEC_SIZE * 3)(%rdi, %rdx), %rax ++# endif ++ vmovdqu %ymm7, (VEC_SIZE * 3)(%rdi) ++ add $(VEC_SIZE - 1), %r8 ++ sub %rdx, %r8 ++ lea ((VEC_SIZE * 3) + 1)(%rdi, %rdx), %rdi ++ jmp L(StrncpyFillTailWithZero) ++# else ++ add $(VEC_SIZE * 3), %rsi ++ add $(VEC_SIZE * 3), %rdi ++ jmp L(CopyVecSizeExit) ++# endif ++ ++/* If source address alignment == destination address alignment */ ++ ++L(SourceStringAlignmentLessTwoVecSize): ++ vmovdqu (%rsi), %ymm3 ++ vmovdqu VEC_SIZE(%rsi), %ymm2 ++ vpcmpeqb %ymm3, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ ++# ifdef USE_AS_STRNCPY ++# if defined USE_AS_STPCPY || defined USE_AS_STRCAT ++ cmp $VEC_SIZE, %r8 ++# else ++ cmp $(VEC_SIZE + 1), %r8 ++# endif ++ jbe L(CopyVecSizeTail1Case2OrCase3) ++# endif ++ test %edx, %edx ++ jnz L(CopyVecSizeTail1) ++ ++ vmovdqu %ymm3, (%rdi) ++ vpcmpeqb %ymm2, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ ++# ifdef USE_AS_STRNCPY ++# if defined USE_AS_STPCPY || defined USE_AS_STRCAT ++ cmp $(VEC_SIZE * 2), %r8 ++# else ++ cmp $((VEC_SIZE * 2) + 1), %r8 ++# endif ++ jbe L(CopyTwoVecSize1Case2OrCase3) ++# endif ++ test %edx, %edx ++ jnz L(CopyTwoVecSize1) ++ ++ and $-VEC_SIZE, %rsi ++ and $(VEC_SIZE - 1), %ecx ++ jmp L(UnalignVecSizeBoth) ++ ++/*------End of main part with loops---------------------*/ ++ ++/* Case1 */ ++ ++# if (!defined USE_AS_STRNCPY) || (defined USE_AS_STRCAT) ++ .p2align 4 ++L(CopyVecSize): ++ add %rcx, %rdi ++# endif ++L(CopyVecSizeTail): ++ add %rcx, %rsi ++L(CopyVecSizeTail1): ++ bsf %edx, %edx ++L(CopyVecSizeExit): ++ cmp $32, %edx ++ jae L(Exit32_63) ++ cmp $16, %edx ++ jae L(Exit16_31) ++ cmp $8, %edx ++ jae L(Exit8_15) ++ cmp $4, %edx ++ jae L(Exit4_7) ++ cmp $3, %edx ++ je L(Exit3) ++ cmp $1, %edx ++ ja L(Exit2) ++ je L(Exit1) ++ movb $0, (%rdi) ++# ifdef USE_AS_STPCPY ++ lea (%rdi), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub $1, %r8 ++ lea 1(%rdi), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(CopyTwoVecSize1): ++ add $VEC_SIZE, %rsi ++ add $VEC_SIZE, %rdi ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub $VEC_SIZE, %r8 ++# endif ++ jmp L(CopyVecSizeTail1) ++ ++ .p2align 4 ++L(CopyTwoVecSize): ++ bsf %edx, %edx ++ add %rcx, %rsi ++ add $VEC_SIZE, %edx ++ sub %ecx, %edx ++ jmp L(CopyVecSizeExit) ++ ++ .p2align 4 ++L(CopyVecSizeUnaligned_0): ++ bsf %edx, %edx ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %rdx), %rax ++# endif ++ vmovdqu %ymm4, (%rdi) ++ add $((VEC_SIZE * 4) - 1), %r8 ++ sub %rdx, %r8 ++ lea 1(%rdi, %rdx), %rdi ++ jmp L(StrncpyFillTailWithZero) ++# else ++ jmp L(CopyVecSizeExit) ++# endif ++ ++ .p2align 4 ++L(CopyVecSizeUnaligned_16): ++ bsf %ecx, %edx ++ vmovdqu %ymm4, (%rdi) ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++# ifdef USE_AS_STPCPY ++ lea VEC_SIZE(%rdi, %rdx), %rax ++# endif ++ vmovdqu %ymm5, VEC_SIZE(%rdi) ++ add $((VEC_SIZE * 3) - 1), %r8 ++ sub %rdx, %r8 ++ lea (VEC_SIZE + 1)(%rdi, %rdx), %rdi ++ jmp L(StrncpyFillTailWithZero) ++# else ++ add $VEC_SIZE, %rsi ++ add $VEC_SIZE, %rdi ++ jmp L(CopyVecSizeExit) ++# endif ++ ++ .p2align 4 ++L(CopyVecSizeUnaligned_32): ++ bsf %edx, %edx ++ vmovdqu %ymm4, (%rdi) ++ vmovdqu %ymm5, VEC_SIZE(%rdi) ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++# ifdef USE_AS_STPCPY ++ lea (VEC_SIZE * 2)(%rdi, %rdx), %rax ++# endif ++ vmovdqu %ymm6, (VEC_SIZE * 2)(%rdi) ++ add $((VEC_SIZE * 2) - 1), %r8 ++ sub %rdx, %r8 ++ lea ((VEC_SIZE * 2) + 1)(%rdi, %rdx), %rdi ++ jmp L(StrncpyFillTailWithZero) ++# else ++ add $(VEC_SIZE * 2), %rsi ++ add $(VEC_SIZE * 2), %rdi ++ jmp L(CopyVecSizeExit) ++# endif ++ ++# ifdef USE_AS_STRNCPY ++# ifndef USE_AS_STRCAT ++ .p2align 4 ++L(CopyVecSizeUnalignedVec6): ++ vmovdqu %ymm6, (%rdi, %rcx) ++ jmp L(CopyVecSizeVecExit) ++ ++ .p2align 4 ++L(CopyVecSizeUnalignedVec5): ++ vmovdqu %ymm5, (%rdi, %rcx) ++ jmp L(CopyVecSizeVecExit) ++ ++ .p2align 4 ++L(CopyVecSizeUnalignedVec4): ++ vmovdqu %ymm4, (%rdi, %rcx) ++ jmp L(CopyVecSizeVecExit) ++ ++ .p2align 4 ++L(CopyVecSizeUnalignedVec3): ++ vmovdqu %ymm3, (%rdi, %rcx) ++ jmp L(CopyVecSizeVecExit) ++# endif ++ ++/* Case2 */ ++ ++ .p2align 4 ++L(CopyVecSizeCase2): ++ add $VEC_SIZE, %r8 ++ add %rcx, %rdi ++ add %rcx, %rsi ++ bsf %edx, %edx ++ cmp %r8d, %edx ++ jb L(CopyVecSizeExit) ++ jmp L(StrncpyExit) ++ ++ .p2align 4 ++L(CopyTwoVecSizeCase2): ++ add %rcx, %rsi ++ bsf %edx, %edx ++ add $VEC_SIZE, %edx ++ sub %ecx, %edx ++ cmp %r8d, %edx ++ jb L(CopyVecSizeExit) ++ jmp L(StrncpyExit) ++ ++L(CopyVecSizeTailCase2): ++ add %rcx, %rsi ++ bsf %edx, %edx ++ cmp %r8d, %edx ++ jb L(CopyVecSizeExit) ++ jmp L(StrncpyExit) ++ ++L(CopyVecSizeTail1Case2): ++ bsf %edx, %edx ++ cmp %r8d, %edx ++ jb L(CopyVecSizeExit) ++ jmp L(StrncpyExit) ++ ++/* Case2 or Case3, Case3 */ ++ ++ .p2align 4 ++L(CopyVecSizeCase2OrCase3): ++ test %rdx, %rdx ++ jnz L(CopyVecSizeCase2) ++L(CopyVecSizeCase3): ++ add $VEC_SIZE, %r8 ++ add %rcx, %rdi ++ add %rcx, %rsi ++ jmp L(StrncpyExit) ++ ++ .p2align 4 ++L(CopyTwoVecSizeCase2OrCase3): ++ test %rdx, %rdx ++ jnz L(CopyTwoVecSizeCase2) ++ add %rcx, %rsi ++ jmp L(StrncpyExit) ++ ++ .p2align 4 ++L(CopyVecSizeTailCase2OrCase3): ++ test %rdx, %rdx ++ jnz L(CopyVecSizeTailCase2) ++ add %rcx, %rsi ++ jmp L(StrncpyExit) ++ ++ .p2align 4 ++L(CopyTwoVecSize1Case2OrCase3): ++ add $VEC_SIZE, %rdi ++ add $VEC_SIZE, %rsi ++ sub $VEC_SIZE, %r8 ++L(CopyVecSizeTail1Case2OrCase3): ++ test %rdx, %rdx ++ jnz L(CopyVecSizeTail1Case2) ++ jmp L(StrncpyExit) ++# endif ++ ++/*------------End labels regarding with copying 1-VEC_SIZE bytes--and 1-(VEC_SIZE*2) bytes----*/ ++ ++ .p2align 4 ++L(Exit1): ++ movzwl (%rsi), %edx ++ mov %dx, (%rdi) ++# ifdef USE_AS_STPCPY ++ lea 1(%rdi), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub $2, %r8 ++ lea 2(%rdi), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(Exit2): ++ movzwl (%rsi), %ecx ++ mov %cx, (%rdi) ++ movb $0, 2(%rdi) ++# ifdef USE_AS_STPCPY ++ lea 2(%rdi), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub $3, %r8 ++ lea 3(%rdi), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(Exit3): ++ mov (%rsi), %edx ++ mov %edx, (%rdi) ++# ifdef USE_AS_STPCPY ++ lea 3(%rdi), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub $4, %r8 ++ lea 4(%rdi), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(Exit4_7): ++ mov (%rsi), %ecx ++ mov %ecx, (%rdi) ++ mov -3(%rsi, %rdx), %ecx ++ mov %ecx, -3(%rdi, %rdx) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %rdx), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub %rdx, %r8 ++ sub $1, %r8 ++ lea 1(%rdi, %rdx), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(Exit8_15): ++ mov (%rsi), %rcx ++ mov -7(%rsi, %rdx), %r9 ++ mov %rcx, (%rdi) ++ mov %r9, -7(%rdi, %rdx) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %rdx), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub %rdx, %r8 ++ sub $1, %r8 ++ lea 1(%rdi, %rdx), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(Exit16_31): ++ vmovdqu (%rsi), %xmm2 ++ vmovdqu -15(%rsi, %rdx), %xmm3 ++ vmovdqu %xmm2, (%rdi) ++ vmovdqu %xmm3, -15(%rdi, %rdx) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %rdx), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub %rdx, %r8 ++ sub $1, %r8 ++ lea 1(%rdi, %rdx), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(Exit32_63): ++ vmovdqu (%rsi), %ymm2 ++ vmovdqu -31(%rsi, %rdx), %ymm3 ++ vmovdqu %ymm2, (%rdi) ++ vmovdqu %ymm3, -31(%rdi, %rdx) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %rdx), %rax ++# endif ++# if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT ++ sub %rdx, %r8 ++ sub $1, %r8 ++ lea 1(%rdi, %rdx), %rdi ++ jnz L(StrncpyFillTailWithZero) ++# endif ++ VZEROUPPER ++ ret ++ ++# ifdef USE_AS_STRNCPY ++ ++ .p2align 4 ++L(StrncpyExit1): ++ movzbl (%rsi), %edx ++ mov %dl, (%rdi) ++# ifdef USE_AS_STPCPY ++ lea 1(%rdi), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, 1(%rdi) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(StrncpyExit2): ++ movzwl (%rsi), %edx ++ mov %dx, (%rdi) ++# ifdef USE_AS_STPCPY ++ lea 2(%rdi), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, 2(%rdi) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(StrncpyExit3_4): ++ movzwl (%rsi), %ecx ++ movzwl -2(%rsi, %r8), %edx ++ mov %cx, (%rdi) ++ mov %dx, -2(%rdi, %r8) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %r8), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, (%rdi, %r8) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(StrncpyExit5_8): ++ mov (%rsi), %ecx ++ mov -4(%rsi, %r8), %edx ++ mov %ecx, (%rdi) ++ mov %edx, -4(%rdi, %r8) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %r8), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, (%rdi, %r8) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(StrncpyExit9_16): ++ mov (%rsi), %rcx ++ mov -8(%rsi, %r8), %rdx ++ mov %rcx, (%rdi) ++ mov %rdx, -8(%rdi, %r8) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %r8), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, (%rdi, %r8) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(StrncpyExit17_32): ++ vmovdqu (%rsi), %xmm2 ++ vmovdqu -16(%rsi, %r8), %xmm3 ++ vmovdqu %xmm2, (%rdi) ++ vmovdqu %xmm3, -16(%rdi, %r8) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %r8), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, (%rdi, %r8) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(StrncpyExit33_64): ++ /* 0/32, 31/16 */ ++ vmovdqu (%rsi), %ymm2 ++ vmovdqu -VEC_SIZE(%rsi, %r8), %ymm3 ++ vmovdqu %ymm2, (%rdi) ++ vmovdqu %ymm3, -VEC_SIZE(%rdi, %r8) ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %r8), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, (%rdi, %r8) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(StrncpyExit65): ++ /* 0/32, 32/32, 64/1 */ ++ vmovdqu (%rsi), %ymm2 ++ vmovdqu 32(%rsi), %ymm3 ++ mov 64(%rsi), %cl ++ vmovdqu %ymm2, (%rdi) ++ vmovdqu %ymm3, 32(%rdi) ++ mov %cl, 64(%rdi) ++# ifdef USE_AS_STPCPY ++ lea 65(%rdi), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, 65(%rdi) ++# endif ++ VZEROUPPER ++ ret ++ ++# ifndef USE_AS_STRCAT ++ ++ .p2align 4 ++L(Fill1): ++ mov %dl, (%rdi) ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(Fill2): ++ mov %dx, (%rdi) ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(Fill3_4): ++ mov %dx, (%rdi) ++ mov %dx, -2(%rdi, %r8) ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(Fill5_8): ++ mov %edx, (%rdi) ++ mov %edx, -4(%rdi, %r8) ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(Fill9_16): ++ mov %rdx, (%rdi) ++ mov %rdx, -8(%rdi, %r8) ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(Fill17_32): ++ vmovdqu %xmmZ, (%rdi) ++ vmovdqu %xmmZ, -16(%rdi, %r8) ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(CopyVecSizeUnalignedVec2): ++ vmovdqu %ymm2, (%rdi, %rcx) ++ ++ .p2align 4 ++L(CopyVecSizeVecExit): ++ bsf %edx, %edx ++ add $(VEC_SIZE - 1), %r8 ++ add %rcx, %rdi ++# ifdef USE_AS_STPCPY ++ lea (%rdi, %rdx), %rax ++# endif ++ sub %rdx, %r8 ++ lea 1(%rdi, %rdx), %rdi ++ ++ .p2align 4 ++L(StrncpyFillTailWithZero): ++ xor %edx, %edx ++ sub $VEC_SIZE, %r8 ++ jbe L(StrncpyFillExit) ++ ++ vmovdqu %ymmZ, (%rdi) ++ add $VEC_SIZE, %rdi ++ ++ mov %rdi, %rsi ++ and $(VEC_SIZE - 1), %esi ++ sub %rsi, %rdi ++ add %rsi, %r8 ++ sub $(VEC_SIZE * 4), %r8 ++ jb L(StrncpyFillLessFourVecSize) ++ ++L(StrncpyFillLoopVmovdqa): ++ vmovdqa %ymmZ, (%rdi) ++ vmovdqa %ymmZ, VEC_SIZE(%rdi) ++ vmovdqa %ymmZ, (VEC_SIZE * 2)(%rdi) ++ vmovdqa %ymmZ, (VEC_SIZE * 3)(%rdi) ++ add $(VEC_SIZE * 4), %rdi ++ sub $(VEC_SIZE * 4), %r8 ++ jae L(StrncpyFillLoopVmovdqa) ++ ++L(StrncpyFillLessFourVecSize): ++ add $(VEC_SIZE * 2), %r8 ++ jl L(StrncpyFillLessTwoVecSize) ++ vmovdqa %ymmZ, (%rdi) ++ vmovdqa %ymmZ, VEC_SIZE(%rdi) ++ add $(VEC_SIZE * 2), %rdi ++ sub $VEC_SIZE, %r8 ++ jl L(StrncpyFillExit) ++ vmovdqa %ymmZ, (%rdi) ++ add $VEC_SIZE, %rdi ++ jmp L(Fill) ++ ++ .p2align 4 ++L(StrncpyFillLessTwoVecSize): ++ add $VEC_SIZE, %r8 ++ jl L(StrncpyFillExit) ++ vmovdqa %ymmZ, (%rdi) ++ add $VEC_SIZE, %rdi ++ jmp L(Fill) ++ ++ .p2align 4 ++L(StrncpyFillExit): ++ add $VEC_SIZE, %r8 ++L(Fill): ++ cmp $17, %r8d ++ jae L(Fill17_32) ++ cmp $9, %r8d ++ jae L(Fill9_16) ++ cmp $5, %r8d ++ jae L(Fill5_8) ++ cmp $3, %r8d ++ jae L(Fill3_4) ++ cmp $1, %r8d ++ ja L(Fill2) ++ je L(Fill1) ++ VZEROUPPER ++ ret ++ ++/* end of ifndef USE_AS_STRCAT */ ++# endif ++ ++ .p2align 4 ++L(UnalignedLeaveCase2OrCase3): ++ test %rdx, %rdx ++ jnz L(UnalignedFourVecSizeLeaveCase2) ++L(UnalignedFourVecSizeLeaveCase3): ++ lea (VEC_SIZE * 4)(%r8), %rcx ++ and $-VEC_SIZE, %rcx ++ add $(VEC_SIZE * 3), %r8 ++ jl L(CopyVecSizeCase3) ++ vmovdqu %ymm4, (%rdi) ++ sub $VEC_SIZE, %r8 ++ jb L(CopyVecSizeCase3) ++ vmovdqu %ymm5, VEC_SIZE(%rdi) ++ sub $VEC_SIZE, %r8 ++ jb L(CopyVecSizeCase3) ++ vmovdqu %ymm6, (VEC_SIZE * 2)(%rdi) ++ sub $VEC_SIZE, %r8 ++ jb L(CopyVecSizeCase3) ++ vmovdqu %ymm7, (VEC_SIZE * 3)(%rdi) ++# ifdef USE_AS_STPCPY ++ lea (VEC_SIZE * 4)(%rdi), %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, (VEC_SIZE * 4)(%rdi) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(UnalignedFourVecSizeLeaveCase2): ++ xor %ecx, %ecx ++ vpcmpeqb %ymm4, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ add $(VEC_SIZE * 3), %r8 ++ jle L(CopyVecSizeCase2OrCase3) ++ test %edx, %edx ++# ifndef USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec4) ++# else ++ jnz L(CopyVecSize) ++# endif ++ vpcmpeqb %ymm5, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ vmovdqu %ymm4, (%rdi) ++ add $VEC_SIZE, %rcx ++ sub $VEC_SIZE, %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++ test %edx, %edx ++# ifndef USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec5) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ vpcmpeqb %ymm6, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ vmovdqu %ymm5, VEC_SIZE(%rdi) ++ add $VEC_SIZE, %rcx ++ sub $VEC_SIZE, %r8 ++ jbe L(CopyVecSizeCase2OrCase3) ++ test %edx, %edx ++# ifndef USE_AS_STRCAT ++ jnz L(CopyVecSizeUnalignedVec6) ++# else ++ jnz L(CopyVecSize) ++# endif ++ ++ vpcmpeqb %ymm7, %ymmZ, %ymmM ++ vpmovmskb %ymmM, %edx ++ vmovdqu %ymm6, (VEC_SIZE * 2)(%rdi) ++ lea VEC_SIZE(%rdi, %rcx), %rdi ++ lea VEC_SIZE(%rsi, %rcx), %rsi ++ bsf %edx, %edx ++ cmp %r8d, %edx ++ jb L(CopyVecSizeExit) ++L(StrncpyExit): ++ cmp $65, %r8d ++ je L(StrncpyExit65) ++ cmp $33, %r8d ++ jae L(StrncpyExit33_64) ++ cmp $17, %r8d ++ jae L(StrncpyExit17_32) ++ cmp $9, %r8d ++ jae L(StrncpyExit9_16) ++ cmp $5, %r8d ++ jae L(StrncpyExit5_8) ++ cmp $3, %r8d ++ jae L(StrncpyExit3_4) ++ cmp $1, %r8d ++ ja L(StrncpyExit2) ++ je L(StrncpyExit1) ++# ifdef USE_AS_STPCPY ++ mov %rdi, %rax ++# endif ++# ifdef USE_AS_STRCAT ++ movb $0, (%rdi) ++# endif ++ VZEROUPPER ++ ret ++ ++ .p2align 4 ++L(ExitZero): ++# ifndef USE_AS_STRCAT ++ mov %rdi, %rax ++# endif ++ VZEROUPPER ++ ret ++ ++# endif ++ ++# ifndef USE_AS_STRCAT ++END (STRCPY) ++# else ++END (STRCAT) ++# endif ++#endif +diff --git a/sysdeps/x86_64/multiarch/strcpy.c b/sysdeps/x86_64/multiarch/strcpy.c +index 12e0e3ffe20602c6..ecf90d4b044a1b01 100644 +--- a/sysdeps/x86_64/multiarch/strcpy.c ++++ b/sysdeps/x86_64/multiarch/strcpy.c +@@ -24,7 +24,7 @@ + # undef strcpy + + # define SYMBOL_NAME strcpy +-# include "ifunc-unaligned-ssse3.h" ++# include "ifunc-strcpy.h" + + libc_ifunc_redirected (__redirect_strcpy, strcpy, IFUNC_SELECTOR ()); + +diff --git a/sysdeps/x86_64/multiarch/strncat-avx2.S b/sysdeps/x86_64/multiarch/strncat-avx2.S +new file mode 100644 +index 0000000000000000..bfefa659bb6281fa +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strncat-avx2.S +@@ -0,0 +1,3 @@ ++#define USE_AS_STRNCAT ++#define STRCAT __strncat_avx2 ++#include "strcat-avx2.S" +diff --git a/sysdeps/x86_64/multiarch/strncat.c b/sysdeps/x86_64/multiarch/strncat.c +index 841c165565add132..74f7d028ae23d700 100644 +--- a/sysdeps/x86_64/multiarch/strncat.c ++++ b/sysdeps/x86_64/multiarch/strncat.c +@@ -24,7 +24,7 @@ + # undef strncat + + # define SYMBOL_NAME strncat +-# include "ifunc-unaligned-ssse3.h" ++# include "ifunc-strcpy.h" + + libc_ifunc_redirected (__redirect_strncat, strncat, IFUNC_SELECTOR ()); + strong_alias (strncat, __strncat); +diff --git a/sysdeps/x86_64/multiarch/strncpy-avx2.S b/sysdeps/x86_64/multiarch/strncpy-avx2.S +new file mode 100644 +index 0000000000000000..9ef8c87627dc4924 +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/strncpy-avx2.S +@@ -0,0 +1,3 @@ ++#define USE_AS_STRNCPY ++#define STRCPY __strncpy_avx2 ++#include "strcpy-avx2.S" +diff --git a/sysdeps/x86_64/multiarch/strncpy.c b/sysdeps/x86_64/multiarch/strncpy.c +index 3c3de8b18ebb177f..93dfb4cfde79467a 100644 +--- a/sysdeps/x86_64/multiarch/strncpy.c ++++ b/sysdeps/x86_64/multiarch/strncpy.c +@@ -24,7 +24,7 @@ + # undef strncpy + + # define SYMBOL_NAME strncpy +-# include "ifunc-unaligned-ssse3.h" ++# include "ifunc-strcpy.h" + + libc_ifunc_redirected (__redirect_strncpy, strncpy, IFUNC_SELECTOR ()); + diff --git a/SOURCES/glibc-rh1817513-18.patch b/SOURCES/glibc-rh1817513-18.patch new file mode 100644 index 0000000..d7d84b7 --- /dev/null +++ b/SOURCES/glibc-rh1817513-18.patch @@ -0,0 +1,191 @@ +commit 32db86d558193ad4ad5a00926ce3c350c89eb8df +Author: Joseph Myers +Date: Tue Feb 12 10:30:34 2019 +0000 + + Add fall-through comments. + + This patch adds fall-through comments in some cases where -Wextra + produces implicit-fallthrough warnings. + + The patch is non-exhaustive. Apart from architecture-specific code + for non-x86_64 architectures, it does not change sunrpc/xdr.c (legacy + code, probably should have such changes, but left to be dealt with + separately), or places that already had comments about the + fall-through but not matching the form expected by + -Wimplicit-fallthrough=3 (the default level with -Wextra; my + inclination is to adjust those comments to match rather than + downgrading to -Wimplicit-fallthrough=1 to allow any comment), or one + place where I thought the implicit fallthrough was not correct and so + should be handled separately as a bug fix. I think the key thing to + consider in review of this patch is whether the fall-through is indeed + intended and correct in each place where such a comment is added. + + Tested for x86_64. + + * elf/dl-exception.c (_dl_exception_create_format): Add + fall-through comments. + * elf/ldconfig.c (parse_conf_include): Likewise. + * elf/rtld.c (print_statistics): Likewise. + * locale/programs/charmap.c (parse_charmap): Likewise. + * misc/mntent_r.c (__getmntent_r): Likewise. + * posix/wordexp.c (parse_arith): Likewise. + (parse_backtick): Likewise. + * resolv/ns_ttl.c (ns_parse_ttl): Likewise. + * sysdeps/x86/cpu-features.c (init_cpu_features): Likewise. + * sysdeps/x86_64/dl-machine.h (elf_machine_rela): Likewise. + +diff --git a/elf/dl-exception.c b/elf/dl-exception.c +index 3e8e0ba3f1442005..d24bf30a5cf39bc2 100644 +--- a/elf/dl-exception.c ++++ b/elf/dl-exception.c +@@ -123,6 +123,7 @@ _dl_exception_create_format (struct dl_exception *exception, const char *objname + ++p; + break; + } ++ /* Fall through. */ + case 'x': + length += INT_WIDTH / 4; + break; +diff --git a/elf/ldconfig.c b/elf/ldconfig.c +index fbdd814edf59bc77..ed7d9ab0412d93fd 100644 +--- a/elf/ldconfig.c ++++ b/elf/ldconfig.c +@@ -1228,6 +1228,7 @@ parse_conf_include (const char *config_file, unsigned int lineno, + + case GLOB_NOSPACE: + errno = ENOMEM; ++ /* Fall through. */ + case GLOB_ABORTED: + if (opt_verbose) + error (0, errno, _("%s:%u: cannot read directory %s"), +diff --git a/elf/rtld.c b/elf/rtld.c +index 7f030f75a22c532e..8bb5f548a0ff8eb4 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2734,8 +2734,10 @@ print_statistics (hp_timing_t *rtld_total_timep) + { + case 3: + *wp++ = *cp++; ++ /* Fall through. */ + case 2: + *wp++ = *cp++; ++ /* Fall through. */ + case 1: + *wp++ = '.'; + *wp++ = *cp++; +@@ -2797,8 +2799,10 @@ print_statistics (hp_timing_t *rtld_total_timep) + { + case 3: + *wp++ = *cp++; ++ /* Fall through. */ + case 2: + *wp++ = *cp++; ++ /* Fall through. */ + case 1: + *wp++ = '.'; + *wp++ = *cp++; +diff --git a/locale/programs/charmap.c b/locale/programs/charmap.c +index 2d54dd3c027d11d2..8041a0e5d292f3f5 100644 +--- a/locale/programs/charmap.c ++++ b/locale/programs/charmap.c +@@ -713,6 +713,7 @@ only WIDTH definitions are allowed to follow the CHARMAP definition")); + state = 95; + continue; + } ++ /* Fall through. */ + + case 96: + if (nowtok != tok_number) +diff --git a/misc/mntent_r.c b/misc/mntent_r.c +index 7bb224f044150ab4..add39d4537eaccb5 100644 +--- a/misc/mntent_r.c ++++ b/misc/mntent_r.c +@@ -167,8 +167,10 @@ get_mnt_entry (FILE *stream, struct mntent *mp, char *buffer, int bufsiz) + { + case 0: + mp->mnt_freq = 0; ++ /* Fall through. */ + case 1: + mp->mnt_passno = 0; ++ /* Fall through. */ + case 2: + break; + } +diff --git a/posix/wordexp.c b/posix/wordexp.c +index 7548e0329fdeafaa..048a8068544c81fa 100644 +--- a/posix/wordexp.c ++++ b/posix/wordexp.c +@@ -799,6 +799,7 @@ parse_arith (char **word, size_t *word_length, size_t *max_length, + + case '(': + ++paren_depth; ++ /* Fall through. */ + default: + expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]); + if (expr == NULL) +@@ -2127,6 +2128,7 @@ parse_backtick (char **word, size_t *word_length, size_t *max_length, + + case '\'': + squoting = 1 - squoting; ++ /* Fall through. */ + default: + comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]); + if (comm == NULL) +diff --git a/resolv/ns_ttl.c b/resolv/ns_ttl.c +index 079948790b94b05e..d29d9dc00cfcab2c 100644 +--- a/resolv/ns_ttl.c ++++ b/resolv/ns_ttl.c +@@ -113,9 +113,13 @@ ns_parse_ttl(const char *src, u_long *dst) { + ch = toupper(ch); + switch (ch) { + case 'W': tmp *= 7; ++ /* Fall through. */ + case 'D': tmp *= 24; ++ /* Fall through. */ + case 'H': tmp *= 60; ++ /* Fall through. */ + case 'M': tmp *= 60; ++ /* Fall through. */ + case 'S': break; + default: goto einval; + } +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 3a02a9c7d08f9603..ade37a9bb3de86cc 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -374,6 +374,7 @@ init_cpu_features (struct cpu_features *cpu_features) + of Core i3/i5/i7 processors if AVX is available. */ + if (!CPU_FEATURES_CPU_P (cpu_features, AVX)) + break; ++ /* Fall through. */ + + case 0x1a: + case 0x1e: +@@ -401,6 +402,7 @@ init_cpu_features (struct cpu_features *cpu_features) + /* Xeon E7 v3 with stepping >= 4 has working TSX. */ + if (stepping >= 4) + break; ++ /* Fall through. */ + case 0x3c: + case 0x45: + case 0x46: +diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h +index 1942ed5061d18c68..23afb3c05dbe17d6 100644 +--- a/sysdeps/x86_64/dl-machine.h ++++ b/sysdeps/x86_64/dl-machine.h +@@ -347,6 +347,7 @@ elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc, + /* Set to symbol size plus addend. */ + value = sym->st_size; + # endif ++ /* Fall through. */ + case R_X86_64_GLOB_DAT: + case R_X86_64_JUMP_SLOT: + *reloc_addr = value + reloc->r_addend; +@@ -460,6 +461,7 @@ elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc, + /* Set to symbol size plus addend. */ + value = sym->st_size; + # endif ++ /* Fall through. */ + case R_X86_64_32: + value += reloc->r_addend; + *(unsigned int *) reloc_addr = value; diff --git a/SOURCES/glibc-rh1817513-19.patch b/SOURCES/glibc-rh1817513-19.patch new file mode 100644 index 0000000..674aa43 --- /dev/null +++ b/SOURCES/glibc-rh1817513-19.patch @@ -0,0 +1,408 @@ +commit 3b856d093f5197637a5927c37d6c07dad8c86d45 +Author: Florian Weimer +Date: Tue Feb 12 13:36:56 2019 +0100 + + elf: Ignore LD_AUDIT interfaces if la_version returns 0 [BZ #24122] + + This change moves the audit module loading and early notification into + separate functions out of dl_main. + + It restores the bug fix from commit + 8e889c5da3c5981c5a46a93fec02de40131ac5a6 ("elf: Fix LD_AUDIT for + modules with invalid version (BZ#24122)") which was reverted in commit + 83e6b59625f45db1eee93e5684091f740c52a083 ("[elf] Revert 8e889c5da3 + (BZ#24122)"). + + The actual bug fix is the separate error message for the case when + la_version returns zero. The dynamic linker error message (which is + NULL in this case) is no longer used. Based on the intended use of + version zero (ignore this module due to explicit request), the message + is only printed if debugging is enabled. + +diff --git a/elf/rtld.c b/elf/rtld.c +index 8bb5f548a0ff8eb4..375e0de8fa2e049e 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -864,6 +864,205 @@ handle_preload_list (const char *preloadlist, struct link_map *main_map, + return npreloads; + } + ++/* Called if the audit DSO cannot be used: if it does not have the ++ appropriate interfaces, or it expects a more recent version library ++ version than what the dynamic linker provides. */ ++static void ++unload_audit_module (struct link_map *map, int original_tls_idx) ++{ ++#ifndef NDEBUG ++ Lmid_t ns = map->l_ns; ++#endif ++ _dl_close (map); ++ ++ /* Make sure the namespace has been cleared entirely. */ ++ assert (GL(dl_ns)[ns]._ns_loaded == NULL); ++ assert (GL(dl_ns)[ns]._ns_nloaded == 0); ++ ++ GL(dl_tls_max_dtv_idx) = original_tls_idx; ++} ++ ++/* Called to print an error message if loading of an audit module ++ failed. */ ++static void ++report_audit_module_load_error (const char *name, const char *err_str, ++ bool malloced) ++{ ++ _dl_error_printf ("\ ++ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", ++ name, err_str); ++ if (malloced) ++ free ((char *) err_str); ++} ++ ++/* Load one audit module. */ ++static void ++load_audit_module (const char *name, struct audit_ifaces **last_audit) ++{ ++ int original_tls_idx = GL(dl_tls_max_dtv_idx); ++ ++ struct dlmopen_args dlmargs; ++ dlmargs.fname = name; ++ dlmargs.map = NULL; ++ ++ const char *objname; ++ const char *err_str = NULL; ++ bool malloced; ++ _dl_catch_error (&objname, &err_str, &malloced, dlmopen_doit, &dlmargs); ++ if (__glibc_unlikely (err_str != NULL)) ++ { ++ report_audit_module_load_error (name, err_str, malloced); ++ return; ++ } ++ ++ struct lookup_args largs; ++ largs.name = "la_version"; ++ largs.map = dlmargs.map; ++ _dl_catch_error (&objname, &err_str, &malloced, lookup_doit, &largs); ++ if (__glibc_likely (err_str != NULL)) ++ { ++ unload_audit_module (dlmargs.map, original_tls_idx); ++ report_audit_module_load_error (name, err_str, malloced); ++ return; ++ } ++ ++ unsigned int (*laversion) (unsigned int) = largs.result; ++ ++ /* A null symbol indicates that something is very wrong with the ++ loaded object because defined symbols are supposed to have a ++ valid, non-null address. */ ++ assert (laversion != NULL); ++ ++ unsigned int lav = laversion (LAV_CURRENT); ++ if (lav == 0) ++ { ++ /* Only print an error message if debugging because this can ++ happen deliberately. */ ++ if (GLRO(dl_debug_mask) & DL_DEBUG_FILES) ++ _dl_debug_printf ("\ ++file=%s [%lu]; audit interface function la_version returned zero; ignored.\n", ++ dlmargs.map->l_name, dlmargs.map->l_ns); ++ unload_audit_module (dlmargs.map, original_tls_idx); ++ return; ++ } ++ ++ if (lav > LAV_CURRENT) ++ { ++ _dl_debug_printf ("\ ++ERROR: audit interface '%s' requires version %d (maximum supported version %d); ignored.\n", ++ name, lav, LAV_CURRENT); ++ unload_audit_module (dlmargs.map, original_tls_idx); ++ return; ++ } ++ ++ enum { naudit_ifaces = 8 }; ++ union ++ { ++ struct audit_ifaces ifaces; ++ void (*fptr[naudit_ifaces]) (void); ++ } *newp = malloc (sizeof (*newp)); ++ if (newp == NULL) ++ _dl_fatal_printf ("Out of memory while loading audit modules\n"); ++ ++ /* Names of the auditing interfaces. All in one ++ long string. */ ++ static const char audit_iface_names[] = ++ "la_activity\0" ++ "la_objsearch\0" ++ "la_objopen\0" ++ "la_preinit\0" ++#if __ELF_NATIVE_CLASS == 32 ++ "la_symbind32\0" ++#elif __ELF_NATIVE_CLASS == 64 ++ "la_symbind64\0" ++#else ++# error "__ELF_NATIVE_CLASS must be defined" ++#endif ++#define STRING(s) __STRING (s) ++ "la_" STRING (ARCH_LA_PLTENTER) "\0" ++ "la_" STRING (ARCH_LA_PLTEXIT) "\0" ++ "la_objclose\0"; ++ unsigned int cnt = 0; ++ const char *cp = audit_iface_names; ++ do ++ { ++ largs.name = cp; ++ _dl_catch_error (&objname, &err_str, &malloced, lookup_doit, &largs); ++ ++ /* Store the pointer. */ ++ if (err_str == NULL && largs.result != NULL) ++ { ++ newp->fptr[cnt] = largs.result; ++ ++ /* The dynamic linker link map is statically allocated, ++ initialize the data now. */ ++ GL(dl_rtld_map).l_audit[cnt].cookie = (intptr_t) &GL(dl_rtld_map); ++ } ++ else ++ newp->fptr[cnt] = NULL; ++ ++cnt; ++ ++ cp = rawmemchr (cp, '\0') + 1; ++ } ++ while (*cp != '\0'); ++ assert (cnt == naudit_ifaces); ++ ++ /* Now append the new auditing interface to the list. */ ++ newp->ifaces.next = NULL; ++ if (*last_audit == NULL) ++ *last_audit = GLRO(dl_audit) = &newp->ifaces; ++ else ++ *last_audit = (*last_audit)->next = &newp->ifaces; ++ ++GLRO(dl_naudit); ++ ++ /* Mark the DSO as being used for auditing. */ ++ dlmargs.map->l_auditing = 1; ++} ++ ++/* Notify the the audit modules that the object MAP has already been ++ loaded. */ ++static void ++notify_audit_modules_of_loaded_object (struct link_map *map) ++{ ++ struct audit_ifaces *afct = GLRO(dl_audit); ++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) ++ { ++ if (afct->objopen != NULL) ++ { ++ map->l_audit[cnt].bindflags ++ = afct->objopen (map, LM_ID_BASE, &map->l_audit[cnt].cookie); ++ map->l_audit_any_plt |= map->l_audit[cnt].bindflags != 0; ++ } ++ ++ afct = afct->next; ++ } ++} ++ ++/* Load all audit modules. */ ++static void ++load_audit_modules (struct link_map *main_map) ++{ ++ struct audit_ifaces *last_audit = NULL; ++ struct audit_list_iter al_iter; ++ audit_list_iter_init (&al_iter); ++ ++ while (true) ++ { ++ const char *name = audit_list_iter_next (&al_iter); ++ if (name == NULL) ++ break; ++ load_audit_module (name, &last_audit); ++ } ++ ++ /* Notify audit modules of the initially loaded modules (the main ++ program and the dynamic linker itself). */ ++ if (GLRO(dl_naudit) > 0) ++ { ++ notify_audit_modules_of_loaded_object (main_map); ++ notify_audit_modules_of_loaded_object (&GL(dl_rtld_map)); ++ } ++} ++ + static void + dl_main (const ElfW(Phdr) *phdr, + ElfW(Word) phnum, +@@ -1402,10 +1601,6 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + if (__glibc_unlikely (audit_list != NULL) + || __glibc_unlikely (audit_list_string != NULL)) + { +- struct audit_ifaces *last_audit = NULL; +- struct audit_list_iter al_iter; +- audit_list_iter_init (&al_iter); +- + /* Since we start using the auditing DSOs right away we need to + initialize the data structures now. */ + tcbp = init_tls (); +@@ -1417,164 +1612,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + security_init (); + need_security_init = false; + +- while (true) +- { +- const char *name = audit_list_iter_next (&al_iter); +- if (name == NULL) +- break; +- +- int tls_idx = GL(dl_tls_max_dtv_idx); +- +- /* Now it is time to determine the layout of the static TLS +- block and allocate it for the initial thread. Note that we +- always allocate the static block, we never defer it even if +- no DF_STATIC_TLS bit is set. The reason is that we know +- glibc will use the static model. */ +- struct dlmopen_args dlmargs; +- dlmargs.fname = name; +- dlmargs.map = NULL; +- +- const char *objname; +- const char *err_str = NULL; +- bool malloced; +- (void) _dl_catch_error (&objname, &err_str, &malloced, dlmopen_doit, +- &dlmargs); +- if (__glibc_unlikely (err_str != NULL)) +- { +- not_loaded: +- _dl_error_printf ("\ +-ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", +- name, err_str); +- if (malloced) +- free ((char *) err_str); +- } +- else +- { +- struct lookup_args largs; +- largs.name = "la_version"; +- largs.map = dlmargs.map; +- +- /* Check whether the interface version matches. */ +- (void) _dl_catch_error (&objname, &err_str, &malloced, +- lookup_doit, &largs); +- +- unsigned int (*laversion) (unsigned int); +- unsigned int lav; +- if (err_str == NULL +- && (laversion = largs.result) != NULL +- && (lav = laversion (LAV_CURRENT)) > 0 +- && lav <= LAV_CURRENT) +- { +- /* Allocate structure for the callback function pointers. +- This call can never fail. */ +- union +- { +- struct audit_ifaces ifaces; +-#define naudit_ifaces 8 +- void (*fptr[naudit_ifaces]) (void); +- } *newp = malloc (sizeof (*newp)); +- +- /* Names of the auditing interfaces. All in one +- long string. */ +- static const char audit_iface_names[] = +- "la_activity\0" +- "la_objsearch\0" +- "la_objopen\0" +- "la_preinit\0" +-#if __ELF_NATIVE_CLASS == 32 +- "la_symbind32\0" +-#elif __ELF_NATIVE_CLASS == 64 +- "la_symbind64\0" +-#else +-# error "__ELF_NATIVE_CLASS must be defined" +-#endif +-#define STRING(s) __STRING (s) +- "la_" STRING (ARCH_LA_PLTENTER) "\0" +- "la_" STRING (ARCH_LA_PLTEXIT) "\0" +- "la_objclose\0"; +- unsigned int cnt = 0; +- const char *cp = audit_iface_names; +- do +- { +- largs.name = cp; +- (void) _dl_catch_error (&objname, &err_str, &malloced, +- lookup_doit, &largs); +- +- /* Store the pointer. */ +- if (err_str == NULL && largs.result != NULL) +- { +- newp->fptr[cnt] = largs.result; +- +- /* The dynamic linker link map is statically +- allocated, initialize the data now. */ +- GL(dl_rtld_map).l_audit[cnt].cookie +- = (intptr_t) &GL(dl_rtld_map); +- } +- else +- newp->fptr[cnt] = NULL; +- ++cnt; +- +- cp = (char *) rawmemchr (cp, '\0') + 1; +- } +- while (*cp != '\0'); +- assert (cnt == naudit_ifaces); +- +- /* Now append the new auditing interface to the list. */ +- newp->ifaces.next = NULL; +- if (last_audit == NULL) +- last_audit = GLRO(dl_audit) = &newp->ifaces; +- else +- last_audit = last_audit->next = &newp->ifaces; +- ++GLRO(dl_naudit); +- +- /* Mark the DSO as being used for auditing. */ +- dlmargs.map->l_auditing = 1; +- } +- else +- { +- /* We cannot use the DSO, it does not have the +- appropriate interfaces or it expects something +- more recent. */ +-#ifndef NDEBUG +- Lmid_t ns = dlmargs.map->l_ns; +-#endif +- _dl_close (dlmargs.map); +- +- /* Make sure the namespace has been cleared entirely. */ +- assert (GL(dl_ns)[ns]._ns_loaded == NULL); +- assert (GL(dl_ns)[ns]._ns_nloaded == 0); +- +- GL(dl_tls_max_dtv_idx) = tls_idx; +- goto not_loaded; +- } +- } +- } +- +- /* If we have any auditing modules, announce that we already +- have two objects loaded. */ +- if (__glibc_unlikely (GLRO(dl_naudit) > 0)) +- { +- struct link_map *ls[2] = { main_map, &GL(dl_rtld_map) }; +- +- for (unsigned int outer = 0; outer < 2; ++outer) +- { +- struct audit_ifaces *afct = GLRO(dl_audit); +- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) +- { +- if (afct->objopen != NULL) +- { +- ls[outer]->l_audit[cnt].bindflags +- = afct->objopen (ls[outer], LM_ID_BASE, +- &ls[outer]->l_audit[cnt].cookie); +- +- ls[outer]->l_audit_any_plt +- |= ls[outer]->l_audit[cnt].bindflags != 0; +- } +- +- afct = afct->next; +- } +- } +- } ++ load_audit_modules (main_map); + } + + /* Keep track of the currently loaded modules to count how many diff --git a/SOURCES/glibc-rh1817513-2.patch b/SOURCES/glibc-rh1817513-2.patch new file mode 100644 index 0000000..f477471 --- /dev/null +++ b/SOURCES/glibc-rh1817513-2.patch @@ -0,0 +1,401 @@ +commit dce452dc5278f2985d21315721a6ba802537b862 +Author: Siddhesh Poyarekar +Date: Thu Aug 2 23:49:19 2018 +0530 + + Rename the glibc.tune namespace to glibc.cpu + + The glibc.tune namespace is vaguely named since it is a 'tunable', so + give it a more specific name that describes what it refers to. Rename + the tunable namespace to 'cpu' to more accurately reflect what it + encompasses. Also rename glibc.tune.cpu to glibc.cpu.name since + glibc.cpu.cpu is weird. + + * NEWS: Mention the change. + * elf/dl-tunables.list: Rename tune namespace to cpu. + * sysdeps/powerpc/dl-tunables.list: Likewise. + * sysdeps/x86/dl-tunables.list: Likewise. + * sysdeps/aarch64/dl-tunables.list: Rename tune.cpu to + cpu.name. + * elf/dl-hwcaps.c (_dl_important_hwcaps): Adjust. + * elf/dl-hwcaps.h (GET_HWCAP_MASK): Likewise. + * manual/README.tunables: Likewise. + * manual/tunables.texi: Likewise. + * sysdeps/powerpc/cpu-features.c: Likewise. + * sysdeps/unix/sysv/linux/aarch64/cpu-features.c + (init_cpu_features): Likewise. + * sysdeps/x86/cpu-features.c: Likewise. + * sysdeps/x86/cpu-features.h: Likewise. + * sysdeps/x86/cpu-tunables.c: Likewise. + * sysdeps/x86_64/Makefile: Likewise. + * sysdeps/x86/dl-cet.c: Likewise. + + Reviewed-by: Carlos O'Donell + +Conflicts: + manual/tunables.texi + (Earlier backport of non-temporal memcpy threshold.) + sysdeps/x86/Makefile + (Earlier CET backports.) + +diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c +index 23482a88a1c9bca9..ecf00b457760e517 100644 +--- a/elf/dl-hwcaps.c ++++ b/elf/dl-hwcaps.c +@@ -140,7 +140,7 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, + string and bit like you can ignore an OS-supplied HWCAP bit. */ + hwcap_mask |= (uint64_t) mask << _DL_FIRST_EXTRA; + #if HAVE_TUNABLES +- TUNABLE_SET (glibc, tune, hwcap_mask, uint64_t, hwcap_mask); ++ TUNABLE_SET (glibc, cpu, hwcap_mask, uint64_t, hwcap_mask); + #else + GLRO(dl_hwcap_mask) = hwcap_mask; + #endif +diff --git a/elf/dl-hwcaps.h b/elf/dl-hwcaps.h +index 17f0da4c73772425..d69ee11dc27bb5e5 100644 +--- a/elf/dl-hwcaps.h ++++ b/elf/dl-hwcaps.h +@@ -19,7 +19,7 @@ + #include + + #if HAVE_TUNABLES +-# define GET_HWCAP_MASK() TUNABLE_GET (glibc, tune, hwcap_mask, uint64_t, NULL) ++# define GET_HWCAP_MASK() TUNABLE_GET (glibc, cpu, hwcap_mask, uint64_t, NULL) + #else + # ifdef SHARED + # define GET_HWCAP_MASK() GLRO(dl_hwcap_mask) +diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list +index 1ff6fcb6f24f93a8..b7cc79f8bfe0a7c6 100644 +--- a/elf/dl-tunables.list ++++ b/elf/dl-tunables.list +@@ -91,7 +91,7 @@ glibc { + security_level: SXID_IGNORE + } + } +- tune { ++ cpu { + hwcap_mask { + type: UINT_64 + env_alias: LD_HWCAP_MASK +diff --git a/manual/README.tunables b/manual/README.tunables +index 3967679f432a6378..f87a31a65e0a3455 100644 +--- a/manual/README.tunables ++++ b/manual/README.tunables +@@ -105,11 +105,11 @@ where 'check' is the tunable name, 'int32_t' is the C type of the tunable and + To get and set tunables in a different namespace from that module, use the full + form of the macros as follows: + +- val = TUNABLE_GET_FULL (glibc, tune, hwcap_mask, uint64_t, NULL) ++ val = TUNABLE_GET_FULL (glibc, cpu, hwcap_mask, uint64_t, NULL) + +- TUNABLE_SET_FULL (glibc, tune, hwcap_mask, uint64_t, val) ++ TUNABLE_SET_FULL (glibc, cpu, hwcap_mask, uint64_t, val) + +-where 'glibc' is the top namespace, 'tune' is the tunable namespace and the ++where 'glibc' is the top namespace, 'cpu' is the tunable namespace and the + remaining arguments are the same as the short form macros. + + When TUNABLE_NAMESPACE is not defined in a module, TUNABLE_GET is equivalent to +diff --git a/manual/tunables.texi b/manual/tunables.texi +index 3e1e519dff153b09..ef10d2872cfc244e 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -307,23 +307,23 @@ The default value of this tunable is @samp{3}. + @cindex non_temporal_threshold tunables + @cindex tunables, non_temporal_threshold + +-@deftp {Tunable namespace} glibc.tune ++@deftp {Tunable namespace} glibc.cpu + Behavior of @theglibc{} can be tuned to assume specific hardware capabilities +-by setting the following tunables in the @code{tune} namespace: ++by setting the following tunables in the @code{cpu} namespace: + @end deftp + +-@deftp Tunable glibc.tune.hwcap_mask ++@deftp Tunable glibc.cpu.hwcap_mask + This tunable supersedes the @env{LD_HWCAP_MASK} environment variable and is + identical in features. + + The @code{AT_HWCAP} key in the Auxiliary Vector specifies instruction set + extensions available in the processor at runtime for some architectures. The +-@code{glibc.tune.hwcap_mask} tunable allows the user to mask out those ++@code{glibc.cpu.hwcap_mask} tunable allows the user to mask out those + capabilities at runtime, thus disabling use of those extensions. + @end deftp + +-@deftp Tunable glibc.tune.hwcaps +-The @code{glibc.tune.hwcaps=-xxx,yyy,-zzz...} tunable allows the user to ++@deftp Tunable glibc.cpu.hwcaps ++The @code{glibc.cpu.hwcaps=-xxx,yyy,-zzz...} tunable allows the user to + enable CPU/ARCH feature @code{yyy}, disable CPU/ARCH feature @code{xxx} + and @code{zzz} where the feature name is case-sensitive and has to match + the ones in @code{sysdeps/x86/cpu-features.h}. +@@ -331,8 +331,8 @@ the ones in @code{sysdeps/x86/cpu-features.h}. + This tunable is specific to i386 and x86-64. + @end deftp + +-@deftp Tunable glibc.tune.cached_memopt +-The @code{glibc.tune.cached_memopt=[0|1]} tunable allows the user to ++@deftp Tunable glibc.cpu.cached_memopt ++The @code{glibc.cpu.cached_memopt=[0|1]} tunable allows the user to + enable optimizations recommended for cacheable memory. If set to + @code{1}, @theglibc{} assumes that the process memory image consists + of cacheable (non-device) memory only. The default, @code{0}, +@@ -341,8 +341,8 @@ indicates that the process may use device memory. + This tunable is specific to powerpc, powerpc64 and powerpc64le. + @end deftp + +-@deftp Tunable glibc.tune.cpu +-The @code{glibc.tune.cpu=xxx} tunable allows the user to tell @theglibc{} to ++@deftp Tunable glibc.cpu.name ++The @code{glibc.cpu.name=xxx} tunable allows the user to tell @theglibc{} to + assume that the CPU is @code{xxx} where xxx may have one of these values: + @code{generic}, @code{falkor}, @code{thunderxt88}, @code{thunderx2t99}, + @code{thunderx2t99p1}. +@@ -350,20 +350,20 @@ assume that the CPU is @code{xxx} where xxx may have one of these values: + This tunable is specific to aarch64. + @end deftp + +-@deftp Tunable glibc.tune.x86_data_cache_size +-The @code{glibc.tune.x86_data_cache_size} tunable allows the user to set ++@deftp Tunable glibc.cpu.x86_data_cache_size ++The @code{glibc.cpu.x86_data_cache_size} tunable allows the user to set + data cache size in bytes for use in memory and string routines. + + This tunable is specific to i386 and x86-64. + @end deftp + +-@deftp Tunable glibc.tune.x86_shared_cache_size +-The @code{glibc.tune.x86_shared_cache_size} tunable allows the user to ++@deftp Tunable glibc.cpu.x86_shared_cache_size ++The @code{glibc.cpu.x86_shared_cache_size} tunable allows the user to + set shared cache size in bytes for use in memory and string routines. + @end deftp + +-@deftp Tunable glibc.tune.x86_non_temporal_threshold +-The @code{glibc.tune.x86_non_temporal_threshold} tunable allows the user ++@deftp Tunable glibc.cpu.x86_non_temporal_threshold ++The @code{glibc.cpu.x86_non_temporal_threshold} tunable allows the user + to set threshold in bytes for non temporal store. Non temporal stores + give a hint to the hardware to move data directly to memory without + displacing other data from the cache. This tunable is used by some +@@ -373,8 +373,8 @@ like memmove and memcpy. + This tunable is specific to i386 and x86-64. + @end deftp + +-@deftp Tunable glibc.tune.x86_ibt +-The @code{glibc.tune.x86_ibt} tunable allows the user to control how ++@deftp Tunable glibc.cpu.x86_ibt ++The @code{glibc.cpu.x86_ibt} tunable allows the user to control how + indirect branch tracking (IBT) should be enabled. Accepted values are + @code{on}, @code{off}, and @code{permissive}. @code{on} always turns + on IBT regardless of whether IBT is enabled in the executable and its +@@ -386,8 +386,8 @@ IBT on non-CET executables and shared libraries. + This tunable is specific to i386 and x86-64. + @end deftp + +-@deftp Tunable glibc.tune.x86_shstk +-The @code{glibc.tune.x86_shstk} tunable allows the user to control how ++@deftp Tunable glibc.cpu.x86_shstk ++The @code{glibc.cpu.x86_shstk} tunable allows the user to control how + the shadow stack (SHSTK) should be enabled. Accepted values are + @code{on}, @code{off}, and @code{permissive}. @code{on} always turns on + SHSTK regardless of whether SHSTK is enabled in the executable and its +diff --git a/sysdeps/aarch64/dl-tunables.list b/sysdeps/aarch64/dl-tunables.list +index f6a88168cc5ec7e6..cfcf940ebd15a9aa 100644 +--- a/sysdeps/aarch64/dl-tunables.list ++++ b/sysdeps/aarch64/dl-tunables.list +@@ -17,8 +17,8 @@ + # . + + glibc { +- tune { +- cpu { ++ cpu { ++ name { + type: STRING + } + } +diff --git a/sysdeps/powerpc/cpu-features.c b/sysdeps/powerpc/cpu-features.c +index 955d4778a69db607..ad809b9815eb68f0 100644 +--- a/sysdeps/powerpc/cpu-features.c ++++ b/sysdeps/powerpc/cpu-features.c +@@ -30,7 +30,7 @@ init_cpu_features (struct cpu_features *cpu_features) + tunables is enable, since for this case user can explicit disable + unaligned optimizations. */ + #if HAVE_TUNABLES +- int32_t cached_memfunc = TUNABLE_GET (glibc, tune, cached_memopt, int32_t, ++ int32_t cached_memfunc = TUNABLE_GET (glibc, cpu, cached_memopt, int32_t, + NULL); + cpu_features->use_cached_memopt = (cached_memfunc > 0); + #else +diff --git a/sysdeps/powerpc/dl-tunables.list b/sysdeps/powerpc/dl-tunables.list +index d26636a16bfcd6d9..b3372555f75f8e38 100644 +--- a/sysdeps/powerpc/dl-tunables.list ++++ b/sysdeps/powerpc/dl-tunables.list +@@ -17,7 +17,7 @@ + # . + + glibc { +- tune { ++ cpu { + cached_memopt { + type: INT_32 + minval: 0 +diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c +index 39eba0186f55b5de..b4f348509eb1c6b3 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c ++++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c +@@ -57,7 +57,7 @@ init_cpu_features (struct cpu_features *cpu_features) + + #if HAVE_TUNABLES + /* Get the tunable override. */ +- const char *mcpu = TUNABLE_GET (glibc, tune, cpu, const char *, NULL); ++ const char *mcpu = TUNABLE_GET (glibc, cpu, name, const char *, NULL); + if (mcpu != NULL) + midr = get_midr_from_mcpu (mcpu); + #endif +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index d5f821e0831997ac..a936134a577e42a5 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -84,21 +84,21 @@ LDFLAGS-tst-cet-legacy-mod-6c.so = -Wl,--enable-new-dtags,-z,nodelete + ifneq (no,$(have-tunables)) + $(objpfx)tst-cet-legacy-4a: $(libdl) + $(objpfx)tst-cet-legacy-4a.out: $(objpfx)tst-cet-legacy-mod-4.so +-tst-cet-legacy-4a-ENV = GLIBC_TUNABLES=glibc.tune.x86_shstk=permissive ++tst-cet-legacy-4a-ENV = GLIBC_TUNABLES=glibc.cpu.x86_shstk=permissive + $(objpfx)tst-cet-legacy-4b: $(libdl) + $(objpfx)tst-cet-legacy-4b.out: $(objpfx)tst-cet-legacy-mod-4.so +-tst-cet-legacy-4b-ENV = GLIBC_TUNABLES=glibc.tune.x86_shstk=on ++tst-cet-legacy-4b-ENV = GLIBC_TUNABLES=glibc.cpu.x86_shstk=on + $(objpfx)tst-cet-legacy-4c: $(libdl) + $(objpfx)tst-cet-legacy-4c.out: $(objpfx)tst-cet-legacy-mod-4.so +-tst-cet-legacy-4c-ENV = GLIBC_TUNABLES=glibc.tune.x86_shstk=off ++tst-cet-legacy-4c-ENV = GLIBC_TUNABLES=glibc.cpu.x86_shstk=off + $(objpfx)tst-cet-legacy-5b: $(libdl) + $(objpfx)tst-cet-legacy-5b.out: $(objpfx)tst-cet-legacy-mod-5a.so \ + $(objpfx)tst-cet-legacy-mod-5b.so +-tst-cet-legacy-5b-ENV = GLIBC_TUNABLES=glibc.tune.x86_ibt=off:glibc.tune.x86_shstk=off ++tst-cet-legacy-5b-ENV = GLIBC_TUNABLES=glibc.cpu.x86_ibt=off:glibc.cpu.x86_shstk=off + $(objpfx)tst-cet-legacy-6b: $(libdl) + $(objpfx)tst-cet-legacy-6b.out: $(objpfx)tst-cet-legacy-mod-6a.so \ + $(objpfx)tst-cet-legacy-mod-6b.so +-tst-cet-legacy-6b-ENV = GLIBC_TUNABLES=glibc.tune.x86_ibt=off:glibc.tune.x86_shstk=off ++tst-cet-legacy-6b-ENV = GLIBC_TUNABLES=glibc.cpu.x86_ibt=off:glibc.cpu.x86_shstk=off + endif + endif + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 41f2d15fa5c8a756..3b268efbce627e6c 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -22,7 +22,7 @@ + #include + + #if HAVE_TUNABLES +-# define TUNABLE_NAMESPACE tune ++# define TUNABLE_NAMESPACE cpu + # include /* Get STDOUT_FILENO for _dl_printf. */ + # include + +@@ -424,7 +424,7 @@ no_cpuid: + + /* Reuse dl_platform, dl_hwcap and dl_hwcap_mask for x86. */ + #if !HAVE_TUNABLES && defined SHARED +- /* The glibc.tune.hwcap_mask tunable is initialized already, so no need to do ++ /* The glibc.cpu.hwcap_mask tunable is initialized already, so no need to do + this. */ + GLRO(dl_hwcap_mask) = HWCAP_IMPORTANT; + #endif +@@ -499,7 +499,7 @@ no_cpuid: + /* Disable IBT and/or SHSTK if they are enabled by kernel, but + disabled by environment variable: + +- GLIBC_TUNABLES=glibc.tune.hwcaps=-IBT,-SHSTK ++ GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK + */ + unsigned int cet_feature = 0; + if (!HAS_CPU_FEATURE (IBT)) +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 347a4b118d007fd8..4c6d08c709eea204 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -141,7 +141,7 @@ struct cpu_features + unsigned long int xsave_state_size; + /* The full state size for XSAVE when XSAVEC is disabled by + +- GLIBC_TUNABLES=glibc.tune.hwcaps=-XSAVEC_Usable ++ GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC_Usable + */ + unsigned int xsave_state_full_size; + unsigned int feature[FEATURE_INDEX_MAX]; +diff --git a/sysdeps/x86/cpu-tunables.c b/sysdeps/x86/cpu-tunables.c +index fad6726882fa7e2d..2e5d37753713e975 100644 +--- a/sysdeps/x86/cpu-tunables.c ++++ b/sysdeps/x86/cpu-tunables.c +@@ -17,7 +17,7 @@ + . */ + + #if HAVE_TUNABLES +-# define TUNABLE_NAMESPACE tune ++# define TUNABLE_NAMESPACE cpu + # include + # include + # include /* Get STDOUT_FILENO for _dl_printf. */ +@@ -116,7 +116,7 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp) + the hardware which wasn't available when the selection was made. + The environment variable: + +- GLIBC_TUNABLES=glibc.tune.hwcaps=-xxx,yyy,-zzz,.... ++ GLIBC_TUNABLES=glibc.cpu.hwcaps=-xxx,yyy,-zzz,.... + + can be used to enable CPU/ARCH feature yyy, disable CPU/ARCH feature + yyy and zzz, where the feature name is case-sensitive and has to +diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c +index ebc0d577e414c807..d481bddc27e5d7cc 100644 +--- a/sysdeps/x86/dl-cet.c ++++ b/sysdeps/x86/dl-cet.c +@@ -72,7 +72,7 @@ dl_cet_check (struct link_map *m, const char *program) + /* Enable IBT and SHSTK only if they are enabled in executable. + NB: IBT and SHSTK may be disabled by environment variable: + +- GLIBC_TUNABLES=glibc.tune.hwcaps=-IBT,-SHSTK ++ GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK + */ + enable_ibt &= (HAS_CPU_FEATURE (IBT) + && (enable_ibt_type == cet_always_on +diff --git a/sysdeps/x86/dl-tunables.list b/sysdeps/x86/dl-tunables.list +index 73886b1352316854..2a457d0eec9c3122 100644 +--- a/sysdeps/x86/dl-tunables.list ++++ b/sysdeps/x86/dl-tunables.list +@@ -17,7 +17,7 @@ + # . + + glibc { +- tune { ++ cpu { + hwcaps { + type: STRING + } +diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile +index 9f1562f1b25a2df5..d51cf03ac92ebcc2 100644 +--- a/sysdeps/x86_64/Makefile ++++ b/sysdeps/x86_64/Makefile +@@ -57,7 +57,7 @@ modules-names += x86_64/tst-x86_64mod-1 + LDFLAGS-tst-x86_64mod-1.so = -Wl,-soname,tst-x86_64mod-1.so + ifneq (no,$(have-tunables)) + # Test the state size for XSAVE when XSAVEC is disabled. +-tst-x86_64-1-ENV = GLIBC_TUNABLES=glibc.tune.hwcaps=-XSAVEC_Usable ++tst-x86_64-1-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC_Usable + endif + + $(objpfx)tst-x86_64-1: $(objpfx)x86_64/tst-x86_64mod-1.so +@@ -74,7 +74,7 @@ $(objpfx)tst-platform-1.out: $(objpfx)x86_64/tst-platformmod-2.so + # Turn off AVX512F_Usable and AVX2_Usable so that GLRO(dl_platform) is + # always set to x86_64. + tst-platform-1-ENV = LD_PRELOAD=$(objpfx)\$$PLATFORM/tst-platformmod-2.so \ +- GLIBC_TUNABLES=glibc.tune.hwcaps=-AVX512F_Usable,-AVX2_Usable ++ GLIBC_TUNABLES=glibc.cpu.hwcaps=-AVX512F_Usable,-AVX2_Usable + endif + + tests += tst-audit3 tst-audit4 tst-audit5 tst-audit6 tst-audit7 \ diff --git a/SOURCES/glibc-rh1817513-20.patch b/SOURCES/glibc-rh1817513-20.patch new file mode 100644 index 0000000..f111f46 --- /dev/null +++ b/SOURCES/glibc-rh1817513-20.patch @@ -0,0 +1,179 @@ +commit b3fbfe81961a1d14d7b54d1c9757e1f487073bcb +Author: Adhemerval Zanella +Date: Tue Feb 12 13:51:43 2019 +0100 + + elf: Test for LD_AUDIT module returning zero from la_version [BZ #24122] + + This includes the original test case from commit + 8e889c5da3c5981c5a46a93fec02de40131ac5a6 ("elf: Fix LD_AUDIT for + modules with invalid version (BZ#24122)). + +Conflicts: + elf/Makefile + (Different backport order of tests.) + +diff --git a/elf/Makefile b/elf/Makefile +index 6d1962b2e4deb871..4e1356b9172aee02 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -191,6 +191,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \ + tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \ + tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \ ++ tst-audit13 \ + tst-sonamemove-link tst-sonamemove-dlopen tst-initfinilazyfail \ + tst-dlopenfail tst-dlopenfail-2 \ + tst-filterobj tst-filterobj-dlopen tst-auxobj tst-auxobj-dlopen +@@ -300,7 +301,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin \ + tst-main1mod tst-libc_dlvsym-dso tst-absolute-sym-lib \ + tst-absolute-zero-lib tst-big-note-lib \ +- tst-sonamemove-linkmod1 \ ++ tst-audit13mod1 tst-sonamemove-linkmod1 \ + tst-sonamemove-runmod1 tst-sonamemove-runmod2 \ + tst-initlazyfailmod tst-finilazyfailmod \ + tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 \ +@@ -1428,6 +1429,10 @@ tst-audit12-ENV = LD_AUDIT=$(objpfx)tst-auditmod12.so + $(objpfx)tst-audit12mod1.so: $(objpfx)tst-audit12mod2.so + LDFLAGS-tst-audit12mod2.so = -Wl,--version-script=tst-audit12mod2.map + ++$(objpfx)tst-audit13.out: $(objpfx)tst-audit13mod1.so ++LDFLAGS-tst-audit13mod1.so = -Wl,-z,lazy ++tst-audit13-ENV = LD_AUDIT=$(objpfx)tst-audit13mod1.so ++ + # tst-sonamemove links against an older implementation of the library. + LDFLAGS-tst-sonamemove-linkmod1.so = \ + -Wl,--version-script=tst-sonamemove-linkmod1.map \ +diff --git a/elf/tst-audit13.c b/elf/tst-audit13.c +new file mode 100644 +index 0000000000000000..6f587baf581ce32c +--- /dev/null ++++ b/elf/tst-audit13.c +@@ -0,0 +1,28 @@ ++/* Check for invalid audit version (BZ#24122). ++ Copyright (C) 2019 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 ++ ++static int ++do_test (void) ++{ ++ puts ("plt call"); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-audit13mod1.c b/elf/tst-audit13mod1.c +new file mode 100644 +index 0000000000000000..cf017e235c7ae030 +--- /dev/null ++++ b/elf/tst-audit13mod1.c +@@ -0,0 +1,93 @@ ++/* Check for invalid audit version (BZ#24122). ++ Copyright (C) 2019 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 ++ ++unsigned int ++la_version (unsigned int version) ++{ ++ /* The audit specification says that a version of 0 or a version ++ greater than any version supported by the dynamic loader shall ++ cause the module to be ignored. */ ++ return 0; ++} ++ ++void ++la_activity (uintptr_t *cookie, unsigned int flag) ++{ ++ exit (EXIT_FAILURE); ++} ++ ++char * ++la_objsearch (const char *name, uintptr_t *cookie, unsigned int flag) ++{ ++ exit (EXIT_FAILURE); ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t * cookie) ++{ ++ exit (EXIT_FAILURE); ++} ++ ++void ++la_preinit (uintptr_t * cookie) ++{ ++ exit (EXIT_FAILURE); ++} ++ ++uintptr_t ++#if __ELF_NATIVE_CLASS == 32 ++la_symbind32 (Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook, ++ uintptr_t *defcook, unsigned int *flags, const char *symname) ++#else ++la_symbind64 (Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook, ++ uintptr_t *defcook, unsigned int *flags, const char *symname) ++#endif ++{ ++ exit (EXIT_FAILURE); ++} ++ ++unsigned int ++la_objclose (uintptr_t * cookie) ++{ ++ exit (EXIT_FAILURE); ++} ++ ++#include ++#if (!defined (pltenter) || !defined (pltexit) || !defined (La_regs) \ ++ || !defined (La_retval) || !defined (int_retval)) ++# error "architecture specific code needed in sysdeps/CPU/tst-audit.h" ++#endif ++ ++ElfW(Addr) ++pltenter (ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook, ++ uintptr_t *defcook, La_regs *regs, unsigned int *flags, ++ const char *symname, long int *framesizep) ++{ ++ exit (EXIT_FAILURE); ++} ++ ++unsigned int ++pltexit (ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook, ++ uintptr_t *defcook, const La_regs *inregs, La_retval *outregs, ++ const char *symname) ++{ ++ exit (EXIT_FAILURE); ++} diff --git a/SOURCES/glibc-rh1817513-21.patch b/SOURCES/glibc-rh1817513-21.patch new file mode 100644 index 0000000..c7550dc --- /dev/null +++ b/SOURCES/glibc-rh1817513-21.patch @@ -0,0 +1,29 @@ +commit 86140c6223b5d14d773cf3050ffd0d14977c2c2d +Author: Joseph Myers +Date: Wed Feb 13 13:34:24 2019 +0000 + + Avoid fall-through in test-container if execlp fails. + + One of the implicit-fallthrough warnings from compiling glibc with + -Wextra appears to indicate an actual bug: the test-container code + could fall through inappropriately if execlp returns (which only + occurs on error). This patch adds appropriate error handling in this + case to avoid that fall-through. + + Tested for x86_64. + + * support/test-container.c (recursive_remove): Use FAIL_EXIT1 if + execlp returns. + +diff --git a/support/test-container.c b/support/test-container.c +index 1d1aebeaf3412573..f0d9e3060e80bda5 100644 +--- a/support/test-container.c ++++ b/support/test-container.c +@@ -361,6 +361,7 @@ recursive_remove (char *path) + case 0: + /* Child. */ + execlp ("rm", "rm", "-rf", path, NULL); ++ FAIL_EXIT1 ("exec rm: %m"); + default: + /* Parent. */ + waitpid (child, &status, 0); diff --git a/SOURCES/glibc-rh1817513-22.patch b/SOURCES/glibc-rh1817513-22.patch new file mode 100644 index 0000000..f7b0320 --- /dev/null +++ b/SOURCES/glibc-rh1817513-22.patch @@ -0,0 +1,223 @@ +commit 77b6f5534778b5403c87fa5415625aeb4c3cbf44 +Author: Adhemerval Zanella +Date: Wed Jan 16 17:30:07 2019 +0000 + + linux: Assume clock_getres CLOCK_{PROCESS,THREAD}_CPUTIME_ID + + The Linux 3.2 clock_getres kernel code (kernel/posix-cpu-timers.c) + issued for clock_getres CLOCK_PROCESS_CPUTIME_ID (process_cpu_clock_getres) + and CLOCK_THREAD_CPUTIME_ID (thread_cpu_clock_getres) call + posix_cpu_clock_getres. And it fails on check_clock only if an invalid + clock is used (not the case) or if we pass an invalid the pid/tid in + 29 msb of clock_id (not the case either). + + This patch assumes that clock_getres syscall always support + CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID, so there is no need + to fallback to hp-timing support for _SC_MONOTONIC_CLOCK neither to issue + the syscall to certify the clock_id is supported bt the kernel. This + allows simplify the sysconf support to always use the syscall. + + it also removes ia64 itc drift check and assume kernel handles it correctly. + + Checked on aarch64-linux-gnu, x86_64-linux-gnu, and i686-linux-gnu. + + * sysdeps/unix/sysv/linux/ia64/has_cpuclock.c: Remove file. + * sysdeps/unix/sysv/linux/ia64/sysconf.c: Likewise. + * sysdeps/unix/sysv/linux/sysconf.c (has_cpuclock): Remove function. + (__sysconf): Assume kernel support for _SC_MONOTONIC_CLOCK, + _SC_CPUTIME, and _SC_THREAD_CPUTIME. + +Conflicts: + sysdeps/unix/sysv/linux/ia64/has_cpuclock.c + sysdeps/unix/sysv/linux/ia64/sysconf.c + (Removal after copyright year update.) + +diff --git a/sysdeps/unix/sysv/linux/ia64/has_cpuclock.c b/sysdeps/unix/sysv/linux/ia64/has_cpuclock.c +deleted file mode 100644 +index 75f3ef9f4d1366fb..0000000000000000 +--- a/sysdeps/unix/sysv/linux/ia64/has_cpuclock.c ++++ /dev/null +@@ -1,51 +0,0 @@ +-/* Copyright (C) 2000-2018 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 +- +-static int itc_usable; +- +-static int +-has_cpuclock (void) +-{ +- if (__builtin_expect (itc_usable == 0, 0)) +- { +- int newval = 1; +- int fd = __open_nocancel ("/proc/sal/itc_drift", O_RDONLY); +- if (__builtin_expect (fd != -1, 1)) +- { +- char buf[16]; +- /* We expect the file to contain a single digit followed by +- a newline. If the format changes we better not rely on +- the file content. */ +- if (__read_nocancel (fd, buf, sizeof buf) != 2 +- || buf[0] != '0' || buf[1] != '\n') +- newval = -1; +- +- __close_nocancel_nostatus (fd); +- } +- +- itc_usable = newval; +- } +- +- return itc_usable; +-} +diff --git a/sysdeps/unix/sysv/linux/ia64/sysconf.c b/sysdeps/unix/sysv/linux/ia64/sysconf.c +deleted file mode 100644 +index 6c39db5a4af3e15a..0000000000000000 +--- a/sysdeps/unix/sysv/linux/ia64/sysconf.c ++++ /dev/null +@@ -1,30 +0,0 @@ +-/* Get file-specific information about a file. Linux/ia64 version. +- Copyright (C) 2003-2018 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 "has_cpuclock.c" +-#define HAS_CPUCLOCK(name) (has_cpuclock () ? _POSIX_VERSION : -1) +- +- +-/* Now the generic Linux version. */ +-#include +diff --git a/sysdeps/unix/sysv/linux/sysconf.c b/sysdeps/unix/sysv/linux/sysconf.c +index 4e49ebaa7a25748c..6fab1601034e4724 100644 +--- a/sysdeps/unix/sysv/linux/sysconf.c ++++ b/sysdeps/unix/sysv/linux/sysconf.c +@@ -35,34 +35,6 @@ + static long int posix_sysconf (int name); + + +-#ifndef HAS_CPUCLOCK +-static long int +-has_cpuclock (int name) +-{ +-# if defined __NR_clock_getres || HP_TIMING_AVAIL +- /* If we have HP_TIMING, we will fall back on that if the system +- call does not work, so we support it either way. */ +-# if !HP_TIMING_AVAIL +- /* Check using the clock_getres system call. */ +- struct timespec ts; +- INTERNAL_SYSCALL_DECL (err); +- int r = INTERNAL_SYSCALL (clock_getres, err, 2, +- (name == _SC_CPUTIME +- ? CLOCK_PROCESS_CPUTIME_ID +- : CLOCK_THREAD_CPUTIME_ID), +- &ts); +- if (INTERNAL_SYSCALL_ERROR_P (r, err)) +- return -1; +-# endif +- return _POSIX_VERSION; +-# else +- return -1; +-# endif +-} +-# define HAS_CPUCLOCK(name) has_cpuclock (name) +-#endif +- +- + /* Get the value of the system variable NAME. */ + long int + __sysconf (int name) +@@ -71,29 +43,20 @@ __sysconf (int name) + + switch (name) + { +- struct rlimit rlimit; +-#ifdef __NR_clock_getres + case _SC_MONOTONIC_CLOCK: +- /* Check using the clock_getres system call. */ +- { +- struct timespec ts; +- INTERNAL_SYSCALL_DECL (err); +- int r; +- r = INTERNAL_SYSCALL (clock_getres, err, 2, CLOCK_MONOTONIC, &ts); +- return INTERNAL_SYSCALL_ERROR_P (r, err) ? -1 : _POSIX_VERSION; +- } +-#endif +- + case _SC_CPUTIME: + case _SC_THREAD_CPUTIME: +- return HAS_CPUCLOCK (name); ++ return _POSIX_VERSION; + + case _SC_ARG_MAX: +- /* Use getrlimit to get the stack limit. */ +- if (__getrlimit (RLIMIT_STACK, &rlimit) == 0) +- return MAX (legacy_ARG_MAX, rlimit.rlim_cur / 4); ++ { ++ struct rlimit rlimit; ++ /* Use getrlimit to get the stack limit. */ ++ if (__getrlimit (RLIMIT_STACK, &rlimit) == 0) ++ return MAX (legacy_ARG_MAX, rlimit.rlim_cur / 4); + +- return legacy_ARG_MAX; ++ return legacy_ARG_MAX; ++ } + + case _SC_NGROUPS_MAX: + /* Try to read the information from the /proc/sys/kernel/ngroups_max +@@ -102,11 +65,14 @@ __sysconf (int name) + break; + + case _SC_SIGQUEUE_MAX: +- if (__getrlimit (RLIMIT_SIGPENDING, &rlimit) == 0) +- return rlimit.rlim_cur; ++ { ++ struct rlimit rlimit; ++ if (__getrlimit (RLIMIT_SIGPENDING, &rlimit) == 0) ++ return rlimit.rlim_cur; + +- /* The /proc/sys/kernel/rtsig-max file contains the answer. */ +- procfname = "/proc/sys/kernel/rtsig-max"; ++ /* The /proc/sys/kernel/rtsig-max file contains the answer. */ ++ procfname = "/proc/sys/kernel/rtsig-max"; ++ } + break; + + default: diff --git a/SOURCES/glibc-rh1817513-23.patch b/SOURCES/glibc-rh1817513-23.patch new file mode 100644 index 0000000..91ccdfa --- /dev/null +++ b/SOURCES/glibc-rh1817513-23.patch @@ -0,0 +1,211 @@ +commit 359653aaacad463d916323f03c0ac3c47405aafa +Author: Adhemerval Zanella +Date: Wed Jan 16 18:10:56 2019 +0000 + + Do not use HP_TIMING_NOW for random bits + + This patch removes the HP_TIMING_BITS usage for fast random bits and replace + with clock_gettime (CLOCK_MONOTONIC). It has unspecified starting time and + nano-second accuracy, so its randomness is significantly better than + gettimeofday. + + Althoug it should incur in more overhead (specially for architecture that + support hp-timing), the symbol is also common implemented as a vDSO. + + Checked on aarch64-linux-gnu, x86_64-linux-gnu, and i686-linux-gnu. I also + checked on a i686-gnu build. + + * include/random-bits.h: New file. + * resolv/res_mkquery.c [HP_TIMING_AVAIL] (RANDOM_BITS, + (__res_context_mkquery): Remove usage hp-timing usage and replace with + random_bits. + * resolv/res_send.c [HP_TIMING_AVAIL] (nameserver_offset): Likewise. + * sysdeps/posix/tempname.c [HP_TIMING_AVAIL] (__gen_tempname): + Likewise. + +diff --git a/include/random-bits.h b/include/random-bits.h +new file mode 100644 +index 0000000000000000..a0651a5a34f80a8d +--- /dev/null ++++ b/include/random-bits.h +@@ -0,0 +1,41 @@ ++/* Fast pseudo-random bits based on clock_gettime. ++ Copyright (C) 2019 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 _RANDOM_BITS_H ++# define _RANDOM_BITS_H ++ ++#include ++#include ++ ++/* Provides fast pseudo-random bits through clock_gettime. It has unspecified ++ starting time, nano-second accuracy, its randomness is significantly better ++ than gettimeofday, and for mostly architectures it is implemented through ++ vDSO instead of a syscall. Since the source is a system clock, the upper ++ bits will have less entropy. */ ++static inline uint32_t ++random_bits (void) ++{ ++ struct timespec tv; ++ __clock_gettime (CLOCK_MONOTONIC, &tv); ++ /* Shuffle the lower bits to minimize the clock bias. */ ++ uint32_t ret = tv.tv_nsec ^ tv.tv_sec; ++ ret ^= (ret << 24) | (ret >> 8); ++ return ret; ++} ++ ++#endif +diff --git a/resolv/res_mkquery.c b/resolv/res_mkquery.c +index 213abeefadf7ece5..4471a8838b1de7ee 100644 +--- a/resolv/res_mkquery.c ++++ b/resolv/res_mkquery.c +@@ -82,6 +82,7 @@ + * SOFTWARE. + */ + ++#include + #include + #include + #include +@@ -92,12 +93,7 @@ + #include + #include + #include +- +-#include +-#include +-#if HP_TIMING_AVAIL +-# define RANDOM_BITS(Var) { uint64_t v64; HP_TIMING_NOW (v64); Var = v64; } +-#endif ++#include + + int + __res_context_mkquery (struct resolv_context *ctx, int op, const char *dname, +@@ -120,16 +116,7 @@ __res_context_mkquery (struct resolv_context *ctx, int op, const char *dname, + /* We randomize the IDs every time. The old code just incremented + by one after the initial randomization which still predictable if + the application does multiple requests. */ +- int randombits; +-#ifdef RANDOM_BITS +- RANDOM_BITS (randombits); +-#else +- struct timeval tv; +- __gettimeofday (&tv, NULL); +- randombits = (tv.tv_sec << 8) ^ tv.tv_usec; +-#endif +- +- hp->id = randombits; ++ hp->id = random_bits (); + hp->opcode = op; + hp->rd = (ctx->resp->options & RES_RECURSE) != 0; + hp->rcode = NOERROR; +diff --git a/resolv/res_send.c b/resolv/res_send.c +index ac19627634281c2f..55e7fa438e7baac1 100644 +--- a/resolv/res_send.c ++++ b/resolv/res_send.c +@@ -109,7 +109,7 @@ + #include + #include + #include +-#include ++#include + + #if PACKETSZ > 65536 + #define MAXPACKET PACKETSZ +@@ -309,15 +309,7 @@ nameserver_offset (struct __res_state *statp) + if ((offset & 1) == 0) + { + /* Initialization is required. */ +-#if HP_TIMING_AVAIL +- uint64_t ticks; +- HP_TIMING_NOW (ticks); +- offset = ticks; +-#else +- struct timeval tv; +- __gettimeofday (&tv, NULL); +- offset = ((tv.tv_sec << 8) ^ tv.tv_usec); +-#endif ++ offset = random_bits (); + /* The lowest bit is the most random. Preserve it. */ + offset <<= 1; + +diff --git a/sysdeps/posix/tempname.c b/sysdeps/posix/tempname.c +index 432262a03b6ecc23..3d26f378021680ae 100644 +--- a/sysdeps/posix/tempname.c ++++ b/sysdeps/posix/tempname.c +@@ -71,22 +71,15 @@ + #endif + + #ifdef _LIBC +-# include +-# if HP_TIMING_AVAIL +-# define RANDOM_BITS(Var) \ +- if (__glibc_unlikely (value == UINT64_C (0))) \ +- { \ +- /* If this is the first time this function is used initialize \ +- the variable we accumulate the value in to some somewhat \ +- random value. If we'd not do this programs at startup time \ +- might have a reduced set of possible names, at least on slow \ +- machines. */ \ +- struct timeval tv; \ +- __gettimeofday (&tv, NULL); \ +- value = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; \ +- } \ +- HP_TIMING_NOW (Var) +-# endif ++# include ++# define RANDOM_BITS(Var) ((Var) = random_bits ()) ++# else ++# define RANDOM_BITS(Var) \ ++ { \ ++ struct timeval tv; \ ++ __gettimeofday (&tv, NULL); \ ++ (Var) = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; \ ++ } + #endif + + /* Use the widest available unsigned type if uint64_t is not +@@ -193,8 +186,7 @@ __gen_tempname (char *tmpl, int suffixlen, int flags, int kind) + { + int len; + char *XXXXXX; +- static uint64_t value; +- uint64_t random_time_bits; ++ uint64_t value; + unsigned int count; + int fd = -1; + int save_errno = errno; +@@ -227,16 +219,8 @@ __gen_tempname (char *tmpl, int suffixlen, int flags, int kind) + XXXXXX = &tmpl[len - 6 - suffixlen]; + + /* Get some more or less random data. */ +-#ifdef RANDOM_BITS +- RANDOM_BITS (random_time_bits); +-#else +- { +- struct timeval tv; +- __gettimeofday (&tv, NULL); +- random_time_bits = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; +- } +-#endif +- value += random_time_bits ^ __getpid (); ++ RANDOM_BITS (value); ++ value ^= (uint64_t)__getpid () << 32; + + for (count = 0; count < attempts; value += 7777, ++count) + { diff --git a/SOURCES/glibc-rh1817513-24.patch b/SOURCES/glibc-rh1817513-24.patch new file mode 100644 index 0000000..3347d97 --- /dev/null +++ b/SOURCES/glibc-rh1817513-24.patch @@ -0,0 +1,702 @@ +commit 1e372ded4f83362509c8672ff501cba871bb1edc +Author: Adhemerval Zanella +Date: Thu Jan 24 12:46:59 2019 +0000 + + Refactor hp-timing rtld usage + + This patch refactor how hp-timing is used on loader code for statistics + report. The HP_TIMING_AVAIL and HP_SMALL_TIMING_AVAIL are removed and + HP_TIMING_INLINE is used instead to check for hp-timing avaliability. + For alpha, which only defines HP_SMALL_TIMING_AVAIL, the HP_TIMING_INLINE + is set iff for IS_IN(rtld). + + Checked on aarch64-linux-gnu, x86_64-linux-gnu, and i686-linux-gnu. I also + checked the builds for all afected ABIs. + + * benchtests/bench-timing.h: Replace HP_TIMING_AVAIL with + HP_TIMING_INLINE. + * nptl/descr.h: Likewise. + * elf/rtld.c (RLTD_TIMING_DECLARE, RTLD_TIMING_NOW, RTLD_TIMING_DIFF, + RTLD_TIMING_ACCUM_NT, RTLD_TIMING_SET): Define. + (dl_start_final_info, _dl_start_final, dl_main, print_statistics): + Abstract hp-timing usage with RTLD_* macros. + * sysdeps/alpha/hp-timing.h (HP_TIMING_INLINE): Define iff IS_IN(rtld). + (HP_TIMING_AVAIL, HP_SMALL_TIMING_AVAIL): Remove. + * sysdeps/generic/hp-timing.h (HP_TIMING_AVAIL, HP_SMALL_TIMING_AVAIL, + HP_TIMING_NONAVAIL): Likewise. + * sysdeps/ia64/hp-timing.h (HP_TIMING_AVAIL, HP_SMALL_TIMING_AVAIL): + Likewise. + * sysdeps/powerpc/powerpc32/power4/hp-timing.h (HP_TIMING_AVAIL, + HP_SMALL_TIMING_AVAIL): Likewise. + * sysdeps/powerpc/powerpc64/hp-timing.h (HP_TIMING_AVAIL, + HP_SMALL_TIMING_AVAIL): Likewise. + * sysdeps/sparc/sparc32/sparcv9/hp-timing.h (HP_TIMING_AVAIL, + HP_SMALL_TIMING_AVAIL): Likewise. + * sysdeps/sparc/sparc64/hp-timing.h (HP_TIMING_AVAIL, + HP_SMALL_TIMING_AVAIL): Likewise. + * sysdeps/x86/hp-timing.h (HP_TIMING_AVAIL, HP_SMALL_TIMING_AVAIL): + Likewise. + * sysdeps/generic/hp-timing-common.h: Update comment with + HP_TIMING_AVAIL removal. + +diff --git a/benchtests/bench-timing.h b/benchtests/bench-timing.h +index 96cde1e8be2e0c2f..8ba6be51d5b6d4e1 100644 +--- a/benchtests/bench-timing.h ++++ b/benchtests/bench-timing.h +@@ -21,7 +21,7 @@ + #include + #include + +-#if HP_TIMING_AVAIL && !defined USE_CLOCK_GETTIME ++#if HP_TIMING_INLINE && !defined USE_CLOCK_GETTIME + # define GL(x) _##x + # define GLRO(x) _##x + typedef hp_timing_t timing_t; +diff --git a/elf/rtld.c b/elf/rtld.c +index 375e0de8fa2e049e..ffbd8f4553bb3425 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -46,6 +46,49 @@ + + #include + ++/* Only enables rtld profiling for architectures which provides non generic ++ hp-timing support. The generic support requires either syscall ++ (clock_gettime), which will incur in extra overhead on loading time. ++ Using vDSO is also an option, but it will require extra support on loader ++ to setup the vDSO pointer before its usage. */ ++#if HP_TIMING_INLINE ++# define RLTD_TIMING_DECLARE(var, classifier,...) \ ++ classifier hp_timing_t var __VA_ARGS__ ++# define RTLD_TIMING_VAR(var) RLTD_TIMING_DECLARE (var, ) ++# define RTLD_TIMING_SET(var, value) (var) = (value) ++# define RTLD_TIMING_REF(var) &(var) ++ ++static inline void ++rtld_timer_start (hp_timing_t *var) ++{ ++ HP_TIMING_NOW (*var); ++} ++ ++static inline void ++rtld_timer_stop (hp_timing_t *var, hp_timing_t start) ++{ ++ hp_timing_t stop; ++ HP_TIMING_NOW (stop); ++ HP_TIMING_DIFF (*var, start, stop); ++} ++ ++static inline void ++rtld_timer_accum (hp_timing_t *sum, hp_timing_t start) ++{ ++ hp_timing_t stop; ++ rtld_timer_stop (&stop, start); ++ HP_TIMING_ACCUM_NT(*sum, stop); ++} ++#else ++# define RLTD_TIMING_DECLARE(var, classifier...) ++# define RTLD_TIMING_SET(var, value) ++# define RTLD_TIMING_VAR(var) ++# define RTLD_TIMING_REF(var) 0 ++# define rtld_timer_start(var) ++# define rtld_timer_stop(var, start) ++# define rtld_timer_accum(sum, start) ++#endif ++ + /* Avoid PLT use for our local calls at startup. */ + extern __typeof (__mempcpy) __mempcpy attribute_hidden; + +@@ -62,7 +105,7 @@ static void print_missing_version (int errcode, const char *objname, + const char *errsting); + + /* Print the various times we collected. */ +-static void print_statistics (hp_timing_t *total_timep); ++static void print_statistics (const hp_timing_t *total_timep); + + /* Add audit objects. */ + static void process_dl_audit (char *str); +@@ -303,11 +346,9 @@ static struct libname_list _dl_rtld_libname; + static struct libname_list _dl_rtld_libname2; + + /* Variable for statistics. */ +-#ifndef HP_TIMING_NONAVAIL +-static hp_timing_t relocate_time; +-static hp_timing_t load_time attribute_relro; +-static hp_timing_t start_time attribute_relro; +-#endif ++RLTD_TIMING_DECLARE (relocate_time, static); ++RLTD_TIMING_DECLARE (load_time, static, attribute_relro); ++RLTD_TIMING_DECLARE (start_time, static, attribute_relro); + + /* Additional definitions needed by TLS initialization. */ + #ifdef TLS_INIT_HELPER +@@ -335,9 +376,7 @@ static ElfW(Addr) _dl_start_final (void *arg); + struct dl_start_final_info + { + struct link_map l; +-#if !defined HP_TIMING_NONAVAIL && HP_TIMING_INLINE +- hp_timing_t start_time; +-#endif ++ RTLD_TIMING_VAR (start_time); + }; + static ElfW(Addr) _dl_start_final (void *arg, + struct dl_start_final_info *info); +@@ -371,16 +410,11 @@ _dl_start_final (void *arg, struct dl_start_final_info *info) + { + ElfW(Addr) start_addr; + +- if (HP_SMALL_TIMING_AVAIL) +- { +- /* If it hasn't happen yet record the startup time. */ +- if (! HP_TIMING_INLINE) +- HP_TIMING_NOW (start_time); +-#if !defined DONT_USE_BOOTSTRAP_MAP && !defined HP_TIMING_NONAVAIL +- else +- start_time = info->start_time; ++ /* If it hasn't happen yet record the startup time. */ ++ rtld_timer_start (&start_time); ++#if !defined DONT_USE_BOOTSTRAP_MAP ++ RTLD_TIMING_SET (start_time, info->start_time); + #endif +- } + + /* Transfer data about ourselves to the permanent link_map structure. */ + #ifndef DONT_USE_BOOTSTRAP_MAP +@@ -412,27 +446,11 @@ _dl_start_final (void *arg, struct dl_start_final_info *info) + entry point on the same stack we entered on. */ + start_addr = _dl_sysdep_start (arg, &dl_main); + +-#ifndef HP_TIMING_NONAVAIL +- hp_timing_t rtld_total_time; +- if (HP_SMALL_TIMING_AVAIL) +- { +- hp_timing_t end_time; +- +- /* Get the current time. */ +- HP_TIMING_NOW (end_time); +- +- /* Compute the difference. */ +- HP_TIMING_DIFF (rtld_total_time, start_time, end_time); +- } +-#endif +- + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS)) + { +-#ifndef HP_TIMING_NONAVAIL +- print_statistics (&rtld_total_time); +-#else +- print_statistics (NULL); +-#endif ++ RTLD_TIMING_VAR (rtld_total_time); ++ rtld_timer_stop (&rtld_total_time, start_time); ++ print_statistics (RTLD_TIMING_REF(rtld_total_time)); + } + + return start_addr; +@@ -457,11 +475,10 @@ _dl_start (void *arg) + #define RESOLVE_MAP(sym, version, flags) BOOTSTRAP_MAP + #include "dynamic-link.h" + +- if (HP_TIMING_INLINE && HP_SMALL_TIMING_AVAIL) + #ifdef DONT_USE_BOOTSTRAP_MAP +- HP_TIMING_NOW (start_time); ++ rtld_timer_start (&start_time); + #else +- HP_TIMING_NOW (info.start_time); ++ rtld_timer_start (&info.start_time); + #endif + + /* Partly clean the `bootstrap_map' structure up. Don't use +@@ -1078,11 +1095,6 @@ dl_main (const ElfW(Phdr) *phdr, + unsigned int i; + bool prelinked = false; + bool rtld_is_main = false; +-#ifndef HP_TIMING_NONAVAIL +- hp_timing_t start; +- hp_timing_t stop; +- hp_timing_t diff; +-#endif + void *tcbp = NULL; + + GL(dl_init_static_tls) = &_dl_nothread_init_static_tls; +@@ -1256,12 +1268,11 @@ of this helper program; chances are you did not intend to run this program.\n\ + } + else + { +- HP_TIMING_NOW (start); ++ RTLD_TIMING_VAR (start); ++ rtld_timer_start (&start); + _dl_map_object (NULL, rtld_progname, lt_executable, 0, + __RTLD_OPENEXEC, LM_ID_BASE); +- HP_TIMING_NOW (stop); +- +- HP_TIMING_DIFF (load_time, start, stop); ++ rtld_timer_stop (&load_time, start); + } + + /* Now the map for the main executable is available. */ +@@ -1664,20 +1675,18 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + + if (__glibc_unlikely (preloadlist != NULL)) + { +- HP_TIMING_NOW (start); ++ RTLD_TIMING_VAR (start); ++ rtld_timer_start (&start); + npreloads += handle_preload_list (preloadlist, main_map, "LD_PRELOAD"); +- HP_TIMING_NOW (stop); +- HP_TIMING_DIFF (diff, start, stop); +- HP_TIMING_ACCUM_NT (load_time, diff); ++ rtld_timer_accum (&load_time, start); + } + + if (__glibc_unlikely (preloadarg != NULL)) + { +- HP_TIMING_NOW (start); ++ RTLD_TIMING_VAR (start); ++ rtld_timer_start (&start); + npreloads += handle_preload_list (preloadarg, main_map, "--preload"); +- HP_TIMING_NOW (stop); +- HP_TIMING_DIFF (diff, start, stop); +- HP_TIMING_ACCUM_NT (load_time, diff); ++ rtld_timer_accum (&load_time, start); + } + + /* There usually is no ld.so.preload file, it should only be used +@@ -1737,7 +1746,8 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + file[file_size - 1] = '\0'; + } + +- HP_TIMING_NOW (start); ++ RTLD_TIMING_VAR (start); ++ rtld_timer_start (&start); + + if (file != problem) + { +@@ -1755,9 +1765,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + npreloads += do_preload (p, main_map, preload_file); + } + +- HP_TIMING_NOW (stop); +- HP_TIMING_DIFF (diff, start, stop); +- HP_TIMING_ACCUM_NT (load_time, diff); ++ rtld_timer_accum (&load_time, start); + + /* We don't need the file anymore. */ + __munmap (file, file_size); +@@ -1781,11 +1789,12 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + /* Load all the libraries specified by DT_NEEDED entries. If LD_PRELOAD + specified some libraries to load, these are inserted before the actual + dependencies in the executable's searchlist for symbol resolution. */ +- HP_TIMING_NOW (start); +- _dl_map_object_deps (main_map, preloads, npreloads, mode == trace, 0); +- HP_TIMING_NOW (stop); +- HP_TIMING_DIFF (diff, start, stop); +- HP_TIMING_ACCUM_NT (load_time, diff); ++ { ++ RTLD_TIMING_VAR (start); ++ rtld_timer_start (&start); ++ _dl_map_object_deps (main_map, preloads, npreloads, mode == trace, 0); ++ rtld_timer_accum (&load_time, start); ++ } + + /* Mark all objects as being in the global scope. */ + for (i = main_map->l_searchlist.r_nlist; i > 0; ) +@@ -2178,12 +2187,10 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + if (main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL) + { + ElfW(Rela) *conflict, *conflictend; +-#ifndef HP_TIMING_NONAVAIL +- hp_timing_t start; +- hp_timing_t stop; +-#endif + +- HP_TIMING_NOW (start); ++ RTLD_TIMING_VAR (start); ++ rtld_timer_start (&start); ++ + assert (main_map->l_info [VALIDX (DT_GNU_CONFLICTSZ)] != NULL); + conflict = (ElfW(Rela) *) + main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)]->d_un.d_ptr; +@@ -2191,8 +2198,8 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + ((char *) conflict + + main_map->l_info [VALIDX (DT_GNU_CONFLICTSZ)]->d_un.d_val); + _dl_resolve_conflicts (main_map, conflict, conflictend); +- HP_TIMING_NOW (stop); +- HP_TIMING_DIFF (relocate_time, start, stop); ++ ++ rtld_timer_stop (&relocate_time, start); + } + + +@@ -2220,15 +2227,12 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + know that because it is self-contained). */ + + int consider_profiling = GLRO(dl_profile) != NULL; +-#ifndef HP_TIMING_NONAVAIL +- hp_timing_t start; +- hp_timing_t stop; +-#endif + + /* If we are profiling we also must do lazy reloaction. */ + GLRO(dl_lazy) |= consider_profiling; + +- HP_TIMING_NOW (start); ++ RTLD_TIMING_VAR (start); ++ rtld_timer_start (&start); + unsigned i = main_map->l_searchlist.r_nlist; + while (i-- > 0) + { +@@ -2255,9 +2259,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + if (l->l_tls_blocksize != 0 && tls_init_tp_called) + _dl_add_to_slotinfo (l, true); + } +- HP_TIMING_NOW (stop); +- +- HP_TIMING_DIFF (relocate_time, start, stop); ++ rtld_timer_stop (&relocate_time, start); + + /* Now enable profiling if needed. Like the previous call, + this has to go here because the calls it makes should use the +@@ -2300,19 +2302,14 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + re-relocation, we might call a user-supplied function + (e.g. calloc from _dl_relocate_object) that uses TLS data. */ + +-#ifndef HP_TIMING_NONAVAIL +- hp_timing_t start; +- hp_timing_t stop; +- hp_timing_t add; +-#endif ++ RTLD_TIMING_VAR (start); ++ rtld_timer_start (&start); + +- HP_TIMING_NOW (start); + /* Mark the link map as not yet relocated again. */ + GL(dl_rtld_map).l_relocated = 0; + _dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0); +- HP_TIMING_NOW (stop); +- HP_TIMING_DIFF (add, start, stop); +- HP_TIMING_ACCUM_NT (relocate_time, add); ++ ++ rtld_timer_accum (&relocate_time, start); + } + + /* Do any necessary cleanups for the startup OS interface code. +@@ -2744,46 +2741,51 @@ process_envvars (enum mode *modep) + } + } + ++#if HP_TIMING_INLINE ++static void ++print_statistics_item (const char *title, hp_timing_t time, ++ hp_timing_t total) ++{ ++ char cycles[HP_TIMING_PRINT_SIZE]; ++ HP_TIMING_PRINT (cycles, sizeof (cycles), time); ++ ++ char relative[3 * sizeof (hp_timing_t) + 2]; ++ char *cp = _itoa ((1000ULL * time) / total, relative + sizeof (relative), ++ 10, 0); ++ /* Sets the decimal point. */ ++ char *wp = relative; ++ switch (relative + sizeof (relative) - cp) ++ { ++ case 3: ++ *wp++ = *cp++; ++ /* Fall through. */ ++ case 2: ++ *wp++ = *cp++; ++ /* Fall through. */ ++ case 1: ++ *wp++ = '.'; ++ *wp++ = *cp++; ++ } ++ *wp = '\0'; ++ _dl_debug_printf ("%s: %s cycles (%s%%)\n", title, cycles, relative); ++} ++#endif + + /* Print the various times we collected. */ + static void + __attribute ((noinline)) +-print_statistics (hp_timing_t *rtld_total_timep) ++print_statistics (const hp_timing_t *rtld_total_timep) + { +-#ifndef HP_TIMING_NONAVAIL +- char buf[200]; +- char *cp; +- char *wp; +- +- /* Total time rtld used. */ +- if (HP_SMALL_TIMING_AVAIL) +- { +- HP_TIMING_PRINT (buf, sizeof (buf), *rtld_total_timep); +- _dl_debug_printf ("\nruntime linker statistics:\n" +- " total startup time in dynamic loader: %s\n", buf); +- +- /* Print relocation statistics. */ +- char pbuf[30]; +- HP_TIMING_PRINT (buf, sizeof (buf), relocate_time); +- cp = _itoa ((1000ULL * relocate_time) / *rtld_total_timep, +- pbuf + sizeof (pbuf), 10, 0); +- wp = pbuf; +- switch (pbuf + sizeof (pbuf) - cp) +- { +- case 3: +- *wp++ = *cp++; +- /* Fall through. */ +- case 2: +- *wp++ = *cp++; +- /* Fall through. */ +- case 1: +- *wp++ = '.'; +- *wp++ = *cp++; +- } +- *wp = '\0'; +- _dl_debug_printf ("\ +- time needed for relocation: %s (%s%%)\n", buf, pbuf); +- } ++#if HP_TIMING_INLINE ++ { ++ char cycles[HP_TIMING_PRINT_SIZE]; ++ HP_TIMING_PRINT (cycles, sizeof (cycles), *rtld_total_timep); ++ _dl_debug_printf ("\nruntime linker statistics:\n" ++ " total startup time in dynamic loader: %s cycles\n", ++ cycles); ++ print_statistics_item (" time needed for relocation", ++ relocate_time, *rtld_total_timep); ++ } + #endif + + unsigned long int num_relative_relocations = 0; +@@ -2824,31 +2826,8 @@ print_statistics (hp_timing_t *rtld_total_timep) + GL(dl_num_cache_relocations), + num_relative_relocations); + +-#ifndef HP_TIMING_NONAVAIL +- /* Time spend while loading the object and the dependencies. */ +- if (HP_SMALL_TIMING_AVAIL) +- { +- char pbuf[30]; +- HP_TIMING_PRINT (buf, sizeof (buf), load_time); +- cp = _itoa ((1000ULL * load_time) / *rtld_total_timep, +- pbuf + sizeof (pbuf), 10, 0); +- wp = pbuf; +- switch (pbuf + sizeof (pbuf) - cp) +- { +- case 3: +- *wp++ = *cp++; +- /* Fall through. */ +- case 2: +- *wp++ = *cp++; +- /* Fall through. */ +- case 1: +- *wp++ = '.'; +- *wp++ = *cp++; +- } +- *wp = '\0'; +- _dl_debug_printf ("\ +- time needed to load objects: %s (%s%%)\n", +- buf, pbuf); +- } ++#if HP_TIMING_INLINE ++ print_statistics_item (" time needed to load objects", ++ load_time, *rtld_total_timep); + #endif + } +diff --git a/nptl/descr.h b/nptl/descr.h +index c3b81d8b27839502..98ba730bfeb7e4dd 100644 +--- a/nptl/descr.h ++++ b/nptl/descr.h +@@ -342,7 +342,7 @@ struct pthread + /* Lock for synchronizing setxid calls. */ + unsigned int setxid_futex; + +-#if HP_TIMING_AVAIL ++#if HP_TIMING_INLINE + hp_timing_t cpuclock_offset_ununsed; + #endif + +diff --git a/sysdeps/alpha/hp-timing.h b/sysdeps/alpha/hp-timing.h +index 62284e003acbca64..d6b603e2c51d1688 100644 +--- a/sysdeps/alpha/hp-timing.h ++++ b/sysdeps/alpha/hp-timing.h +@@ -17,16 +17,13 @@ + License along with the GNU C Library. If not, see + . */ + +-#ifndef _HP_TIMING_H +-#define _HP_TIMING_H 1 ++#ifndef _HP_TIMING_ALPHA_H ++#define _HP_TIMING_ALPHA_H 1 + ++#if IS_IN(rtld) + /* We always have the timestamp register, but it's got only a 4 second + range. Use it for ld.so profiling only. */ +-#define HP_TIMING_AVAIL (0) +-#define HP_SMALL_TIMING_AVAIL (1) +- +-/* We indeed have inlined functions. */ +-#define HP_TIMING_INLINE (1) ++# define HP_TIMING_INLINE (1) + + /* We use 32 bit values for the times. */ + typedef unsigned int hp_timing_t; +@@ -34,13 +31,16 @@ typedef unsigned int hp_timing_t; + /* The "rpcc" instruction returns a 32-bit counting half and a 32-bit + "virtual cycle counter displacement". Subtracting the two gives us + a virtual cycle count. */ +-#define HP_TIMING_NOW(VAR) \ ++# define HP_TIMING_NOW(VAR) \ + do { \ + unsigned long int x_; \ + asm volatile ("rpcc %0" : "=r"(x_)); \ + (VAR) = (int) (x_) - (int) (x_ >> 32); \ + } while (0) ++# include + +-#include ++#else ++# include ++#endif /* IS_IN(rtld) */ + + #endif /* hp-timing.h */ +diff --git a/sysdeps/generic/hp-timing-common.h b/sysdeps/generic/hp-timing-common.h +index 505c6bf5d2ee9395..ce338c990bd9fccd 100644 +--- a/sysdeps/generic/hp-timing-common.h ++++ b/sysdeps/generic/hp-timing-common.h +@@ -20,8 +20,6 @@ + /* In case a platform supports timers in the hardware the following macros + and types must be defined: + +- - HP_TIMING_AVAIL: test for availability. +- + - HP_TIMING_INLINE: this macro is non-zero if the functionality is not + implemented using function calls but instead uses some inlined code + which might simply consist of a few assembler instructions. We have to +@@ -47,16 +45,16 @@ + /* Accumulate ADD into SUM. No attempt is made to be thread-safe. */ + #define HP_TIMING_ACCUM_NT(Sum, Diff) ((Sum) += (Diff)) + ++#define HP_TIMING_PRINT_SIZE (3 * sizeof (hp_timing_t) + 1) ++ + /* Write a decimal representation of the timing value into the given string. */ + #define HP_TIMING_PRINT(Dest, Len, Val) \ + do { \ +- char __buf[20]; \ ++ char __buf[HP_TIMING_PRINT_SIZE]; \ + char *__dest = (Dest); \ + size_t __len = (Len); \ + char *__cp = _itoa ((Val), __buf + sizeof (__buf), 10, 0); \ + size_t __cp_len = MIN (__buf + sizeof (__buf) - __cp, __len); \ + memcpy (__dest, __cp, __cp_len); \ +- memcpy (__dest + __cp_len, " cycles", \ +- MIN (__len - __cp_len, sizeof (" cycles"))); \ + __dest[__len - 1] = '\0'; \ + } while (0) +diff --git a/sysdeps/generic/hp-timing.h b/sysdeps/generic/hp-timing.h +index e2c02c2bc0fd1564..97598099db29d69d 100644 +--- a/sysdeps/generic/hp-timing.h ++++ b/sysdeps/generic/hp-timing.h +@@ -25,8 +25,6 @@ + the system call might be too high. */ + + /* Provide dummy definitions. */ +-#define HP_TIMING_AVAIL (0) +-#define HP_SMALL_TIMING_AVAIL (0) + #define HP_TIMING_INLINE (0) + typedef int hp_timing_t; + #define HP_TIMING_NOW(var) +@@ -34,7 +32,4 @@ typedef int hp_timing_t; + #define HP_TIMING_ACCUM_NT(Sum, Diff) + #define HP_TIMING_PRINT(Buf, Len, Val) + +-/* Since this implementation is not available we tell the user about it. */ +-#define HP_TIMING_NONAVAIL 1 +- + #endif /* hp-timing.h */ +diff --git a/sysdeps/ia64/hp-timing.h b/sysdeps/ia64/hp-timing.h +index d8d1d7bf2c21f6e6..5ebbbc45746d5cf2 100644 +--- a/sysdeps/ia64/hp-timing.h ++++ b/sysdeps/ia64/hp-timing.h +@@ -20,10 +20,6 @@ + #ifndef _HP_TIMING_H + #define _HP_TIMING_H 1 + +-/* We always assume having the timestamp register. */ +-#define HP_TIMING_AVAIL (1) +-#define HP_SMALL_TIMING_AVAIL (1) +- + /* We indeed have inlined functions. */ + #define HP_TIMING_INLINE (1) + +diff --git a/sysdeps/powerpc/powerpc32/power4/hp-timing.h b/sysdeps/powerpc/powerpc32/power4/hp-timing.h +index 10efcac481349ee3..0e81f4fe6a46ab86 100644 +--- a/sysdeps/powerpc/powerpc32/power4/hp-timing.h ++++ b/sysdeps/powerpc/powerpc32/power4/hp-timing.h +@@ -20,10 +20,6 @@ + #ifndef _HP_TIMING_H + #define _HP_TIMING_H 1 + +-/* We always assume having the timestamp register. */ +-#define HP_TIMING_AVAIL (1) +-#define HP_SMALL_TIMING_AVAIL (1) +- + /* We indeed have inlined functions. */ + #define HP_TIMING_INLINE (1) + +diff --git a/sysdeps/powerpc/powerpc64/hp-timing.h b/sysdeps/powerpc/powerpc64/hp-timing.h +index c0aa3642f6ff1a42..77fe5e85bb32c163 100644 +--- a/sysdeps/powerpc/powerpc64/hp-timing.h ++++ b/sysdeps/powerpc/powerpc64/hp-timing.h +@@ -20,10 +20,6 @@ + #ifndef _HP_TIMING_H + #define _HP_TIMING_H 1 + +-/* We always assume having the timestamp register. */ +-#define HP_TIMING_AVAIL (1) +-#define HP_SMALL_TIMING_AVAIL (1) +- + /* We indeed have inlined functions. */ + #define HP_TIMING_INLINE (1) + +diff --git a/sysdeps/sparc/sparc32/sparcv9/hp-timing.h b/sysdeps/sparc/sparc32/sparcv9/hp-timing.h +index 42451966f6192bcb..aedf9c031a0daad9 100644 +--- a/sysdeps/sparc/sparc32/sparcv9/hp-timing.h ++++ b/sysdeps/sparc/sparc32/sparcv9/hp-timing.h +@@ -20,8 +20,6 @@ + #ifndef _HP_TIMING_H + #define _HP_TIMING_H 1 + +-#define HP_TIMING_AVAIL (1) +-#define HP_SMALL_TIMING_AVAIL (1) + #define HP_TIMING_INLINE (1) + + typedef unsigned long long int hp_timing_t; +diff --git a/sysdeps/sparc/sparc64/hp-timing.h b/sysdeps/sparc/sparc64/hp-timing.h +index 66325641067e1198..ee22729063745944 100644 +--- a/sysdeps/sparc/sparc64/hp-timing.h ++++ b/sysdeps/sparc/sparc64/hp-timing.h +@@ -20,8 +20,6 @@ + #ifndef _HP_TIMING_H + #define _HP_TIMING_H 1 + +-#define HP_TIMING_AVAIL (1) +-#define HP_SMALL_TIMING_AVAIL (1) + #define HP_TIMING_INLINE (1) + + typedef unsigned long int hp_timing_t; +diff --git a/sysdeps/x86/hp-timing.h b/sysdeps/x86/hp-timing.h +index 0aa6f5e3f83e0d34..4dbd2aa8af69f95e 100644 +--- a/sysdeps/x86/hp-timing.h ++++ b/sysdeps/x86/hp-timing.h +@@ -22,10 +22,6 @@ + #include + + #if MINIMUM_ISA == 686 || MINIMUM_ISA == 8664 +-/* We always assume having the timestamp register. */ +-# define HP_TIMING_AVAIL (1) +-# define HP_SMALL_TIMING_AVAIL (1) +- + /* We indeed have inlined functions. */ + # define HP_TIMING_INLINE (1) + diff --git a/SOURCES/glibc-rh1817513-25.patch b/SOURCES/glibc-rh1817513-25.patch new file mode 100644 index 0000000..91c0bf1 --- /dev/null +++ b/SOURCES/glibc-rh1817513-25.patch @@ -0,0 +1,113 @@ +commit b2af6fb2ed23930c148bae382ca85fad4d1cf32e +Author: Adhemerval Zanella +Date: Tue Apr 30 16:11:57 2019 -0300 + + elf: Fix elf/tst-pldd with --enable-hardcoded-path-in-tests (BZ#24506) + + The elf/tst-pldd (added by 1a4c27355e146 to fix BZ#18035) test does + not expect the hardcoded paths that are output by pldd when the test + is built with --enable-hardcoded-path-in-tests. Instead of showing + the ABI installed library names for loader and libc (such as + ld-linux-x86-64.so.2 and libc.so.6 for x86_64), pldd shows the default + built ld.so and libc.so. + + It makes the tests fail with an invalid expected loader/libc name. + + This patch fixes the elf-pldd test by adding the canonical ld.so and + libc.so names in the expected list of possible outputs when parsing + the result output from pldd. The test now handles both default + build and --enable-hardcoded-path-in-tests option. + + Checked on x86_64-linux-gnu (built with and without + --enable-hardcoded-path-in-tests) and i686-linux-gnu. + + * elf/tst-pldd.c (in_str_list): New function. + (do_test): Add default names for ld and libc as one option. + + Reviewed-by: Carlos O'Donell + +Conflicts: + elf/tst-pldd.c + (Original backport uses spaces instead of tabs.) + +diff --git a/elf/tst-pldd.c b/elf/tst-pldd.c +index 0f51c95935ffb2cf..40abee9efb9e7484 100644 +--- a/elf/tst-pldd.c ++++ b/elf/tst-pldd.c +@@ -20,7 +20,6 @@ + #include + #include + #include +-#include + #include + + #include +@@ -39,6 +38,15 @@ target_process (void *arg) + /* The test runs in a container because pldd does not support tracing + a binary started by the loader iself (as with testrun.sh). */ + ++static bool ++in_str_list (const char *libname, const char *const strlist[]) ++{ ++ for (const char *const *str = strlist; *str != NULL; str++) ++ if (strcmp (libname, *str) == 0) ++ return true; ++ return false; ++} ++ + static int + do_test (void) + { +@@ -82,26 +90,32 @@ do_test (void) + { + /* Ignore vDSO. */ + if (buffer[0] != '/') +- continue; +- +- /* Remove newline so baseline (buffer) can compare against the +- LD_SO and LIBC_SO macros unmodified. */ +- if (buffer[strlen(buffer)-1] == '\n') +- buffer[strlen(buffer)-1] = '\0'; +- +- if (strcmp (basename (buffer), LD_SO) == 0) +- { +- TEST_COMPARE (interpreter_found, false); +- interpreter_found = true; +- continue; +- } +- +- if (strcmp (basename (buffer), LIBC_SO) == 0) +- { +- TEST_COMPARE (libc_found, false); +- libc_found = true; +- continue; +- } ++ continue; ++ ++ /* Remove newline so baseline (buffer) can compare against the ++ LD_SO and LIBC_SO macros unmodified. */ ++ if (buffer[strlen(buffer)-1] == '\n') ++ buffer[strlen(buffer)-1] = '\0'; ++ ++ const char *libname = basename (buffer); ++ ++ /* It checks for default names in case of build configure with ++ --enable-hardcoded-path-in-tests (BZ #24506). */ ++ if (in_str_list (libname, ++ (const char *const []) { "ld.so", LD_SO, NULL })) ++ { ++ TEST_COMPARE (interpreter_found, false); ++ interpreter_found = true; ++ continue; ++ } ++ ++ if (in_str_list (libname, ++ (const char *const []) { "libc.so", LIBC_SO, NULL })) ++ { ++ TEST_COMPARE (libc_found, false); ++ libc_found = true; ++ continue; ++ } + } + TEST_COMPARE (interpreter_found, true); + TEST_COMPARE (libc_found, true); diff --git a/SOURCES/glibc-rh1817513-26.patch b/SOURCES/glibc-rh1817513-26.patch new file mode 100644 index 0000000..ff53662 --- /dev/null +++ b/SOURCES/glibc-rh1817513-26.patch @@ -0,0 +1,54 @@ +commit da2b83ef6ba6f4c974664f69e715cc85b9173938 +Author: Adhemerval Zanella +Date: Mon May 13 13:13:46 2019 -0300 + + elf: Fix tst-pldd for non-default --prefix and/or --bindir (BZ#24544) + + Use a new libsupport support_bindir_prefix instead of a hardcoded + /usr/bin to create the pldd path on container directory. + + Checked on x86_64-linux-gnu with default and non-default --prefix and + --bindir paths, as well with --enable-hardcoded-path-in-tests. + + [BZ #24544] + * elf/tst-pldd.c (do_test): Use support_bindir_prefix instead of + pre-defined value. + + Reviewed-by: DJ Delorie + +diff --git a/elf/tst-pldd.c b/elf/tst-pldd.c +index 40abee9efb9e7484..e2de31282a131166 100644 +--- a/elf/tst-pldd.c ++++ b/elf/tst-pldd.c +@@ -18,6 +18,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -28,6 +29,7 @@ + #include + #include + #include ++#include + + static void + target_process (void *arg) +@@ -60,12 +62,14 @@ do_test (void) + char pid[3 * sizeof (uint32_t) + 1]; + snprintf (pid, array_length (pid), "%d", target.pid); + +- const char prog[] = "/usr/bin/pldd"; ++ char *prog = xasprintf ("%s/pldd", support_bindir_prefix); + + pldd = support_capture_subprogram (prog, + (char *const []) { (char *) prog, pid, NULL }); + + support_capture_subprocess_check (&pldd, "pldd", 0, sc_allow_stdout); ++ ++ free (prog); + } + + /* Check 'pldd' output. The test is expected to be linked against only diff --git a/SOURCES/glibc-rh1817513-27.patch b/SOURCES/glibc-rh1817513-27.patch new file mode 100644 index 0000000..48e5930 --- /dev/null +++ b/SOURCES/glibc-rh1817513-27.patch @@ -0,0 +1,49 @@ +commit 75c51570c710aa9c6df6b7a1e131392e1408c63f +Author: Florian Weimer +Date: Mon May 20 21:08:40 2019 +0200 + + support: Expose sbindir as support_sbindir_prefix + +diff --git a/support/Makefile b/support/Makefile +index 6afaa6836c944398..65b16299573af1ed 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -178,6 +178,7 @@ CFLAGS-support_paths.c = \ + -DINSTDIR_PATH=\"$(prefix)\" \ + -DLIBDIR_PATH=\"$(libdir)\" \ + -DBINDIR_PATH=\"$(bindir)\" \ ++ -DSBINDIR_PATH=\"$(sbindir)\" \ + -DROOTSBINDIR_PATH=\"$(rootsbindir)\" + + ifeq (,$(CXX)) +diff --git a/support/support.h b/support/support.h +index 97d142e9b6f68188..121cc9e9b7c98ca6 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -109,6 +109,8 @@ extern const char support_libdir_prefix[]; + /* Corresponds to the install's bin/ directory. */ + extern const char support_bindir_prefix[]; + /* Corresponds to the install's sbin/ directory. */ ++extern const char support_sbindir_prefix[]; ++/* Corresponds to the install's sbin/ directory (without prefix). */ + extern const char support_install_rootsbindir[]; + + extern ssize_t support_copy_file_range (int, off64_t *, int, off64_t *, +diff --git a/support/support_paths.c b/support/support_paths.c +index a37a0720dc7339f0..eb2390227433aa70 100644 +--- a/support/support_paths.c ++++ b/support/support_paths.c +@@ -65,6 +65,13 @@ const char support_bindir_prefix[] = BINDIR_PATH; + # error please -DBINDIR_PATH=something in the Makefile + #endif + ++#ifdef SBINDIR_PATH ++/* Corresponds to the install's bin/ directory. */ ++const char support_sbindir_prefix[] = SBINDIR_PATH; ++#else ++# error please -DSBINDIR_PATH=something in the Makefile ++#endif ++ + #ifdef ROOTSBINDIR_PATH + /* Corresponds to the install's sbin/ directory. */ + const char support_install_rootsbindir[] = ROOTSBINDIR_PATH; diff --git a/SOURCES/glibc-rh1817513-28.patch b/SOURCES/glibc-rh1817513-28.patch new file mode 100644 index 0000000..c52ed81 --- /dev/null +++ b/SOURCES/glibc-rh1817513-28.patch @@ -0,0 +1,58 @@ +commit d039da1c00e01f8d3c3d74f439a971eb73e3045e +Author: H.J. Lu +Date: Wed Jun 26 15:07:18 2019 -0700 + + x86: Add sysdeps/x86/dl-lookupcfg.h + + Since sysdeps/i386/dl-lookupcfg.h and sysdeps/x86_64/dl-lookupcfg.h are + identical, we can replace them with sysdeps/x86/dl-lookupcfg.h. + + * sysdeps/i386/dl-lookupcfg.h: Moved to ... + * sysdeps/x86/dl-lookupcfg.h: Here. + * sysdeps/x86_64/dl-lookupcfg.h: Removed. + +Conflicts: + sysdeps/x86_64/dl-lookupcfg.h + (Removal after copyright year update.) + +diff --git a/sysdeps/i386/dl-lookupcfg.h b/sysdeps/x86/dl-lookupcfg.h +similarity index 100% +rename from sysdeps/i386/dl-lookupcfg.h +rename to sysdeps/x86/dl-lookupcfg.h +diff --git a/sysdeps/x86_64/dl-lookupcfg.h b/sysdeps/x86_64/dl-lookupcfg.h +deleted file mode 100644 +index 5399cf25abde592d..0000000000000000 +--- a/sysdeps/x86_64/dl-lookupcfg.h ++++ /dev/null +@@ -1,31 +0,0 @@ +-/* Configuration of lookup functions. +- Copyright (C) 2005-2018 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 +- . */ +- +-#define DL_UNMAP_IS_SPECIAL +- +-#include_next +- +-/* Address of protected data defined in the shared library may be +- external due to copy relocation. */ +-#define DL_EXTERN_PROTECTED_DATA +- +-struct link_map; +- +-extern void _dl_unmap (struct link_map *map) attribute_hidden; +- +-#define DL_UNMAP(map) _dl_unmap (map) diff --git a/SOURCES/glibc-rh1817513-29.patch b/SOURCES/glibc-rh1817513-29.patch new file mode 100644 index 0000000..bc9a8f4 --- /dev/null +++ b/SOURCES/glibc-rh1817513-29.patch @@ -0,0 +1,109 @@ +commit 23d2e5faf0bca6d9b31bef4aa162b95ee64cbfc6 +Author: Florian Weimer +Date: Thu Aug 15 14:37:50 2019 +0200 + + elf: Self-dlopen failure with explict loader invocation [BZ #24900] + + In case of an explicit loader invocation, ld.so essentially performs + a dlopen call to load the main executable. Since the pathname of + the executable is known at this point, it gets stored in the link + map. In regular mode, the pathname is not known and "" is used + instead. + + As a result, if a program calls dlopen on the pathname of the main + program, the dlopen call succeeds and returns a handle for the main + map. This results in an unnecessary difference between glibc + testing (without --enable-hardcoded-path-in-tests) and production + usage. + + This commit discards the names when building the link map in + _dl_new_object for the main executable, but it still determines + the origin at this point in case of an explict loader invocation. + The reason is that the specified pathname has to be used; the kernel + has a different notion of the main executable. + +Conflicts: + elf/Makefile + elf/tst-dlopen-aout.c + (Differences due to the complicated history of the test. + The new test elf/tst-dlopen-aout-container is not backported + here.) + +diff --git a/elf/dl-object.c b/elf/dl-object.c +index b37bcc1295f475f6..f6544a8fec45bdce 100644 +--- a/elf/dl-object.c ++++ b/elf/dl-object.c +@@ -57,14 +57,30 @@ struct link_map * + _dl_new_object (char *realname, const char *libname, int type, + struct link_map *loader, int mode, Lmid_t nsid) + { ++#ifdef SHARED ++ unsigned int naudit; ++ if (__glibc_unlikely ((mode & __RTLD_OPENEXEC) != 0)) ++ { ++ assert (type == lt_executable); ++ assert (nsid == LM_ID_BASE); ++ ++ /* Ignore the specified libname for the main executable. It is ++ only known with an explicit loader invocation. */ ++ libname = ""; ++ ++ /* We create the map for the executable before we know whether ++ we have auditing libraries and if yes, how many. Assume the ++ worst. */ ++ naudit = DL_NNS; ++ } ++ else ++ naudit = GLRO (dl_naudit); ++#endif ++ + size_t libname_len = strlen (libname) + 1; + struct link_map *new; + struct libname_list *newname; + #ifdef SHARED +- /* We create the map for the executable before we know whether we have +- auditing libraries and if yes, how many. Assume the worst. */ +- unsigned int naudit = GLRO(dl_naudit) ?: ((mode & __RTLD_OPENEXEC) +- ? DL_NNS : 0); + size_t audit_space = naudit * sizeof (new->l_audit[0]); + #else + # define audit_space 0 +@@ -91,8 +107,20 @@ _dl_new_object (char *realname, const char *libname, int type, + and won't get dumped during core file generation. Therefore to assist + gdb and to create more self-contained core files we adjust l_name to + point at the newly allocated copy (which will get dumped) instead of +- the ld.so rodata copy. */ +- new->l_name = *realname ? realname : (char *) newname->name + libname_len - 1; ++ the ld.so rodata copy. ++ ++ Furthermore, in case of explicit loader invocation, discard the ++ name of the main executable, to match the regular behavior, where ++ name of the executable is not known. */ ++#ifdef SHARED ++ if (*realname != '\0' && (mode & __RTLD_OPENEXEC) == 0) ++#else ++ if (*realname != '\0') ++#endif ++ new->l_name = realname; ++ else ++ new->l_name = (char *) newname->name + libname_len - 1; ++ + new->l_type = type; + /* If we set the bit now since we know it is never used we avoid + dirtying the cache line later. */ +@@ -149,7 +177,14 @@ _dl_new_object (char *realname, const char *libname, int type, + + new->l_local_scope[0] = &new->l_searchlist; + +- /* Don't try to find the origin for the main map which has the name "". */ ++ /* Determine the origin. If allocating the link map for the main ++ executable, the realname is not known and "". In this case, the ++ origin needs to be determined by other means. However, in case ++ of an explicit loader invocation, the pathname of the main ++ executable is known and needs to be processed here: From the ++ point of view of the kernel, the main executable is the ++ dynamic loader, and this would lead to a computation of the wrong ++ origin. */ + if (realname[0] != '\0') + { + size_t realname_len = strlen (realname) + 1; diff --git a/SOURCES/glibc-rh1817513-3.patch b/SOURCES/glibc-rh1817513-3.patch new file mode 100644 index 0000000..f6eccb4 --- /dev/null +++ b/SOURCES/glibc-rh1817513-3.patch @@ -0,0 +1,56 @@ +commit ae67f2e562603a0b58f59aef4f31aa33de05ba88 +Author: H.J. Lu +Date: Fri Aug 3 06:40:48 2018 -0700 + + x86: Cleanup cpu-features-offsets.sym + + Remove the unused macros. There is no code changes in libc.so nor + ld.so on i686 and x86-64. + + * sysdeps/x86/cpu-features-offsets.sym + (rtld_global_ro_offsetof): Removed. + (CPU_FEATURES_SIZE): Likewise. + (CPUID_OFFSET): Likewise. + (CPUID_SIZE): Likewise. + (CPUID_EAX_OFFSET): Likewise. + (CPUID_EBX_OFFSET): Likewise. + (CPUID_ECX_OFFSET): Likewise. + (CPUID_EDX_OFFSET): Likewise. + (FAMILY_OFFSET): Likewise. + (MODEL_OFFSET): Likewise. + (FEATURE_OFFSET): Likewise. + (FEATURE_SIZ): Likewise. + (COMMON_CPUID_INDEX_1): Likewise. + (COMMON_CPUID_INDEX_7): Likewise. + (FEATURE_INDEX_1): Likewise. + (RTLD_GLOBAL_RO_DL_X86_CPU_FEATURES_OFFSET): Updated. + +diff --git a/sysdeps/x86/cpu-features-offsets.sym b/sysdeps/x86/cpu-features-offsets.sym +index 33dd094e37f0fec7..6d03cea8e8fcdc36 100644 +--- a/sysdeps/x86/cpu-features-offsets.sym ++++ b/sysdeps/x86/cpu-features-offsets.sym +@@ -2,23 +2,5 @@ + + #include + +-#define rtld_global_ro_offsetof(mem) offsetof (struct rtld_global_ro, mem) +- +-RTLD_GLOBAL_RO_DL_X86_CPU_FEATURES_OFFSET rtld_global_ro_offsetof (_dl_x86_cpu_features) +- +-CPU_FEATURES_SIZE sizeof (struct cpu_features) +-CPUID_OFFSET offsetof (struct cpu_features, cpuid) +-CPUID_SIZE sizeof (struct cpuid_registers) +-CPUID_EAX_OFFSET offsetof (struct cpuid_registers, eax) +-CPUID_EBX_OFFSET offsetof (struct cpuid_registers, ebx) +-CPUID_ECX_OFFSET offsetof (struct cpuid_registers, ecx) +-CPUID_EDX_OFFSET offsetof (struct cpuid_registers, edx) +-FAMILY_OFFSET offsetof (struct cpu_features, family) +-MODEL_OFFSET offsetof (struct cpu_features, model) ++RTLD_GLOBAL_RO_DL_X86_CPU_FEATURES_OFFSET offsetof (struct rtld_global_ro, _dl_x86_cpu_features) + XSAVE_STATE_SIZE_OFFSET offsetof (struct cpu_features, xsave_state_size) +-FEATURE_OFFSET offsetof (struct cpu_features, feature) +-FEATURE_SIZE sizeof (unsigned int) +- +-COMMON_CPUID_INDEX_1 +-COMMON_CPUID_INDEX_7 +-FEATURE_INDEX_1 diff --git a/SOURCES/glibc-rh1817513-30.patch b/SOURCES/glibc-rh1817513-30.patch new file mode 100644 index 0000000..8fe1e89 --- /dev/null +++ b/SOURCES/glibc-rh1817513-30.patch @@ -0,0 +1,141 @@ +commit edd8d70b91e1ccef549a7c668499596cc4d56ad1 +Author: Mihailo Stojanovic +Date: Fri Aug 23 16:47:27 2019 +0000 + + [MIPS] Raise highest supported EI_ABIVERSION value [BZ #24916] + + This bumps the highest valid EI_ABIVERSION value to ABSOLUTE ABI. + + New testcase loads the symbol from the GOT with the "lb" instruction + so that the EI_ABIVERSION header field of the shared object is set + to ABSOLUTE (it doesn't actually check the value of the symbol), and + makes sure that the main executable is executed without "ABI version + invalid" error. + + Tested for all three ABIs (o32, n32, n64) using both static linker which + handles undefined weak symbols correctly [1] (and sets the EI_ABIVERSION + of the test module) and the one that doesn't (EI_ABIVERSION left as 0). + + [1] https://sourceware.org/ml/binutils/2018-07/msg00268.html + + [BZ #24916] + * sysdeps/mips/Makefile [$(subdir) = elf] (tests): Add + tst-undefined-weak. + [$(subdir) = elf] (modules-names): Add tst-undefined-weak-lib. + [$(subdir) = elf] ($(objpfx)tst-undefined-weak): Add dependency. + * sysdeps/mips/tst-undefined-weak-lib.S: New file. + * sysdeps/mips/tst-undefined-weak.c: Likewise. + * sysdeps/unix/sysv/linux/mips/ldsodefs.h (VALID_ELF_ABIVERSION): + Increment highest valid ABIVERSION value. + +diff --git a/sysdeps/mips/Makefile b/sysdeps/mips/Makefile +index 7ac6fa50311d60b7..6ad69e9ef9e88728 100644 +--- a/sysdeps/mips/Makefile ++++ b/sysdeps/mips/Makefile +@@ -82,3 +82,10 @@ $(objpfx)tst-mode-switch-2: $(shared-thread-library) + endif + endif + endif ++ ++ifeq ($(subdir),elf) ++tests += tst-undefined-weak ++modules-names += tst-undefined-weak-lib ++ ++$(objpfx)tst-undefined-weak: $(objpfx)tst-undefined-weak-lib.so ++endif +diff --git a/sysdeps/mips/tst-undefined-weak-lib.S b/sysdeps/mips/tst-undefined-weak-lib.S +new file mode 100644 +index 0000000000000000..a175ebf90e01b372 +--- /dev/null ++++ b/sysdeps/mips/tst-undefined-weak-lib.S +@@ -0,0 +1,43 @@ ++/* Undefined weak symbol loading shared module. ++ Copyright (C) 2019 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 ++ ++ .text ++ .globl x ++ .set nomips16 ++ .set nomicromips ++ .ent x ++ .type x, @function ++x: ++ .set noreorder ++#if _MIPS_SIM == _ABIO32 ++ .cpload $25 ++ jr $31 ++ lb $2,%got(a)($28) ++#else ++ .cpsetup $25,$24,x ++ lb $2,%got_disp(a)($28) ++ jr $31 ++ .cpreturn ++#endif ++ .set reorder ++ .end x ++ .size x, .-x ++ .weak a ++ .hidden a +diff --git a/sysdeps/mips/tst-undefined-weak.c b/sysdeps/mips/tst-undefined-weak.c +new file mode 100644 +index 0000000000000000..1231da6912508c19 +--- /dev/null ++++ b/sysdeps/mips/tst-undefined-weak.c +@@ -0,0 +1,28 @@ ++/* Undefined weak symbol loading main executable. ++ Copyright (C) 2019 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 ++ . */ ++ ++int *x (void); ++ ++int ++do_test (void) ++{ ++ x (); ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/unix/sysv/linux/mips/ldsodefs.h b/sysdeps/unix/sysv/linux/mips/ldsodefs.h +index 68a0a99bb1f1ec85..d2912cadabfd6877 100644 +--- a/sysdeps/unix/sysv/linux/mips/ldsodefs.h ++++ b/sysdeps/unix/sysv/linux/mips/ldsodefs.h +@@ -34,7 +34,7 @@ extern void _dl_static_init (struct link_map *map); + #undef VALID_ELF_ABIVERSION + #define VALID_ELF_ABIVERSION(osabi,ver) \ + (ver == 0 \ +- || (osabi == ELFOSABI_SYSV && ver < 4) \ ++ || (osabi == ELFOSABI_SYSV && ver < 5) \ + || (osabi == ELFOSABI_GNU && ver < LIBC_ABI_MAX)) + + #endif /* ldsodefs.h */ diff --git a/SOURCES/glibc-rh1817513-31.patch b/SOURCES/glibc-rh1817513-31.patch new file mode 100644 index 0000000..2081d6b --- /dev/null +++ b/SOURCES/glibc-rh1817513-31.patch @@ -0,0 +1,241 @@ +commit 23c1c256ae7b0f010d0fcaff60682b620887b164 +Author: Mihailo Stojanovic +Date: Thu Aug 29 20:11:42 2019 +0000 + + MIPS support for GNU hash + + This patch is a reimplementation of [1], which was submitted back in + 2015. Copyright issue has been sorted [2] last year. It proposed a new + section (.gnu.xhash) and related dynamic tag (GT_GNU_XHASH). The new + section would be virtually identical to the existing .gnu.hash except + for the translation table (xlat) which would contain correct MIPS + .dynsym indexes corresponding to the hashvals in chains. This is because + MIPS ABI imposes a different ordering of the dynsyms than the one + expected by the .gnu.hash section. Another addition would be a leading + word at the beggining of the section, which would contain the number of + entries in the translation table. + + In this patch, the new section name and dynamic tag are changed to + reflect the fact that the section should be treated as MIPS specific + (.MIPS.xhash and DT_MIPS_XHASH). + + This patch addresses the alignment issue reported in [3] which is caused + by the leading word of the .MIPS.xhash section. Leading word is now + removed in the corresponding binutils patch, and the number of entries + in the translation table is computed using DT_MIPS_SYMTABNO dynamic tag. + + Since the MIPS specific dl-lookup.c file was removed following the + initial patch submission, I opted for the definition of three new macros + in the generic ldsodefs.h. ELF_MACHINE_GNU_HASH_ADDRIDX defines the + index of the dynamic tag in the l_info array. ELF_MACHINE_HASH_SYMIDX is + used to calculate the index of a symbol in GNU hash. On MIPS, it is + defined to look up the symbol index in the translation table. + ELF_MACHINE_XHASH_SETUP is defined for MIPS only. It initializes the + .MIPS.xhash pointer in the link_map_machine struct. + + The other major change is bumping the highest EI_ABIVERSION value for + MIPS to suggest that the dynamic linker now supports GNU hash. + + The patch was tested by running the glibc testsuite for the three MIPS + ABIs (o32, n32 and n64) and for x86_64-linux-gnu. + + [1] https://sourceware.org/ml/binutils/2015-10/msg00057.html + [2] https://sourceware.org/ml/binutils/2018-03/msg00025.html + [3] https://sourceware.org/ml/binutils/2016-01/msg00006.html + + * elf/dl-addr.c (determine_info): Calculate the symbol index + using the newly defined ELF_MACHINE_HASH_SYMIDX macro. + * elf/dl-lookup.c (do_lookup_x): Ditto. + (_dl_setup_hash): Initialize MIPS xhash translation table. + * elf/elf.h (SHT_MIPS_XHASH): New define. + (DT_MIPS_XHASH): New define. + * sysdeps/generic/ldsodefs.h (ELF_MACHINE_GNU_HASH_ADDRIDX): New + define. + (ELF_MACHINE_HASH_SYMIDX): Ditto. + (ELF_MACHINE_XHASH_SETUP): Ditto. + * sysdeps/mips/ldsodefs.h (ELF_MACHINE_GNU_HASH_ADDRIDX): New + define. + (ELF_MACHINE_HASH_SYMIDX): Ditto. + (ELF_MACHINE_XHASH_SETUP): Ditto. + * sysdeps/mips/linkmap.h (struct link_map_machine): New member. + * sysdeps/unix/sysv/linux/mips/ldsodefs.h: Increment valid ABI + version. + * sysdeps/unix/sysv/linux/mips/libc-abis: New ABI version. + +diff --git a/elf/dl-addr.c b/elf/dl-addr.c +index e6c7d020945c51d2..b146fed09a46ff76 100644 +--- a/elf/dl-addr.c ++++ b/elf/dl-addr.c +@@ -42,7 +42,7 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info, + ElfW(Word) strtabsize = match->l_info[DT_STRSZ]->d_un.d_val; + + const ElfW(Sym) *matchsym = NULL; +- if (match->l_info[ADDRIDX (DT_GNU_HASH)] != NULL) ++ if (match->l_info[ELF_MACHINE_GNU_HASH_ADDRIDX] != NULL) + { + /* We look at all symbol table entries referenced by the hash + table. */ +@@ -57,6 +57,7 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info, + { + /* The hash table never references local symbols so + we can omit that test here. */ ++ symndx = ELF_MACHINE_HASH_SYMIDX (match, hasharr); + if ((symtab[symndx].st_shndx != SHN_UNDEF + || symtab[symndx].st_value != 0) + && symtab[symndx].st_shndx != SHN_ABS +@@ -65,8 +66,6 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info, + matchsym, addr) + && symtab[symndx].st_name < strtabsize) + matchsym = (ElfW(Sym) *) &symtab[symndx]; +- +- ++symndx; + } + while ((*hasharr++ & 1u) == 0); + } +diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c +index 01724a54f8840f9f..42fdaed99296137f 100644 +--- a/elf/dl-lookup.c ++++ b/elf/dl-lookup.c +@@ -432,7 +432,7 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash, + do + if (((*hasharr ^ new_hash) >> 1) == 0) + { +- symidx = hasharr - map->l_gnu_chain_zero; ++ symidx = ELF_MACHINE_HASH_SYMIDX (map, hasharr); + sym = check_match (undef_name, ref, version, flags, + type_class, &symtab[symidx], symidx, + strtab, map, &versioned_sym, +@@ -961,10 +961,10 @@ _dl_setup_hash (struct link_map *map) + { + Elf_Symndx *hash; + +- if (__glibc_likely (map->l_info[ADDRIDX (DT_GNU_HASH)] != NULL)) ++ if (__glibc_likely (map->l_info[ELF_MACHINE_GNU_HASH_ADDRIDX] != NULL)) + { + Elf32_Word *hash32 +- = (void *) D_PTR (map, l_info[ADDRIDX (DT_GNU_HASH)]); ++ = (void *) D_PTR (map, l_info[ELF_MACHINE_GNU_HASH_ADDRIDX]); + map->l_nbuckets = *hash32++; + Elf32_Word symbias = *hash32++; + Elf32_Word bitmask_nwords = *hash32++; +@@ -979,6 +979,10 @@ _dl_setup_hash (struct link_map *map) + map->l_gnu_buckets = hash32; + hash32 += map->l_nbuckets; + map->l_gnu_chain_zero = hash32 - symbias; ++ ++ /* Initialize MIPS xhash translation table. */ ++ ELF_MACHINE_XHASH_SETUP (hash32, symbias, map); ++ + return; + } + +diff --git a/elf/elf.h b/elf/elf.h +index 74f7f479ce817040..d6506ea1c7160dea 100644 +--- a/elf/elf.h ++++ b/elf/elf.h +@@ -1698,6 +1698,7 @@ typedef struct + #define SHT_MIPS_EH_REGION 0x70000027 + #define SHT_MIPS_XLATE_OLD 0x70000028 + #define SHT_MIPS_PDR_EXCEPTION 0x70000029 ++#define SHT_MIPS_XHASH 0x7000002b + + /* Legal values for sh_flags field of Elf32_Shdr. */ + +@@ -1945,7 +1946,9 @@ typedef struct + in a PIE as it stores a relative offset from the address of the tag + rather than an absolute address. */ + #define DT_MIPS_RLD_MAP_REL 0x70000035 +-#define DT_MIPS_NUM 0x36 ++/* GNU-style hash table with xlat. */ ++#define DT_MIPS_XHASH 0x70000036 ++#define DT_MIPS_NUM 0x37 + + /* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ + +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index f0185ce0d16c0f69..3bdbdd6e67dacc85 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -47,6 +47,23 @@ __BEGIN_DECLS + #define ADDRIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \ + + DT_EXTRANUM + DT_VALNUM + DT_ADDRTAGIDX (tag)) + ++/* Type of GNU hash which the machine uses. */ ++#ifndef ELF_MACHINE_GNU_HASH_ADDRIDX ++# define ELF_MACHINE_GNU_HASH_ADDRIDX ADDRIDX (DT_GNU_HASH) ++#endif ++ ++/* Calculate the index of a symbol in GNU hash. */ ++#ifndef ELF_MACHINE_HASH_SYMIDX ++# define ELF_MACHINE_HASH_SYMIDX(map, hasharr) \ ++ ((hasharr) - (map)->l_gnu_chain_zero) ++#endif ++ ++/* Setup MIPS xhash. Defined only for MIPS. */ ++#ifndef ELF_MACHINE_XHASH_SETUP ++# define ELF_MACHINE_XHASH_SETUP(hash32, symbias, map) \ ++ ((void) (hash32), (void) (symbias), (void) (map)) ++#endif ++ + /* We use this macro to refer to ELF types independent of the native wordsize. + `ElfW(TYPE)' is used in place of `Elf32_TYPE' or `Elf64_TYPE'. */ + #define ELFW(type) _ElfW (ELF, __ELF_NATIVE_CLASS, type) +diff --git a/sysdeps/mips/ldsodefs.h b/sysdeps/mips/ldsodefs.h +index c6e5ce7e660325c1..35043b7c6d416c50 100644 +--- a/sysdeps/mips/ldsodefs.h ++++ b/sysdeps/mips/ldsodefs.h +@@ -26,6 +26,21 @@ struct La_mips_32_retval; + struct La_mips_64_regs; + struct La_mips_64_retval; + ++#define ELF_MACHINE_GNU_HASH_ADDRIDX (DT_MIPS_XHASH - DT_LOPROC + DT_NUM) ++ ++/* Calculate the index of a symbol in MIPS xhash. */ ++#define ELF_MACHINE_HASH_SYMIDX(map, hasharr) \ ++ ((map)->l_mach.mips_xlat_zero[(hasharr) - (map)->l_gnu_chain_zero]) ++ ++/* Setup MIPS xhash. */ ++#define ELF_MACHINE_XHASH_SETUP(hash32, symbias, map) \ ++ do \ ++ { \ ++ (hash32) += (map)->l_info[DT_MIPS (SYMTABNO)]->d_un.d_val - (symbias); \ ++ (map)->l_mach.mips_xlat_zero = (hash32) - (symbias); \ ++ } \ ++ while (0) ++ + #define ARCH_PLTENTER_MEMBERS \ + Elf32_Addr (*mips_o32_gnu_pltenter) (Elf32_Sym *, unsigned int, \ + uintptr_t *, uintptr_t *, \ +diff --git a/sysdeps/mips/linkmap.h b/sysdeps/mips/linkmap.h +index 1fb9678a6d1625fd..1e640c3ba9bd18e4 100644 +--- a/sysdeps/mips/linkmap.h ++++ b/sysdeps/mips/linkmap.h +@@ -3,4 +3,5 @@ struct link_map_machine + ElfW(Addr) plt; /* Address of .plt */ + ElfW(Word) fpabi; /* FP ABI of the object */ + unsigned int odd_spreg; /* Does the object require odd_spreg support? */ ++ const Elf32_Word *mips_xlat_zero; /* .MIPS.xhash */ + }; +diff --git a/sysdeps/unix/sysv/linux/mips/ldsodefs.h b/sysdeps/unix/sysv/linux/mips/ldsodefs.h +index d2912cadabfd6877..03f3e12f202a0563 100644 +--- a/sysdeps/unix/sysv/linux/mips/ldsodefs.h ++++ b/sysdeps/unix/sysv/linux/mips/ldsodefs.h +@@ -34,7 +34,7 @@ extern void _dl_static_init (struct link_map *map); + #undef VALID_ELF_ABIVERSION + #define VALID_ELF_ABIVERSION(osabi,ver) \ + (ver == 0 \ +- || (osabi == ELFOSABI_SYSV && ver < 5) \ ++ || (osabi == ELFOSABI_SYSV && ver < 6) \ + || (osabi == ELFOSABI_GNU && ver < LIBC_ABI_MAX)) + + #endif /* ldsodefs.h */ +diff --git a/sysdeps/unix/sysv/linux/mips/libc-abis b/sysdeps/unix/sysv/linux/mips/libc-abis +index eaea558720f42a48..c0b67dae3ece1511 100644 +--- a/sysdeps/unix/sysv/linux/mips/libc-abis ++++ b/sysdeps/unix/sysv/linux/mips/libc-abis +@@ -16,3 +16,5 @@ UNIQUE + MIPS_O32_FP64 mips*-*-linux* + # Absolute (SHN_ABS) symbols working correctly. + ABSOLUTE ++# GNU-style hash table with translation table. ++MIPS_XHASH diff --git a/SOURCES/glibc-rh1817513-32.patch b/SOURCES/glibc-rh1817513-32.patch new file mode 100644 index 0000000..4f68439 --- /dev/null +++ b/SOURCES/glibc-rh1817513-32.patch @@ -0,0 +1,254 @@ +commit 2f9046fb059e94fe254c9a4ff5bcd52182069e44 +Author: Stefan Liebler +Date: Wed Sep 18 12:40:00 2019 +0200 + + Add UNSUPPORTED check in elf/tst-pldd. + + The testcase forks a child process and runs pldd with PID of + this child. On systems where /proc/sys/kernel/yama/ptrace_scope + differs from zero, pldd will fail with + /usr/bin/pldd: cannot attach to process 3: Operation not permitted + + This patch checks if ptrace_scope exists, is zero "classic ptrace permissions" + or one "restricted ptrace". If ptrace_scope exists and has a higher + restriction, then the test is marked as UNSUPPORTED. + + The case "restricted ptrace" is handled by rearranging the processes involved + during the test. Now we have the following process tree: + -parent: do_test (performs output checks) + --subprocess 1: pldd_process (becomes pldd via execve) + ---subprocess 2: target_process (ptraced via pldd) + + ChangeLog: + + * elf/tst-pldd.c (do_test): Add UNSUPPORTED check. + Rearrange subprocesses. + (pldd_process): New function. + * support/Makefile (libsupport-routines): Add support_ptrace. + * support/xptrace.h: New file. + * support/support_ptrace.c: Likewise. + +Conflicts: + elf/tst-pldd.c + (Original backport uses spaces instead of tabs.) + +diff --git a/elf/tst-pldd.c b/elf/tst-pldd.c +index e2de31282a131166..f381cb0fa7e6b93d 100644 +--- a/elf/tst-pldd.c ++++ b/elf/tst-pldd.c +@@ -30,6 +30,11 @@ + #include + #include + #include ++#include ++#include ++#include ++#include ++#include + + static void + target_process (void *arg) +@@ -37,6 +42,34 @@ target_process (void *arg) + pause (); + } + ++static void ++pldd_process (void *arg) ++{ ++ pid_t *target_pid_ptr = (pid_t *) arg; ++ ++ /* Create a copy of current test to check with pldd. As the ++ target_process is a child of this pldd_process, pldd is also able ++ to attach to target_process if YAMA is configured to 1 = ++ "restricted ptrace". */ ++ struct support_subprocess target = support_subprocess (target_process, NULL); ++ ++ /* Store the pid of target-process as do_test needs it in order to ++ e.g. terminate it at end of the test. */ ++ *target_pid_ptr = target.pid; ++ ++ /* Three digits per byte plus null terminator. */ ++ char pid[3 * sizeof (uint32_t) + 1]; ++ snprintf (pid, array_length (pid), "%d", target.pid); ++ ++ char *prog = xasprintf ("%s/pldd", support_bindir_prefix); ++ ++ /* Run pldd and use the pid of target_process as argument. */ ++ execve (prog, (char *const []) { (char *) prog, pid, NULL }, ++ (char *const []) { NULL }); ++ ++ FAIL_EXIT1 ("Returned from execve: errno=%d=%m\n", errno); ++} ++ + /* The test runs in a container because pldd does not support tracing + a binary started by the loader iself (as with testrun.sh). */ + +@@ -52,25 +85,22 @@ in_str_list (const char *libname, const char *const strlist[]) + static int + do_test (void) + { +- /* Create a copy of current test to check with pldd. */ +- struct support_subprocess target = support_subprocess (target_process, NULL); +- +- /* Run 'pldd' on test subprocess. */ +- struct support_capture_subprocess pldd; ++ /* Check if our subprocess can be debugged with ptrace. */ + { +- /* Three digits per byte plus null terminator. */ +- char pid[3 * sizeof (uint32_t) + 1]; +- snprintf (pid, array_length (pid), "%d", target.pid); +- +- char *prog = xasprintf ("%s/pldd", support_bindir_prefix); +- +- pldd = support_capture_subprogram (prog, +- (char *const []) { (char *) prog, pid, NULL }); ++ int ptrace_scope = support_ptrace_scope (); ++ if (ptrace_scope >= 2) ++ FAIL_UNSUPPORTED ("/proc/sys/kernel/yama/ptrace_scope >= 2"); ++ } + +- support_capture_subprocess_check (&pldd, "pldd", 0, sc_allow_stdout); ++ pid_t *target_pid_ptr = (pid_t *) xmmap (NULL, sizeof (pid_t), ++ PROT_READ | PROT_WRITE, ++ MAP_SHARED | MAP_ANONYMOUS, -1); + +- free (prog); +- } ++ /* Run 'pldd' on test subprocess which will be created in pldd_process. ++ The pid of the subprocess will be written to target_pid_ptr. */ ++ struct support_capture_subprocess pldd; ++ pldd = support_capture_subprocess (pldd_process, target_pid_ptr); ++ support_capture_subprocess_check (&pldd, "pldd", 0, sc_allow_stdout); + + /* Check 'pldd' output. The test is expected to be linked against only + loader and libc. */ +@@ -85,15 +115,15 @@ do_test (void) + /* First line is in the form of : */ + TEST_COMPARE (fscanf (out, "%u: " STRINPUT (512), &pid, buffer), 2); + +- TEST_COMPARE (pid, target.pid); ++ TEST_COMPARE (pid, *target_pid_ptr); + TEST_COMPARE (strcmp (basename (buffer), "tst-pldd"), 0); + + /* It expects only one loader and libc loaded by the program. */ + bool interpreter_found = false, libc_found = false; + while (fgets (buffer, array_length (buffer), out) != NULL) + { +- /* Ignore vDSO. */ +- if (buffer[0] != '/') ++ /* Ignore vDSO. */ ++ if (buffer[0] != '/') + continue; + + /* Remove newline so baseline (buffer) can compare against the +@@ -128,7 +158,9 @@ do_test (void) + } + + support_capture_subprocess_free (&pldd); +- support_process_terminate (&target); ++ if (kill (*target_pid_ptr, SIGKILL) != 0) ++ FAIL_EXIT1 ("Unable to kill target_process: errno=%d=%m\n", errno); ++ xmunmap (target_pid_ptr, sizeof (pid_t)); + + return 0; + } +diff --git a/support/Makefile b/support/Makefile +index 65b16299573af1ed..79d03bd6bfe02540 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -58,6 +58,7 @@ libsupport-routines = \ + support_format_hostent \ + support_format_netent \ + support_isolate_in_subprocess \ ++ support_ptrace \ + support_openpty \ + support_paths \ + support_quote_blob \ +diff --git a/support/support_ptrace.c b/support/support_ptrace.c +new file mode 100644 +index 0000000000000000..616b08cff33022ef +--- /dev/null ++++ b/support/support_ptrace.c +@@ -0,0 +1,44 @@ ++/* Support functions handling ptrace_scope. ++ Copyright (C) 2019 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 ++ ++int ++support_ptrace_scope (void) ++{ ++ int ptrace_scope = -1; ++ ++#ifdef __linux__ ++ /* YAMA may be not enabled. Otherwise it contains a value from 0 to 3: ++ - 0 classic ptrace permissions ++ - 1 restricted ptrace ++ - 2 admin-only attach ++ - 3 no attach */ ++ FILE *f = fopen ("/proc/sys/kernel/yama/ptrace_scope", "r"); ++ if (f != NULL) ++ { ++ TEST_COMPARE (fscanf (f, "%d", &ptrace_scope), 1); ++ xfclose (f); ++ } ++#endif ++ ++ return ptrace_scope; ++} +diff --git a/support/xptrace.h b/support/xptrace.h +new file mode 100644 +index 0000000000000000..7af892680578fffd +--- /dev/null ++++ b/support/xptrace.h +@@ -0,0 +1,32 @@ ++/* Support functions handling ptrace_scope. ++ Copyright (C) 2019 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 SUPPORT_PTRACE_H ++#define SUPPORT_PTRACE_H ++ ++#include ++ ++__BEGIN_DECLS ++ ++/* Return the current YAMA mode set on the machine (0 to 3) or -1 ++ if YAMA is not supported. */ ++int support_ptrace_scope (void); ++ ++__END_DECLS ++ ++#endif diff --git a/SOURCES/glibc-rh1817513-33.patch b/SOURCES/glibc-rh1817513-33.patch new file mode 100644 index 0000000..db77728 --- /dev/null +++ b/SOURCES/glibc-rh1817513-33.patch @@ -0,0 +1,29 @@ +commit 64fab3633aecc8eadc1338aa8953f8b2f37e3ebf +Author: Stefan Liebler +Date: Thu Sep 19 12:26:18 2019 +0200 + + Fix building support_ptrace.c on i686-gnu. + + On i686-gnu the build is broken: + In file included from support_ptrace.c:22: + ../include/sys/prctl.h:2:15: fatal error: sys/prctl.h: No such file or directory + #include_next + + This patch just removes the unused prctl.h inclusion. + + ChangeLog: + + * support/support_ptrace.c: Remove inclusion of sys/prctl.h. + +diff --git a/support/support_ptrace.c b/support/support_ptrace.c +index 616b08cff33022ef..a733adf2c8dfd073 100644 +--- a/support/support_ptrace.c ++++ b/support/support_ptrace.c +@@ -19,7 +19,6 @@ + #include + #include + #include +-#include + + int + support_ptrace_scope (void) diff --git a/SOURCES/glibc-rh1817513-34.patch b/SOURCES/glibc-rh1817513-34.patch new file mode 100644 index 0000000..1d8b561 --- /dev/null +++ b/SOURCES/glibc-rh1817513-34.patch @@ -0,0 +1,155 @@ +commit 4052fa22f69c0964bb42c0f13daa791617253de5 +Author: DJ Delorie +Date: Wed Oct 2 14:46:46 2019 -0400 + + Add wait-for-debugger test harness hooks + + If WAIT_FOR_DEBUGGER is set to a non-zero value in the environment, + any test that runs will print some useful gdb information and wait + for gdb to attach to it and clear the "wait_for_debugger" variable. + + Reviewed-by: Carlos O'Donell + +diff --git a/support/support_test_main.c b/support/support_test_main.c +index fa3c2e06dee5ae0f..def84d803928176b 100644 +--- a/support/support_test_main.c ++++ b/support/support_test_main.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -36,6 +37,8 @@ + #include + #include + ++#include ++ + static const struct option default_options[] = + { + TEST_DEFAULT_OPTIONS +@@ -176,10 +179,55 @@ signal_handler (int sig) + exit (1); + } + ++/* This must be volatile as it will be modified by the debugger. */ ++static volatile int wait_for_debugger = 0; ++ + /* Run test_function or test_function_argv. */ + static int + run_test_function (int argc, char **argv, const struct test_config *config) + { ++ const char *wfd = getenv("WAIT_FOR_DEBUGGER"); ++ if (wfd != NULL) ++ wait_for_debugger = atoi (wfd); ++ if (wait_for_debugger) ++ { ++ pid_t mypid; ++ FILE *gdb_script; ++ char *gdb_script_name; ++ int inside_container = 0; ++ ++ mypid = getpid(); ++ if (mypid < 3) ++ { ++ const char *outside_pid = getenv("PID_OUTSIDE_CONTAINER"); ++ if (outside_pid) ++ { ++ mypid = atoi (outside_pid); ++ inside_container = 1; ++ } ++ } ++ ++ gdb_script_name = (char *) xmalloc (strlen (argv[0]) + strlen (".gdb") + 1); ++ sprintf (gdb_script_name, "%s.gdb", argv[0]); ++ gdb_script = xfopen (gdb_script_name, "w"); ++ ++ fprintf (stderr, "Waiting for debugger, test process is pid %d\n", mypid); ++ fprintf (stderr, "gdb -x %s\n", gdb_script_name); ++ if (inside_container) ++ fprintf (gdb_script, "set sysroot %s/testroot.root\n", support_objdir_root); ++ fprintf (gdb_script, "file\n"); ++ fprintf (gdb_script, "file %s\n", argv[0]); ++ fprintf (gdb_script, "symbol-file %s\n", argv[0]); ++ fprintf (gdb_script, "exec-file %s\n", argv[0]); ++ fprintf (gdb_script, "attach %ld\n", (long int) mypid); ++ fprintf (gdb_script, "set wait_for_debugger = 0\n"); ++ fclose (gdb_script); ++ } ++ ++ /* Wait for the debugger to set wait_for_debugger to zero. */ ++ while (wait_for_debugger) ++ usleep (1000); ++ + if (config->test_function != NULL) + return config->test_function (); + else if (config->test_function_argv != NULL) +@@ -229,6 +277,11 @@ support_test_main (int argc, char **argv, const struct test_config *config) + unsigned int timeoutfactor = 1; + pid_t termpid; + ++ /* If we're debugging the test, we need to disable timeouts and use ++ the initial pid (esp if we're running inside a container). */ ++ if (getenv("WAIT_FOR_DEBUGGER") != NULL) ++ direct = 1; ++ + if (!config->no_mallopt) + { + /* Make uses of freed and uninitialized memory known. Do not +diff --git a/support/test-container.c b/support/test-container.c +index f0d9e3060e80bda5..6503cea90309b9b0 100644 +--- a/support/test-container.c ++++ b/support/test-container.c +@@ -676,6 +676,9 @@ main (int argc, char **argv) + char *so_base; + int do_postclean = 0; + ++ int pipes[2]; ++ char pid_buf[20]; ++ + uid_t original_uid; + gid_t original_gid; + /* If set, the test runs as root instead of the user running the testsuite. */ +@@ -999,6 +1002,11 @@ main (int argc, char **argv) + if (chdir (new_cwd_path) < 0) + FAIL_EXIT1 ("Can't cd to new %s - ", new_cwd_path); + ++ /* This is to pass the "outside" PID to the child, which will be PID ++ 1. */ ++ if (pipe2 (pipes, O_CLOEXEC) < 0) ++ FAIL_EXIT1 ("Can't create pid pipe"); ++ + /* To complete the containerization, we need to fork () at least + once. We can't exec, nor can we somehow link the new child to + our parent. So we run the child and propogate it's exit status +@@ -1010,6 +1018,12 @@ main (int argc, char **argv) + { + /* Parent. */ + int status; ++ ++ /* Send the child's "outside" pid to it. */ ++ write (pipes[1], &child, sizeof(child)); ++ close (pipes[0]); ++ close (pipes[1]); ++ + waitpid (child, &status, 0); + + if (WIFEXITED (status)) +@@ -1028,6 +1042,14 @@ main (int argc, char **argv) + /* The rest is the child process, which is now PID 1 and "in" the + new root. */ + ++ /* Get our "outside" pid from our parent. We use this to help with ++ debugging from outside the container. */ ++ read (pipes[0], &child, sizeof(child)); ++ close (pipes[0]); ++ close (pipes[1]); ++ sprintf (pid_buf, "%lu", (long unsigned)child); ++ setenv ("PID_OUTSIDE_CONTAINER", pid_buf, 0); ++ + maybe_xmkdir ("/tmp", 0755); + + /* Now that we're pid 1 (effectively "root") we can mount /proc */ diff --git a/SOURCES/glibc-rh1817513-35.patch b/SOURCES/glibc-rh1817513-35.patch new file mode 100644 index 0000000..4cea796 --- /dev/null +++ b/SOURCES/glibc-rh1817513-35.patch @@ -0,0 +1,421 @@ +commit c7bf5ceab6ec776ac7350d3b0190776bf532ac54 +Author: Florian Weimer +Date: Sat Nov 2 21:55:35 2019 +0100 + + Properly initialize audit cookie for the dynamic loader [BZ #25157] + + The l_audit array is indexed by audit module, not audit function. + + Change-Id: I180eb3573dc1c57433750f5d8cb18271460ba5f2 + +Conflicts: + elf/Makefile + (Test backport differences.) + +diff --git a/elf/Makefile b/elf/Makefile +index 4e1356b9172aee02..4ab73dc48d9ac126 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -192,7 +192,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \ + tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \ + tst-audit13 \ +- tst-sonamemove-link tst-sonamemove-dlopen tst-initfinilazyfail \ ++ tst-sonamemove-link tst-sonamemove-dlopen \ ++ tst-auditmany tst-initfinilazyfail \ + tst-dlopenfail tst-dlopenfail-2 \ + tst-filterobj tst-filterobj-dlopen tst-auxobj tst-auxobj-dlopen + # reldep9 +@@ -303,6 +304,9 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-absolute-zero-lib tst-big-note-lib \ + tst-audit13mod1 tst-sonamemove-linkmod1 \ + tst-sonamemove-runmod1 tst-sonamemove-runmod2 \ ++ tst-auditmanymod1 tst-auditmanymod2 tst-auditmanymod3 \ ++ tst-auditmanymod4 tst-auditmanymod5 tst-auditmanymod6 \ ++ tst-auditmanymod7 tst-auditmanymod8 tst-auditmanymod9 \ + tst-initlazyfailmod tst-finilazyfailmod \ + tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 \ + tst-dlopenfailmod3 \ +@@ -1433,6 +1437,14 @@ $(objpfx)tst-audit13.out: $(objpfx)tst-audit13mod1.so + LDFLAGS-tst-audit13mod1.so = -Wl,-z,lazy + tst-audit13-ENV = LD_AUDIT=$(objpfx)tst-audit13mod1.so + ++$(objpfx)tst-auditmany.out: $(objpfx)tst-auditmanymod1.so \ ++ $(objpfx)tst-auditmanymod2.so $(objpfx)tst-auditmanymod3.so \ ++ $(objpfx)tst-auditmanymod4.so $(objpfx)tst-auditmanymod5.so \ ++ $(objpfx)tst-auditmanymod6.so $(objpfx)tst-auditmanymod7.so \ ++ $(objpfx)tst-auditmanymod8.so $(objpfx)tst-auditmanymod9.so ++tst-auditmany-ENV = \ ++ LD_AUDIT=tst-auditmanymod1.so:tst-auditmanymod2.so:tst-auditmanymod3.so:tst-auditmanymod4.so:tst-auditmanymod5.so:tst-auditmanymod6.so:tst-auditmanymod7.so:tst-auditmanymod8.so:tst-auditmanymod9.so ++ + # tst-sonamemove links against an older implementation of the library. + LDFLAGS-tst-sonamemove-linkmod1.so = \ + -Wl,--version-script=tst-sonamemove-linkmod1.map \ +diff --git a/elf/rtld.c b/elf/rtld.c +index ffbd8f4553bb3425..f557f39a70669c09 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -1008,13 +1008,7 @@ ERROR: audit interface '%s' requires version %d (maximum supported version %d); + + /* Store the pointer. */ + if (err_str == NULL && largs.result != NULL) +- { +- newp->fptr[cnt] = largs.result; +- +- /* The dynamic linker link map is statically allocated, +- initialize the data now. */ +- GL(dl_rtld_map).l_audit[cnt].cookie = (intptr_t) &GL(dl_rtld_map); +- } ++ newp->fptr[cnt] = largs.result; + else + newp->fptr[cnt] = NULL; + ++cnt; +@@ -1030,6 +1024,12 @@ ERROR: audit interface '%s' requires version %d (maximum supported version %d); + *last_audit = GLRO(dl_audit) = &newp->ifaces; + else + *last_audit = (*last_audit)->next = &newp->ifaces; ++ ++ /* The dynamic linker link map is statically allocated, initialize ++ the data now. */ ++ GL (dl_rtld_map).l_audit[GLRO (dl_naudit)].cookie ++ = (intptr_t) &GL (dl_rtld_map); ++ + ++GLRO(dl_naudit); + + /* Mark the DSO as being used for auditing. */ +diff --git a/elf/tst-auditmany.c b/elf/tst-auditmany.c +new file mode 100644 +index 0000000000000000..9d68105b9e707b46 +--- /dev/null ++++ b/elf/tst-auditmany.c +@@ -0,0 +1,26 @@ ++/* Check cookie initialization for many auditors. Main program. ++ Copyright (C) 2019 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 ++ . */ ++ ++/* It does not make sense to use the test harness for this test ++ because the testing happens in auditors. */ ++ ++int ++main (void) ++{ ++ return 0; ++} +diff --git a/elf/tst-auditmanymod.h b/elf/tst-auditmanymod.h +new file mode 100644 +index 0000000000000000..d1d89e08431ce32f +--- /dev/null ++++ b/elf/tst-auditmanymod.h +@@ -0,0 +1,64 @@ ++/* Check cookie initialization for many auditors. Auditor template. ++ Copyright (C) 2019 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 ++ . */ ++ ++/* The macro MOD must be defined to the number of this auditor (an ++ integer) before including this file. */ ++ ++#include ++#include ++#include ++ ++/* Error counter for delayed error reporting. */ ++static int errors; ++ ++unsigned int ++la_version (unsigned int version) ++{ ++ return version; ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, ++ uintptr_t *cookie) ++{ ++ struct link_map *cookie_map = (struct link_map *) *cookie; ++ printf ("info: %d, la_objopen: map=%p name=%s cookie=%p:%p diff=%td\n", ++ MOD, map, map->l_name, cookie, cookie_map, ++ (char *) cookie - (char *) map); ++ fflush (stdout); ++ if (map != cookie_map) ++ { ++ printf ("error: %d, la_objopen:" ++ " map address does not match cookie value\n", ++ MOD); ++ fflush (stdout); ++ ++errors; ++ } ++ return 0; ++} ++ ++extern unsigned int ++la_objclose (uintptr_t *__cookie) ++{ ++ if (errors != 0) ++ { ++ printf ("error: exiting due to previous errors"); ++ _exit (1); ++ } ++ return 0; ++} +diff --git a/elf/tst-auditmanymod1.c b/elf/tst-auditmanymod1.c +new file mode 100644 +index 0000000000000000..c7de49d446a7e52d +--- /dev/null ++++ b/elf/tst-auditmanymod1.c +@@ -0,0 +1,20 @@ ++/* Check cookie initialization for many auditors. Auditor 1. ++ Copyright (C) 2019 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 ++ . */ ++ ++#define MOD 1 ++#include "tst-auditmanymod.h" +diff --git a/elf/tst-auditmanymod2.c b/elf/tst-auditmanymod2.c +new file mode 100644 +index 0000000000000000..4254f022a177b844 +--- /dev/null ++++ b/elf/tst-auditmanymod2.c +@@ -0,0 +1,20 @@ ++/* Check cookie initialization for many auditors. Auditor 2. ++ Copyright (C) 2019 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 ++ . */ ++ ++#define MOD 2 ++#include "tst-auditmanymod.h" +diff --git a/elf/tst-auditmanymod3.c b/elf/tst-auditmanymod3.c +new file mode 100644 +index 0000000000000000..ee90f4eb3a5c1b35 +--- /dev/null ++++ b/elf/tst-auditmanymod3.c +@@ -0,0 +1,20 @@ ++/* Check cookie initialization for many auditors. Auditor 3. ++ Copyright (C) 2019 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 ++ . */ ++ ++#define MOD 3 ++#include "tst-auditmanymod.h" +diff --git a/elf/tst-auditmanymod4.c b/elf/tst-auditmanymod4.c +new file mode 100644 +index 0000000000000000..6379fa1d55014998 +--- /dev/null ++++ b/elf/tst-auditmanymod4.c +@@ -0,0 +1,20 @@ ++/* Check cookie initialization for many auditors. Auditor 4. ++ Copyright (C) 2019 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 ++ . */ ++ ++#define MOD 4 ++#include "tst-auditmanymod.h" +diff --git a/elf/tst-auditmanymod5.c b/elf/tst-auditmanymod5.c +new file mode 100644 +index 0000000000000000..17c0f617aa4d1893 +--- /dev/null ++++ b/elf/tst-auditmanymod5.c +@@ -0,0 +1,20 @@ ++/* Check cookie initialization for many auditors. Auditor 5. ++ Copyright (C) 2019 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 ++ . */ ++ ++#define MOD 5 ++#include "tst-auditmanymod.h" +diff --git a/elf/tst-auditmanymod6.c b/elf/tst-auditmanymod6.c +new file mode 100644 +index 0000000000000000..86bc6801a4454742 +--- /dev/null ++++ b/elf/tst-auditmanymod6.c +@@ -0,0 +1,20 @@ ++/* Check cookie initialization for many auditors. Auditor 6. ++ Copyright (C) 2019 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 ++ . */ ++ ++#define MOD 6 ++#include "tst-auditmanymod.h" +diff --git a/elf/tst-auditmanymod7.c b/elf/tst-auditmanymod7.c +new file mode 100644 +index 0000000000000000..92b0bf6006876dff +--- /dev/null ++++ b/elf/tst-auditmanymod7.c +@@ -0,0 +1,20 @@ ++/* Check cookie initialization for many auditors. Auditor 7. ++ Copyright (C) 2019 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 ++ . */ ++ ++#define MOD 7 ++#include "tst-auditmanymod.h" +diff --git a/elf/tst-auditmanymod8.c b/elf/tst-auditmanymod8.c +new file mode 100644 +index 0000000000000000..d42f884d2f24f4c0 +--- /dev/null ++++ b/elf/tst-auditmanymod8.c +@@ -0,0 +1,20 @@ ++/* Check cookie initialization for many auditors. Auditor 8. ++ Copyright (C) 2019 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 ++ . */ ++ ++#define MOD 8 ++#include "tst-auditmanymod.h" +diff --git a/elf/tst-auditmanymod9.c b/elf/tst-auditmanymod9.c +new file mode 100644 +index 0000000000000000..6bee81d69c6d3c22 +--- /dev/null ++++ b/elf/tst-auditmanymod9.c +@@ -0,0 +1,20 @@ ++/* Check cookie initialization for many auditors. Auditor 9. ++ Copyright (C) 2019 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 ++ . */ ++ ++#define MOD 9 ++#include "tst-auditmanymod.h" diff --git a/SOURCES/glibc-rh1817513-36.patch b/SOURCES/glibc-rh1817513-36.patch new file mode 100644 index 0000000..a7ac8c7 --- /dev/null +++ b/SOURCES/glibc-rh1817513-36.patch @@ -0,0 +1,340 @@ +commit e1d559f337de2c8ab68a6749dfe873477c883807 +Author: Florian Weimer +Date: Sat Nov 2 20:04:02 2019 +0100 + + Introduce link_map_audit_state accessor function + + To improve GCC 10 compatibility, it is necessary to remove the l_audit + zero-length array from the end of struct link_map. In preparation of + that, this commit introduces an accessor function for the audit state, + so that it is possible to change the representation of the audit state + without adjusting the code that accesses it. + + Tested on x86_64-linux-gnu. Built on i686-gnu. + + Change-Id: Id815673c29950fc011ae5301d7cde12624f658df + +diff --git a/csu/libc-start.c b/csu/libc-start.c +index 494132368f8fe486..dfbf195328239a17 100644 +--- a/csu/libc-start.c ++++ b/csu/libc-start.c +@@ -272,7 +272,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) + { + if (afct->preinit != NULL) +- afct->preinit (&head->l_audit[cnt].cookie); ++ afct->preinit (&link_map_audit_state (head, cnt)->cookie); + + afct = afct->next; + } +diff --git a/elf/dl-close.c b/elf/dl-close.c +index a9ecdff62dba88fb..1ece0ae1dd062d1e 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -305,8 +305,12 @@ _dl_close_worker (struct link_map *map, bool force) + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) + { + if (afct->objclose != NULL) +- /* Return value is ignored. */ +- (void) afct->objclose (&imap->l_audit[cnt].cookie); ++ { ++ struct auditstate *state ++ = link_map_audit_state (imap, cnt); ++ /* Return value is ignored. */ ++ (void) afct->objclose (&state->cookie); ++ } + + afct = afct->next; + } +@@ -481,7 +485,10 @@ _dl_close_worker (struct link_map *map, bool force) + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) + { + if (afct->activity != NULL) +- afct->activity (&head->l_audit[cnt].cookie, LA_ACT_DELETE); ++ { ++ struct auditstate *state = link_map_audit_state (head, cnt); ++ afct->activity (&state->cookie, LA_ACT_DELETE); ++ } + + afct = afct->next; + } +@@ -781,7 +788,10 @@ _dl_close_worker (struct link_map *map, bool force) + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) + { + if (afct->activity != NULL) +- afct->activity (&head->l_audit[cnt].cookie, LA_ACT_CONSISTENT); ++ { ++ struct auditstate *state = link_map_audit_state (head, cnt); ++ afct->activity (&state->cookie, LA_ACT_CONSISTENT); ++ } + + afct = afct->next; + } +diff --git a/elf/dl-fini.c b/elf/dl-fini.c +index 3cfc262400da4db9..915ceb104e1c81d6 100644 +--- a/elf/dl-fini.c ++++ b/elf/dl-fini.c +@@ -152,9 +152,12 @@ _dl_fini (void) + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) + { + if (afct->objclose != NULL) +- /* Return value is ignored. */ +- (void) afct->objclose (&l->l_audit[cnt].cookie); +- ++ { ++ struct auditstate *state ++ = link_map_audit_state (l, cnt); ++ /* Return value is ignored. */ ++ (void) afct->objclose (&state->cookie); ++ } + afct = afct->next; + } + } +diff --git a/elf/dl-load.c b/elf/dl-load.c +index b190b28e32e47391..8f8869ff524ab9f2 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -979,7 +979,8 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) + { + if (afct->activity != NULL) +- afct->activity (&head->l_audit[cnt].cookie, LA_ACT_ADD); ++ afct->activity (&link_map_audit_state (head, cnt)->cookie, ++ LA_ACT_ADD); + + afct = afct->next; + } +@@ -1418,10 +1419,9 @@ cannot enable executable stack as shared object requires"); + { + if (afct->objopen != NULL) + { +- l->l_audit[cnt].bindflags +- = afct->objopen (l, nsid, &l->l_audit[cnt].cookie); +- +- l->l_audit_any_plt |= l->l_audit[cnt].bindflags != 0; ++ struct auditstate *state = link_map_audit_state (l, cnt); ++ state->bindflags = afct->objopen (l, nsid, &state->cookie); ++ l->l_audit_any_plt |= state->bindflags != 0; + } + + afct = afct->next; +@@ -1527,8 +1527,8 @@ open_verify (const char *name, int fd, + { + if (afct->objsearch != NULL) + { +- name = afct->objsearch (name, &loader->l_audit[cnt].cookie, +- whatcode); ++ struct auditstate *state = link_map_audit_state (loader, cnt); ++ name = afct->objsearch (name, &state->cookie, whatcode); + if (name == NULL) + /* Ignore the path. */ + return -1; +@@ -1998,8 +1998,8 @@ _dl_map_object (struct link_map *loader, const char *name, + if (afct->objsearch != NULL) + { + const char *before = name; +- name = afct->objsearch (name, &loader->l_audit[cnt].cookie, +- LA_SER_ORIG); ++ struct auditstate *state = link_map_audit_state (loader, cnt); ++ name = afct->objsearch (name, &state->cookie, LA_SER_ORIG); + if (name == NULL) + { + /* Do not try anything further. */ +diff --git a/elf/dl-object.c b/elf/dl-object.c +index f6544a8fec45bdce..05a7750c65305771 100644 +--- a/elf/dl-object.c ++++ b/elf/dl-object.c +@@ -81,7 +81,7 @@ _dl_new_object (char *realname, const char *libname, int type, + struct link_map *new; + struct libname_list *newname; + #ifdef SHARED +- size_t audit_space = naudit * sizeof (new->l_audit[0]); ++ size_t audit_space = naudit * sizeof (struct auditstate); + #else + # define audit_space 0 + #endif +@@ -134,10 +134,8 @@ _dl_new_object (char *realname, const char *libname, int type, + + #ifdef SHARED + for (unsigned int cnt = 0; cnt < naudit; ++cnt) +- { +- new->l_audit[cnt].cookie = (uintptr_t) new; +- /* new->l_audit[cnt].bindflags = 0; */ +- } ++ /* No need to initialize bindflags due to calloc. */ ++ link_map_audit_state (new, cnt)->cookie = (uintptr_t) new; + #endif + + /* new->l_global = 0; We use calloc therefore not necessary. */ +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 46a4c1e5a3f8d2dd..7113c4a04f0fddbc 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -589,7 +589,10 @@ dl_open_worker (void *a) + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) + { + if (afct->activity != NULL) +- afct->activity (&head->l_audit[cnt].cookie, LA_ACT_CONSISTENT); ++ { ++ struct auditstate *state = link_map_audit_state (head, cnt); ++ afct->activity (&state->cookie, LA_ACT_CONSISTENT); ++ } + + afct = afct->next; + } +diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c +index 3d2f4a7a76e616e3..72b03e000dcf190e 100644 +--- a/elf/dl-runtime.c ++++ b/elf/dl-runtime.c +@@ -325,15 +325,18 @@ _dl_profile_fixup ( + { + /* XXX Check whether both DSOs must request action or + only one */ +- if ((l->l_audit[cnt].bindflags & LA_FLG_BINDFROM) != 0 +- && (result->l_audit[cnt].bindflags & LA_FLG_BINDTO) != 0) ++ struct auditstate *l_state = link_map_audit_state (l, cnt); ++ struct auditstate *result_state ++ = link_map_audit_state (result, cnt); ++ if ((l_state->bindflags & LA_FLG_BINDFROM) != 0 ++ && (result_state->bindflags & LA_FLG_BINDTO) != 0) + { + if (afct->symbind != NULL) + { + uintptr_t new_value + = afct->symbind (&sym, reloc_result->boundndx, +- &l->l_audit[cnt].cookie, +- &result->l_audit[cnt].cookie, ++ &l_state->cookie, ++ &result_state->cookie, + &flags, + strtab2 + defsym->st_name); + if (new_value != (uintptr_t) sym.st_value) +@@ -421,10 +424,13 @@ _dl_profile_fixup ( + & (LA_SYMB_NOPLTENTER << (2 * (cnt + 1)))) == 0) + { + long int new_framesize = -1; ++ struct auditstate *l_state = link_map_audit_state (l, cnt); ++ struct auditstate *bound_state ++ = link_map_audit_state (reloc_result->bound, cnt); + uintptr_t new_value + = afct->ARCH_LA_PLTENTER (&sym, reloc_result->boundndx, +- &l->l_audit[cnt].cookie, +- &reloc_result->bound->l_audit[cnt].cookie, ++ &l_state->cookie, ++ &bound_state->cookie, + regs, &flags, symname, + &new_framesize); + if (new_value != (uintptr_t) sym.st_value) +@@ -504,9 +510,11 @@ _dl_call_pltexit (struct link_map *l, ElfW(Word) reloc_arg, + && (reloc_result->enterexit + & (LA_SYMB_NOPLTEXIT >> (2 * cnt))) == 0) + { ++ struct auditstate *l_state = link_map_audit_state (l, cnt); ++ struct auditstate *bound_state ++ = link_map_audit_state (reloc_result->bound, cnt); + afct->ARCH_LA_PLTEXIT (&sym, reloc_result->boundndx, +- &l->l_audit[cnt].cookie, +- &reloc_result->bound->l_audit[cnt].cookie, ++ &l_state->cookie, &bound_state->cookie, + inregs, outregs, symname); + } + +diff --git a/elf/dl-sym.c b/elf/dl-sym.c +index 189628adc05aedf1..286cf7e27fd59f20 100644 +--- a/elf/dl-sym.c ++++ b/elf/dl-sym.c +@@ -198,17 +198,20 @@ RTLD_NEXT used in code not dynamically loaded")); + + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) + { ++ struct auditstate *match_audit ++ = link_map_audit_state (match, cnt); ++ struct auditstate *result_audit ++ = link_map_audit_state (result, cnt); + if (afct->symbind != NULL +- && ((match->l_audit[cnt].bindflags & LA_FLG_BINDFROM) +- != 0 +- || ((result->l_audit[cnt].bindflags & LA_FLG_BINDTO) ++ && ((match_audit->bindflags & LA_FLG_BINDFROM) != 0 ++ || ((result_audit->bindflags & LA_FLG_BINDTO) + != 0))) + { + unsigned int flags = altvalue | LA_SYMB_DLSYM; + uintptr_t new_value + = afct->symbind (&sym, ndx, +- &match->l_audit[cnt].cookie, +- &result->l_audit[cnt].cookie, ++ &match_audit->cookie, ++ &result_audit->cookie, + &flags, strtab + ref->st_name); + if (new_value != (uintptr_t) sym.st_value) + { +diff --git a/elf/rtld.c b/elf/rtld.c +index f557f39a70669c09..18335bc666f2b89d 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -1025,9 +1025,9 @@ ERROR: audit interface '%s' requires version %d (maximum supported version %d); + else + *last_audit = (*last_audit)->next = &newp->ifaces; + +- /* The dynamic linker link map is statically allocated, initialize +- the data now. */ +- GL (dl_rtld_map).l_audit[GLRO (dl_naudit)].cookie ++ /* The dynamic linker link map is statically allocated, so the ++ cookie in _dl_new_object has not happened. */ ++ link_map_audit_state (&GL (dl_rtld_map), GLRO (dl_naudit))->cookie + = (intptr_t) &GL (dl_rtld_map); + + ++GLRO(dl_naudit); +@@ -1046,9 +1046,9 @@ notify_audit_modules_of_loaded_object (struct link_map *map) + { + if (afct->objopen != NULL) + { +- map->l_audit[cnt].bindflags +- = afct->objopen (map, LM_ID_BASE, &map->l_audit[cnt].cookie); +- map->l_audit_any_plt |= map->l_audit[cnt].bindflags != 0; ++ struct auditstate *state = link_map_audit_state (map, cnt); ++ state->bindflags = afct->objopen (map, LM_ID_BASE, &state->cookie); ++ map->l_audit_any_plt |= state->bindflags != 0; + } + + afct = afct->next; +@@ -1660,7 +1660,8 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) + { + if (afct->activity != NULL) +- afct->activity (&main_map->l_audit[cnt].cookie, LA_ACT_ADD); ++ afct->activity (&link_map_audit_state (main_map, cnt)->cookie, ++ LA_ACT_ADD); + + afct = afct->next; + } +@@ -2331,7 +2332,8 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) + { + if (afct->activity != NULL) +- afct->activity (&head->l_audit[cnt].cookie, LA_ACT_CONSISTENT); ++ afct->activity (&link_map_audit_state (head, cnt)->cookie, ++ LA_ACT_CONSISTENT); + + afct = afct->next; + } +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 3bdbdd6e67dacc85..a8fb0d211426e4b1 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1197,7 +1197,13 @@ rtld_active (void) + initialized and active ld.so copy. */ + return GLRO(dl_init_all_dirs) != NULL; + } +-#endif ++ ++static inline struct auditstate * ++link_map_audit_state (struct link_map *l, size_t index) ++{ ++ return &l->l_audit[index]; ++} ++#endif /* SHARED */ + + __END_DECLS + diff --git a/SOURCES/glibc-rh1817513-37.patch b/SOURCES/glibc-rh1817513-37.patch new file mode 100644 index 0000000..33008bf --- /dev/null +++ b/SOURCES/glibc-rh1817513-37.patch @@ -0,0 +1,80 @@ +commit 4a2ab5843a5cc4a5db1b3b79916a520ea8b115dc +Author: Florian Weimer +Date: Fri Nov 8 15:48:51 2019 +0100 + + dlsym: Do not determine caller link map if not needed + + Obtaining the link map is potentially very slow because it requires + iterating over all loaded objects in the current implementation. If + the caller supplied an explicit handle (i.e., not one of the RTLD_* + constants), the dlsym implementation does not need the identity of the + caller (except in the special case of auditing), so this change + avoids computing it in that case. + + Even in the minimal case (dlsym called from a main program linked with + -dl), this shows a small speedup, perhaps around five percent. The + performance improvement can be arbitrarily large in principle (if + _dl_find_dso_for_object has to iterate over many link maps). + + Change-Id: Ide5d9e2cc7ac25a0ffae8fb4c26def0c898efa29 + +diff --git a/elf/dl-sym.c b/elf/dl-sym.c +index 286cf7e27fd59f20..b133850a3c6657a4 100644 +--- a/elf/dl-sym.c ++++ b/elf/dl-sym.c +@@ -80,6 +80,18 @@ call_dl_lookup (void *ptr) + args->flags, NULL); + } + ++/* Return the link map containing the caller address. */ ++static inline struct link_map * ++find_caller_link_map (ElfW(Addr) caller) ++{ ++ struct link_map *l = _dl_find_dso_for_object (caller); ++ if (l != NULL) ++ return l; ++ else ++ /* If the address is not recognized the call comes from the main ++ program (we hope). */ ++ return GL(dl_ns)[LM_ID_BASE]._ns_loaded; ++} + + static void * + do_sym (void *handle, const char *name, void *who, +@@ -89,13 +101,13 @@ do_sym (void *handle, const char *name, void *who, + lookup_t result; + ElfW(Addr) caller = (ElfW(Addr)) who; + +- struct link_map *l = _dl_find_dso_for_object (caller); +- /* If the address is not recognized the call comes from the main +- program (we hope). */ +- struct link_map *match = l ? l : GL(dl_ns)[LM_ID_BASE]._ns_loaded; ++ /* Link map of the caller if needed. */ ++ struct link_map *match = NULL; + + if (handle == RTLD_DEFAULT) + { ++ match = find_caller_link_map (caller); ++ + /* Search the global scope. We have the simple case where + we look up in the scope of an object which was part of + the initial binary. And then the more complex part +@@ -128,6 +140,8 @@ do_sym (void *handle, const char *name, void *who, + } + else if (handle == RTLD_NEXT) + { ++ match = find_caller_link_map (caller); ++ + if (__glibc_unlikely (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded)) + { + if (match == NULL +@@ -187,6 +201,9 @@ RTLD_NEXT used in code not dynamically loaded")); + unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result, + l_info[DT_SYMTAB])); + ++ if (match == NULL) ++ match = find_caller_link_map (caller); ++ + if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0) + { + unsigned int altvalue = 0; diff --git a/SOURCES/glibc-rh1817513-38.patch b/SOURCES/glibc-rh1817513-38.patch new file mode 100644 index 0000000..4700cf4 --- /dev/null +++ b/SOURCES/glibc-rh1817513-38.patch @@ -0,0 +1,211 @@ +commit 4f79b3e2fb3eba003240ec38a0e68702b9a60b86 +Author: DJ Delorie +Date: Mon Feb 3 14:49:25 2020 -0500 + + test-container: add exec, cwd + + exec [optional_argv_0] + + copies test binary to specified location and runs it from + there. If the second argument is provided, that will + be used for argv[0] + + cwd + + attempts to chdir(directory) before running test + + Note: "cwd" not "cd" as it takes effect just before the + test binary runs, not when it's encountered in the script, + so it can't be used as a path shortcut like "cd" would imply. + + cleanup: use xstrdup() instead of strdup() + + Reviewed-by: Carlos O'Donell + +diff --git a/support/test-container.c b/support/test-container.c +index 6503cea90309b9b0..9488ec7b4a824380 100644 +--- a/support/test-container.c ++++ b/support/test-container.c +@@ -95,6 +95,8 @@ int verbose = 0; + mv FILE FILE + cp FILE FILE + rm FILE ++ cwd PATH ++ exec FILE + FILE must start with $B/, $S/, $I/, $L/, or / + (expands to build dir, source dir, install dir, library dir + (in container), or container's root) +@@ -104,6 +106,8 @@ int verbose = 0; + - 'mv': A minimal move files command. + - 'cp': A minimal copy files command. + - 'rm': A minimal remove files command. ++ - 'cwd': set test working directory ++ - 'exec': change test binary location (may end in /) + * mytest.root/postclean.req causes fresh rsync (with delete) after + test if present + +@@ -147,7 +151,7 @@ maybe_xmkdir (const char *path, mode_t mode) + } + + /* Temporarily concatenate multiple strings into one. Allows up to 10 +- temporary results; use strdup () if you need them to be ++ temporary results; use xstrdup () if you need them to be + permanent. */ + static char * + concat (const char *str, ...) +@@ -670,11 +674,13 @@ main (int argc, char **argv) + char *new_objdir_path; + char *new_srcdir_path; + char **new_child_proc; ++ char *new_child_exec; + char *command_root; + char *command_base; + char *command_basename; + char *so_base; + int do_postclean = 0; ++ char *change_cwd = NULL; + + int pipes[2]; + char pid_buf[20]; +@@ -701,7 +707,7 @@ main (int argc, char **argv) + + if (argc < 2) + { +- fprintf (stderr, "Usage: containerize \n"); ++ fprintf (stderr, "Usage: test-container \n"); + exit (1); + } + +@@ -746,12 +752,13 @@ main (int argc, char **argv) + } + } + +- pristine_root_path = strdup (concat (support_objdir_root, ++ pristine_root_path = xstrdup (concat (support_objdir_root, + "/testroot.pristine", NULL)); +- new_root_path = strdup (concat (support_objdir_root, ++ new_root_path = xstrdup (concat (support_objdir_root, + "/testroot.root", NULL)); + new_cwd_path = get_current_dir_name (); + new_child_proc = argv + 1; ++ new_child_exec = argv[1]; + + lock_fd = open (concat (pristine_root_path, "/lock.fd", NULL), + O_CREAT | O_TRUNC | O_RDWR, 0666); +@@ -778,10 +785,10 @@ main (int argc, char **argv) + command_root = concat (support_srcdir_root, + argv[1] + strlen (support_objdir_root), + ".root", NULL); +- command_root = strdup (command_root); ++ command_root = xstrdup (command_root); + + /* This cuts off the ".root" we appended above. */ +- command_base = strdup (command_root); ++ command_base = xstrdup (command_root); + command_base[strlen (command_base) - 5] = 0; + + /* This is the basename of the test we're running. */ +@@ -792,7 +799,7 @@ main (int argc, char **argv) + ++command_basename; + + /* Shared object base directory. */ +- so_base = strdup (argv[1]); ++ so_base = xstrdup (argv[1]); + if (strrchr (so_base, '/') != NULL) + strrchr (so_base, '/')[1] = 0; + +@@ -806,9 +813,9 @@ main (int argc, char **argv) + && S_ISDIR (st.st_mode)) + rsync (command_root, new_root_path, 0); + +- new_objdir_path = strdup (concat (new_root_path, ++ new_objdir_path = xstrdup (concat (new_root_path, + support_objdir_root, NULL)); +- new_srcdir_path = strdup (concat (new_root_path, ++ new_srcdir_path = xstrdup (concat (new_root_path, + support_srcdir_root, NULL)); + + /* new_cwd_path starts with '/' so no "/" needed between the two. */ +@@ -868,7 +875,10 @@ main (int argc, char **argv) + the_words[i] = concat (new_root_path, + support_libdir_prefix, + the_words[i] + 2, NULL); +- else if (the_words[i][0] == '/') ++ /* "exec" and "cwd" use inside-root paths. */ ++ else if (strcmp (the_words[0], "exec") != 0 ++ && strcmp (the_words[0], "cwd") != 0 ++ && the_words[i][0] == '/') + the_words[i] = concat (new_root_path, + the_words[i], NULL); + } +@@ -912,13 +922,49 @@ main (int argc, char **argv) + { + maybe_xunlink (the_words[1]); + } ++ else if (nt >= 2 && strcmp (the_words[0], "exec") == 0) ++ { ++ /* The first argument is the desired location and name ++ of the test binary as we wish to exec it; we will ++ copy the binary there. The second (optional) ++ argument is the value to pass as argv[0], it ++ defaults to the same as the first argument. */ ++ char *new_exec_path = the_words[1]; ++ ++ /* If the new exec path ends with a slash, that's the ++ * directory, and use the old test base name. */ ++ if (new_exec_path [strlen(new_exec_path) - 1] == '/') ++ new_exec_path = concat (new_exec_path, ++ basename (new_child_proc[0]), ++ NULL); ++ ++ ++ /* new_child_proc is in the build tree, so has the ++ same path inside the chroot as outside. The new ++ exec path is, by definition, relative to the ++ chroot. */ ++ copy_one_file (new_child_proc[0], concat (new_root_path, ++ new_exec_path, ++ NULL)); ++ ++ new_child_exec = xstrdup (new_exec_path); ++ if (the_words[2]) ++ new_child_proc[0] = xstrdup (the_words[2]); ++ else ++ new_child_proc[0] = new_child_exec; ++ } ++ else if (nt == 2 && strcmp (the_words[0], "cwd") == 0) ++ { ++ change_cwd = xstrdup (the_words[1]); ++ } + else if (nt == 1 && strcmp (the_words[0], "su") == 0) + { + be_su = 1; + } + else if (nt > 0 && the_words[0][0] != '#') + { +- printf ("\033[31minvalid [%s]\033[0m\n", the_words[0]); ++ fprintf (stderr, "\033[31minvalid [%s]\033[0m\n", the_words[0]); ++ exit (1); + } + } + fclose (f); +@@ -1089,11 +1135,17 @@ main (int argc, char **argv) + write (GMAP, tmp, strlen (tmp)); + xclose (GMAP); + ++ if (change_cwd) ++ { ++ if (chdir (change_cwd) < 0) ++ FAIL_EXIT1 ("Can't cd to %s inside container - ", change_cwd); ++ } ++ + /* Now run the child. */ +- execvp (new_child_proc[0], new_child_proc); ++ execvp (new_child_exec, new_child_proc); + + /* Or don't run the child? */ +- FAIL_EXIT1 ("Unable to exec %s\n", new_child_proc[0]); ++ FAIL_EXIT1 ("Unable to exec %s\n", new_child_exec); + + /* Because gcc won't know error () never returns... */ + exit (EXIT_UNSUPPORTED); diff --git a/SOURCES/glibc-rh1817513-39.patch b/SOURCES/glibc-rh1817513-39.patch new file mode 100644 index 0000000..d514b49 --- /dev/null +++ b/SOURCES/glibc-rh1817513-39.patch @@ -0,0 +1,50 @@ +commit abcc039d2e26b3c9c723d6419e086753a791b3d5 +Author: Florian Weimer +Date: Fri Feb 7 20:06:32 2020 +0100 + + elf: Introduce the rtld-stubbed-symbols makefile variable + + This generalizes a mechanism used for stack-protector support, so + that it can be applied to other symbols if required. + + Reviewed-by: Carlos O'Donell + +diff --git a/elf/Makefile b/elf/Makefile +index 4ab73dc48d9ac126..a1ea44f231d8cec5 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -474,21 +474,25 @@ $(objpfx)dl-allobjs.os: $(all-rtld-routines:%=$(objpfx)%.os) + # are compiled with special flags, and puts these modules into rtld-libc.a + # for us. Then we do the real link using rtld-libc.a instead of libc_pic.a. + +-# If the compiler can do SSP, build the mapfile with dummy __stack_chk_fail +-# and __stack_chk_fail_local symbols defined, to prevent the real things +-# being dragged into rtld even though rtld is never built with stack- +-# protection. ++# These symbols need to be stubbed out during symbol discovery because ++# their implementation is provided differently in rtld, and the symbol ++# discovery mechanism is not compatible with the libc implementation ++# when compiled for libc. ++rtld-stubbed-symbols = ++ ++# The GCC arguments that implement $(rtld-stubbed-symbols). ++rtld-stubbed-symbols-args = \ ++ $(patsubst %,-Wl$(comma)--defsym=%=0, $(rtld-stubbed-symbols)) + + ifeq ($(have-ssp),yes) +-dummy-stack-chk-fail := -Wl,--defsym='__stack_chk_fail=0' \ +- -Wl,--defsym='__stack_chk_fail_local=0' +-else +-dummy-stack-chk-fail := ++# rtld is not built with the stack protector, so these references will ++# go away in the rebuilds. ++rtld-stubbed-symbols += __stack_chk_fail __stack_chk_fail_local + endif + + $(objpfx)librtld.map: $(objpfx)dl-allobjs.os $(common-objpfx)libc_pic.a + @-rm -f $@T +- $(reloc-link) -o $@.o $(dummy-stack-chk-fail) \ ++ $(reloc-link) -o $@.o $(rtld-stubbed-symbols-args) \ + '-Wl,-(' $^ -lgcc '-Wl,-)' -Wl,-Map,$@T + rm -f $@.o + mv -f $@T $@ diff --git a/SOURCES/glibc-rh1817513-4.patch b/SOURCES/glibc-rh1817513-4.patch new file mode 100644 index 0000000..b3b1c74 --- /dev/null +++ b/SOURCES/glibc-rh1817513-4.patch @@ -0,0 +1,64 @@ +commit 430388d5dc0e1861b869096f4f5d946d7d74232a +Author: H.J. Lu +Date: Fri Aug 3 08:04:49 2018 -0700 + + x86: Don't include in assembly codes + + There is no need to include in assembly codes since all + x86 IFUNC selector functions are written in C. Tested on i686 and + x86-64. There is no code change in libc.so, ld.so and libmvec.so. + + * sysdeps/i386/i686/multiarch/bzero-ia32.S: Don't include + . + * sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core-avx2.S: Likewise. + * sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core-avx2.S: Likewise. + * sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S: Likewise. + +diff --git a/sysdeps/i386/i686/multiarch/bzero-ia32.S b/sysdeps/i386/i686/multiarch/bzero-ia32.S +index 68ff9e1e903f7c4c..94d13e88f7532bc0 100644 +--- a/sysdeps/i386/i686/multiarch/bzero-ia32.S ++++ b/sysdeps/i386/i686/multiarch/bzero-ia32.S +@@ -17,7 +17,6 @@ + . */ + + #include +-#include + + #if IS_IN (libc) + # define __bzero __bzero_ia32 +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core-avx2.S b/sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core-avx2.S +index b64c3390d6169d18..87536a06a3ed54c6 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core-avx2.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core-avx2.S +@@ -17,7 +17,6 @@ + . */ + + #include +-#include + + #define _ZGVeN8v_sin _ZGVeN8v_sin_avx2_wrapper + #include "../svml_d_sin8_core.S" +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core-avx2.S b/sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core-avx2.S +index e0b7fd787fa6428d..16713ba7142ecad6 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core-avx2.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core-avx2.S +@@ -17,7 +17,6 @@ + . */ + + #include +-#include + + #define _ZGVeN16v_expf _ZGVeN16v_expf_avx2_wrapper + #include "../svml_s_expf16_core.S" +diff --git a/sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S +index be6671759beaaa84..56b81f5cc5288808 100644 +--- a/sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S +@@ -19,7 +19,6 @@ + + #include + #include +-#include + + #if IS_IN (libc) + # define MEMSET_SYMBOL(p,s) p##_sse2_##s diff --git a/SOURCES/glibc-rh1817513-40.patch b/SOURCES/glibc-rh1817513-40.patch new file mode 100644 index 0000000..d30002b --- /dev/null +++ b/SOURCES/glibc-rh1817513-40.patch @@ -0,0 +1,248 @@ +commit c76147afe917ef7d309ee893f8f017a3c2934aac +Author: Florian Weimer +Date: Sat Feb 8 15:00:28 2020 +0100 + + elf: Extract _dl_sym_post, _dl_sym_find_caller_map from elf/dl-sym.c + + The definitions are moved into a new file, elf/dl-sym-post.h, so that + this code can be used by the dynamic loader as well. + + Reviewed-by: Carlos O'Donell + +diff --git a/elf/dl-sym-post.h b/elf/dl-sym-post.h +new file mode 100644 +index 0000000000000000..4c4f574633497789 +--- /dev/null ++++ b/elf/dl-sym-post.h +@@ -0,0 +1,106 @@ ++/* Post-processing of a symbol produced by dlsym, dlvsym. ++ Copyright (C) 1999-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 ++ . */ ++ ++ ++/* Return the link map containing the caller address. */ ++static struct link_map * ++_dl_sym_find_caller_link_map (ElfW(Addr) caller) ++{ ++ struct link_map *l = _dl_find_dso_for_object (caller); ++ if (l != NULL) ++ return l; ++ else ++ /* If the address is not recognized the call comes from the main ++ program (we hope). */ ++ return GL(dl_ns)[LM_ID_BASE]._ns_loaded; ++} ++ ++/* Translates RESULT, *REF, VALUE into a symbol address from the point ++ of view of MATCH. Performs IFUNC resolution and auditing if ++ necessary. If MATCH is NULL, CALLER is used to determine it. */ ++static void * ++_dl_sym_post (lookup_t result, const ElfW(Sym) *ref, void *value, ++ ElfW(Addr) caller, struct link_map *match) ++{ ++ /* Resolve indirect function address. */ ++ if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC)) ++ { ++ DL_FIXUP_VALUE_TYPE fixup ++ = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value); ++ fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup)); ++ value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup); ++ } ++ ++#ifdef SHARED ++ /* Auditing checkpoint: we have a new binding. Provide the ++ auditing libraries the possibility to change the value and ++ tell us whether further auditing is wanted. */ ++ if (__glibc_unlikely (GLRO(dl_naudit) > 0)) ++ { ++ const char *strtab = (const char *) D_PTR (result, ++ l_info[DT_STRTAB]); ++ /* Compute index of the symbol entry in the symbol table of ++ the DSO with the definition. */ ++ unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result, ++ l_info[DT_SYMTAB])); ++ ++ if (match == NULL) ++ match = _dl_sym_find_caller_link_map (caller); ++ ++ if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0) ++ { ++ unsigned int altvalue = 0; ++ struct audit_ifaces *afct = GLRO(dl_audit); ++ /* Synthesize a symbol record where the st_value field is ++ the result. */ ++ ElfW(Sym) sym = *ref; ++ sym.st_value = (ElfW(Addr)) value; ++ ++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) ++ { ++ struct auditstate *match_audit ++ = link_map_audit_state (match, cnt); ++ struct auditstate *result_audit ++ = link_map_audit_state (result, cnt); ++ if (afct->symbind != NULL ++ && ((match_audit->bindflags & LA_FLG_BINDFROM) != 0 ++ || ((result_audit->bindflags & LA_FLG_BINDTO) ++ != 0))) ++ { ++ unsigned int flags = altvalue | LA_SYMB_DLSYM; ++ uintptr_t new_value ++ = afct->symbind (&sym, ndx, ++ &match_audit->cookie, ++ &result_audit->cookie, ++ &flags, strtab + ref->st_name); ++ if (new_value != (uintptr_t) sym.st_value) ++ { ++ altvalue = LA_SYMB_ALTVALUE; ++ sym.st_value = new_value; ++ } ++ } ++ ++ afct = afct->next; ++ } ++ ++ value = (void *) sym.st_value; ++ } ++ } ++#endif ++ return value; ++} +diff --git a/elf/dl-sym.c b/elf/dl-sym.c +index b133850a3c6657a4..5698fd7874a0ce48 100644 +--- a/elf/dl-sym.c ++++ b/elf/dl-sym.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + + #ifdef SHARED +@@ -80,19 +81,6 @@ call_dl_lookup (void *ptr) + args->flags, NULL); + } + +-/* Return the link map containing the caller address. */ +-static inline struct link_map * +-find_caller_link_map (ElfW(Addr) caller) +-{ +- struct link_map *l = _dl_find_dso_for_object (caller); +- if (l != NULL) +- return l; +- else +- /* If the address is not recognized the call comes from the main +- program (we hope). */ +- return GL(dl_ns)[LM_ID_BASE]._ns_loaded; +-} +- + static void * + do_sym (void *handle, const char *name, void *who, + struct r_found_version *vers, int flags) +@@ -106,7 +94,7 @@ do_sym (void *handle, const char *name, void *who, + + if (handle == RTLD_DEFAULT) + { +- match = find_caller_link_map (caller); ++ match = _dl_sym_find_caller_link_map (caller); + + /* Search the global scope. We have the simple case where + we look up in the scope of an object which was part of +@@ -140,7 +128,7 @@ do_sym (void *handle, const char *name, void *who, + } + else if (handle == RTLD_NEXT) + { +- match = find_caller_link_map (caller); ++ match = _dl_sym_find_caller_link_map (caller); + + if (__glibc_unlikely (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded)) + { +@@ -179,73 +167,7 @@ RTLD_NEXT used in code not dynamically loaded")); + #endif + value = DL_SYMBOL_ADDRESS (result, ref); + +- /* Resolve indirect function address. */ +- if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC)) +- { +- DL_FIXUP_VALUE_TYPE fixup +- = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value); +- fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup)); +- value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup); +- } +- +-#ifdef SHARED +- /* Auditing checkpoint: we have a new binding. Provide the +- auditing libraries the possibility to change the value and +- tell us whether further auditing is wanted. */ +- if (__glibc_unlikely (GLRO(dl_naudit) > 0)) +- { +- const char *strtab = (const char *) D_PTR (result, +- l_info[DT_STRTAB]); +- /* Compute index of the symbol entry in the symbol table of +- the DSO with the definition. */ +- unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result, +- l_info[DT_SYMTAB])); +- +- if (match == NULL) +- match = find_caller_link_map (caller); +- +- if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0) +- { +- unsigned int altvalue = 0; +- struct audit_ifaces *afct = GLRO(dl_audit); +- /* Synthesize a symbol record where the st_value field is +- the result. */ +- ElfW(Sym) sym = *ref; +- sym.st_value = (ElfW(Addr)) value; +- +- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) +- { +- struct auditstate *match_audit +- = link_map_audit_state (match, cnt); +- struct auditstate *result_audit +- = link_map_audit_state (result, cnt); +- if (afct->symbind != NULL +- && ((match_audit->bindflags & LA_FLG_BINDFROM) != 0 +- || ((result_audit->bindflags & LA_FLG_BINDTO) +- != 0))) +- { +- unsigned int flags = altvalue | LA_SYMB_DLSYM; +- uintptr_t new_value +- = afct->symbind (&sym, ndx, +- &match_audit->cookie, +- &result_audit->cookie, +- &flags, strtab + ref->st_name); +- if (new_value != (uintptr_t) sym.st_value) +- { +- altvalue = LA_SYMB_ALTVALUE; +- sym.st_value = new_value; +- } +- } +- +- afct = afct->next; +- } +- +- value = (void *) sym.st_value; +- } +- } +-#endif +- +- return value; ++ return _dl_sym_post (result, ref, value, caller, match); + } + + return NULL; diff --git a/SOURCES/glibc-rh1817513-41.patch b/SOURCES/glibc-rh1817513-41.patch new file mode 100644 index 0000000..0c00b3a --- /dev/null +++ b/SOURCES/glibc-rh1817513-41.patch @@ -0,0 +1,1102 @@ +commit 3a0ecccb599a6b1ad4b149dc569c0080e92d057b +Author: Florian Weimer +Date: Sat Feb 8 19:58:43 2020 +0100 + + ld.so: Do not export free/calloc/malloc/realloc functions [BZ #25486] + + Exporting functions and relying on symbol interposition from libc.so + makes the choice of implementation dependent on DT_NEEDED order, which + is not what some compiler drivers expect. + + This commit replaces one magic mechanism (symbol interposition) with + another one (preprocessor-/compiler-based redirection). This makes + the hand-over from the minimal malloc to the full malloc more + explicit. + + Removing the ABI symbols is backwards-compatible because libc.so is + always in scope, and the dynamic loader will find the malloc-related + symbols there since commit f0b2132b35248c1f4a80f62a2c38cddcc802aa8c + ("ld.so: Support moving versioned symbols between sonames + [BZ #24741]"). + + Reviewed-by: Carlos O'Donell + +Conflicts: + sysdeps/unix/sysv/linux/arm/le/ld.abilist + sysdeps/unix/sysv/linux/sh/le/ld.abilist + (Missing abilist split.) + sysdeps/unix/sysv/linux/csky/ld.abilist + sysdeps/unix/sysv/linux/csky/localplt.data + (Missing architecture.) + +diff --git a/elf/Makefile b/elf/Makefile +index a1ea44f231d8cec5..5b0aeccb0a53c182 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -478,7 +478,11 @@ $(objpfx)dl-allobjs.os: $(all-rtld-routines:%=$(objpfx)%.os) + # their implementation is provided differently in rtld, and the symbol + # discovery mechanism is not compatible with the libc implementation + # when compiled for libc. +-rtld-stubbed-symbols = ++rtld-stubbed-symbols = \ ++ calloc \ ++ free \ ++ malloc \ ++ realloc \ + + # The GCC arguments that implement $(rtld-stubbed-symbols). + rtld-stubbed-symbols-args = \ +diff --git a/elf/Versions b/elf/Versions +index 3b09901f6c31e3d4..705489fc51f4ac5f 100644 +--- a/elf/Versions ++++ b/elf/Versions +@@ -35,9 +35,6 @@ libc { + + ld { + GLIBC_2.0 { +- # Functions which are interposed from libc.so. +- calloc; free; malloc; realloc; +- + _r_debug; + } + GLIBC_2.1 { +diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c +index 42fdaed99296137f..e4c479de9a1fd6ec 100644 +--- a/elf/dl-lookup.c ++++ b/elf/dl-lookup.c +@@ -291,7 +291,7 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash, + tab->size = newsize; + size = newsize; + entries = tab->entries = newentries; +- tab->free = free; ++ tab->free = __rtld_free; + } + } + else +@@ -322,7 +322,7 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash, + + tab->entries = entries; + tab->size = size; +- tab->free = free; ++ tab->free = __rtld_free; + } + + if ((type_class & ELF_RTYPE_CLASS_COPY) != 0) +diff --git a/elf/dl-minimal.c b/elf/dl-minimal.c +index 25ceded6fe120b07..95ea7b024044864f 100644 +--- a/elf/dl-minimal.c ++++ b/elf/dl-minimal.c +@@ -26,11 +26,87 @@ + #include + #include + #include ++#include ++#include ++#include + #include <_itoa.h> + #include + + #include + ++/* The rtld startup code calls __rtld_malloc_init_stubs after the ++ first self-relocation to adjust the pointers to the minimal ++ implementation below. Before the final relocation, ++ __rtld_malloc_init_real is called to replace the pointers with the ++ real implementation. */ ++__typeof (calloc) *__rtld_calloc; ++__typeof (free) *__rtld_free; ++__typeof (malloc) *__rtld_malloc; ++__typeof (realloc) *__rtld_realloc; ++ ++/* Defined below. */ ++static __typeof (calloc) rtld_calloc attribute_relro; ++static __typeof (free) rtld_free attribute_relro; ++static __typeof (malloc) rtld_malloc attribute_relro; ++static __typeof (realloc) rtld_realloc attribute_relro; ++ ++void ++__rtld_malloc_init_stubs (void) ++{ ++ __rtld_calloc = &rtld_calloc; ++ __rtld_free = &rtld_free; ++ __rtld_malloc = &rtld_malloc; ++ __rtld_realloc = &rtld_realloc; ++} ++ ++/* Lookup NAME at VERSION in the scope of MATCH. */ ++static void * ++lookup_malloc_symbol (struct link_map *main_map, const char *name, ++ struct r_found_version *version) ++{ ++ ++ const ElfW(Sym) *ref = NULL; ++ lookup_t result = _dl_lookup_symbol_x (name, main_map, &ref, ++ main_map->l_scope, ++ version, 0, 0, NULL); ++ ++ assert (ELFW(ST_TYPE) (ref->st_info) != STT_TLS); ++ void *value = DL_SYMBOL_ADDRESS (result, ref); ++ ++ return _dl_sym_post (result, ref, value, 0, main_map); ++} ++ ++void ++__rtld_malloc_init_real (struct link_map *main_map) ++{ ++ /* We cannot use relocations and initializers for this because the ++ changes made by __rtld_malloc_init_stubs break REL-style ++ (non-RELA) relocations that depend on the previous pointer ++ contents. Also avoid direct relocation depedencies for the ++ malloc symbols so this function can be called before the final ++ rtld relocation (which enables RELRO, after which the pointer ++ variables cannot be written to). */ ++ ++ struct r_found_version version; ++ version.name = symbol_version_string (libc, GLIBC_2_0); ++ version.hidden = 0; ++ version.hash = _dl_elf_hash (version.name); ++ version.filename = NULL; ++ ++ void *new_calloc = lookup_malloc_symbol (main_map, "calloc", &version); ++ void *new_free = lookup_malloc_symbol (main_map, "free", &version); ++ void *new_malloc = lookup_malloc_symbol (main_map, "malloc", &version); ++ void *new_realloc = lookup_malloc_symbol (main_map, "realloc", &version); ++ ++ /* Update the pointers in one go, so that any internal allocations ++ performed by lookup_malloc_symbol see a consistent ++ implementation. */ ++ __rtld_calloc = new_calloc; ++ __rtld_free = new_free; ++ __rtld_malloc = new_malloc; ++ __rtld_realloc = new_realloc; ++} ++ + /* Minimal malloc allocator for used during initial link. After the + initial link, a full malloc implementation is interposed, either + the one in libc, or a different one supplied by the user through +@@ -38,14 +114,9 @@ + + static void *alloc_ptr, *alloc_end, *alloc_last_block; + +-/* Declarations of global functions. */ +-extern void weak_function free (void *ptr); +-extern void * weak_function realloc (void *ptr, size_t n); +- +- + /* Allocate an aligned memory block. */ +-void * weak_function +-malloc (size_t n) ++static void * ++rtld_malloc (size_t n) + { + if (alloc_end == 0) + { +@@ -87,8 +158,8 @@ malloc (size_t n) + /* We use this function occasionally since the real implementation may + be optimized when it can assume the memory it returns already is + set to NUL. */ +-void * weak_function +-calloc (size_t nmemb, size_t size) ++static void * ++rtld_calloc (size_t nmemb, size_t size) + { + /* New memory from the trivial malloc above is always already cleared. + (We make sure that's true in the rare occasion it might not be, +@@ -104,8 +175,8 @@ calloc (size_t nmemb, size_t size) + } + + /* This will rarely be called. */ +-void weak_function +-free (void *ptr) ++void ++rtld_free (void *ptr) + { + /* We can free only the last block allocated. */ + if (ptr == alloc_last_block) +@@ -118,8 +189,8 @@ free (void *ptr) + } + + /* This is only called with the most recent block returned by malloc. */ +-void * weak_function +-realloc (void *ptr, size_t n) ++void * ++rtld_realloc (void *ptr, size_t n) + { + if (ptr == NULL) + return malloc (n); +diff --git a/elf/rtld.c b/elf/rtld.c +index 18335bc666f2b89d..f755dc30331f799f 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -532,6 +532,9 @@ _dl_start (void *arg) + header table in core. Put the rest of _dl_start into a separate + function, that way the compiler cannot put accesses to the GOT + before ELF_DYNAMIC_RELOCATE. */ ++ ++ __rtld_malloc_init_stubs (); ++ + { + #ifdef DONT_USE_BOOTSTRAP_MAP + ElfW(Addr) entry = _dl_start_final (arg); +@@ -2203,6 +2206,10 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + rtld_timer_stop (&relocate_time, start); + } + ++ /* The library defining malloc has already been relocated due to ++ prelinking. Resolve the malloc symbols for the dynamic ++ loader. */ ++ __rtld_malloc_init_real (main_map); + + /* Mark all the objects so we know they have been already relocated. */ + for (struct link_map *l = main_map; l != NULL; l = l->l_next) +@@ -2303,6 +2310,11 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + re-relocation, we might call a user-supplied function + (e.g. calloc from _dl_relocate_object) that uses TLS data. */ + ++ /* The malloc implementation has been relocated, so resolving ++ its symbols (and potentially calling IFUNC resolvers) is safe ++ at this point. */ ++ __rtld_malloc_init_real (main_map); ++ + RTLD_TIMING_VAR (start); + rtld_timer_start (&start); + +diff --git a/include/inline-hashtab.h b/include/inline-hashtab.h +index ad73650ecc59dec1..b658e4a54b9c8187 100644 +--- a/include/inline-hashtab.h ++++ b/include/inline-hashtab.h +@@ -53,7 +53,7 @@ htab_create (void) + return NULL; + ht->size = 3; + ht->entries = malloc (sizeof (void *) * ht->size); +- ht->free = free; ++ ht->free = __rtld_free; + if (! ht->entries) + { + if (ht->free) +@@ -172,7 +172,7 @@ htab_expand (struct hashtab *htab, int (*hash_fn) (void *)) + + /* Use the free() corresponding to the malloc() above to free this + up. */ +- htab->free = free; ++ htab->free = __rtld_free; + + return 1; + } +diff --git a/include/libc-symbols.h b/include/libc-symbols.h +index 8b9273c13a19f265..41436050d060b89f 100644 +--- a/include/libc-symbols.h ++++ b/include/libc-symbols.h +@@ -413,7 +413,14 @@ for linking") + # define _default_symbol_version(real, name, version) \ + __asm__ (".symver " #real "," #name "@@" #version) + # endif +-#else ++ ++/* Evalutes to a string literal for VERSION in LIB. */ ++# define symbol_version_string(lib, version) \ ++ _symbol_version_stringify_1 (VERSION_##lib##_##version) ++# define _symbol_version_stringify_1(arg) _symbol_version_stringify_2 (arg) ++# define _symbol_version_stringify_2(arg) #arg ++ ++#else /* !SHARED */ + # define symbol_version(real, name, version) + # define default_symbol_version(real, name, version) \ + strong_alias(real, name) +diff --git a/include/malloc.h b/include/malloc.h +index d4cd9a5ffc929a96..e528718ac0734e5e 100644 +--- a/include/malloc.h ++++ b/include/malloc.h +@@ -1,7 +1,9 @@ + #ifndef _MALLOC_H ++ + #include + + # ifndef _ISOMAC ++# include + + /* In the GNU libc we rename the global variable + `__malloc_initialized' to `__libc_malloc_initialized'. */ +diff --git a/include/rtld-malloc.h b/include/rtld-malloc.h +new file mode 100644 +index 0000000000000000..b026a3270cd24819 +--- /dev/null ++++ b/include/rtld-malloc.h +@@ -0,0 +1,85 @@ ++/* Redirection of malloc inside the dynamic linker. ++ 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 ++ . */ ++ ++/* The dynamic linker needs to use its own minimal malloc before libc ++ has been relocated, and the libc malloc afterwards. The active ++ malloc implementation is reached via the __rtld_* function pointers ++ declared below. They are initialized to the minimal malloc by ++ __rtld_malloc_init_stubs, and set to the final implementation by ++ __rtld_malloc_init_real. */ ++ ++#ifndef _RTLD_MALLOC_H ++#define _RTLD_MALLOC_H ++ ++#if IS_IN (rtld) ++ ++extern __typeof (calloc) *__rtld_calloc attribute_hidden; ++extern __typeof (free) *__rtld_free attribute_hidden; ++extern __typeof (malloc) *__rtld_malloc attribute_hidden; ++extern __typeof (realloc) *__rtld_realloc attribute_hidden; ++ ++/* Wrapper functions which call through the function pointers above. ++ Note that it is not supported to take the address of those ++ functions. Instead the function pointers must be used ++ directly. */ ++ ++__extern_inline void * ++calloc (size_t a, size_t b) ++{ ++ return __rtld_calloc (a, b); ++} ++ ++__extern_inline void ++free (void *ptr) ++{ ++ __rtld_free (ptr); ++} ++ ++__extern_inline void * ++malloc (size_t size) ++{ ++ return __rtld_malloc (size); ++} ++ ++__extern_inline void * ++realloc (void *ptr, size_t size) ++{ ++ return __rtld_realloc (ptr, size); ++} ++ ++/* Called after the first self-relocation to activate the minimal malloc ++ implementation. */ ++void __rtld_malloc_init_stubs (void) attribute_hidden; ++ ++/* Called shortly before the final self-relocation (when RELRO ++ variables are still writable) to activate the real malloc ++ implementation. MAIN_MAP is the link map of the executable. */ ++struct link_map; ++void __rtld_malloc_init_real (struct link_map *main_map) attribute_hidden; ++ ++#else /* !IS_IN (rtld) */ ++ ++/* This allows static/non-rtld builds to get a pointer to the ++ functions, in the same way that is required inside rtld. */ ++# define __rtld_calloc (&calloc) ++# define __rtld_free (&free) ++# define __rtld_malloc (&malloc) ++# define __rtld_realloc (&realloc) ++ ++#endif /* !IS_IN (rtld) */ ++#endif /* _RTLD_MALLOC_H */ +diff --git a/include/stdlib.h b/include/stdlib.h +index 114e12d255977676..d7720967448f2a8f 100644 +--- a/include/stdlib.h ++++ b/include/stdlib.h +@@ -9,6 +9,8 @@ + #if !defined _ISOMAC + # include + ++# include ++ + extern __typeof (strtol_l) __strtol_l; + extern __typeof (strtoul_l) __strtoul_l; + extern __typeof (strtoll_l) __strtoll_l; +diff --git a/sysdeps/generic/localplt.data b/sysdeps/generic/localplt.data +index 2d5c66ae28a2e851..e2083c0ce6869572 100644 +--- a/sysdeps/generic/localplt.data ++++ b/sysdeps/generic/localplt.data +@@ -7,12 +7,6 @@ libc.so: malloc + libc.so: memalign + libc.so: realloc + libm.so: matherr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/mach/hurd/i386/ld.abilist b/sysdeps/mach/hurd/i386/ld.abilist +index c76b913486acf6d8..6f591b249699e10c 100644 +--- a/sysdeps/mach/hurd/i386/ld.abilist ++++ b/sysdeps/mach/hurd/i386/ld.abilist +@@ -16,10 +16,6 @@ GLIBC_2.2.6 _dl_mcount F + GLIBC_2.2.6 _hurd_intr_rpc_mach_msg F + GLIBC_2.2.6 _r_debug D 0x14 + GLIBC_2.2.6 abort F +-GLIBC_2.2.6 calloc F +-GLIBC_2.2.6 free F +-GLIBC_2.2.6 malloc F +-GLIBC_2.2.6 realloc F + GLIBC_2.3 ___tls_get_addr F + GLIBC_2.3 __tls_get_addr F + GLIBC_2.4 __stack_chk_guard D 0x4 +diff --git a/sysdeps/mach/hurd/i386/localplt.data b/sysdeps/mach/hurd/i386/localplt.data +index a5b5241b84812425..4b9dbf5acc088cff 100644 +--- a/sysdeps/mach/hurd/i386/localplt.data ++++ b/sysdeps/mach/hurd/i386/localplt.data +@@ -9,12 +9,6 @@ libc.so: malloc + REL R_386_GLOB_DAT + libc.so: memalign + REL R_386_GLOB_DAT + libc.so: realloc + REL R_386_GLOB_DAT + libm.so: matherr + REL R_386_GLOB_DAT +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc + REL R_386_GLOB_DAT +-ld.so: calloc + REL R_386_GLOB_DAT +-ld.so: realloc + REL R_386_GLOB_DAT +-ld.so: free + REL R_386_GLOB_DAT + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + REL R_386_GLOB_DAT + ld.so: _dl_catch_error + REL R_386_GLOB_DAT +diff --git a/sysdeps/unix/sysv/linux/aarch64/ld.abilist b/sysdeps/unix/sysv/linux/aarch64/ld.abilist +index 4ffe688649ca02e2..80b2fe672541c6e9 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/aarch64/ld.abilist +@@ -3,7 +3,3 @@ GLIBC_2.17 __stack_chk_guard D 0x8 + GLIBC_2.17 __tls_get_addr F + GLIBC_2.17 _dl_mcount F + GLIBC_2.17 _r_debug D 0x28 +-GLIBC_2.17 calloc F +-GLIBC_2.17 free F +-GLIBC_2.17 malloc F +-GLIBC_2.17 realloc F +diff --git a/sysdeps/unix/sysv/linux/aarch64/localplt.data b/sysdeps/unix/sysv/linux/aarch64/localplt.data +index 08af68b5e840b5d8..2c14b652efbfdf44 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/localplt.data ++++ b/sysdeps/unix/sysv/linux/aarch64/localplt.data +@@ -12,12 +12,6 @@ libm.so: matherr + libc.so: __getauxval ? + # The dynamic loader needs __tls_get_addr for TLS. + ld.so: __tls_get_addr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/alpha/ld.abilist b/sysdeps/unix/sysv/linux/alpha/ld.abilist +index 98b66edabf1a79c7..98a03f611f98f3a4 100644 +--- a/sysdeps/unix/sysv/linux/alpha/ld.abilist ++++ b/sysdeps/unix/sysv/linux/alpha/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.0 _r_debug D 0x28 +-GLIBC_2.0 calloc F +-GLIBC_2.0 free F +-GLIBC_2.0 malloc F +-GLIBC_2.0 realloc F + GLIBC_2.1 __libc_stack_end D 0x8 + GLIBC_2.1 _dl_mcount F + GLIBC_2.3 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/alpha/localplt.data b/sysdeps/unix/sysv/linux/alpha/localplt.data +index c69eb04ce53e292e..43f6fdaea18b25f3 100644 +--- a/sysdeps/unix/sysv/linux/alpha/localplt.data ++++ b/sysdeps/unix/sysv/linux/alpha/localplt.data +@@ -26,12 +26,6 @@ libm.so: matherr + RELA R_ALPHA_GLOB_DAT + libm.so: __atan2 + # The dynamic loader needs __tls_get_addr for TLS. + ld.so: __tls_get_addr ? +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc + RELA R_ALPHA_GLOB_DAT +-ld.so: calloc + RELA R_ALPHA_GLOB_DAT +-ld.so: realloc + RELA R_ALPHA_GLOB_DAT +-ld.so: free + RELA R_ALPHA_GLOB_DAT + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + RELA R_ALPHA_GLOB_DAT + ld.so: _dl_catch_error + RELA R_ALPHA_GLOB_DAT +diff --git a/sysdeps/unix/sysv/linux/arm/ld.abilist b/sysdeps/unix/sysv/linux/arm/ld.abilist +index a301c6ebc49db1d7..cc8825c3bc68ad4a 100644 +--- a/sysdeps/unix/sysv/linux/arm/ld.abilist ++++ b/sysdeps/unix/sysv/linux/arm/ld.abilist +@@ -3,7 +3,3 @@ GLIBC_2.4 __stack_chk_guard D 0x4 + GLIBC_2.4 __tls_get_addr F + GLIBC_2.4 _dl_mcount F + GLIBC_2.4 _r_debug D 0x14 +-GLIBC_2.4 calloc F +-GLIBC_2.4 free F +-GLIBC_2.4 malloc F +-GLIBC_2.4 realloc F +diff --git a/sysdeps/unix/sysv/linux/arm/localplt.data b/sysdeps/unix/sysv/linux/arm/localplt.data +index 7bd541c28a842526..0c3af0c64e95df4b 100644 +--- a/sysdeps/unix/sysv/linux/arm/localplt.data ++++ b/sysdeps/unix/sysv/linux/arm/localplt.data +@@ -8,12 +8,6 @@ libm.so: matherr + libpthread.so: raise + # The dynamic loader needs __tls_get_addr for TLS. + ld.so: __tls_get_addr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/hppa/ld.abilist b/sysdeps/unix/sysv/linux/hppa/ld.abilist +index 0387614d8fd784eb..d155a59843df9091 100644 +--- a/sysdeps/unix/sysv/linux/hppa/ld.abilist ++++ b/sysdeps/unix/sysv/linux/hppa/ld.abilist +@@ -1,9 +1,5 @@ + GLIBC_2.2 __libc_stack_end D 0x4 + GLIBC_2.2 _dl_mcount F + GLIBC_2.2 _r_debug D 0x14 +-GLIBC_2.2 calloc F +-GLIBC_2.2 free F +-GLIBC_2.2 malloc F +-GLIBC_2.2 realloc F + GLIBC_2.3 __tls_get_addr F + GLIBC_2.4 __stack_chk_guard D 0x4 +diff --git a/sysdeps/unix/sysv/linux/hppa/localplt.data b/sysdeps/unix/sysv/linux/hppa/localplt.data +index 867413f0c54d3d71..09893d4dcfd3a1f3 100644 +--- a/sysdeps/unix/sysv/linux/hppa/localplt.data ++++ b/sysdeps/unix/sysv/linux/hppa/localplt.data +@@ -10,12 +10,6 @@ libc.so: __sigsetjmp + libc.so: _IO_funlockfile + libc.so: __errno_location + libm.so: matherr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/i386/ld.abilist b/sysdeps/unix/sysv/linux/i386/ld.abilist +index edb7307228110c33..0478e220712a55e6 100644 +--- a/sysdeps/unix/sysv/linux/i386/ld.abilist ++++ b/sysdeps/unix/sysv/linux/i386/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.0 _r_debug D 0x14 +-GLIBC_2.0 calloc F +-GLIBC_2.0 free F +-GLIBC_2.0 malloc F +-GLIBC_2.0 realloc F + GLIBC_2.1 __libc_stack_end D 0x4 + GLIBC_2.1 _dl_mcount F + GLIBC_2.3 ___tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/i386/localplt.data b/sysdeps/unix/sysv/linux/i386/localplt.data +index f6f20a5d15bc79e4..5334875b4b4a4dee 100644 +--- a/sysdeps/unix/sysv/linux/i386/localplt.data ++++ b/sysdeps/unix/sysv/linux/i386/localplt.data +@@ -7,12 +7,6 @@ libc.so: malloc + REL R_386_GLOB_DAT + libc.so: memalign + REL R_386_GLOB_DAT + libc.so: realloc + REL R_386_GLOB_DAT + libm.so: matherr + REL R_386_GLOB_DAT +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc + REL R_386_GLOB_DAT +-ld.so: calloc + REL R_386_GLOB_DAT +-ld.so: realloc + REL R_386_GLOB_DAT +-ld.so: free + REL R_386_GLOB_DAT + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + REL R_386_GLOB_DAT + ld.so: _dl_catch_error + REL R_386_GLOB_DAT +diff --git a/sysdeps/unix/sysv/linux/ia64/ld.abilist b/sysdeps/unix/sysv/linux/ia64/ld.abilist +index 82042472c3089a29..33f91199bfa516fb 100644 +--- a/sysdeps/unix/sysv/linux/ia64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/ia64/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.2 __libc_stack_end D 0x8 + GLIBC_2.2 _dl_mcount F + GLIBC_2.2 _r_debug D 0x28 +-GLIBC_2.2 calloc F +-GLIBC_2.2 free F +-GLIBC_2.2 malloc F +-GLIBC_2.2 realloc F + GLIBC_2.3 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/ia64/localplt.data b/sysdeps/unix/sysv/linux/ia64/localplt.data +index 3820e2a4e682af2e..1c566a503e2eba00 100644 +--- a/sysdeps/unix/sysv/linux/ia64/localplt.data ++++ b/sysdeps/unix/sysv/linux/ia64/localplt.data +@@ -6,12 +6,6 @@ libc.so: realloc + libm.so: matherr + libm.so: matherrf + libm.so: matherrl +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/ld.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/ld.abilist +index a301c6ebc49db1d7..cc8825c3bc68ad4a 100644 +--- a/sysdeps/unix/sysv/linux/m68k/coldfire/ld.abilist ++++ b/sysdeps/unix/sysv/linux/m68k/coldfire/ld.abilist +@@ -3,7 +3,3 @@ GLIBC_2.4 __stack_chk_guard D 0x4 + GLIBC_2.4 __tls_get_addr F + GLIBC_2.4 _dl_mcount F + GLIBC_2.4 _r_debug D 0x14 +-GLIBC_2.4 calloc F +-GLIBC_2.4 free F +-GLIBC_2.4 malloc F +-GLIBC_2.4 realloc F +diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data b/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data +index 4a07bf387e2da296..3c5efb7204281e2a 100644 +--- a/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data ++++ b/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data +@@ -5,12 +5,6 @@ libc.so: malloc + libc.so: memalign + libc.so: realloc + libm.so: matherr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/ld.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/ld.abilist +index c9ec45cf1cf6c1c5..3ba474c27f62fb10 100644 +--- a/sysdeps/unix/sysv/linux/m68k/m680x0/ld.abilist ++++ b/sysdeps/unix/sysv/linux/m68k/m680x0/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.0 _r_debug D 0x14 +-GLIBC_2.0 calloc F +-GLIBC_2.0 free F +-GLIBC_2.0 malloc F +-GLIBC_2.0 realloc F + GLIBC_2.1 __libc_stack_end D 0x4 + GLIBC_2.1 _dl_mcount F + GLIBC_2.3 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data b/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data +index c70d6ea3011c4511..843f4e25f213d632 100644 +--- a/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data ++++ b/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data +@@ -6,12 +6,6 @@ libc.so: malloc + libc.so: memalign + libc.so: realloc + libm.so: matherr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/microblaze/ld.abilist b/sysdeps/unix/sysv/linux/microblaze/ld.abilist +index aa0d71150af8c62c..a4933c3541119538 100644 +--- a/sysdeps/unix/sysv/linux/microblaze/ld.abilist ++++ b/sysdeps/unix/sysv/linux/microblaze/ld.abilist +@@ -3,7 +3,3 @@ GLIBC_2.18 __stack_chk_guard D 0x4 + GLIBC_2.18 __tls_get_addr F + GLIBC_2.18 _dl_mcount F + GLIBC_2.18 _r_debug D 0x14 +-GLIBC_2.18 calloc F +-GLIBC_2.18 free F +-GLIBC_2.18 malloc F +-GLIBC_2.18 realloc F +diff --git a/sysdeps/unix/sysv/linux/microblaze/localplt.data b/sysdeps/unix/sysv/linux/microblaze/localplt.data +index 8ca23897dfa5b01c..0e98d5251ee14475 100644 +--- a/sysdeps/unix/sysv/linux/microblaze/localplt.data ++++ b/sysdeps/unix/sysv/linux/microblaze/localplt.data +@@ -7,12 +7,6 @@ libc.so: realloc + libm.so: matherr + # The dynamic loader needs __tls_get_addr for TLS. + ld.so: __tls_get_addr ? +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/mips/mips32/ld.abilist b/sysdeps/unix/sysv/linux/mips/mips32/ld.abilist +index 55d48868e8b686dc..be09641a48962434 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/mips/mips32/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.0 _r_debug D 0x14 +-GLIBC_2.0 calloc F +-GLIBC_2.0 free F +-GLIBC_2.0 malloc F +-GLIBC_2.0 realloc F + GLIBC_2.2 __libc_stack_end D 0x4 + GLIBC_2.2 _dl_mcount F + GLIBC_2.3 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/ld.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/ld.abilist +index 55d48868e8b686dc..be09641a48962434 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.0 _r_debug D 0x14 +-GLIBC_2.0 calloc F +-GLIBC_2.0 free F +-GLIBC_2.0 malloc F +-GLIBC_2.0 realloc F + GLIBC_2.2 __libc_stack_end D 0x4 + GLIBC_2.2 _dl_mcount F + GLIBC_2.3 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist +index 44b345b7cf31e854..1ea36e13f294a249 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.0 _r_debug D 0x28 +-GLIBC_2.0 calloc F +-GLIBC_2.0 free F +-GLIBC_2.0 malloc F +-GLIBC_2.0 realloc F + GLIBC_2.2 __libc_stack_end D 0x8 + GLIBC_2.2 _dl_mcount F + GLIBC_2.3 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/nios2/ld.abilist b/sysdeps/unix/sysv/linux/nios2/ld.abilist +index 110f1039fa39fb1c..52178802dd82b59a 100644 +--- a/sysdeps/unix/sysv/linux/nios2/ld.abilist ++++ b/sysdeps/unix/sysv/linux/nios2/ld.abilist +@@ -3,7 +3,3 @@ GLIBC_2.21 __stack_chk_guard D 0x4 + GLIBC_2.21 __tls_get_addr F + GLIBC_2.21 _dl_mcount F + GLIBC_2.21 _r_debug D 0x14 +-GLIBC_2.21 calloc F +-GLIBC_2.21 free F +-GLIBC_2.21 malloc F +-GLIBC_2.21 realloc F +diff --git a/sysdeps/unix/sysv/linux/nios2/localplt.data b/sysdeps/unix/sysv/linux/nios2/localplt.data +index 4430a5891e847aed..39009a62d6385849 100644 +--- a/sysdeps/unix/sysv/linux/nios2/localplt.data ++++ b/sysdeps/unix/sysv/linux/nios2/localplt.data +@@ -27,12 +27,6 @@ libc.so: __nedf2 + libc.so: __eqdf2 + libc.so: __extendsfdf2 + libm.so: matherr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data +index e822e0a4809e5088..a02dd5cc246329a0 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data +@@ -5,12 +5,6 @@ libc.so: malloc + libc.so: memalign + libc.so: realloc + libm.so: matherr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/ld.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/ld.abilist +index e8b0ea3a9bd98b92..4bbfba7a61c7a5ef 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.0 _r_debug D 0x14 +-GLIBC_2.0 calloc F +-GLIBC_2.0 free F +-GLIBC_2.0 malloc F +-GLIBC_2.0 realloc F + GLIBC_2.1 __libc_stack_end D 0x4 + GLIBC_2.1 _dl_mcount F + GLIBC_2.22 __tls_get_addr_opt F +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data +index fead931d4e5c4bc4..a4cd7cfb04249ae3 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data +@@ -35,12 +35,6 @@ libc.so: realloc + libm.so: copysignl ? + libm.so: fabsl + libm.so: matherr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld-le.abilist +index 37c8f6684b54341b..b1f313c7cd33defc 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld-le.abilist ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld-le.abilist +@@ -2,9 +2,5 @@ GLIBC_2.17 __libc_stack_end D 0x8 + GLIBC_2.17 __tls_get_addr F + GLIBC_2.17 _dl_mcount F + GLIBC_2.17 _r_debug D 0x28 +-GLIBC_2.17 calloc F +-GLIBC_2.17 free F +-GLIBC_2.17 malloc F +-GLIBC_2.17 realloc F + GLIBC_2.22 __tls_get_addr_opt F + GLIBC_2.23 __parse_hwcap_and_convert_at_platform F +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld.abilist +index edfc9ca56f2e4fee..283fb4510bea40ba 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld.abilist +@@ -4,7 +4,3 @@ GLIBC_2.3 __libc_stack_end D 0x8 + GLIBC_2.3 __tls_get_addr F + GLIBC_2.3 _dl_mcount F + GLIBC_2.3 _r_debug D 0x28 +-GLIBC_2.3 calloc F +-GLIBC_2.3 free F +-GLIBC_2.3 malloc F +-GLIBC_2.3 realloc F +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data +index c1209336d2d339d4..bb498fbe3ae28d03 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data +@@ -4,12 +4,6 @@ libc.so: malloc + libc.so: memalign + libc.so: realloc + libm.so: matherr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/riscv/localplt.data b/sysdeps/unix/sysv/linux/riscv/localplt.data +index 14c02cb2d6c016d3..0ed8650b65a0ecbf 100644 +--- a/sysdeps/unix/sysv/linux/riscv/localplt.data ++++ b/sysdeps/unix/sysv/linux/riscv/localplt.data +@@ -6,12 +6,6 @@ libc.so: free + libc.so: malloc + libc.so: memalign + libc.so: realloc +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist +index b411871d0631e1a3..845f356c3c3fad54 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist +@@ -3,7 +3,3 @@ GLIBC_2.27 __stack_chk_guard D 0x8 + GLIBC_2.27 __tls_get_addr F + GLIBC_2.27 _dl_mcount F + GLIBC_2.27 _r_debug D 0x28 +-GLIBC_2.27 calloc F +-GLIBC_2.27 free F +-GLIBC_2.27 malloc F +-GLIBC_2.27 realloc F +diff --git a/sysdeps/unix/sysv/linux/s390/localplt.data b/sysdeps/unix/sysv/linux/s390/localplt.data +index e822e0a4809e5088..a02dd5cc246329a0 100644 +--- a/sysdeps/unix/sysv/linux/s390/localplt.data ++++ b/sysdeps/unix/sysv/linux/s390/localplt.data +@@ -5,12 +5,6 @@ libc.so: malloc + libc.so: memalign + libc.so: realloc + libm.so: matherr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/ld.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/ld.abilist +index 0576c9575ea6118e..b56f005bebd3baf1 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/s390/s390-32/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.0 _r_debug D 0x14 +-GLIBC_2.0 calloc F +-GLIBC_2.0 free F +-GLIBC_2.0 malloc F +-GLIBC_2.0 realloc F + GLIBC_2.1 __libc_stack_end D 0x4 + GLIBC_2.1 _dl_mcount F + GLIBC_2.3 __tls_get_offset F +diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist +index 1fbb890d1dc495e5..6f788a086d68aaa5 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.2 __libc_stack_end D 0x8 + GLIBC_2.2 _dl_mcount F + GLIBC_2.2 _r_debug D 0x28 +-GLIBC_2.2 calloc F +-GLIBC_2.2 free F +-GLIBC_2.2 malloc F +-GLIBC_2.2 realloc F + GLIBC_2.3 __tls_get_offset F +diff --git a/sysdeps/unix/sysv/linux/sh/ld.abilist b/sysdeps/unix/sysv/linux/sh/ld.abilist +index 0387614d8fd784eb..d155a59843df9091 100644 +--- a/sysdeps/unix/sysv/linux/sh/ld.abilist ++++ b/sysdeps/unix/sysv/linux/sh/ld.abilist +@@ -1,9 +1,5 @@ + GLIBC_2.2 __libc_stack_end D 0x4 + GLIBC_2.2 _dl_mcount F + GLIBC_2.2 _r_debug D 0x14 +-GLIBC_2.2 calloc F +-GLIBC_2.2 free F +-GLIBC_2.2 malloc F +-GLIBC_2.2 realloc F + GLIBC_2.3 __tls_get_addr F + GLIBC_2.4 __stack_chk_guard D 0x4 +diff --git a/sysdeps/unix/sysv/linux/sh/localplt.data b/sysdeps/unix/sysv/linux/sh/localplt.data +index babb19d71785515d..3225177c50956972 100644 +--- a/sysdeps/unix/sysv/linux/sh/localplt.data ++++ b/sysdeps/unix/sysv/linux/sh/localplt.data +@@ -12,12 +12,6 @@ libc.so: __errno_location + libm.so: matherr + # Generated by the compiler because there is no trap insn pattern. + libc.so: abort ? +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/ld.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/ld.abilist +index fd0b33f86d3f9c5c..0c6610e3c2f00cf3 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.0 _r_debug D 0x14 +-GLIBC_2.0 calloc F +-GLIBC_2.0 free F +-GLIBC_2.0 malloc F +-GLIBC_2.0 realloc F + GLIBC_2.1 __libc_stack_end D 0x4 + GLIBC_2.1 _dl_mcount F + GLIBC_2.3 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data +index 1668f4017e0f28f0..be40910c4de9859a 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data ++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data +@@ -17,12 +17,6 @@ libc.so: malloc + libc.so: memalign + libc.so: realloc + libm.so: matherr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist +index 82042472c3089a29..33f91199bfa516fb 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.2 __libc_stack_end D 0x8 + GLIBC_2.2 _dl_mcount F + GLIBC_2.2 _r_debug D 0x28 +-GLIBC_2.2 calloc F +-GLIBC_2.2 free F +-GLIBC_2.2 malloc F +-GLIBC_2.2 realloc F + GLIBC_2.3 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data +index b881b9096d9fa38f..809062d46c1b4837 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data +@@ -18,12 +18,6 @@ libc.so: malloc + libc.so: memalign + libc.so: realloc + libm.so: matherr +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc +-ld.so: calloc +-ld.so: realloc +-ld.so: free + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + ld.so: _dl_catch_error +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist b/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist +index 0dc943061197d374..d3cdf7611eb9cab3 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist +@@ -1,8 +1,4 @@ + GLIBC_2.2.5 __libc_stack_end D 0x8 + GLIBC_2.2.5 _dl_mcount F + GLIBC_2.2.5 _r_debug D 0x28 +-GLIBC_2.2.5 calloc F +-GLIBC_2.2.5 free F +-GLIBC_2.2.5 malloc F +-GLIBC_2.2.5 realloc F + GLIBC_2.3 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist +index 80f3161586414674..c70bccf78245a552 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist +@@ -2,7 +2,3 @@ GLIBC_2.16 __libc_stack_end D 0x4 + GLIBC_2.16 __tls_get_addr F + GLIBC_2.16 _dl_mcount F + GLIBC_2.16 _r_debug D 0x14 +-GLIBC_2.16 calloc F +-GLIBC_2.16 free F +-GLIBC_2.16 malloc F +-GLIBC_2.16 realloc F +diff --git a/sysdeps/x86_64/localplt.data b/sysdeps/x86_64/localplt.data +index c27a02b66acd2ab4..8f41e928708d9a42 100644 +--- a/sysdeps/x86_64/localplt.data ++++ b/sysdeps/x86_64/localplt.data +@@ -9,12 +9,6 @@ libc.so: malloc + RELA R_X86_64_GLOB_DAT + libc.so: memalign + RELA R_X86_64_GLOB_DAT + libc.so: realloc + RELA R_X86_64_GLOB_DAT + libm.so: matherr + RELA R_X86_64_GLOB_DAT +-# The main malloc is interposed into the dynamic linker, for +-# allocations after the initial link (when dlopen is used). +-ld.so: malloc + RELA R_X86_64_GLOB_DAT +-ld.so: calloc + RELA R_X86_64_GLOB_DAT +-ld.so: realloc + RELA R_X86_64_GLOB_DAT +-ld.so: free + RELA R_X86_64_GLOB_DAT + # The TLS-enabled version of these functions is interposed from libc.so. + ld.so: _dl_signal_error + RELA R_X86_64_GLOB_DAT + ld.so: _dl_catch_error + RELA R_X86_64_GLOB_DAT diff --git a/SOURCES/glibc-rh1817513-42.patch b/SOURCES/glibc-rh1817513-42.patch new file mode 100644 index 0000000..473724f --- /dev/null +++ b/SOURCES/glibc-rh1817513-42.patch @@ -0,0 +1,46 @@ +commit 758599bc9dcc5764e862bd9e1613c5d1e6efc5d3 +Author: Florian Weimer +Date: Wed Feb 26 15:58:23 2020 +0100 + + elf: Apply attribute_relro to pointers in elf/dl-minimal.c + + The present code leaves the function pointers unprotected, but moves + some of the static functions into .data.rel.ro instead. This causes + the linker to produce an allocatable, executable, writable section + and eventually an RWX load segment. Not only do we really do not + want that, it also breaks valgrind because valgrind does not load + debuginfo from the mmap interceptor if all it sees are RX and RWX + mappings. + + Fixes commit 3a0ecccb599a6b1ad4b149dc569c0080e92d057b ("ld.so: Do not + export free/calloc/malloc/realloc functions [BZ #25486]"). + +diff --git a/elf/dl-minimal.c b/elf/dl-minimal.c +index 95ea7b024044864f..4335f1bd24289b01 100644 +--- a/elf/dl-minimal.c ++++ b/elf/dl-minimal.c +@@ -39,16 +39,16 @@ + implementation below. Before the final relocation, + __rtld_malloc_init_real is called to replace the pointers with the + real implementation. */ +-__typeof (calloc) *__rtld_calloc; +-__typeof (free) *__rtld_free; +-__typeof (malloc) *__rtld_malloc; +-__typeof (realloc) *__rtld_realloc; ++__typeof (calloc) *__rtld_calloc attribute_relro; ++__typeof (free) *__rtld_free attribute_relro; ++__typeof (malloc) *__rtld_malloc attribute_relro; ++__typeof (realloc) *__rtld_realloc attribute_relro; + + /* Defined below. */ +-static __typeof (calloc) rtld_calloc attribute_relro; +-static __typeof (free) rtld_free attribute_relro; +-static __typeof (malloc) rtld_malloc attribute_relro; +-static __typeof (realloc) rtld_realloc attribute_relro; ++static __typeof (calloc) rtld_calloc; ++static __typeof (free) rtld_free; ++static __typeof (malloc) rtld_malloc; ++static __typeof (realloc) rtld_realloc; + + void + __rtld_malloc_init_stubs (void) diff --git a/SOURCES/glibc-rh1817513-43.patch b/SOURCES/glibc-rh1817513-43.patch new file mode 100644 index 0000000..212bdc1 --- /dev/null +++ b/SOURCES/glibc-rh1817513-43.patch @@ -0,0 +1,356 @@ +commit dfe9aa91564c1bf2a23b5589a5db42f9da5d29b5 +Author: Adhemerval Zanella +Date: Tue Nov 19 17:17:05 2019 -0300 + + support: Add support_process_state_wait + + It allows parent process to wait for child state using a polling + strategy over procfs on Linux. The polling is used over ptrace to + avoid the need to handle signals on the target pid and to handle some + system specific limitation (such as YAMA). + + The polling has some limitations, such as resource consumption due + the procfs read in a loop and the lack of synchronization after the + state is obtained. + + The interface idea is to simplify some sleep synchronization waitid + tests and is to reduce timeouts by replacing arbitrary waits. + +diff --git a/support/Makefile b/support/Makefile +index 79d03bd6bfe02540..117cfdd4f22fc405 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -58,6 +58,7 @@ libsupport-routines = \ + support_format_hostent \ + support_format_netent \ + support_isolate_in_subprocess \ ++ support_process_state \ + support_ptrace \ + support_openpty \ + support_paths \ +@@ -90,6 +91,7 @@ libsupport-routines = \ + xfopen \ + xfork \ + xftruncate \ ++ xgetline \ + xgetsockname \ + xlisten \ + xlseek \ +@@ -217,6 +219,7 @@ tests = \ + tst-support_capture_subprocess \ + tst-support_descriptors \ + tst-support_format_dns_packet \ ++ tst-support-process_state \ + tst-support_quote_blob \ + tst-support_quote_string \ + tst-support_record_failure \ +diff --git a/support/process_state.h b/support/process_state.h +new file mode 100644 +index 0000000000000000..6c19afdbb7462277 +--- /dev/null ++++ b/support/process_state.h +@@ -0,0 +1,43 @@ ++/* Wait for process state. ++ 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 SUPPORT_PROCESS_STATE_H ++#define SUPPORT_PROCESS_STATE_H ++ ++#include ++ ++enum support_process_state ++{ ++ support_process_state_running = 0x01, /* R (running). */ ++ support_process_state_sleeping = 0x02, /* S (sleeping). */ ++ support_process_state_disk_sleep = 0x04, /* D (disk sleep). */ ++ support_process_state_stopped = 0x08, /* T (stopped). */ ++ support_process_state_tracing_stop = 0x10, /* t (tracing stop). */ ++ support_process_state_dead = 0x20, /* X (dead). */ ++ support_process_state_zombie = 0x40, /* Z (zombie). */ ++ support_process_state_parked = 0x80, /* P (parked). */ ++}; ++ ++/* Wait for process PID to reach state STATE. It can be a combination of ++ multiple possible states ('process_state_running | process_state_sleeping') ++ where the function return when any of these state are observed. ++ For an invalid state not represented by SUPPORT_PROCESS_STATE, it fallbacks ++ to a 2 second sleep. */ ++void support_process_state_wait (pid_t pid, enum support_process_state state); ++ ++#endif +diff --git a/support/support_process_state.c b/support/support_process_state.c +new file mode 100644 +index 0000000000000000..76dc798728ece0d9 +--- /dev/null ++++ b/support/support_process_state.c +@@ -0,0 +1,92 @@ ++/* Wait for process state. ++ 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 ++#include ++ ++void ++support_process_state_wait (pid_t pid, enum support_process_state state) ++{ ++#ifdef __linux__ ++ /* For Linux it does a polling check on /proc//status checking on ++ third field. */ ++ ++ /* It mimics the kernel states from fs/proc/array.c */ ++ static const struct process_states ++ { ++ enum support_process_state s; ++ char v; ++ } process_states[] = { ++ { support_process_state_running, 'R' }, ++ { support_process_state_sleeping, 'S' }, ++ { support_process_state_disk_sleep, 'D' }, ++ { support_process_state_stopped, 'T' }, ++ { support_process_state_tracing_stop, 't' }, ++ { support_process_state_dead, 'X' }, ++ { support_process_state_zombie, 'Z' }, ++ { support_process_state_parked, 'P' }, ++ }; ++ ++ char spath[sizeof ("/proc/" + 3) * sizeof (pid_t) + sizeof ("/status") + 1]; ++ snprintf (spath, sizeof (spath), "/proc/%i/status", pid); ++ ++ FILE *fstatus = xfopen (spath, "r"); ++ char *line = NULL; ++ size_t linesiz = 0; ++ ++ for (;;) ++ { ++ char cur_state = -1; ++ while (xgetline (&line, &linesiz, fstatus) != -1) ++ if (strncmp (line, "State:", strlen ("State:")) == 0) ++ { ++ TEST_COMPARE (sscanf (line, "%*s %c", &cur_state), 1); ++ break; ++ } ++ /* Fallback to nanosleep for invalid state. */ ++ if (cur_state == -1) ++ break; ++ ++ for (size_t i = 0; i < array_length (process_states); ++i) ++ if (state & process_states[i].s && cur_state == process_states[i].v) ++ { ++ free (line); ++ xfclose (fstatus); ++ return; ++ } ++ ++ rewind (fstatus); ++ fflush (fstatus); ++ ++ if (nanosleep (&(struct timespec) { 0, 10000000 }, NULL) != 0) ++ FAIL_EXIT1 ("nanosleep: %m"); ++ } ++ ++ free (line); ++ xfclose (fstatus); ++ /* Fallback to nanosleep if an invalid state is found. */ ++#endif ++ nanosleep (&(struct timespec) { 2, 0 }, NULL); ++} +diff --git a/support/tst-support-process_state.c b/support/tst-support-process_state.c +new file mode 100644 +index 0000000000000000..3fc103ab9205ddb0 +--- /dev/null ++++ b/support/tst-support-process_state.c +@@ -0,0 +1,105 @@ ++/* Wait for process state tests. ++ 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 ++#include ++#include ++#include ++ ++#ifndef WEXITED ++# define WEXITED 0 ++#endif ++ ++static void ++sigusr1_handler (int signo) ++{ ++} ++ ++static void ++test_child (void) ++{ ++ xsignal (SIGUSR1, sigusr1_handler); ++ ++ raise (SIGSTOP); ++ ++ TEST_COMPARE (pause (), -1); ++ TEST_COMPARE (errno, EINTR); ++ ++ while (1) ++ asm (""); ++} ++ ++static int ++do_test (void) ++{ ++ pid_t pid = xfork (); ++ if (pid == 0) ++ { ++ test_child (); ++ _exit (127); ++ } ++ ++ /* Adding process_state_tracing_stop ('t') allows the test to work under ++ trace programs such as ptrace. */ ++ enum support_process_state stop_state = support_process_state_stopped ++ | support_process_state_tracing_stop; ++ ++ if (test_verbose) ++ printf ("info: waiting pid %d, state_stopped/state_tracing_stop\n", ++ (int) pid); ++ support_process_state_wait (pid, stop_state); ++ ++ if (kill (pid, SIGCONT) != 0) ++ FAIL_RET ("kill (%d, SIGCONT): %m\n", pid); ++ ++ if (test_verbose) ++ printf ("info: waiting pid %d, state_sleeping\n", (int) pid); ++ support_process_state_wait (pid, support_process_state_sleeping); ++ ++ if (kill (pid, SIGUSR1) != 0) ++ FAIL_RET ("kill (%d, SIGUSR1): %m\n", pid); ++ ++ if (test_verbose) ++ printf ("info: waiting pid %d, state_running\n", (int) pid); ++ support_process_state_wait (pid, support_process_state_running); ++ ++ if (kill (pid, SIGKILL) != 0) ++ FAIL_RET ("kill (%d, SIGKILL): %m\n", pid); ++ ++ if (test_verbose) ++ printf ("info: waiting pid %d, state_zombie\n", (int) pid); ++ support_process_state_wait (pid, support_process_state_zombie); ++ ++ siginfo_t info; ++ int r = waitid (P_PID, pid, &info, WEXITED); ++ TEST_COMPARE (r, 0); ++ TEST_COMPARE (info.si_signo, SIGCHLD); ++ TEST_COMPARE (info.si_code, CLD_KILLED); ++ TEST_COMPARE (info.si_status, SIGKILL); ++ TEST_COMPARE (info.si_pid, pid); ++ ++ return 0; ++} ++ ++#include +diff --git a/support/xgetline.c b/support/xgetline.c +new file mode 100644 +index 0000000000000000..180bc2db95a9c5d4 +--- /dev/null ++++ b/support/xgetline.c +@@ -0,0 +1,33 @@ ++/* fopen with error checking. ++ 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 ++ ++ssize_t ++xgetline (char **lineptr, size_t *n, FILE *stream) ++{ ++ int old_errno = errno; ++ errno = 0; ++ size_t ret = getline (lineptr, n, stream); ++ if (!feof (stream) && ferror (stream)) ++ FAIL_EXIT1 ("getline failed: %m"); ++ errno = old_errno; ++ return ret; ++} +diff --git a/support/xstdio.h b/support/xstdio.h +index e7d0274474706380..9446b1f27b0f881e 100644 +--- a/support/xstdio.h ++++ b/support/xstdio.h +@@ -27,6 +27,8 @@ __BEGIN_DECLS + FILE *xfopen (const char *path, const char *mode); + void xfclose (FILE *); + ++ssize_t xgetline (char **lineptr, size_t *n, FILE *stream); ++ + __END_DECLS + + #endif /* SUPPORT_XSTDIO_H */ diff --git a/SOURCES/glibc-rh1817513-44.patch b/SOURCES/glibc-rh1817513-44.patch new file mode 100644 index 0000000..1b591b4 --- /dev/null +++ b/SOURCES/glibc-rh1817513-44.patch @@ -0,0 +1,24 @@ +commit 083d644d420f49c992667f4c7a54848ad3dee54d +Author: Michael Hudson-Doyle +Date: Wed Mar 11 13:05:25 2020 +1300 + + test-container: print errno when execvp fails + + I'm debugging a situation where lots of tests using test-container fail + and it's possible knowing errno would help understand why. + + Reviewed-by: DJ Delorie + +diff --git a/support/test-container.c b/support/test-container.c +index 9488ec7b4a824380..9eff8baeef0e9d8a 100644 +--- a/support/test-container.c ++++ b/support/test-container.c +@@ -1145,7 +1145,7 @@ main (int argc, char **argv) + execvp (new_child_exec, new_child_proc); + + /* Or don't run the child? */ +- FAIL_EXIT1 ("Unable to exec %s\n", new_child_exec); ++ FAIL_EXIT1 ("Unable to exec %s: %s\n", new_child_exec, strerror (errno)); + + /* Because gcc won't know error () never returns... */ + exit (EXIT_UNSUPPORTED); diff --git a/SOURCES/glibc-rh1817513-45.patch b/SOURCES/glibc-rh1817513-45.patch new file mode 100644 index 0000000..b578717 --- /dev/null +++ b/SOURCES/glibc-rh1817513-45.patch @@ -0,0 +1,106 @@ +commit b7176cc2aff4a8883e4834ddf65f8a6fdb1f160e +Author: DJ Delorie +Date: Wed Feb 19 12:31:38 2020 -0500 + + ldconfig: trace origin paths with -v + + With this patch, -v turns on a "from" trace for each directory + searched, that tells you WHY that directory is being searched - + is it a builtin, from the command line, or from some config file? + +diff --git a/elf/ldconfig.c b/elf/ldconfig.c +index ed7d9ab0412d93fd..5e6516688a1c192a 100644 +--- a/elf/ldconfig.c ++++ b/elf/ldconfig.c +@@ -79,6 +79,8 @@ struct dir_entry + int flag; + ino64_t ino; + dev_t dev; ++ const char *from_file; ++ int from_line; + struct dir_entry *next; + }; + +@@ -344,7 +346,12 @@ add_single_dir (struct dir_entry *entry, int verbose) + if (ptr->ino == entry->ino && ptr->dev == entry->dev) + { + if (opt_verbose && verbose) +- error (0, 0, _("Path `%s' given more than once"), entry->path); ++ { ++ error (0, 0, _("Path `%s' given more than once"), entry->path); ++ fprintf (stderr, _("(from %s:%d and %s:%d)\n"), ++ entry->from_file, entry->from_line, ++ ptr->from_file, ptr->from_line); ++ } + /* Use the newer information. */ + ptr->flag = entry->flag; + free (entry->path); +@@ -363,12 +370,15 @@ add_single_dir (struct dir_entry *entry, int verbose) + + /* Add one directory to the list of directories to process. */ + static void +-add_dir (const char *line) ++add_dir_1 (const char *line, const char *from_file, int from_line) + { + unsigned int i; + struct dir_entry *entry = xmalloc (sizeof (struct dir_entry)); + entry->next = NULL; + ++ entry->from_file = strdup (from_file); ++ entry->from_line = from_line; ++ + /* Search for an '=' sign. */ + entry->path = xstrdup (line); + char *equal_sign = strchr (entry->path, '='); +@@ -428,6 +438,11 @@ add_dir (const char *line) + free (path); + } + ++static void ++add_dir (const char *line) ++{ ++ add_dir_1 (line, "", 0); ++} + + static int + chroot_stat (const char *real_path, const char *path, struct stat64 *st) +@@ -672,9 +687,10 @@ search_dir (const struct dir_entry *entry) + if (opt_verbose) + { + if (hwcap != 0) +- printf ("%s: (hwcap: %#.16" PRIx64 ")\n", entry->path, hwcap); ++ printf ("%s: (hwcap: %#.16" PRIx64 ")", entry->path, hwcap); + else +- printf ("%s:\n", entry->path); ++ printf ("%s:", entry->path); ++ printf (_(" (from %s:%d)\n"), entry->from_file, entry->from_line); + } + + char *dir_name; +@@ -815,6 +831,8 @@ search_dir (const struct dir_entry *entry) + struct dir_entry *new_entry; + + new_entry = xmalloc (sizeof (struct dir_entry)); ++ new_entry->from_file = entry->from_file; ++ new_entry->from_line = entry->from_line; + new_entry->path = xstrdup (file_name); + new_entry->flag = entry->flag; + new_entry->next = NULL; +@@ -1174,7 +1192,7 @@ Warning: ignoring configuration file that cannot be opened: %s"), + } + } + else +- add_dir (cp); ++ add_dir_1 (cp, filename, lineno); + } + while (!feof_unlocked (file)); + +@@ -1282,7 +1300,7 @@ main (int argc, char **argv) + _("relative path `%s' used to build cache"), + argv[i]); + else +- add_dir (argv[i]); ++ add_dir_1 (argv[i], "", 0); + } + + /* The last entry in hwcap_extra is reserved for the "tls" pseudo-hwcap which diff --git a/SOURCES/glibc-rh1817513-46.patch b/SOURCES/glibc-rh1817513-46.patch new file mode 100644 index 0000000..7947d9f --- /dev/null +++ b/SOURCES/glibc-rh1817513-46.patch @@ -0,0 +1,83 @@ +commit cea56af185eae45b1f0963351e3d4daa1cbde521 +Author: Florian Weimer +Date: Thu Apr 2 17:09:36 2020 +0200 + + support: Change xgetline to return 0 on EOF + + The advantage is that the buffer will always contain the number + of characters as returned from the function, which allows one to use + a sequence like + + /* No more audit module output. */ + line_length = xgetline (&buffer, &buffer_length, fp); + TEST_COMPARE_BLOB ("", 0, buffer, line_length); + + to check for an expected EOF, while also reporting any unexpected + extra data encountered. + + Reviewed-by: Carlos O'Donell + +diff --git a/support/support_process_state.c b/support/support_process_state.c +index 76dc798728ece0d9..e303c78fc874b2f9 100644 +--- a/support/support_process_state.c ++++ b/support/support_process_state.c +@@ -59,7 +59,7 @@ support_process_state_wait (pid_t pid, enum support_process_state state) + for (;;) + { + char cur_state = -1; +- while (xgetline (&line, &linesiz, fstatus) != -1) ++ while (xgetline (&line, &linesiz, fstatus) > 0) + if (strncmp (line, "State:", strlen ("State:")) == 0) + { + TEST_COMPARE (sscanf (line, "%*s %c", &cur_state), 1); +diff --git a/support/xgetline.c b/support/xgetline.c +index 180bc2db95a9c5d4..d91c09ac108b4c75 100644 +--- a/support/xgetline.c ++++ b/support/xgetline.c +@@ -18,16 +18,22 @@ + + #include + #include +-#include + +-ssize_t ++size_t + xgetline (char **lineptr, size_t *n, FILE *stream) + { +- int old_errno = errno; +- errno = 0; +- size_t ret = getline (lineptr, n, stream); +- if (!feof (stream) && ferror (stream)) +- FAIL_EXIT1 ("getline failed: %m"); +- errno = old_errno; ++ TEST_VERIFY (!ferror (stream)); ++ ssize_t ret = getline (lineptr, n, stream); ++ if (ferror (stream)) ++ { ++ TEST_VERIFY (ret < 0); ++ FAIL_EXIT1 ("getline: %m"); ++ } ++ if (feof (stream)) ++ { ++ TEST_VERIFY (ret <= 0); ++ return 0; ++ } ++ TEST_VERIFY (ret > 0); + return ret; + } +diff --git a/support/xstdio.h b/support/xstdio.h +index 9446b1f27b0f881e..36071cf78822ec8d 100644 +--- a/support/xstdio.h ++++ b/support/xstdio.h +@@ -27,7 +27,10 @@ __BEGIN_DECLS + FILE *xfopen (const char *path, const char *mode); + void xfclose (FILE *); + +-ssize_t xgetline (char **lineptr, size_t *n, FILE *stream); ++/* Read a line from FP, using getline. *BUFFER must be NULL, or a ++ heap-allocated pointer of *LENGTH bytes. Return the number of ++ bytes in the line if a line was read, or 0 on EOF. */ ++size_t xgetline (char **lineptr, size_t *n, FILE *stream); + + __END_DECLS + diff --git a/SOURCES/glibc-rh1817513-47.patch b/SOURCES/glibc-rh1817513-47.patch new file mode 100644 index 0000000..ef5036c --- /dev/null +++ b/SOURCES/glibc-rh1817513-47.patch @@ -0,0 +1,373 @@ +commit 4c6e0415ef206a595c62d5d37e3b9a821782c533 +Author: Florian Weimer +Date: Fri Apr 3 13:17:48 2020 +0200 + + elf: Simplify handling of lists of audit strings + + All list elements are colon-separated strings, and there is a hard + upper limit for the number of audit modules, so it is possible to + pre-allocate a fixed-size array of strings to which the LD_AUDIT + environment variable and --audit arguments are added. + + Also eliminate the global variables for the audit list because + the list is only needed briefly during startup. + + There is a slight behavior change: All duplicate LD_AUDIT environment + variables are now processed, not just the last one as before. However, + such environment vectors are invalid anyway. + + Reviewed-by: Carlos O'Donell + +diff --git a/elf/rtld.c b/elf/rtld.c +index f755dc30331f799f..c39cb8f2cd4bb1cc 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -43,6 +43,7 @@ + #include + #include + #include ++#include + + #include + +@@ -107,8 +108,53 @@ static void print_missing_version (int errcode, const char *objname, + /* Print the various times we collected. */ + static void print_statistics (const hp_timing_t *total_timep); + +-/* Add audit objects. */ +-static void process_dl_audit (char *str); ++/* Length limits for names and paths, to protect the dynamic linker, ++ particularly when __libc_enable_secure is active. */ ++#ifdef NAME_MAX ++# define SECURE_NAME_LIMIT NAME_MAX ++#else ++# define SECURE_NAME_LIMIT 255 ++#endif ++#ifdef PATH_MAX ++# define SECURE_PATH_LIMIT PATH_MAX ++#else ++# define SECURE_PATH_LIMIT 1024 ++#endif ++ ++/* Strings containing colon-separated lists of audit modules. */ ++struct audit_list ++{ ++ /* Array of strings containing colon-separated path lists. Each ++ audit module needs its own namespace, so pre-allocate the largest ++ possible list. */ ++ const char *audit_strings[DL_NNS]; ++ ++ /* Number of entries added to audit_strings. */ ++ size_t length; ++ ++ /* Index into the audit_strings array (for the iteration phase). */ ++ size_t current_index; ++ ++ /* Tail of audit_strings[current_index] which still needs ++ processing. */ ++ const char *current_tail; ++ ++ /* Scratch buffer for returning a name which is part of the strings ++ in audit_strings. */ ++ char fname[SECURE_NAME_LIMIT]; ++}; ++ ++/* Creates an empty audit list. */ ++static void audit_list_init (struct audit_list *); ++ ++/* Add a string to the end of the audit list, for later parsing. Must ++ not be called after audit_list_next. */ ++static void audit_list_add_string (struct audit_list *, const char *); ++ ++/* Extract the next audit module from the audit list. Only modules ++ for which dso_name_valid_for_suid is true are returned. Must be ++ called after all the audit_list_add_string calls. */ ++static const char *audit_list_next (struct audit_list *); + + /* This is a list of all the modes the dynamic loader can be in. */ + enum mode { normal, list, verify, trace }; +@@ -116,7 +162,7 @@ enum mode { normal, list, verify, trace }; + /* Process all environments variables the dynamic linker must recognize. + Since all of them start with `LD_' we are a bit smarter while finding + all the entries. */ +-static void process_envvars (enum mode *modep); ++static void process_envvars (enum mode *modep, struct audit_list *); + + #ifdef DL_ARGV_NOT_RELRO + int _dl_argc attribute_hidden; +@@ -144,19 +190,6 @@ uintptr_t __pointer_chk_guard_local + strong_alias (__pointer_chk_guard_local, __pointer_chk_guard) + #endif + +-/* Length limits for names and paths, to protect the dynamic linker, +- particularly when __libc_enable_secure is active. */ +-#ifdef NAME_MAX +-# define SECURE_NAME_LIMIT NAME_MAX +-#else +-# define SECURE_NAME_LIMIT 255 +-#endif +-#ifdef PATH_MAX +-# define SECURE_PATH_LIMIT PATH_MAX +-#else +-# define SECURE_PATH_LIMIT 1024 +-#endif +- + /* Check that AT_SECURE=0, or that the passed name does not contain + directories and is not overly long. Reject empty names + unconditionally. */ +@@ -174,89 +207,75 @@ dso_name_valid_for_suid (const char *p) + return *p != '\0'; + } + +-/* LD_AUDIT variable contents. Must be processed before the +- audit_list below. */ +-const char *audit_list_string; +- +-/* Cyclic list of auditing DSOs. audit_list->next is the first +- element. */ +-static struct audit_list ++static void ++audit_list_init (struct audit_list *list) + { +- const char *name; +- struct audit_list *next; +-} *audit_list; ++ list->length = 0; ++ list->current_index = 0; ++ list->current_tail = NULL; ++} + +-/* Iterator for audit_list_string followed by audit_list. */ +-struct audit_list_iter ++static void ++audit_list_add_string (struct audit_list *list, const char *string) + { +- /* Tail of audit_list_string still needing processing, or NULL. */ +- const char *audit_list_tail; ++ /* Empty strings do not load anything. */ ++ if (*string == '\0') ++ return; + +- /* The list element returned in the previous iteration. NULL before +- the first element. */ +- struct audit_list *previous; ++ if (list->length == array_length (list->audit_strings)) ++ _dl_fatal_printf ("Fatal glibc error: Too many audit modules requested\n"); + +- /* Scratch buffer for returning a name which is part of +- audit_list_string. */ +- char fname[SECURE_NAME_LIMIT]; +-}; ++ list->audit_strings[list->length++] = string; + +-/* Initialize an audit list iterator. */ +-static void +-audit_list_iter_init (struct audit_list_iter *iter) +-{ +- iter->audit_list_tail = audit_list_string; +- iter->previous = NULL; ++ /* Initialize processing of the first string for ++ audit_list_next. */ ++ if (list->length == 1) ++ list->current_tail = string; + } + +-/* Iterate through both audit_list_string and audit_list. */ + static const char * +-audit_list_iter_next (struct audit_list_iter *iter) ++audit_list_next (struct audit_list *list) + { +- if (iter->audit_list_tail != NULL) ++ if (list->current_tail == NULL) ++ return NULL; ++ ++ while (true) + { +- /* First iterate over audit_list_string. */ +- while (*iter->audit_list_tail != '\0') ++ /* Advance to the next string in audit_strings if the current ++ string has been exhausted. */ ++ while (*list->current_tail == '\0') + { +- /* Split audit list at colon. */ +- size_t len = strcspn (iter->audit_list_tail, ":"); +- if (len > 0 && len < sizeof (iter->fname)) ++ ++list->current_index; ++ if (list->current_index == list->length) + { +- memcpy (iter->fname, iter->audit_list_tail, len); +- iter->fname[len] = '\0'; ++ list->current_tail = NULL; ++ return NULL; + } +- else +- /* Do not return this name to the caller. */ +- iter->fname[0] = '\0'; +- +- /* Skip over the substring and the following delimiter. */ +- iter->audit_list_tail += len; +- if (*iter->audit_list_tail == ':') +- ++iter->audit_list_tail; +- +- /* If the name is valid, return it. */ +- if (dso_name_valid_for_suid (iter->fname)) +- return iter->fname; +- /* Otherwise, wrap around and try the next name. */ ++ list->current_tail = list->audit_strings[list->current_index]; + } +- /* Fall through to the procesing of audit_list. */ +- } + +- if (iter->previous == NULL) +- { +- if (audit_list == NULL) +- /* No pre-parsed audit list. */ +- return NULL; +- /* Start of audit list. The first list element is at +- audit_list->next (cyclic list). */ +- iter->previous = audit_list->next; +- return iter->previous->name; ++ /* Split the in-string audit list at the next colon colon. */ ++ size_t len = strcspn (list->current_tail, ":"); ++ if (len > 0 && len < sizeof (list->fname)) ++ { ++ memcpy (list->fname, list->current_tail, len); ++ list->fname[len] = '\0'; ++ } ++ else ++ /* Mark the name as unusable for dso_name_valid_for_suid. */ ++ list->fname[0] = '\0'; ++ ++ /* Skip over the substring and the following delimiter. */ ++ list->current_tail += len; ++ if (*list->current_tail == ':') ++ ++list->current_tail; ++ ++ /* If the name is valid, return it. */ ++ if (dso_name_valid_for_suid (list->fname)) ++ return list->fname; ++ ++ /* Otherwise wrap around to find the next list element. . */ + } +- if (iter->previous == audit_list) +- /* Cyclic list wrap-around. */ +- return NULL; +- iter->previous = iter->previous->next; +- return iter->previous->name; + } + + /* Set nonzero during loading and initialization of executable and +@@ -1060,15 +1079,13 @@ notify_audit_modules_of_loaded_object (struct link_map *map) + + /* Load all audit modules. */ + static void +-load_audit_modules (struct link_map *main_map) ++load_audit_modules (struct link_map *main_map, struct audit_list *audit_list) + { + struct audit_ifaces *last_audit = NULL; +- struct audit_list_iter al_iter; +- audit_list_iter_init (&al_iter); + + while (true) + { +- const char *name = audit_list_iter_next (&al_iter); ++ const char *name = audit_list_next (audit_list); + if (name == NULL) + break; + load_audit_module (name, &last_audit); +@@ -1100,6 +1117,9 @@ dl_main (const ElfW(Phdr) *phdr, + bool rtld_is_main = false; + void *tcbp = NULL; + ++ struct audit_list audit_list; ++ audit_list_init (&audit_list); ++ + GL(dl_init_static_tls) = &_dl_nothread_init_static_tls; + + #if defined SHARED && defined _LIBC_REENTRANT \ +@@ -1113,7 +1133,7 @@ dl_main (const ElfW(Phdr) *phdr, + GL(dl_make_stack_executable_hook) = &_dl_make_stack_executable; + + /* Process the environment variable which control the behaviour. */ +- process_envvars (&mode); ++ process_envvars (&mode, &audit_list); + + /* Set up a flag which tells we are just starting. */ + _dl_starting_up = 1; +@@ -1185,7 +1205,7 @@ dl_main (const ElfW(Phdr) *phdr, + } + else if (! strcmp (_dl_argv[1], "--audit") && _dl_argc > 2) + { +- process_dl_audit (_dl_argv[2]); ++ audit_list_add_string (&audit_list, _dl_argv[2]); + + _dl_skip_args += 2; + _dl_argc -= 2; +@@ -1612,8 +1632,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + + /* If we have auditing DSOs to load, do it now. */ + bool need_security_init = true; +- if (__glibc_unlikely (audit_list != NULL) +- || __glibc_unlikely (audit_list_string != NULL)) ++ if (audit_list.length > 0) + { + /* Since we start using the auditing DSOs right away we need to + initialize the data structures now. */ +@@ -1626,7 +1645,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + security_init (); + need_security_init = false; + +- load_audit_modules (main_map); ++ load_audit_modules (main_map, &audit_list); + } + + /* Keep track of the currently loaded modules to count how many +@@ -2500,30 +2519,6 @@ a filename can be specified using the LD_DEBUG_OUTPUT environment variable.\n"); + } + } + +-static void +-process_dl_audit (char *str) +-{ +- /* The parameter is a colon separated list of DSO names. */ +- char *p; +- +- while ((p = (strsep) (&str, ":")) != NULL) +- if (dso_name_valid_for_suid (p)) +- { +- /* This is using the local malloc, not the system malloc. The +- memory can never be freed. */ +- struct audit_list *newp = malloc (sizeof (*newp)); +- newp->name = p; +- +- if (audit_list == NULL) +- audit_list = newp->next = newp; +- else +- { +- newp->next = audit_list->next; +- audit_list = audit_list->next = newp; +- } +- } +-} +- + /* Process all environments variables the dynamic linker must recognize. + Since all of them start with `LD_' we are a bit smarter while finding + all the entries. */ +@@ -2531,7 +2526,7 @@ extern char **_environ attribute_hidden; + + + static void +-process_envvars (enum mode *modep) ++process_envvars (enum mode *modep, struct audit_list *audit_list) + { + char **runp = _environ; + char *envline; +@@ -2571,7 +2566,7 @@ process_envvars (enum mode *modep) + break; + } + if (memcmp (envline, "AUDIT", 5) == 0) +- audit_list_string = &envline[6]; ++ audit_list_add_string (audit_list, &envline[6]); + break; + + case 7: diff --git a/SOURCES/glibc-rh1817513-48.patch b/SOURCES/glibc-rh1817513-48.patch new file mode 100644 index 0000000..455373d --- /dev/null +++ b/SOURCES/glibc-rh1817513-48.patch @@ -0,0 +1,379 @@ +commit 8f7a75d700af809eeb4363895078fabfb3a9d7c3 +Author: Florian Weimer +Date: Mon Feb 17 16:49:40 2020 +0100 + + elf: Implement DT_AUDIT, DT_DEPAUDIT support [BZ #24943] + + binutils ld has supported --audit, --depaudit for a long time, + only support in glibc has been missing. + + Reviewed-by: Carlos O'Donell + +Conflicts: + elf/Makefile + (Test backport differences.) + +diff --git a/elf/Makefile b/elf/Makefile +index 5b0aeccb0a53c182..a6601ba84c8f4017 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -195,7 +195,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-sonamemove-link tst-sonamemove-dlopen \ + tst-auditmany tst-initfinilazyfail \ + tst-dlopenfail tst-dlopenfail-2 \ +- tst-filterobj tst-filterobj-dlopen tst-auxobj tst-auxobj-dlopen ++ tst-filterobj tst-filterobj-dlopen tst-auxobj tst-auxobj-dlopen \ ++ tst-audit14 tst-audit15 tst-audit16 + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -310,7 +311,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-initlazyfailmod tst-finilazyfailmod \ + tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 \ + tst-dlopenfailmod3 \ +- tst-filterobj-flt tst-filterobj-aux tst-filterobj-filtee ++ tst-filterobj-flt tst-filterobj-aux tst-filterobj-filtee \ ++ tst-auditlogmod-1 tst-auditlogmod-2 tst-auditlogmod-3 + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +@@ -1453,6 +1455,22 @@ $(objpfx)tst-auditmany.out: $(objpfx)tst-auditmanymod1.so \ + tst-auditmany-ENV = \ + LD_AUDIT=tst-auditmanymod1.so:tst-auditmanymod2.so:tst-auditmanymod3.so:tst-auditmanymod4.so:tst-auditmanymod5.so:tst-auditmanymod6.so:tst-auditmanymod7.so:tst-auditmanymod8.so:tst-auditmanymod9.so + ++LDFLAGS-tst-audit14 = -Wl,--audit=tst-auditlogmod-1.so ++$(objpfx)tst-auditlogmod-1.so: $(libsupport) ++$(objpfx)tst-audit14.out: $(objpfx)tst-auditlogmod-1.so ++LDFLAGS-tst-audit15 = \ ++ -Wl,--audit=tst-auditlogmod-1.so,--depaudit=tst-auditlogmod-2.so ++$(objpfx)tst-auditlogmod-2.so: $(libsupport) ++$(objpfx)tst-audit15.out: \ ++ $(objpfx)tst-auditlogmod-1.so $(objpfx)tst-auditlogmod-2.so ++LDFLAGS-tst-audit16 = \ ++ -Wl,--audit=tst-auditlogmod-1.so:tst-auditlogmod-2.so \ ++ -Wl,--depaudit=tst-auditlogmod-3.so ++$(objpfx)tst-auditlogmod-3.so: $(libsupport) ++$(objpfx)tst-audit16.out: \ ++ $(objpfx)tst-auditlogmod-1.so $(objpfx)tst-auditlogmod-2.so \ ++ $(objpfx)tst-auditlogmod-3.so ++ + # tst-sonamemove links against an older implementation of the library. + LDFLAGS-tst-sonamemove-linkmod1.so = \ + -Wl,--version-script=tst-sonamemove-linkmod1.map \ +diff --git a/elf/rtld.c b/elf/rtld.c +index c39cb8f2cd4bb1cc..d44facf5343b3301 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -151,9 +151,17 @@ static void audit_list_init (struct audit_list *); + not be called after audit_list_next. */ + static void audit_list_add_string (struct audit_list *, const char *); + ++/* Add the audit strings from the link map, found in the dynamic ++ segment at TG (either DT_AUDIT and DT_DEPAUDIT). Must be called ++ before audit_list_next. */ ++static void audit_list_add_dynamic_tag (struct audit_list *, ++ struct link_map *, ++ unsigned int tag); ++ + /* Extract the next audit module from the audit list. Only modules + for which dso_name_valid_for_suid is true are returned. Must be +- called after all the audit_list_add_string calls. */ ++ called after all the audit_list_add_string, ++ audit_list_add_dynamic_tags calls. */ + static const char *audit_list_next (struct audit_list *); + + /* This is a list of all the modes the dynamic loader can be in. */ +@@ -233,6 +241,16 @@ audit_list_add_string (struct audit_list *list, const char *string) + list->current_tail = string; + } + ++static void ++audit_list_add_dynamic_tag (struct audit_list *list, struct link_map *main_map, ++ unsigned int tag) ++{ ++ ElfW(Dyn) *info = main_map->l_info[ADDRIDX (tag)]; ++ const char *strtab = (const char *) D_PTR (main_map, l_info[DT_STRTAB]); ++ if (info != NULL) ++ audit_list_add_string (list, strtab + info->d_un.d_val); ++} ++ + static const char * + audit_list_next (struct audit_list *list) + { +@@ -1630,6 +1648,9 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + /* Assign a module ID. Do this before loading any audit modules. */ + GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid (); + ++ audit_list_add_dynamic_tag (&audit_list, main_map, DT_AUDIT); ++ audit_list_add_dynamic_tag (&audit_list, main_map, DT_DEPAUDIT); ++ + /* If we have auditing DSOs to load, do it now. */ + bool need_security_init = true; + if (audit_list.length > 0) +diff --git a/elf/tst-audit14.c b/elf/tst-audit14.c +new file mode 100644 +index 0000000000000000..27ff8db9480a98cc +--- /dev/null ++++ b/elf/tst-audit14.c +@@ -0,0 +1,46 @@ ++/* Main program with DT_AUDIT. One audit module. ++ 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 int ++do_test (void) ++{ ++ /* Verify what the audit module has written. This test assumes that ++ standard output has been redirected to a regular file. */ ++ FILE *fp = xfopen ("/dev/stdout", "r"); ++ ++ char *buffer = NULL; ++ size_t buffer_length = 0; ++ size_t line_length = xgetline (&buffer, &buffer_length, fp); ++ const char *message = "info: tst-auditlogmod-1.so loaded\n"; ++ TEST_COMPARE_BLOB (message, strlen (message), buffer, line_length); ++ ++ /* No more audit module output. */ ++ line_length = xgetline (&buffer, &buffer_length, fp); ++ TEST_COMPARE_BLOB ("", 0, buffer, line_length); ++ ++ free (buffer); ++ xfclose (fp); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-audit15.c b/elf/tst-audit15.c +new file mode 100644 +index 0000000000000000..cbd1589ec40653d1 +--- /dev/null ++++ b/elf/tst-audit15.c +@@ -0,0 +1,50 @@ ++/* Main program with DT_AUDIT and DT_DEPAUDIT. Two audit modules. ++ 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 int ++do_test (void) ++{ ++ /* Verify what the audit modules have written. This test assumes ++ that standard output has been redirected to a regular file. */ ++ FILE *fp = xfopen ("/dev/stdout", "r"); ++ ++ char *buffer = NULL; ++ size_t buffer_length = 0; ++ size_t line_length = xgetline (&buffer, &buffer_length, fp); ++ const char *message = "info: tst-auditlogmod-1.so loaded\n"; ++ TEST_COMPARE_BLOB (message, strlen (message), buffer, line_length); ++ ++ line_length = xgetline (&buffer, &buffer_length, fp); ++ message = "info: tst-auditlogmod-2.so loaded\n"; ++ TEST_COMPARE_BLOB (message, strlen (message), buffer, line_length); ++ ++ /* No more audit module output. */ ++ line_length = xgetline (&buffer, &buffer_length, fp); ++ TEST_COMPARE_BLOB ("", 0, buffer, line_length); ++ ++ free (buffer); ++ xfclose (fp); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-audit16.c b/elf/tst-audit16.c +new file mode 100644 +index 0000000000000000..dd6ce189ea6fffa3 +--- /dev/null ++++ b/elf/tst-audit16.c +@@ -0,0 +1,54 @@ ++/* Main program with DT_AUDIT and DT_DEPAUDIT. Three audit modules. ++ 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 int ++do_test (void) ++{ ++ /* Verify what the audit modules have written. This test assumes ++ that standard output has been redirected to a regular file. */ ++ FILE *fp = xfopen ("/dev/stdout", "r"); ++ ++ char *buffer = NULL; ++ size_t buffer_length = 0; ++ size_t line_length = xgetline (&buffer, &buffer_length, fp); ++ const char *message = "info: tst-auditlogmod-1.so loaded\n"; ++ TEST_COMPARE_BLOB (message, strlen (message), buffer, line_length); ++ ++ line_length = xgetline (&buffer, &buffer_length, fp); ++ message = "info: tst-auditlogmod-2.so loaded\n"; ++ TEST_COMPARE_BLOB (message, strlen (message), buffer, line_length); ++ ++ line_length = xgetline (&buffer, &buffer_length, fp); ++ message = "info: tst-auditlogmod-3.so loaded\n"; ++ TEST_COMPARE_BLOB (message, strlen (message), buffer, line_length); ++ ++ /* No more audit module output. */ ++ line_length = xgetline (&buffer, &buffer_length, fp); ++ TEST_COMPARE_BLOB ("", 0, buffer, line_length); ++ ++ free (buffer); ++ xfclose (fp); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-auditlogmod-1.c b/elf/tst-auditlogmod-1.c +new file mode 100644 +index 0000000000000000..db9dac4c01a58dcd +--- /dev/null ++++ b/elf/tst-auditlogmod-1.c +@@ -0,0 +1,27 @@ ++/* Audit module which logs that it was loaded. Variant 1. ++ 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 ++ ++unsigned int ++la_version (unsigned int v) ++{ ++ write_message ("info: tst-auditlogmod-1.so loaded\n"); ++ return LAV_CURRENT; ++} +diff --git a/elf/tst-auditlogmod-2.c b/elf/tst-auditlogmod-2.c +new file mode 100644 +index 0000000000000000..871c22641c47fed0 +--- /dev/null ++++ b/elf/tst-auditlogmod-2.c +@@ -0,0 +1,27 @@ ++/* Audit module which logs that it was loaded. Variant 2. ++ 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 ++ ++unsigned int ++la_version (unsigned int v) ++{ ++ write_message ("info: tst-auditlogmod-2.so loaded\n"); ++ return LAV_CURRENT; ++} +diff --git a/elf/tst-auditlogmod-3.c b/elf/tst-auditlogmod-3.c +new file mode 100644 +index 0000000000000000..da2ee19d4ab9e861 +--- /dev/null ++++ b/elf/tst-auditlogmod-3.c +@@ -0,0 +1,27 @@ ++/* Audit module which logs that it was loaded. Variant 3. ++ 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 ++ ++unsigned int ++la_version (unsigned int v) ++{ ++ write_message ("info: tst-auditlogmod-3.so loaded\n"); ++ return LAV_CURRENT; ++} diff --git a/SOURCES/glibc-rh1817513-49.patch b/SOURCES/glibc-rh1817513-49.patch new file mode 100644 index 0000000..23a310a --- /dev/null +++ b/SOURCES/glibc-rh1817513-49.patch @@ -0,0 +1,163 @@ +commit 50a2d83c08a94a10f88a1fedeb7a6e3667a6b732 +Author: Florian Weimer +Date: Fri Apr 24 22:13:03 2020 +0200 + + elf: Introduce + + MIPS needs to ignore certain existing symbols during symbol lookup. + The old scheme uses the ELF_MACHINE_SYM_NO_MATCH macro, with an + inline function, within its own header, with a sysdeps override for + MIPS. This allows re-use of the function from another file (without + having to include or providing the default definition + for ELF_MACHINE_SYM_NO_MATCH). + + Reviewed-by: Carlos O'Donell + +diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c +index e4c479de9a1fd6ec..47acd134600b44b5 100644 +--- a/elf/dl-lookup.c ++++ b/elf/dl-lookup.c +@@ -28,18 +28,12 @@ + #include + #include + #include ++#include + + #include + +-/* Return nonzero if check_match should consider SYM to fail to match a +- symbol reference for some machine-specific reason. */ +-#ifndef ELF_MACHINE_SYM_NO_MATCH +-# define ELF_MACHINE_SYM_NO_MATCH(sym) 0 +-#endif +- + #define VERSTAG(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag)) + +- + struct sym_val + { + const ElfW(Sym) *s; +@@ -78,7 +72,7 @@ check_match (const char *const undef_name, + if (__glibc_unlikely ((sym->st_value == 0 /* No value. */ + && sym->st_shndx != SHN_ABS + && stt != STT_TLS) +- || ELF_MACHINE_SYM_NO_MATCH (sym) ++ || elf_machine_sym_no_match (sym) + || (type_class & (sym->st_shndx == SHN_UNDEF)))) + return NULL; + +diff --git a/sysdeps/generic/elf_machine_sym_no_match.h b/sysdeps/generic/elf_machine_sym_no_match.h +new file mode 100644 +index 0000000000000000..27155de4c0358460 +--- /dev/null ++++ b/sysdeps/generic/elf_machine_sym_no_match.h +@@ -0,0 +1,34 @@ ++/* Function to ignore certain symbol matches for machine-specific reasons. ++ 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 _ELF_MACHINE_SYM_NO_MATCH_H ++#define _ELF_MACHINE_SYM_NO_MATCH_H ++ ++#include ++#include ++ ++/* This can be customized to ignore certain symbols during lookup in ++ case there are machine-specific rules to disregard some ++ symbols. */ ++static inline bool ++elf_machine_sym_no_match (const ElfW(Sym) *sym) ++{ ++ return false; ++} ++ ++#endif /* _ELF_MACHINE_SYM_NO_MATCH_H */ +diff --git a/sysdeps/mips/dl-machine.h b/sysdeps/mips/dl-machine.h +index 91fc640388a735c7..b41e10647d81843b 100644 +--- a/sysdeps/mips/dl-machine.h ++++ b/sysdeps/mips/dl-machine.h +@@ -467,21 +467,6 @@ elf_machine_plt_value (struct link_map *map, const ElfW(Rel) *reloc, + return value; + } + +-/* The semantics of zero/non-zero values of undefined symbols differs +- depending on whether the non-PIC ABI is in use. Under the non-PIC +- ABI, a non-zero value indicates that there is an address reference +- to the symbol and thus it must always be resolved (except when +- resolving a jump slot relocation) to the PLT entry whose address is +- provided as the symbol's value; a zero value indicates that this +- canonical-address behaviour is not required. Yet under the classic +- MIPS psABI, a zero value indicates that there is an address +- reference to the function and the dynamic linker must resolve the +- symbol immediately upon loading. To avoid conflict, symbols for +- which the dynamic linker must assume the non-PIC ABI semantics are +- marked with the STO_MIPS_PLT flag. */ +-#define ELF_MACHINE_SYM_NO_MATCH(sym) \ +- ((sym)->st_shndx == SHN_UNDEF && !((sym)->st_other & STO_MIPS_PLT)) +- + #endif /* !dl_machine_h */ + + #ifdef RESOLVE_MAP +diff --git a/sysdeps/mips/elf_machine_sym_no_match.h b/sysdeps/mips/elf_machine_sym_no_match.h +new file mode 100644 +index 0000000000000000..9d09e5fa2db1ff6c +--- /dev/null ++++ b/sysdeps/mips/elf_machine_sym_no_match.h +@@ -0,0 +1,43 @@ ++/* MIPS-specific handling of undefined symbols. ++ Copyright (C) 2008-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 _ELF_MACHINE_SYM_NO_MATCH_H ++#define _ELF_MACHINE_SYM_NO_MATCH_H ++ ++#include ++#include ++ ++/* The semantics of zero/non-zero values of undefined symbols differs ++ depending on whether the non-PIC ABI is in use. Under the non-PIC ++ ABI, a non-zero value indicates that there is an address reference ++ to the symbol and thus it must always be resolved (except when ++ resolving a jump slot relocation) to the PLT entry whose address is ++ provided as the symbol's value; a zero value indicates that this ++ canonical-address behaviour is not required. Yet under the classic ++ MIPS psABI, a zero value indicates that there is an address ++ reference to the function and the dynamic linker must resolve the ++ symbol immediately upon loading. To avoid conflict, symbols for ++ which the dynamic linker must assume the non-PIC ABI semantics are ++ marked with the STO_MIPS_PLT flag. */ ++static inline bool ++elf_machine_sym_no_match (const ElfW(Sym) *sym) ++{ ++ return sym->st_shndx == SHN_UNDEF && !(sym->st_other & STO_MIPS_PLT); ++} ++ ++#endif /* _ELF_MACHINE_SYM_NO_MATCH_H */ diff --git a/SOURCES/glibc-rh1817513-5.patch b/SOURCES/glibc-rh1817513-5.patch new file mode 100644 index 0000000..dba4a6e --- /dev/null +++ b/SOURCES/glibc-rh1817513-5.patch @@ -0,0 +1,82 @@ +commit fb4c32aef64500c65c7fc95ca06d7e17d467be45 +Author: H.J. Lu +Date: Mon Aug 6 06:25:28 2018 -0700 + + x86: Move STATE_SAVE_OFFSET/STATE_SAVE_MASK to sysdep.h + + Move STATE_SAVE_OFFSET and STATE_SAVE_MASK to sysdep.h to make + sysdeps/x86/cpu-features.h a C header file. + + * sysdeps/x86/cpu-features.h (STATE_SAVE_OFFSET): Removed. + (STATE_SAVE_MASK): Likewise. + Don't check __ASSEMBLER__ to include . + * sysdeps/x86/sysdep.h (STATE_SAVE_OFFSET): New. + (STATE_SAVE_MASK): Likewise. + * sysdeps/x86_64/dl-trampoline.S: Include + instead of . + +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 4c6d08c709eea204..d342664c64ab7aa1 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -92,18 +92,6 @@ + /* The current maximum size of the feature integer bit array. */ + #define FEATURE_INDEX_MAX 1 + +-/* Offset for fxsave/xsave area used by _dl_runtime_resolve. Also need +- space to preserve RCX, RDX, RSI, RDI, R8, R9 and RAX. It must be +- aligned to 16 bytes for fxsave and 64 bytes for xsave. */ +-#define STATE_SAVE_OFFSET (8 * 7 + 8) +- +-/* Save SSE, AVX, AVX512, mask and bound registers. */ +-#define STATE_SAVE_MASK \ +- ((1 << 1) | (1 << 2) | (1 << 3) | (1 << 5) | (1 << 6) | (1 << 7)) +- +-#ifdef __ASSEMBLER__ +-# include +-#else /* __ASSEMBLER__ */ + enum + { + COMMON_CPUID_INDEX_1 = 0, +@@ -267,8 +255,6 @@ extern const struct cpu_features *__get_cpu_features (void) + # define index_arch_XSAVEC_Usable FEATURE_INDEX_1 + # define index_arch_Prefer_FSRM FEATURE_INDEX_1 + +-#endif /* !__ASSEMBLER__ */ +- + #ifdef __x86_64__ + # define HAS_CPUID 1 + #elif defined __i586__ || defined __pentium__ +diff --git a/sysdeps/x86/sysdep.h b/sysdeps/x86/sysdep.h +index 8776ad8374e056d3..f41f4ebd425cfbaf 100644 +--- a/sysdeps/x86/sysdep.h ++++ b/sysdeps/x86/sysdep.h +@@ -48,6 +48,15 @@ enum cf_protection_level + # define SHSTK_ENABLED 0 + #endif + ++/* Offset for fxsave/xsave area used by _dl_runtime_resolve. Also need ++ space to preserve RCX, RDX, RSI, RDI, R8, R9 and RAX. It must be ++ aligned to 16 bytes for fxsave and 64 bytes for xsave. */ ++#define STATE_SAVE_OFFSET (8 * 7 + 8) ++ ++/* Save SSE, AVX, AVX512, mask and bound registers. */ ++#define STATE_SAVE_MASK \ ++ ((1 << 1) | (1 << 2) | (1 << 3) | (1 << 5) | (1 << 6) | (1 << 7)) ++ + #ifdef __ASSEMBLER__ + + /* Syntactic details of assembler. */ +diff --git a/sysdeps/x86_64/dl-trampoline.S b/sysdeps/x86_64/dl-trampoline.S +index ef1425cbb909529a..fd918510fe155733 100644 +--- a/sysdeps/x86_64/dl-trampoline.S ++++ b/sysdeps/x86_64/dl-trampoline.S +@@ -18,7 +18,7 @@ + + #include + #include +-#include ++#include + #include + + #ifndef DL_STACK_ALIGNMENT diff --git a/SOURCES/glibc-rh1817513-50.patch b/SOURCES/glibc-rh1817513-50.patch new file mode 100644 index 0000000..a3092bd --- /dev/null +++ b/SOURCES/glibc-rh1817513-50.patch @@ -0,0 +1,538 @@ +commit ec935dea6332cb22f9881cd1162bad156173f4b0 +Author: Florian Weimer +Date: Fri Apr 24 22:31:15 2020 +0200 + + elf: Implement __libc_early_init + + This function is defined in libc.so, and the dynamic loader calls + right after relocation has been finished, before any ELF constructors + or the preinit function is invoked. It is also used in the static + build for initializing parts of the static libc. + + To locate __libc_early_init, a direct symbol lookup function is used, + _dl_lookup_direct. It does not search the entire symbol scope and + consults merely a single link map. This function could also be used + to implement lookups in the vDSO (as an optimization). + + A per-namespace variable (libc_map) is added for locating libc.so, + to avoid repeated traversals of the search scope. It is similar to + GL(dl_initfirst). An alternative would have been to thread a context + argument from _dl_open down to _dl_map_object_from_fd (where libc.so + is identified). This could have avoided the global variable, but + the change would be larger as a result. It would not have been + possible to use this to replace GL(dl_initfirst) because that global + variable is used to pass the function pointer past the stack switch + from dl_main to the main program. Replacing that requires adding + a new argument to _dl_init, which in turn needs changes to the + architecture-specific libc.so startup code written in assembler. + + __libc_early_init should not be used to replace _dl_var_init (as + it exists today on some architectures). Instead, _dl_lookup_direct + should be used to look up a new variable symbol in libc.so, and + that should then be initialized from the dynamic loader, immediately + after the object has been loaded in _dl_map_object_from_fd (before + relocation is run). This way, more IFUNC resolvers which depend on + these variables will work. + + Reviewed-by: Carlos O'Donell + +diff --git a/csu/init-first.c b/csu/init-first.c +index 289373f9d8bd98f4..544229151ef79c67 100644 +--- a/csu/init-first.c ++++ b/csu/init-first.c +@@ -16,7 +16,6 @@ + License along with the GNU C Library; if not, see + . */ + +-#include + #include + #include + #include +@@ -80,9 +79,6 @@ _init (int argc, char **argv, char **envp) + + __init_misc (argc, argv, envp); + +- /* Initialize ctype data. */ +- __ctype_init (); +- + #if defined SHARED && !defined NO_CTORS_DTORS_SECTIONS + __libc_global_ctors (); + #endif +diff --git a/csu/libc-start.c b/csu/libc-start.c +index dfbf195328239a17..d9c3248219d8f84f 100644 +--- a/csu/libc-start.c ++++ b/csu/libc-start.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #include + +@@ -238,6 +239,10 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), + __cxa_atexit ((void (*) (void *)) rtld_fini, NULL, NULL); + + #ifndef SHARED ++ /* Perform early initialization. In the shared case, this function ++ is called from the dynamic loader as early as possible. */ ++ __libc_early_init (); ++ + /* Call the initializer of the libc. This is only needed here if we + are compiling for the static library in which case we haven't + run the constructors in `_dl_start_user'. */ +diff --git a/elf/Makefile b/elf/Makefile +index a6601ba84c8f4017..cbced7605ebe2443 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -25,7 +25,7 @@ headers = elf.h bits/elfclass.h link.h bits/link.h + routines = $(all-dl-routines) dl-support dl-iteratephdr \ + dl-addr dl-addr-obj enbl-secure dl-profstub \ + dl-origin dl-libc dl-sym dl-sysdep dl-error \ +- dl-reloc-static-pie ++ dl-reloc-static-pie libc_early_init + + # The core dynamic linking functions are in libc for the static and + # profiled libraries. +@@ -33,7 +33,8 @@ dl-routines = $(addprefix dl-,load lookup object reloc deps hwcaps \ + runtime init fini debug misc \ + version profile tls origin scope \ + execstack open close trampoline \ +- exception sort-maps) ++ exception sort-maps lookup-direct \ ++ call-libc-early-init) + ifeq (yes,$(use-ldconfig)) + dl-routines += dl-cache + endif +diff --git a/elf/Versions b/elf/Versions +index 705489fc51f4ac5f..3be879c4adfa74c7 100644 +--- a/elf/Versions ++++ b/elf/Versions +@@ -26,6 +26,7 @@ libc { + _dl_open_hook; _dl_open_hook2; + _dl_sym; _dl_vsym; + __libc_dlclose; __libc_dlopen_mode; __libc_dlsym; __libc_dlvsym; ++ __libc_early_init; + + # Internal error handling support. Interposes the functions in ld.so. + _dl_signal_exception; _dl_catch_exception; +diff --git a/elf/dl-call-libc-early-init.c b/elf/dl-call-libc-early-init.c +new file mode 100644 +index 0000000000000000..41e9ad9aad8b5b46 +--- /dev/null ++++ b/elf/dl-call-libc-early-init.c +@@ -0,0 +1,41 @@ ++/* Invoke the early initialization function in libc.so. ++ 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 ++ ++void ++_dl_call_libc_early_init (struct link_map *libc_map) ++{ ++ /* There is nothing to do if we did not actually load libc.so. */ ++ if (libc_map == NULL) ++ return; ++ ++ const ElfW(Sym) *sym ++ = _dl_lookup_direct (libc_map, "__libc_early_init", ++ 0x069682ac, /* dl_new_hash output. */ ++ "GLIBC_PRIVATE", ++ 0x0963cf85); /* _dl_elf_hash output. */ ++ assert (sym != NULL); ++ __typeof (__libc_early_init) *early_init ++ = DL_SYMBOL_ADDRESS (libc_map, sym); ++ early_init (); ++} +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 8f8869ff524ab9f2..64da5323d0e368c1 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + + /* Type for the buffer we put the ELF header and hopefully the program + header. This buffer does not really have to be too large. In most +@@ -1390,6 +1391,14 @@ cannot enable executable stack as shared object requires"); + add_name_to_object (l, ((const char *) D_PTR (l, l_info[DT_STRTAB]) + + l->l_info[DT_SONAME]->d_un.d_val)); + ++ /* If we have newly loaded libc.so, update the namespace ++ description. */ ++ if (GL(dl_ns)[nsid].libc_map == NULL ++ && l->l_info[DT_SONAME] != NULL ++ && strcmp (((const char *) D_PTR (l, l_info[DT_STRTAB]) ++ + l->l_info[DT_SONAME]->d_un.d_val), LIBC_SO) == 0) ++ GL(dl_ns)[nsid].libc_map = l; ++ + /* _dl_close can only eventually undo the module ID assignment (via + remove_slotinfo) if this function returns a pointer to a link + map. Therefore, delay this step until all possibilities for +diff --git a/elf/dl-lookup-direct.c b/elf/dl-lookup-direct.c +new file mode 100644 +index 0000000000000000..5637ae89de8a9d61 +--- /dev/null ++++ b/elf/dl-lookup-direct.c +@@ -0,0 +1,116 @@ ++/* Look up a symbol in a single specified object. ++ Copyright (C) 1995-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 ++ ++/* This function corresponds to do_lookup_x in elf/dl-lookup.c. The ++ variant here is simplified because it requires symbol ++ versioning. */ ++static const ElfW(Sym) * ++check_match (const struct link_map *const map, const char *const undef_name, ++ const char *version, uint32_t version_hash, ++ const Elf_Symndx symidx) ++{ ++ const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]); ++ const ElfW(Sym) *sym = &symtab[symidx]; ++ ++ unsigned int stt = ELFW(ST_TYPE) (sym->st_info); ++ if (__glibc_unlikely ((sym->st_value == 0 /* No value. */ ++ && sym->st_shndx != SHN_ABS ++ && stt != STT_TLS) ++ || elf_machine_sym_no_match (sym))) ++ return NULL; ++ ++ /* Ignore all but STT_NOTYPE, STT_OBJECT, STT_FUNC, ++ STT_COMMON, STT_TLS, and STT_GNU_IFUNC since these are no ++ code/data definitions. */ ++#define ALLOWED_STT \ ++ ((1 << STT_NOTYPE) | (1 << STT_OBJECT) | (1 << STT_FUNC) \ ++ | (1 << STT_COMMON) | (1 << STT_TLS) | (1 << STT_GNU_IFUNC)) ++ if (__glibc_unlikely (((1 << stt) & ALLOWED_STT) == 0)) ++ return NULL; ++ ++ const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]); ++ ++ if (strcmp (strtab + sym->st_name, undef_name) != 0) ++ /* Not the symbol we are looking for. */ ++ return NULL; ++ ++ ElfW(Half) ndx = map->l_versyms[symidx] & 0x7fff; ++ if (map->l_versions[ndx].hash != version_hash ++ || strcmp (map->l_versions[ndx].name, version) != 0) ++ /* It's not the version we want. */ ++ return NULL; ++ ++ return sym; ++} ++ ++ ++/* This function corresponds to do_lookup_x in elf/dl-lookup.c. The ++ variant here is simplified because it does not search object ++ dependencies. It is optimized for a successful lookup. */ ++const ElfW(Sym) * ++_dl_lookup_direct (struct link_map *map, ++ const char *undef_name, uint32_t new_hash, ++ const char *version, uint32_t version_hash) ++{ ++ const ElfW(Addr) *bitmask = map->l_gnu_bitmask; ++ if (__glibc_likely (bitmask != NULL)) ++ { ++ Elf32_Word bucket = map->l_gnu_buckets[new_hash % map->l_nbuckets]; ++ if (bucket != 0) ++ { ++ const Elf32_Word *hasharr = &map->l_gnu_chain_zero[bucket]; ++ ++ do ++ if (((*hasharr ^ new_hash) >> 1) == 0) ++ { ++ Elf_Symndx symidx = ELF_MACHINE_HASH_SYMIDX (map, hasharr); ++ const ElfW(Sym) *sym = check_match (map, undef_name, ++ version, version_hash, ++ symidx); ++ if (sym != NULL) ++ return sym; ++ } ++ while ((*hasharr++ & 1u) == 0); ++ } ++ } ++ else ++ { ++ /* Fallback code for lack of GNU_HASH support. */ ++ uint32_t old_hash = _dl_elf_hash (undef_name); ++ ++ /* Use the old SysV-style hash table. Search the appropriate ++ hash bucket in this object's symbol table for a definition ++ for the same symbol name. */ ++ for (Elf_Symndx symidx = map->l_buckets[old_hash % map->l_nbuckets]; ++ symidx != STN_UNDEF; ++ symidx = map->l_chain[symidx]) ++ { ++ const ElfW(Sym) *sym = check_match (map, undef_name, ++ version, version_hash, symidx); ++ if (sym != NULL) ++ return sym; ++ } ++ } ++ ++ return NULL; ++} +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 7113c4a04f0fddbc..1a77ec833cad6c55 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -57,6 +58,13 @@ struct dl_open_args + (non-negative). */ + unsigned int original_global_scope_pending_adds; + ++ /* Set to true by dl_open_worker if libc.so was already loaded into ++ the namespace at the time dl_open_worker was called. This is ++ used to determine whether libc.so early initialization has ++ already been done before, and whether to roll back the cached ++ libc_map value in the namespace in case of a dlopen failure. */ ++ bool libc_already_loaded; ++ + /* Original parameters to the program and the current environment. */ + int argc; + char **argv; +@@ -500,6 +508,11 @@ dl_open_worker (void *a) + args->nsid = call_map->l_ns; + } + ++ /* The namespace ID is now known. Keep track of whether libc.so was ++ already loaded, to determine whether it is necessary to call the ++ early initialization routine (or clear libc_map on error). */ ++ args->libc_already_loaded = GL(dl_ns)[args->nsid].libc_map != NULL; ++ + /* Retain the old value, so that it can be restored. */ + args->original_global_scope_pending_adds + = GL (dl_ns)[args->nsid]._ns_global_scope_pending_adds; +@@ -734,6 +747,11 @@ dl_open_worker (void *a) + if (relocation_in_progress) + LIBC_PROBE (reloc_complete, 3, args->nsid, r, new); + ++ /* If libc.so was not there before, attempt to call its early ++ initialization routine. */ ++ if (!args->libc_already_loaded) ++ _dl_call_libc_early_init (GL(dl_ns)[args->nsid].libc_map); ++ + #ifndef SHARED + DL_STATIC_INIT (new); + #endif +@@ -828,6 +846,8 @@ no more namespaces available for dlmopen()")); + args.caller_dlopen = caller_dlopen; + args.map = NULL; + args.nsid = nsid; ++ /* args.libc_already_loaded is always assigned by dl_open_worker ++ (before any explicit/non-local returns). */ + args.argc = argc; + args.argv = argv; + args.env = env; +@@ -856,6 +876,11 @@ no more namespaces available for dlmopen()")); + /* See if an error occurred during loading. */ + if (__glibc_unlikely (exception.errstring != NULL)) + { ++ /* Avoid keeping around a dangling reference to the libc.so link ++ map in case it has been cached in libc_map. */ ++ if (!args.libc_already_loaded) ++ GL(dl_ns)[nsid].libc_map = NULL; ++ + /* Remove the object from memory. It may be in an inconsistent + state if relocation failed, for example. */ + if (args.map) +diff --git a/elf/libc-early-init.h b/elf/libc-early-init.h +new file mode 100644 +index 0000000000000000..5185fa8895c0e11a +--- /dev/null ++++ b/elf/libc-early-init.h +@@ -0,0 +1,35 @@ ++/* Early initialization of libc.so. ++ 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 _LIBC_EARLY_INIT_H ++#define _LIBC_EARLY_INIT_H ++ ++struct link_map; ++ ++/* If LIBC_MAP is not NULL, look up the __libc_early_init symbol in it ++ and call this function. */ ++void _dl_call_libc_early_init (struct link_map *libc_map) attribute_hidden; ++ ++/* In the shared case, this function is defined in libc.so and invoked ++ from ld.so (or on the fist static dlopen) after complete relocation ++ of a new loaded libc.so, but before user-defined ELF constructors ++ run. In the static case, this function is called directly from the ++ startup code. */ ++void __libc_early_init (void); ++ ++#endif /* _LIBC_EARLY_INIT_H */ +diff --git a/elf/libc_early_init.c b/elf/libc_early_init.c +new file mode 100644 +index 0000000000000000..7f4ca332b805a22c +--- /dev/null ++++ b/elf/libc_early_init.c +@@ -0,0 +1,27 @@ ++/* Early initialization of libc.so, libc.so side. ++ 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 ++ ++void ++__libc_early_init (void) ++{ ++ /* Initialize ctype data. */ ++ __ctype_init (); ++} +diff --git a/elf/rtld.c b/elf/rtld.c +index d44facf5343b3301..a40d5f17db0dac8b 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -44,6 +44,7 @@ + #include + #include + #include ++#include + + #include + +@@ -2365,6 +2366,9 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + rtld_timer_accum (&relocate_time, start); + } + ++ /* Relocation is complete. Perform early libc initialization. */ ++ _dl_call_libc_early_init (GL(dl_ns)[LM_ID_BASE].libc_map); ++ + /* Do any necessary cleanups for the startup OS interface code. + We do these now so that no calls are made after rtld re-relocation + which might be resolved to different functions than we expect. +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index a8fb0d211426e4b1..ccec08929e4ad4e7 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -336,6 +336,10 @@ struct rtld_global + recursive dlopen calls from ELF constructors. */ + unsigned int _ns_global_scope_pending_adds; + ++ /* Once libc.so has been loaded into the namespace, this points to ++ its link map. */ ++ struct link_map *libc_map; ++ + /* Search table for unique objects. */ + struct unique_sym_table + { +@@ -943,6 +947,19 @@ extern lookup_t _dl_lookup_symbol_x (const char *undef, + attribute_hidden; + + ++/* Restricted version of _dl_lookup_symbol_x. Searches MAP (and only ++ MAP) for the symbol UNDEF_NAME, with GNU hash NEW_HASH (computed ++ with dl_new_hash), symbol version VERSION, and symbol version hash ++ VERSION_HASH (computed with _dl_elf_hash). Returns a pointer to ++ the symbol table entry in MAP on success, or NULL on failure. MAP ++ must have symbol versioning information, or otherwise the result is ++ undefined. */ ++const ElfW(Sym) *_dl_lookup_direct (struct link_map *map, ++ const char *undef_name, ++ uint32_t new_hash, ++ const char *version, ++ uint32_t version_hash) attribute_hidden; ++ + /* Add the new link_map NEW to the end of the namespace list. */ + extern void _dl_add_to_namespace_list (struct link_map *new, Lmid_t nsid) + attribute_hidden; +diff --git a/sysdeps/mach/hurd/i386/init-first.c b/sysdeps/mach/hurd/i386/init-first.c +index f8ad2ceb8e324f92..1636a40ee5d78858 100644 +--- a/sysdeps/mach/hurd/i386/init-first.c ++++ b/sysdeps/mach/hurd/i386/init-first.c +@@ -17,7 +17,6 @@ + . */ + + #include +-#include + #include + #include + #include +@@ -84,9 +83,6 @@ posixland_init (int argc, char **argv, char **envp) + #endif + __init_misc (argc, argv, envp); + +- /* Initialize ctype data. */ +- __ctype_init (); +- + #if defined SHARED && !defined NO_CTORS_DTORS_SECTIONS + __libc_global_ctors (); + #endif diff --git a/SOURCES/glibc-rh1817513-51.patch b/SOURCES/glibc-rh1817513-51.patch new file mode 100644 index 0000000..2b56755 --- /dev/null +++ b/SOURCES/glibc-rh1817513-51.patch @@ -0,0 +1,688 @@ +commit 92954ffa5a5662fbfde14febd7e5dcc358c85470 +Author: Carlos O'Donell +Date: Wed Jan 8 13:24:42 2020 -0500 + + localedef: Add verbose messages for failure paths. + + During testing of localedef running in a minimal container + there were several error cases which were hard to diagnose + since they appeared as strerror (errno) values printed by the + higher level functions. This change adds three new verbose + messages for potential failure paths. The new messages give + the user the opportunity to use -v and display additional + information about why localedef might be failing. I found + these messages useful myself while writing a localedef + container test for --no-hard-links. + + Since the changes cleanup the code that handle codeset + normalization we add tst-localedef-path-norm which contains + many sub-tests to verify the correct expected normalization of + codeset strings both when installing to default paths (the + only time normalization is enabled) and installing to absolute + paths. During the refactoring I created at least one + buffer-overflow which valgrind caught, but these tests did not + catch because the exec in the container had a very clean heap + with zero-initialized memory. However, between valgrind and + the tests the results are clean. + + The new tst-localedef-path-norm passes without regression on + x86_64. + + Change-Id: I28b9f680711ff00252a2cb15625b774cc58ecb9d + +diff --git a/include/programs/xasprintf.h b/include/programs/xasprintf.h +new file mode 100644 +index 0000000000000000..53193ba3837f7418 +--- /dev/null ++++ b/include/programs/xasprintf.h +@@ -0,0 +1,24 @@ ++/* asprintf with out of memory checking ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published ++ by the Free Software Foundation; version 2 of the License, or ++ (at your option) any later version. ++ ++ This program 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 General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, see . */ ++ ++#ifndef _XASPRINTF_H ++#define _XASPRINTF_H 1 ++ ++extern char *xasprintf (const char *format, ...) ++ __attribute__ ((__format__ (__printf__, 1, 2), __warn_unused_result__)); ++ ++#endif /* xasprintf.h */ +diff --git a/locale/Makefile b/locale/Makefile +index 23a71321b6646c49..4278350cdc7be28d 100644 +--- a/locale/Makefile ++++ b/locale/Makefile +@@ -28,6 +28,7 @@ routines = setlocale findlocale loadlocale loadarchive \ + localeconv nl_langinfo nl_langinfo_l mb_cur_max \ + newlocale duplocale freelocale uselocale + tests = tst-C-locale tst-locname tst-duplocale ++tests-container = tst-localedef-path-norm + categories = ctype messages monetary numeric time paper name \ + address telephone measurement identification collate + aux = $(categories:%=lc-%) $(categories:%=C-%) SYS_libc C_name \ +@@ -54,7 +55,7 @@ localedef-modules := localedef $(categories:%=ld-%) \ + localedef-aux := md5 + locale-modules := locale locale-spec + lib-modules := charmap-dir simple-hash xmalloc xstrdup \ +- record-status ++ record-status xasprintf + + + GPERF = gperf +diff --git a/locale/programs/localedef.c b/locale/programs/localedef.c +index d718d2e9f47382bc..9a57d2cb435b25ed 100644 +--- a/locale/programs/localedef.c ++++ b/locale/programs/localedef.c +@@ -174,14 +174,14 @@ static struct argp argp = + + /* Prototypes for local functions. */ + static void error_print (void); +-static const char *construct_output_path (char *path); +-static const char *normalize_codeset (const char *codeset, size_t name_len); ++static char *construct_output_path (char *path); ++static char *normalize_codeset (const char *codeset, size_t name_len); + + + int + main (int argc, char *argv[]) + { +- const char *output_path; ++ char *output_path; + int cannot_write_why; + struct charmap_t *charmap; + struct localedef_t global; +@@ -226,7 +226,8 @@ main (int argc, char *argv[]) + } + + /* The parameter describes the output path of the constructed files. +- If the described files cannot be written return a NULL pointer. */ ++ If the described files cannot be written return a NULL pointer. ++ We don't free output_path because we will exit. */ + output_path = construct_output_path (argv[remaining]); + if (output_path == NULL && ! no_archive) + error (4, errno, _("cannot create directory for output files")); +@@ -424,20 +425,16 @@ more_help (int key, const char *text, void *input) + { + case ARGP_KEY_HELP_EXTRA: + /* We print some extra information. */ +- if (asprintf (&tp, gettext ("\ ++ tp = xasprintf (gettext ("\ + For bug reporting instructions, please see:\n\ +-%s.\n"), REPORT_BUGS_TO) < 0) +- return NULL; +- if (asprintf (&cp, gettext ("\ ++%s.\n"), REPORT_BUGS_TO); ++ cp = xasprintf (gettext ("\ + System's directory for character maps : %s\n\ + repertoire maps: %s\n\ + locale path : %s\n\ + %s"), +- CHARMAP_PATH, REPERTOIREMAP_PATH, LOCALE_PATH, tp) < 0) +- { +- free (tp); +- return NULL; +- } ++ CHARMAP_PATH, REPERTOIREMAP_PATH, LOCALE_PATH, tp); ++ free (tp); + return cp; + default: + break; +@@ -467,15 +464,13 @@ error_print (void) + } + + +-/* The parameter to localedef describes the output path. If it does +- contain a '/' character it is a relative path. Otherwise it names the +- locale this definition is for. */ +-static const char * ++/* The parameter to localedef describes the output path. If it does contain a ++ '/' character it is a relative path. Otherwise it names the locale this ++ definition is for. The returned path must be freed by the caller. */ ++static char * + construct_output_path (char *path) + { +- const char *normal = NULL; + char *result; +- char *endp; + + if (strchr (path, '/') == NULL) + { +@@ -483,50 +478,44 @@ construct_output_path (char *path) + contains a reference to the codeset. This should be + normalized. */ + char *startp; ++ char *endp = NULL; ++ char *normal = NULL; + + startp = path; +- /* We must be prepared for finding a CEN name or a location of +- the introducing `.' where it is not possible anymore. */ ++ /* Either we have a '@' which starts a CEN name or '.' which starts the ++ codeset specification. The CEN name starts with '@' and may also have ++ a codeset specification, but we do not normalize the string after '@'. ++ If we only find the codeset specification then we normalize only the codeset ++ specification (but not anything after a subsequent '@'). */ + while (*startp != '\0' && *startp != '@' && *startp != '.') + ++startp; + if (*startp == '.') + { + /* We found a codeset specification. Now find the end. */ + endp = ++startp; ++ ++ /* Stop at the first '@', and don't normalize anything past that. */ + while (*endp != '\0' && *endp != '@') + ++endp; + + if (endp > startp) + normal = normalize_codeset (startp, endp - startp); + } +- else +- /* This is to keep gcc quiet. */ +- endp = NULL; + +- /* We put an additional '\0' at the end of the string because at +- the end of the function we need another byte for the trailing +- '/'. */ +- ssize_t n; + if (normal == NULL) +- n = asprintf (&result, "%s%s/%s%c", output_prefix ?: "", +- COMPLOCALEDIR, path, '\0'); ++ result = xasprintf ("%s%s/%s/", output_prefix ?: "", ++ COMPLOCALEDIR, path); + else +- n = asprintf (&result, "%s%s/%.*s%s%s%c", +- output_prefix ?: "", COMPLOCALEDIR, +- (int) (startp - path), path, normal, endp, '\0'); +- +- if (n < 0) +- return NULL; +- +- endp = result + n - 1; ++ result = xasprintf ("%s%s/%.*s%s%s/", ++ output_prefix ?: "", COMPLOCALEDIR, ++ (int) (startp - path), path, normal, endp ?: ""); ++ /* Free the allocated normalized codeset name. */ ++ free (normal); + } + else + { +- /* This is a user path. Please note the additional byte in the +- memory allocation. */ +- size_t len = strlen (path) + 1; +- result = xmalloc (len + 1); +- endp = mempcpy (result, path, len) - 1; ++ /* This is a user path. */ ++ result = xasprintf ("%s/", path); + + /* If the user specified an output path we cannot add the output + to the archive. */ +@@ -536,25 +525,41 @@ construct_output_path (char *path) + errno = 0; + + if (no_archive && euidaccess (result, W_OK) == -1) +- /* Perhaps the directory does not exist now. Try to create it. */ +- if (errno == ENOENT) +- { +- errno = 0; +- if (mkdir (result, 0777) < 0) +- return NULL; +- } +- +- *endp++ = '/'; +- *endp = '\0'; ++ { ++ /* Perhaps the directory does not exist now. Try to create it. */ ++ if (errno == ENOENT) ++ { ++ errno = 0; ++ if (mkdir (result, 0777) < 0) ++ { ++ record_verbose (stderr, ++ _("cannot create output path \'%s\': %s"), ++ result, strerror (errno)); ++ free (result); ++ return NULL; ++ } ++ } ++ else ++ record_verbose (stderr, ++ _("no write permission to output path \'%s\': %s"), ++ result, strerror (errno)); ++ } + + return result; + } + + +-/* Normalize codeset name. There is no standard for the codeset +- names. Normalization allows the user to use any of the common +- names. */ +-static const char * ++/* Normalize codeset name. There is no standard for the codeset names. ++ Normalization allows the user to use any of the common names e.g. UTF-8, ++ utf-8, utf8, UTF8 etc. ++ ++ We normalize using the following rules: ++ - Remove all non-alpha-numeric characters ++ - Lowercase all characters. ++ - If there are only digits assume it's an ISO standard and prefix with 'iso' ++ ++ We return the normalized string which needs to be freed by free. */ ++static char * + normalize_codeset (const char *codeset, size_t name_len) + { + int len = 0; +@@ -563,6 +568,7 @@ normalize_codeset (const char *codeset, size_t name_len) + char *wp; + size_t cnt; + ++ /* Compute the length of only the alpha-numeric characters. */ + for (cnt = 0; cnt < name_len; ++cnt) + if (isalnum (codeset[cnt])) + { +@@ -572,25 +578,24 @@ normalize_codeset (const char *codeset, size_t name_len) + only_digit = 0; + } + +- retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1); ++ /* If there were only digits we assume it's an ISO standard and we will ++ prefix with 'iso' so include space for that. We fill in the required ++ space from codeset up to the converted length. */ ++ wp = retval = xasprintf ("%s%.*s", only_digit ? "iso" : "", len, codeset); + +- if (retval != NULL) +- { +- if (only_digit) +- wp = stpcpy (retval, "iso"); +- else +- wp = retval; +- +- for (cnt = 0; cnt < name_len; ++cnt) +- if (isalpha (codeset[cnt])) +- *wp++ = tolower (codeset[cnt]); +- else if (isdigit (codeset[cnt])) +- *wp++ = codeset[cnt]; ++ /* Skip "iso". */ ++ if (only_digit) ++ wp += 3; + +- *wp = '\0'; +- } ++ /* Lowercase all characters. */ ++ for (cnt = 0; cnt < name_len; ++cnt) ++ if (isalpha (codeset[cnt])) ++ *wp++ = tolower (codeset[cnt]); ++ else if (isdigit (codeset[cnt])) ++ *wp++ = codeset[cnt]; + +- return (const char *) retval; ++ /* Return allocated and converted name for caller to free. */ ++ return retval; + } + + +diff --git a/locale/programs/localedef.h b/locale/programs/localedef.h +index 0083faceabbf3dd9..c528dbb97854dbd1 100644 +--- a/locale/programs/localedef.h ++++ b/locale/programs/localedef.h +@@ -122,6 +122,7 @@ extern const char *alias_file; + + /* Prototypes for a few program-wide used functions. */ + #include ++#include + + + /* Mark given locale as to be read. */ +diff --git a/locale/programs/xasprintf.c b/locale/programs/xasprintf.c +new file mode 100644 +index 0000000000000000..efc91a9c34074736 +--- /dev/null ++++ b/locale/programs/xasprintf.c +@@ -0,0 +1,34 @@ ++/* asprintf with out of memory checking ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published ++ by the Free Software Foundation; version 2 of the License, or ++ (at your option) any later version. ++ ++ This program 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 General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, see . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++char * ++xasprintf (const char *format, ...) ++{ ++ va_list ap; ++ va_start (ap, format); ++ char *result; ++ if (vasprintf (&result, format, ap) < 0) ++ error (EXIT_FAILURE, 0, _("memory exhausted")); ++ va_end (ap); ++ return result; ++} +diff --git a/locale/tst-localedef-path-norm.c b/locale/tst-localedef-path-norm.c +new file mode 100644 +index 0000000000000000..2ef1d26f07084c68 +--- /dev/null ++++ b/locale/tst-localedef-path-norm.c +@@ -0,0 +1,242 @@ ++/* Test for localedef path name handling and normalization. ++ Copyright (C) 2019 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 ++ . */ ++ ++/* The test runs localedef with various named paths to test for expected ++ behaviours dealing with codeset name normalization. That is to say that use ++ of UTF-8, and it's variations, are normalized to utf8. Likewise that values ++ after the @ are not normalized and left as-is. The test needs to run ++ localedef with known input values and then check that the generated path ++ matches the expected value after normalization. */ ++ ++/* Note: In some cases adding -v (verbose) to localedef changes the exit ++ status to a non-zero value because some warnings are only enabled in verbose ++ mode. This should probably be changed so warnings are either present or not ++ present, regardless of verbosity. POSIX requires that any warnings cause the ++ exit status to be non-zero. */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++/* Full path to localedef. */ ++char *prog; ++ ++/* Execute localedef in a subprocess. */ ++static void ++execv_wrapper (void *args) ++{ ++ char **argv = args; ++ ++ execv (prog, argv); ++ FAIL_EXIT1 ("execv: %m"); ++} ++ ++struct test_closure ++{ ++ /* Arguments for running localedef. */ ++ const char *const argv[16]; ++ /* Expected directory name for compiled locale. */ ++ const char *exp; ++ /* Expected path to compiled locale. */ ++ const char *complocaledir; ++}; ++ ++/* Run localedef with DATA.ARGV arguments (NULL terminated), and expect path to ++ the compiled locale is "DATA.COMPLOCALEDIR/DATA.EXP". */ ++static void ++run_test (struct test_closure data) ++{ ++ const char * const *args = data.argv; ++ const char *exp = data.exp; ++ const char *complocaledir = data.complocaledir; ++ struct stat64 fs; ++ ++ /* Expected output path. */ ++ const char *path = xasprintf ("%s/%s", complocaledir, exp); ++ ++ /* Run test. */ ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (execv_wrapper, (void *)args); ++ support_capture_subprocess_check (&result, "execv", 0, sc_allow_none); ++ support_capture_subprocess_free (&result); ++ ++ /* Verify path is present and is a directory. */ ++ xstat (path, &fs); ++ TEST_VERIFY_EXIT (S_ISDIR (fs.st_mode)); ++ printf ("info: Directory '%s' exists.\n", path); ++} ++ ++static int ++do_test (void) ++{ ++ /* We are running as root inside the container. */ ++ prog = xasprintf ("%s/localedef", support_bindir_prefix); ++ ++ /* Create the needed directories: ++ - We need the default compiled locale dir for default output. ++ - We need an arbitrary absolute path for localedef output. ++ ++ Note: Writing to a non-default absolute path disables any kind ++ of path normalization since we expect the user wants the path ++ exactly as they specified it. */ ++ xmkdirp (support_complocaledir_prefix, 0777); ++ xmkdirp ("/output", 0777); ++ ++ /* It takes ~10 seconds to serially execute 9 localedef test. We ++ could run the compilations in parallel if we want to reduce test ++ time. We don't want to split this out into distinct tests because ++ it would require multiple chroots. Batching the same localedef ++ tests saves disk space during testing. */ ++ ++ /* Test 1: Expected normalization. ++ Run localedef and expect output in /usr/lib/locale/en_US1.utf8, ++ with normalization changing UTF-8 to utf8. */ ++ run_test ((struct test_closure) ++ { ++ .argv = { prog, ++ "--no-archive", ++ "-i", "en_US", ++ "-f", "UTF-8", ++ "en_US1.UTF-8", NULL }, ++ .exp = "en_US1.utf8", ++ .complocaledir = support_complocaledir_prefix ++ }); ++ ++ /* Test 2: No normalization past '@'. ++ Run localedef and expect output in /usr/lib/locale/en_US2.utf8@tEsT, ++ with normalization changing UTF-8@tEsT to utf8@tEsT (everything after ++ @ is untouched). */ ++ run_test ((struct test_closure) ++ { ++ .argv = { prog, ++ "--no-archive", ++ "-i", "en_US", ++ "-f", "UTF-8", ++ "en_US2.UTF-8@tEsT", NULL }, ++ .exp = "en_US2.utf8@tEsT", ++ .complocaledir = support_complocaledir_prefix ++ }); ++ ++ /* Test 3: No normalization past '@' despite period. ++ Run localedef and expect output in /usr/lib/locale/en_US3@tEsT.UTF-8, ++ with normalization changing nothing (everything after @ is untouched) ++ despite there being a period near the end. */ ++ run_test ((struct test_closure) ++ { ++ .argv = { prog, ++ "--no-archive", ++ "-i", "en_US", ++ "-f", "UTF-8", ++ "en_US3@tEsT.UTF-8", NULL }, ++ .exp = "en_US3@tEsT.UTF-8", ++ .complocaledir = support_complocaledir_prefix ++ }); ++ ++ /* Test 4: Normalize numeric codeset by adding 'iso' prefix. ++ Run localedef and expect output in /usr/lib/locale/en_US4.88591, ++ with normalization changing 88591 to iso88591. */ ++ run_test ((struct test_closure) ++ { ++ .argv = { prog, ++ "--no-archive", ++ "-i", "en_US", ++ "-f", "UTF-8", ++ "en_US4.88591", NULL }, ++ .exp = "en_US4.iso88591", ++ .complocaledir = support_complocaledir_prefix ++ }); ++ ++ /* Test 5: Don't add 'iso' prefix if first char is alpha. ++ Run localedef and expect output in /usr/lib/locale/en_US5.a88591, ++ with normalization changing nothing. */ ++ run_test ((struct test_closure) ++ { ++ .argv = { prog, ++ "--no-archive", ++ "-i", "en_US", ++ "-f", "UTF-8", ++ "en_US5.a88591", NULL }, ++ .exp = "en_US5.a88591", ++ .complocaledir = support_complocaledir_prefix ++ }); ++ ++ /* Test 6: Don't add 'iso' prefix if last char is alpha. ++ Run localedef and expect output in /usr/lib/locale/en_US6.88591a, ++ with normalization changing nothing. */ ++ run_test ((struct test_closure) ++ { ++ .argv = { prog, ++ "--no-archive", ++ "-i", "en_US", ++ "-f", "UTF-8", ++ "en_US6.88591a", NULL }, ++ .exp = "en_US6.88591a", ++ .complocaledir = support_complocaledir_prefix ++ }); ++ ++ /* Test 7: Don't normalize anything with an absolute path. ++ Run localedef and expect output in /output/en_US7.UTF-8, ++ with normalization changing nothing. */ ++ run_test ((struct test_closure) ++ { ++ .argv = { prog, ++ "--no-archive", ++ "-i", "en_US", ++ "-f", "UTF-8", ++ "/output/en_US7.UTF-8", NULL }, ++ .exp = "en_US7.UTF-8", ++ .complocaledir = "/output" ++ }); ++ ++ /* Test 8: Don't normalize anything with an absolute path. ++ Run localedef and expect output in /output/en_US8.UTF-8@tEsT, ++ with normalization changing nothing. */ ++ run_test ((struct test_closure) ++ { ++ .argv = { prog, ++ "--no-archive", ++ "-i", "en_US", ++ "-f", "UTF-8", ++ "/output/en_US8.UTF-8@tEsT", NULL }, ++ .exp = "en_US8.UTF-8@tEsT", ++ .complocaledir = "/output" ++ }); ++ ++ /* Test 9: Don't normalize anything with an absolute path. ++ Run localedef and expect output in /output/en_US9@tEsT.UTF-8, ++ with normalization changing nothing. */ ++ run_test ((struct test_closure) ++ { ++ .argv = { prog, ++ "--no-archive", ++ "-i", "en_US", ++ "-f", "UTF-8", ++ "/output/en_US9@tEsT.UTF-8", NULL }, ++ .exp = "en_US9@tEsT.UTF-8", ++ .complocaledir = "/output" ++ }); ++ ++ return 0; ++} ++ ++#include +diff --git a/locale/tst-localedef-path-norm.root/postclean.req b/locale/tst-localedef-path-norm.root/postclean.req +new file mode 100644 +index 0000000000000000..e69de29bb2d1d643 +diff --git a/locale/tst-localedef-path-norm.root/tst-localedef-path-norm.script b/locale/tst-localedef-path-norm.root/tst-localedef-path-norm.script +new file mode 100644 +index 0000000000000000..b0f016256a47f762 +--- /dev/null ++++ b/locale/tst-localedef-path-norm.root/tst-localedef-path-norm.script +@@ -0,0 +1,2 @@ ++# Must run localedef as root to write into default paths. ++su +diff --git a/support/Makefile b/support/Makefile +index 117cfdd4f22fc405..5808a42dce87151f 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -182,7 +182,8 @@ CFLAGS-support_paths.c = \ + -DLIBDIR_PATH=\"$(libdir)\" \ + -DBINDIR_PATH=\"$(bindir)\" \ + -DSBINDIR_PATH=\"$(sbindir)\" \ +- -DROOTSBINDIR_PATH=\"$(rootsbindir)\" ++ -DROOTSBINDIR_PATH=\"$(rootsbindir)\" \ ++ -DCOMPLOCALEDIR_PATH=\"$(complocaledir)\" + + ifeq (,$(CXX)) + LINKS_DSO_PROGRAM = links-dso-program-c +diff --git a/support/support.h b/support/support.h +index 121cc9e9b7c98ca6..3af87f85fe1b762d 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -112,6 +112,8 @@ extern const char support_bindir_prefix[]; + extern const char support_sbindir_prefix[]; + /* Corresponds to the install's sbin/ directory (without prefix). */ + extern const char support_install_rootsbindir[]; ++/* Corresponds to the install's compiled locale directory. */ ++extern const char support_complocaledir_prefix[]; + + extern ssize_t support_copy_file_range (int, off64_t *, int, off64_t *, + size_t, unsigned int); +diff --git a/support/support_paths.c b/support/support_paths.c +index eb2390227433aa70..6b15fae0f0173b1e 100644 +--- a/support/support_paths.c ++++ b/support/support_paths.c +@@ -78,3 +78,10 @@ const char support_install_rootsbindir[] = ROOTSBINDIR_PATH; + #else + # error please -DROOTSBINDIR_PATH=something in the Makefile + #endif ++ ++#ifdef COMPLOCALEDIR_PATH ++/* Corresponds to the install's compiled locale directory. */ ++const char support_complocaledir_prefix[] = COMPLOCALEDIR_PATH; ++#else ++# error please -DCOMPLOCALEDIR_PATH=something in the Makefile ++#endif diff --git a/SOURCES/glibc-rh1817513-52.patch b/SOURCES/glibc-rh1817513-52.patch new file mode 100644 index 0000000..61dbcf9 --- /dev/null +++ b/SOURCES/glibc-rh1817513-52.patch @@ -0,0 +1,141 @@ +commit 03e187a41d91069543cfcf33469a05912e555447 +Author: Florian Weimer +Date: Wed Apr 29 15:44:03 2020 +0200 + + elf: Add initial flag argument to __libc_early_init + + The rseq initialization should happen only for the libc in the base + namespace (in the dynamic case) or the statically linked libc. The + __libc_multiple_libcs flag does not quite cover this case at present, + so this commit introduces a flag argument to __libc_early_init, + indicating whether the libc being libc is the primary one (of the main + program). + + Reviewed-by: Carlos O'Donell + +diff --git a/csu/libc-start.c b/csu/libc-start.c +index d9c3248219d8f84f..fd0f8640eaeae34c 100644 +--- a/csu/libc-start.c ++++ b/csu/libc-start.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + #include + +@@ -241,7 +242,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), + #ifndef SHARED + /* Perform early initialization. In the shared case, this function + is called from the dynamic loader as early as possible. */ +- __libc_early_init (); ++ __libc_early_init (true); + + /* Call the initializer of the libc. This is only needed here if we + are compiling for the static library in which case we haven't +diff --git a/elf/dl-call-libc-early-init.c b/elf/dl-call-libc-early-init.c +index 41e9ad9aad8b5b46..9a84680a1ceafba2 100644 +--- a/elf/dl-call-libc-early-init.c ++++ b/elf/dl-call-libc-early-init.c +@@ -23,7 +23,7 @@ + #include + + void +-_dl_call_libc_early_init (struct link_map *libc_map) ++_dl_call_libc_early_init (struct link_map *libc_map, _Bool initial) + { + /* There is nothing to do if we did not actually load libc.so. */ + if (libc_map == NULL) +@@ -37,5 +37,5 @@ _dl_call_libc_early_init (struct link_map *libc_map) + assert (sym != NULL); + __typeof (__libc_early_init) *early_init + = DL_SYMBOL_ADDRESS (libc_map, sym); +- early_init (); ++ early_init (initial); + } +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 1a77ec833cad6c55..3d49a84596e99bf6 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -748,9 +748,22 @@ dl_open_worker (void *a) + LIBC_PROBE (reloc_complete, 3, args->nsid, r, new); + + /* If libc.so was not there before, attempt to call its early +- initialization routine. */ ++ initialization routine. Indicate to the initialization routine ++ whether the libc being initialized is the one in the base ++ namespace. */ + if (!args->libc_already_loaded) +- _dl_call_libc_early_init (GL(dl_ns)[args->nsid].libc_map); ++ { ++ struct link_map *libc_map = GL(dl_ns)[args->nsid].libc_map; ++#ifdef SHARED ++ bool initial = libc_map->l_ns == LM_ID_BASE; ++#else ++ /* In the static case, there is only one namespace, but it ++ contains a secondary libc (the primary libc is statically ++ linked). */ ++ bool initial = false; ++#endif ++ _dl_call_libc_early_init (libc_map, initial); ++ } + + #ifndef SHARED + DL_STATIC_INIT (new); +diff --git a/elf/libc-early-init.h b/elf/libc-early-init.h +index 5185fa8895c0e11a..8f7836dceaeecd5a 100644 +--- a/elf/libc-early-init.h ++++ b/elf/libc-early-init.h +@@ -22,14 +22,17 @@ + struct link_map; + + /* If LIBC_MAP is not NULL, look up the __libc_early_init symbol in it +- and call this function. */ +-void _dl_call_libc_early_init (struct link_map *libc_map) attribute_hidden; ++ and call this function, with INITIAL as the argument. */ ++void _dl_call_libc_early_init (struct link_map *libc_map, _Bool initial) ++ attribute_hidden; + + /* In the shared case, this function is defined in libc.so and invoked + from ld.so (or on the fist static dlopen) after complete relocation + of a new loaded libc.so, but before user-defined ELF constructors + run. In the static case, this function is called directly from the +- startup code. */ +-void __libc_early_init (void); ++ startup code. If INITIAL is true, the libc being initialized is ++ the libc for the main program. INITIAL is false for libcs loaded ++ for audit modules, dlmopen, and static dlopen. */ ++void __libc_early_init (_Bool initial); + + #endif /* _LIBC_EARLY_INIT_H */ +diff --git a/elf/libc_early_init.c b/elf/libc_early_init.c +index 7f4ca332b805a22c..e6c64fb526600fae 100644 +--- a/elf/libc_early_init.c ++++ b/elf/libc_early_init.c +@@ -20,7 +20,7 @@ + #include + + void +-__libc_early_init (void) ++__libc_early_init (_Bool initial) + { + /* Initialize ctype data. */ + __ctype_init (); +diff --git a/elf/rtld.c b/elf/rtld.c +index a40d5f17db0dac8b..772aff5160359b7b 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2366,8 +2366,10 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + rtld_timer_accum (&relocate_time, start); + } + +- /* Relocation is complete. Perform early libc initialization. */ +- _dl_call_libc_early_init (GL(dl_ns)[LM_ID_BASE].libc_map); ++ /* Relocation is complete. Perform early libc initialization. This ++ is the initial libc, even if audit modules have been loaded with ++ other libcs. */ ++ _dl_call_libc_early_init (GL(dl_ns)[LM_ID_BASE].libc_map, true); + + /* Do any necessary cleanups for the startup OS interface code. + We do these now so that no calls are made after rtld re-relocation diff --git a/SOURCES/glibc-rh1817513-53.patch b/SOURCES/glibc-rh1817513-53.patch new file mode 100644 index 0000000..fdd8a41 --- /dev/null +++ b/SOURCES/glibc-rh1817513-53.patch @@ -0,0 +1,86 @@ +commit 32ac0b988466785d6e3cc1dffc364bb26fc63193 +Author: mayshao +Date: Fri Apr 24 12:55:38 2020 +0800 + + x86: Add CPU Vendor ID detection support for Zhaoxin processors + + To recognize Zhaoxin CPU Vendor ID, add a new architecture type + arch_kind_zhaoxin for Vendor Zhaoxin detection. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index ade37a9bb3de86cc..c432d646ce6806a6 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -464,6 +464,60 @@ init_cpu_features (struct cpu_features *cpu_features) + } + } + } ++ /* This spells out "CentaurHauls" or " Shanghai ". */ ++ else if ((ebx == 0x746e6543 && ecx == 0x736c7561 && edx == 0x48727561) ++ || (ebx == 0x68532020 && ecx == 0x20206961 && edx == 0x68676e61)) ++ { ++ unsigned int extended_model, stepping; ++ ++ kind = arch_kind_zhaoxin; ++ ++ get_common_indices (cpu_features, &family, &model, &extended_model, ++ &stepping); ++ ++ get_extended_indices (cpu_features); ++ ++ model += extended_model; ++ if (family == 0x6) ++ { ++ if (model == 0xf || model == 0x19) ++ { ++ cpu_features->feature[index_arch_AVX_Usable] ++ &= (~bit_arch_AVX_Usable ++ & ~bit_arch_AVX2_Usable); ++ ++ cpu_features->feature[index_arch_Slow_SSE4_2] ++ |= (bit_arch_Slow_SSE4_2); ++ ++ cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load] ++ &= ~bit_arch_AVX_Fast_Unaligned_Load; ++ } ++ } ++ else if (family == 0x7) ++ { ++ if (model == 0x1b) ++ { ++ cpu_features->feature[index_arch_AVX_Usable] ++ &= (~bit_arch_AVX_Usable ++ & ~bit_arch_AVX2_Usable); ++ ++ cpu_features->feature[index_arch_Slow_SSE4_2] ++ |= bit_arch_Slow_SSE4_2; ++ ++ cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load] ++ &= ~bit_arch_AVX_Fast_Unaligned_Load; ++ } ++ else if (model == 0x3b) ++ { ++ cpu_features->feature[index_arch_AVX_Usable] ++ &= (~bit_arch_AVX_Usable ++ & ~bit_arch_AVX2_Usable); ++ ++ cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load] ++ &= ~bit_arch_AVX_Fast_Unaligned_Load; ++ } ++ } ++ } + else + { + kind = arch_kind_other; +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 4917182e99a8ee90..388172a1c07bf979 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -53,6 +53,7 @@ enum cpu_features_kind + arch_kind_unknown = 0, + arch_kind_intel, + arch_kind_amd, ++ arch_kind_zhaoxin, + arch_kind_other + }; + diff --git a/SOURCES/glibc-rh1817513-54.patch b/SOURCES/glibc-rh1817513-54.patch new file mode 100644 index 0000000..44a747e --- /dev/null +++ b/SOURCES/glibc-rh1817513-54.patch @@ -0,0 +1,534 @@ +commit a98dc92dd1e278df4c501deb07985018bc2b06de +Author: mayshao-oc +Date: Sun Apr 26 13:48:27 2020 +0800 + + x86: Add cache information support for Zhaoxin processors + + To obtain Zhaoxin CPU cache information, add a new function + handle_zhaoxin(). + + Add a new function get_common_cache_info() that extracts the code + in init_cacheinfo() to get the value of the variable shared, threads. + + Add Zhaoxin branch in init_cacheinfo() for initializing variables, + such as __x86_shared_cache_size. + +diff --git a/sysdeps/x86/cacheinfo.c b/sysdeps/x86/cacheinfo.c +index f1125f30223f5ca3..aa7cb705d546bcd0 100644 +--- a/sysdeps/x86/cacheinfo.c ++++ b/sysdeps/x86/cacheinfo.c +@@ -436,6 +436,57 @@ handle_amd (int name) + } + + ++static long int __attribute__ ((noinline)) ++handle_zhaoxin (int name) ++{ ++ unsigned int eax; ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++ ++ int folded_rel_name = (M(name) / 3) * 3; ++ ++ unsigned int round = 0; ++ while (1) ++ { ++ __cpuid_count (4, round, eax, ebx, ecx, edx); ++ ++ enum { null = 0, data = 1, inst = 2, uni = 3 } type = eax & 0x1f; ++ if (type == null) ++ break; ++ ++ unsigned int level = (eax >> 5) & 0x7; ++ ++ if ((level == 1 && type == data ++ && folded_rel_name == M(_SC_LEVEL1_DCACHE_SIZE)) ++ || (level == 1 && type == inst ++ && folded_rel_name == M(_SC_LEVEL1_ICACHE_SIZE)) ++ || (level == 2 && folded_rel_name == M(_SC_LEVEL2_CACHE_SIZE)) ++ || (level == 3 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE))) ++ { ++ unsigned int offset = M(name) - folded_rel_name; ++ ++ if (offset == 0) ++ /* Cache size. */ ++ return (((ebx >> 22) + 1) ++ * (((ebx >> 12) & 0x3ff) + 1) ++ * ((ebx & 0xfff) + 1) ++ * (ecx + 1)); ++ if (offset == 1) ++ return (ebx >> 22) + 1; ++ ++ assert (offset == 2); ++ return (ebx & 0xfff) + 1; ++ } ++ ++ ++round; ++ } ++ ++ /* Nothing found. */ ++ return 0; ++} ++ ++ + /* Get the value of the system variable NAME. */ + long int + attribute_hidden +@@ -449,6 +500,9 @@ __cache_sysconf (int name) + if (cpu_features->basic.kind == arch_kind_amd) + return handle_amd (name); + ++ if (cpu_features->basic.kind == arch_kind_zhaoxin) ++ return handle_zhaoxin (name); ++ + // XXX Fill in more vendors. + + /* CPU not known, we have no information. */ +@@ -482,6 +536,224 @@ int __x86_prefetchw attribute_hidden; + #endif + + ++static void ++get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, ++ long int core) ++{ ++ unsigned int eax; ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++ ++ /* Number of logical processors sharing L2 cache. */ ++ int threads_l2; ++ ++ /* Number of logical processors sharing L3 cache. */ ++ int threads_l3; ++ ++ const struct cpu_features *cpu_features = __get_cpu_features (); ++ int max_cpuid = cpu_features->basic.max_cpuid; ++ unsigned int family = cpu_features->basic.family; ++ unsigned int model = cpu_features->basic.model; ++ long int shared = *shared_ptr; ++ unsigned int threads = *threads_ptr; ++ bool inclusive_cache = true; ++ bool support_count_mask = true; ++ ++ /* Try L3 first. */ ++ unsigned int level = 3; ++ ++ if (cpu_features->basic.kind == arch_kind_zhaoxin && family == 6) ++ support_count_mask = false; ++ ++ if (shared <= 0) ++ { ++ /* Try L2 otherwise. */ ++ level = 2; ++ shared = core; ++ threads_l2 = 0; ++ threads_l3 = -1; ++ } ++ else ++ { ++ threads_l2 = 0; ++ threads_l3 = 0; ++ } ++ ++ /* A value of 0 for the HTT bit indicates there is only a single ++ logical processor. */ ++ if (HAS_CPU_FEATURE (HTT)) ++ { ++ /* Figure out the number of logical threads that share the ++ highest cache level. */ ++ if (max_cpuid >= 4) ++ { ++ int i = 0; ++ ++ /* Query until cache level 2 and 3 are enumerated. */ ++ int check = 0x1 | (threads_l3 == 0) << 1; ++ do ++ { ++ __cpuid_count (4, i++, eax, ebx, ecx, edx); ++ ++ /* There seems to be a bug in at least some Pentium Ds ++ which sometimes fail to iterate all cache parameters. ++ Do not loop indefinitely here, stop in this case and ++ assume there is no such information. */ ++ if (cpu_features->basic.kind == arch_kind_intel ++ && (eax & 0x1f) == 0 ) ++ goto intel_bug_no_cache_info; ++ ++ switch ((eax >> 5) & 0x7) ++ { ++ default: ++ break; ++ case 2: ++ if ((check & 0x1)) ++ { ++ /* Get maximum number of logical processors ++ sharing L2 cache. */ ++ threads_l2 = (eax >> 14) & 0x3ff; ++ check &= ~0x1; ++ } ++ break; ++ case 3: ++ if ((check & (0x1 << 1))) ++ { ++ /* Get maximum number of logical processors ++ sharing L3 cache. */ ++ threads_l3 = (eax >> 14) & 0x3ff; ++ ++ /* Check if L2 and L3 caches are inclusive. */ ++ inclusive_cache = (edx & 0x2) != 0; ++ check &= ~(0x1 << 1); ++ } ++ break; ++ } ++ } ++ while (check); ++ ++ /* If max_cpuid >= 11, THREADS_L2/THREADS_L3 are the maximum ++ numbers of addressable IDs for logical processors sharing ++ the cache, instead of the maximum number of threads ++ sharing the cache. */ ++ if (max_cpuid >= 11 && support_count_mask) ++ { ++ /* Find the number of logical processors shipped in ++ one core and apply count mask. */ ++ i = 0; ++ ++ /* Count SMT only if there is L3 cache. Always count ++ core if there is no L3 cache. */ ++ int count = ((threads_l2 > 0 && level == 3) ++ | ((threads_l3 > 0 ++ || (threads_l2 > 0 && level == 2)) << 1)); ++ ++ while (count) ++ { ++ __cpuid_count (11, i++, eax, ebx, ecx, edx); ++ ++ int shipped = ebx & 0xff; ++ int type = ecx & 0xff00; ++ if (shipped == 0 || type == 0) ++ break; ++ else if (type == 0x100) ++ { ++ /* Count SMT. */ ++ if ((count & 0x1)) ++ { ++ int count_mask; ++ ++ /* Compute count mask. */ ++ asm ("bsr %1, %0" ++ : "=r" (count_mask) : "g" (threads_l2)); ++ count_mask = ~(-1 << (count_mask + 1)); ++ threads_l2 = (shipped - 1) & count_mask; ++ count &= ~0x1; ++ } ++ } ++ else if (type == 0x200) ++ { ++ /* Count core. */ ++ if ((count & (0x1 << 1))) ++ { ++ int count_mask; ++ int threads_core ++ = (level == 2 ? threads_l2 : threads_l3); ++ ++ /* Compute count mask. */ ++ asm ("bsr %1, %0" ++ : "=r" (count_mask) : "g" (threads_core)); ++ count_mask = ~(-1 << (count_mask + 1)); ++ threads_core = (shipped - 1) & count_mask; ++ if (level == 2) ++ threads_l2 = threads_core; ++ else ++ threads_l3 = threads_core; ++ count &= ~(0x1 << 1); ++ } ++ } ++ } ++ } ++ if (threads_l2 > 0) ++ threads_l2 += 1; ++ if (threads_l3 > 0) ++ threads_l3 += 1; ++ if (level == 2) ++ { ++ if (threads_l2) ++ { ++ threads = threads_l2; ++ if (cpu_features->basic.kind == arch_kind_intel ++ && threads > 2 ++ && family == 6) ++ switch (model) ++ { ++ case 0x37: ++ case 0x4a: ++ case 0x4d: ++ case 0x5a: ++ case 0x5d: ++ /* Silvermont has L2 cache shared by 2 cores. */ ++ threads = 2; ++ break; ++ default: ++ break; ++ } ++ } ++ } ++ else if (threads_l3) ++ threads = threads_l3; ++ } ++ else ++ { ++intel_bug_no_cache_info: ++ /* Assume that all logical threads share the highest cache ++ level. */ ++ threads ++ = ((cpu_features->cpuid[COMMON_CPUID_INDEX_1].ebx ++ >> 16) & 0xff); ++ } ++ ++ /* Cap usage of highest cache level to the number of supported ++ threads. */ ++ if (shared > 0 && threads > 0) ++ shared /= threads; ++ } ++ ++ /* Account for non-inclusive L2 and L3 caches. */ ++ if (!inclusive_cache) ++ { ++ if (threads_l2 > 0) ++ core /= threads_l2; ++ shared += core; ++ } ++ ++ *shared_ptr = shared; ++ *threads_ptr = threads; ++} ++ ++ + static void + __attribute__((constructor)) + init_cacheinfo (void) +@@ -494,211 +766,25 @@ init_cacheinfo (void) + int max_cpuid_ex; + long int data = -1; + long int shared = -1; +- unsigned int level; ++ long int core; + unsigned int threads = 0; + const struct cpu_features *cpu_features = __get_cpu_features (); +- int max_cpuid = cpu_features->basic.max_cpuid; + + if (cpu_features->basic.kind == arch_kind_intel) + { + data = handle_intel (_SC_LEVEL1_DCACHE_SIZE, cpu_features); +- +- long int core = handle_intel (_SC_LEVEL2_CACHE_SIZE, cpu_features); +- bool inclusive_cache = true; +- +- /* Try L3 first. */ +- level = 3; ++ core = handle_intel (_SC_LEVEL2_CACHE_SIZE, cpu_features); + shared = handle_intel (_SC_LEVEL3_CACHE_SIZE, cpu_features); + +- /* Number of logical processors sharing L2 cache. */ +- int threads_l2; +- +- /* Number of logical processors sharing L3 cache. */ +- int threads_l3; +- +- if (shared <= 0) +- { +- /* Try L2 otherwise. */ +- level = 2; +- shared = core; +- threads_l2 = 0; +- threads_l3 = -1; +- } +- else +- { +- threads_l2 = 0; +- threads_l3 = 0; +- } +- +- /* A value of 0 for the HTT bit indicates there is only a single +- logical processor. */ +- if (HAS_CPU_FEATURE (HTT)) +- { +- /* Figure out the number of logical threads that share the +- highest cache level. */ +- if (max_cpuid >= 4) +- { +- unsigned int family = cpu_features->basic.family; +- unsigned int model = cpu_features->basic.model; +- +- int i = 0; +- +- /* Query until cache level 2 and 3 are enumerated. */ +- int check = 0x1 | (threads_l3 == 0) << 1; +- do +- { +- __cpuid_count (4, i++, eax, ebx, ecx, edx); +- +- /* There seems to be a bug in at least some Pentium Ds +- which sometimes fail to iterate all cache parameters. +- Do not loop indefinitely here, stop in this case and +- assume there is no such information. */ +- if ((eax & 0x1f) == 0) +- goto intel_bug_no_cache_info; +- +- switch ((eax >> 5) & 0x7) +- { +- default: +- break; +- case 2: +- if ((check & 0x1)) +- { +- /* Get maximum number of logical processors +- sharing L2 cache. */ +- threads_l2 = (eax >> 14) & 0x3ff; +- check &= ~0x1; +- } +- break; +- case 3: +- if ((check & (0x1 << 1))) +- { +- /* Get maximum number of logical processors +- sharing L3 cache. */ +- threads_l3 = (eax >> 14) & 0x3ff; +- +- /* Check if L2 and L3 caches are inclusive. */ +- inclusive_cache = (edx & 0x2) != 0; +- check &= ~(0x1 << 1); +- } +- break; +- } +- } +- while (check); +- +- /* If max_cpuid >= 11, THREADS_L2/THREADS_L3 are the maximum +- numbers of addressable IDs for logical processors sharing +- the cache, instead of the maximum number of threads +- sharing the cache. */ +- if (max_cpuid >= 11) +- { +- /* Find the number of logical processors shipped in +- one core and apply count mask. */ +- i = 0; +- +- /* Count SMT only if there is L3 cache. Always count +- core if there is no L3 cache. */ +- int count = ((threads_l2 > 0 && level == 3) +- | ((threads_l3 > 0 +- || (threads_l2 > 0 && level == 2)) << 1)); +- +- while (count) +- { +- __cpuid_count (11, i++, eax, ebx, ecx, edx); +- +- int shipped = ebx & 0xff; +- int type = ecx & 0xff00; +- if (shipped == 0 || type == 0) +- break; +- else if (type == 0x100) +- { +- /* Count SMT. */ +- if ((count & 0x1)) +- { +- int count_mask; +- +- /* Compute count mask. */ +- asm ("bsr %1, %0" +- : "=r" (count_mask) : "g" (threads_l2)); +- count_mask = ~(-1 << (count_mask + 1)); +- threads_l2 = (shipped - 1) & count_mask; +- count &= ~0x1; +- } +- } +- else if (type == 0x200) +- { +- /* Count core. */ +- if ((count & (0x1 << 1))) +- { +- int count_mask; +- int threads_core +- = (level == 2 ? threads_l2 : threads_l3); +- +- /* Compute count mask. */ +- asm ("bsr %1, %0" +- : "=r" (count_mask) : "g" (threads_core)); +- count_mask = ~(-1 << (count_mask + 1)); +- threads_core = (shipped - 1) & count_mask; +- if (level == 2) +- threads_l2 = threads_core; +- else +- threads_l3 = threads_core; +- count &= ~(0x1 << 1); +- } +- } +- } +- } +- if (threads_l2 > 0) +- threads_l2 += 1; +- if (threads_l3 > 0) +- threads_l3 += 1; +- if (level == 2) +- { +- if (threads_l2) +- { +- threads = threads_l2; +- if (threads > 2 && family == 6) +- switch (model) +- { +- case 0x37: +- case 0x4a: +- case 0x4d: +- case 0x5a: +- case 0x5d: +- /* Silvermont has L2 cache shared by 2 cores. */ +- threads = 2; +- break; +- default: +- break; +- } +- } +- } +- else if (threads_l3) +- threads = threads_l3; +- } +- else +- { +-intel_bug_no_cache_info: +- /* Assume that all logical threads share the highest cache +- level. */ +- +- threads +- = ((cpu_features->cpuid[COMMON_CPUID_INDEX_1].ebx +- >> 16) & 0xff); +- } +- +- /* Cap usage of highest cache level to the number of supported +- threads. */ +- if (shared > 0 && threads > 0) +- shared /= threads; +- } ++ get_common_cache_info (&shared, &threads, core); ++ } ++ else if (cpu_features->basic.kind == arch_kind_zhaoxin) ++ { ++ data = handle_zhaoxin (_SC_LEVEL1_DCACHE_SIZE); ++ core = handle_zhaoxin (_SC_LEVEL2_CACHE_SIZE); ++ shared = handle_zhaoxin (_SC_LEVEL3_CACHE_SIZE); + +- /* Account for non-inclusive L2 and L3 caches. */ +- if (!inclusive_cache) +- { +- if (threads_l2 > 0) +- core /= threads_l2; +- shared += core; +- } ++ get_common_cache_info (&shared, &threads, core); + } + else if (cpu_features->basic.kind == arch_kind_amd) + { diff --git a/SOURCES/glibc-rh1817513-55.patch b/SOURCES/glibc-rh1817513-55.patch new file mode 100644 index 0000000..b649118 --- /dev/null +++ b/SOURCES/glibc-rh1817513-55.patch @@ -0,0 +1,136 @@ +commit 033362cfd7e0e1dccd6c9a2642710d6e3a7e7007 +Author: Carlos O'Donell +Date: Thu Jan 23 09:45:00 2020 -0500 + + test-container: Support $(complocaledir) and mkdirp. + + Expand the support infrastructure: + - Create $(complocaledir) in the testroot.pristine to support localedef. + - Add the variable $complocaledir to script support. + - Add the script command 'mkdirp'. + + All localedef tests which run with default paths need to have the + $(complocaledir) created in testroot.pristine. The localedef binary + will not by itself create the default path, but it will write into + the path. By adding this we can simplify the localedef tests. + + The variable $complocaledir is the value of the configured + $(complocaledir) which is the location of the compiled locales that + will be searched by the runtime by default. + + The command mkdirp will be available in script setup and will + be equivalent to running `mkdir -p`. + + The variable and command can be used to write more complex tests. + + Reviewed-by: DJ Delorie + +diff --git a/Makefile b/Makefile +index ae44b9cdd29fb0e3..3748d6f7cfb6223b 100644 +--- a/Makefile ++++ b/Makefile +@@ -371,6 +371,9 @@ $(objpfx)testroot.pristine/install.stamp : + # We need a working /bin/sh for some of the tests. + test -d $(objpfx)testroot.pristine/bin || \ + mkdir $(objpfx)testroot.pristine/bin ++ # We need the compiled locale dir for localedef tests. ++ test -d $(objpfx)testroot.pristine/$(complocaledir) || \ ++ mkdir -p $(objpfx)testroot.pristine/$(complocaledir) + cp $(objpfx)support/shell-container $(objpfx)testroot.pristine/bin/sh + cp $(objpfx)support/echo-container $(objpfx)testroot.pristine/bin/echo + cp $(objpfx)support/true-container $(objpfx)testroot.pristine/bin/true +diff --git a/support/test-container.c b/support/test-container.c +index 9eff8baeef0e9d8a..9fcc91e478038232 100644 +--- a/support/test-container.c ++++ b/support/test-container.c +@@ -72,6 +72,10 @@ int verbose = 0; + + * mkdir $buildroot/testroot.pristine/ + * install into it ++ * default glibc install ++ * create /bin for /bin/sh ++ * create $(complocaledir) so localedef tests work with default paths. ++ * install /bin/sh, /bin/echo, and /bin/true. + * rsync to $buildroot/testroot.root/ + + "Per-test" actions: +@@ -97,9 +101,23 @@ int verbose = 0; + rm FILE + cwd PATH + exec FILE +- FILE must start with $B/, $S/, $I/, $L/, or / +- (expands to build dir, source dir, install dir, library dir +- (in container), or container's root) ++ mkdirp MODE DIR ++ ++ variables: ++ $B/ build dir, equivalent to $(common-objpfx) ++ $S/ source dir, equivalent to $(srcdir) ++ $I/ install dir, equivalent to $(prefix) ++ $L/ library dir (in container), equivalent to $(libdir) ++ $complocaledir/ compiled locale dir, equivalent to $(complocaledir) ++ / container's root ++ ++ If FILE begins with any of these variables then they will be ++ substituted for the described value. ++ ++ The goal is to expose as many of the runtime's configured paths ++ via variables so they can be used to setup the container environment ++ before execution reaches the test. ++ + details: + - '#': A comment. + - 'su': Enables running test as root in the container. +@@ -108,6 +126,8 @@ int verbose = 0; + - 'rm': A minimal remove files command. + - 'cwd': set test working directory + - 'exec': change test binary location (may end in /) ++ - 'mkdirp': A minimal "mkdir -p FILE" command. ++ + * mytest.root/postclean.req causes fresh rsync (with delete) after + test if present + +@@ -859,6 +879,7 @@ main (int argc, char **argv) + int nt = tokenize (the_line, the_words, 3); + int i; + ++ /* Expand variables. */ + for (i = 1; i < nt; ++i) + { + if (memcmp (the_words[i], "$B/", 3) == 0) +@@ -875,6 +896,10 @@ main (int argc, char **argv) + the_words[i] = concat (new_root_path, + support_libdir_prefix, + the_words[i] + 2, NULL); ++ else if (memcmp (the_words[i], "$complocaledir/", 15) == 0) ++ the_words[i] = concat (new_root_path, ++ support_complocaledir_prefix, ++ the_words[i] + 14, NULL); + /* "exec" and "cwd" use inside-root paths. */ + else if (strcmp (the_words[0], "exec") != 0 + && strcmp (the_words[0], "cwd") != 0 +@@ -892,6 +917,9 @@ main (int argc, char **argv) + the_words[2] = concat (the_words[2], the_words[1], NULL); + } + ++ /* Run the following commands in the_words[0] with NT number of ++ arguments (including the command). */ ++ + if (nt == 2 && strcmp (the_words[0], "so") == 0) + { + the_words[2] = concat (new_root_path, support_libdir_prefix, +@@ -961,6 +989,14 @@ main (int argc, char **argv) + { + be_su = 1; + } ++ else if (nt == 3 && strcmp (the_words[0], "mkdirp") == 0) ++ { ++ long int m; ++ errno = 0; ++ m = strtol (the_words[1], NULL, 0); ++ TEST_COMPARE (errno, 0); ++ xmkdirp (the_words[2], m); ++ } + else if (nt > 0 && the_words[0][0] != '#') + { + fprintf (stderr, "\033[31minvalid [%s]\033[0m\n", the_words[0]); diff --git a/SOURCES/glibc-rh1817513-56.patch b/SOURCES/glibc-rh1817513-56.patch new file mode 100644 index 0000000..1cfb701 --- /dev/null +++ b/SOURCES/glibc-rh1817513-56.patch @@ -0,0 +1,45 @@ +commit 183083c35972611e7786c7ee0c96d7da571631ed +Author: Carlos O'Donell +Date: Wed Apr 29 16:31:29 2020 -0400 + + support: Set errno before testing it. + + In test-conainer we should set errno to 0 before calling strtol, + and check after with TEST_COMPARE. + + In tst-support_capture_subprocess we should set errno to 0 before + checking it after the call to strtol. + + Tested on x86_64. + + Reviewed-by: DJ Delorie + +diff --git a/support/test-container.c b/support/test-container.c +index 9fcc91e478038232..d7ed073812305f71 100644 +--- a/support/test-container.c ++++ b/support/test-container.c +@@ -940,7 +940,9 @@ main (int argc, char **argv) + else if (nt == 3 && strcmp (the_words[0], "chmod") == 0) + { + long int m; ++ errno = 0; + m = strtol (the_words[1], NULL, 0); ++ TEST_COMPARE (errno, 0); + if (chmod (the_words[2], m) < 0) + FAIL_EXIT1 ("chmod %s: %s\n", + the_words[2], strerror (errno)); +diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c +index 99570879eedd65b1..fe6649dda6032de2 100644 +--- a/support/tst-support_capture_subprocess.c ++++ b/support/tst-support_capture_subprocess.c +@@ -133,7 +133,9 @@ static int + parse_int (const char *str) + { + char *endptr; +- long int ret = strtol (str, &endptr, 10); ++ long int ret; ++ errno = 0; ++ ret = strtol (str, &endptr, 10); + TEST_COMPARE (errno, 0); + TEST_VERIFY (ret >= 0 && ret <= INT_MAX); + return ret; diff --git a/SOURCES/glibc-rh1817513-57.patch b/SOURCES/glibc-rh1817513-57.patch new file mode 100644 index 0000000..93ac1e4 --- /dev/null +++ b/SOURCES/glibc-rh1817513-57.patch @@ -0,0 +1,30 @@ +commit cad64f778aced84efdaa04ae64f8737b86f063ab +Author: Josh Triplett +Date: Tue May 19 14:41:48 2020 +0200 + + ldconfig: Default to the new format for ld.so.cache + + glibc has supported this format for close to 20 years. + +diff --git a/elf/ldconfig.c b/elf/ldconfig.c +index 5e6516688a1c192a..f31e10817dd5d665 100644 +--- a/elf/ldconfig.c ++++ b/elf/ldconfig.c +@@ -97,7 +97,7 @@ int opt_verbose; + + /* Format to support. */ + /* 0: only libc5/glibc2; 1: both; 2: only glibc 2.2. */ +-int opt_format = 1; ++int opt_format = 2; + + /* Build cache. */ + static int opt_build_cache = 1; +@@ -150,7 +150,7 @@ static const struct argp_option options[] = + { NULL, 'f', N_("CONF"), 0, N_("Use CONF as configuration file"), 0}, + { NULL, 'n', NULL, 0, N_("Only process directories specified on the command line. Don't build cache."), 0}, + { NULL, 'l', NULL, 0, N_("Manually link individual libraries."), 0}, +- { "format", 'c', N_("FORMAT"), 0, N_("Format to use: new, old or compat (default)"), 0}, ++ { "format", 'c', N_("FORMAT"), 0, N_("Format to use: new (default), old, or compat"), 0}, + { "ignore-aux-cache", 'i', NULL, 0, N_("Ignore auxiliary cache file"), 0}, + { NULL, 0, NULL, 0, NULL, 0 } + }; diff --git a/SOURCES/glibc-rh1817513-58.patch b/SOURCES/glibc-rh1817513-58.patch new file mode 100644 index 0000000..9133d56 --- /dev/null +++ b/SOURCES/glibc-rh1817513-58.patch @@ -0,0 +1,59 @@ +commit 76d5b2f002a1243ddba06bd646249553353f4322 +Author: H.J. Lu +Date: Thu May 21 13:36:54 2020 -0700 + + x86: Update Intel Atom processor family optimization + + Enable Intel Silvermont optimization for Intel Goldmont Plus. Detect more + Intel Airmont processors. Optimize Intel Tremont like Intel Silvermont + with rep string instructions. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index c432d646ce6806a6..2a801e1856cfe1b3 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -347,18 +347,23 @@ init_cpu_features (struct cpu_features *cpu_features) + case 0x57: + /* Knights Landing. Enable Silvermont optimizations. */ + ++ case 0x7a: ++ /* Unaligned load versions are faster than SSSE3 ++ on Goldmont Plus. */ ++ + case 0x5c: + case 0x5f: + /* Unaligned load versions are faster than SSSE3 + on Goldmont. */ + + case 0x4c: ++ case 0x5a: ++ case 0x75: + /* Airmont is a die shrink of Silvermont. */ + + case 0x37: + case 0x4a: + case 0x4d: +- case 0x5a: + case 0x5d: + /* Unaligned load versions are faster than SSSE3 + on Silvermont. */ +@@ -369,6 +374,19 @@ init_cpu_features (struct cpu_features *cpu_features) + | bit_arch_Slow_SSE4_2); + break; + ++ case 0x86: ++ case 0x96: ++ case 0x9c: ++ /* Enable rep string instructions, unaligned load, unaligned ++ copy, pminub and avoid SSE 4.2 on Tremont. */ ++ cpu_features->feature[index_arch_Fast_Rep_String] ++ |= (bit_arch_Fast_Rep_String ++ | bit_arch_Fast_Unaligned_Load ++ | bit_arch_Fast_Unaligned_Copy ++ | bit_arch_Prefer_PMINUB_for_stringop ++ | bit_arch_Slow_SSE4_2); ++ break; ++ + default: + /* Unknown family 0x06 processors. Assuming this is one + of Core i3/i5/i7 processors if AVX is available. */ diff --git a/SOURCES/glibc-rh1817513-59.patch b/SOURCES/glibc-rh1817513-59.patch new file mode 100644 index 0000000..0fbaab7 --- /dev/null +++ b/SOURCES/glibc-rh1817513-59.patch @@ -0,0 +1,148 @@ +commit dcbc6b83eff5b9238170bdfed834ba934150895f +Author: Florian Weimer +Date: Thu May 28 10:20:56 2020 +0200 + + elf: Do not read hwcaps from the vDSO in ld.so + + This was only ever used for the "nosegneg" flag. This approach for + passing hardware capability information creates a subtle dependency + between the kernel and userspace, and ld.so.cache contents. It seems + inappropriate for toady, where people expect to be able to run + system images which very different kernel versions. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c +index ecf00b457760e517..ae2e4ca7fe91d407 100644 +--- a/elf/dl-hwcaps.c ++++ b/elf/dl-hwcaps.c +@@ -26,12 +26,6 @@ + #include + #include + +-#ifdef _DL_FIRST_PLATFORM +-# define _DL_FIRST_EXTRA (_DL_FIRST_PLATFORM + _DL_PLATFORMS_COUNT) +-#else +-# define _DL_FIRST_EXTRA _DL_HWCAP_COUNT +-#endif +- + /* Return an array of useful/necessary hardware capability names. */ + const struct r_strlenpair * + _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, +@@ -52,116 +46,12 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, + if ((masked & (1ULL << n)) != 0) + ++cnt; + +-#ifdef NEED_DL_SYSINFO_DSO +- /* The system-supplied DSO can contain a note of type 2, vendor "GNU". +- This gives us a list of names to treat as fake hwcap bits. */ +- +- const char *dsocaps = NULL; +- size_t dsocapslen = 0; +- if (GLRO(dl_sysinfo_map) != NULL) +- { +- const ElfW(Phdr) *const phdr = GLRO(dl_sysinfo_map)->l_phdr; +- const ElfW(Word) phnum = GLRO(dl_sysinfo_map)->l_phnum; +- for (uint_fast16_t i = 0; i < phnum; ++i) +- if (phdr[i].p_type == PT_NOTE) +- { +- const ElfW(Addr) start = (phdr[i].p_vaddr +- + GLRO(dl_sysinfo_map)->l_addr); +- /* NB: Some PT_NOTE segment may have alignment value of 0 +- or 1. gABI specifies that PT_NOTE segments should be +- aligned to 4 bytes in 32-bit objects and to 8 bytes in +- 64-bit objects. As a Linux extension, we also support +- 4 byte alignment in 64-bit objects. If p_align is less +- than 4, we treate alignment as 4 bytes since some note +- segments have 0 or 1 byte alignment. */ +- ElfW(Addr) align = phdr[i].p_align; +- if (align < 4) +- align = 4; +- else if (align != 4 && align != 8) +- continue; +- /* The standard ELF note layout is exactly as the anonymous struct. +- The next element is a variable length vendor name of length +- VENDORLEN (with a real length rounded to ElfW(Word)), followed +- by the data of length DATALEN (with a real length rounded to +- ElfW(Word)). */ +- const struct +- { +- ElfW(Word) vendorlen; +- ElfW(Word) datalen; +- ElfW(Word) type; +- } *note = (const void *) start; +- while ((ElfW(Addr)) (note + 1) - start < phdr[i].p_memsz) +- { +- /* The layout of the type 2, vendor "GNU" note is as follows: +- .long +- .long (as mask >> _DL_FIRST_EXTRA). +- .byte +- .asciz . */ +- if (note->type == NT_GNU_HWCAP +- && note->vendorlen == sizeof "GNU" +- && !memcmp ((note + 1), "GNU", sizeof "GNU") +- && note->datalen > 2 * sizeof (ElfW(Word)) + 2) +- { +- const ElfW(Word) *p +- = ((const void *) note +- + ELF_NOTE_DESC_OFFSET (sizeof "GNU", align)); +- cnt += *p++; +- ++p; /* Skip mask word. */ +- dsocaps = (const char *) p; /* Pseudo-string "name" */ +- dsocapslen = note->datalen - sizeof *p * 2; +- break; +- } +- note = ((const void *) note +- + ELF_NOTE_NEXT_OFFSET (note->vendorlen, +- note->datalen, align)); +- } +- if (dsocaps != NULL) +- break; +- } +- } +-#endif +- + /* For TLS enabled builds always add 'tls'. */ + ++cnt; + + /* Create temporary data structure to generate result table. */ + struct r_strlenpair temp[cnt]; + m = 0; +-#ifdef NEED_DL_SYSINFO_DSO +- if (dsocaps != NULL) +- { +- /* dsocaps points to the .asciz string, and -1 points to the mask +- .long just before the string. */ +- const ElfW(Word) mask = ((const ElfW(Word) *) dsocaps)[-1]; +- GLRO(dl_hwcap) |= (uint64_t) mask << _DL_FIRST_EXTRA; +- /* Note that we add the dsocaps to the set already chosen by the +- LD_HWCAP_MASK environment variable (or default HWCAP_IMPORTANT). +- So there is no way to request ignoring an OS-supplied dsocap +- string and bit like you can ignore an OS-supplied HWCAP bit. */ +- hwcap_mask |= (uint64_t) mask << _DL_FIRST_EXTRA; +-#if HAVE_TUNABLES +- TUNABLE_SET (glibc, cpu, hwcap_mask, uint64_t, hwcap_mask); +-#else +- GLRO(dl_hwcap_mask) = hwcap_mask; +-#endif +- size_t len; +- for (const char *p = dsocaps; p < dsocaps + dsocapslen; p += len + 1) +- { +- uint_fast8_t bit = *p++; +- len = strlen (p); +- +- /* Skip entries that are not enabled in the mask word. */ +- if (__glibc_likely (mask & ((ElfW(Word)) 1 << bit))) +- { +- temp[m].str = p; +- temp[m].len = len; +- ++m; +- } +- else +- --cnt; +- } +- } +-#endif + for (n = 0; masked != 0; ++n) + if ((masked & (1ULL << n)) != 0) + { diff --git a/SOURCES/glibc-rh1817513-6.patch b/SOURCES/glibc-rh1817513-6.patch new file mode 100644 index 0000000..4f8e256 --- /dev/null +++ b/SOURCES/glibc-rh1817513-6.patch @@ -0,0 +1,53 @@ +commit d330f31af68f96dde82840d1e9343b479a8c179e +Author: Carlos O'Donell +Date: Thu Aug 30 11:01:33 2018 -0400 + + Fix test failure with -DNDEBUG. + + The elf/tst-dlopen-aout.c test uses asserts to verify properties of the + test execution. Instead of using assert it should use xpthread_create + and xpthread_join to catch errors starting the threads and fail the + test. This shows up in Fedora 28 when building for i686-pc-linux-gnu + and using gcc 8.1.1. + + Tested on i686, and fixes a check failure with -DNDEBUG. + + Signed-off-by: Carlos O'Donell + +diff --git a/elf/tst-dlopen-aout.c b/elf/tst-dlopen-aout.c +index 9038e2096add8798..b0264515cfe62276 100644 +--- a/elf/tst-dlopen-aout.c ++++ b/elf/tst-dlopen-aout.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + __thread int x; + +@@ -45,7 +46,6 @@ do_test (int argc, char *argv[]) + { + pthread_t thr; + void *p; +- int rc; + + p = dlopen (argv[0], RTLD_LAZY); + if (p != NULL) +@@ -53,11 +53,11 @@ do_test (int argc, char *argv[]) + fprintf (stderr, "dlopen unexpectedly succeeded\n"); + return 1; + } +- rc = pthread_create (&thr, NULL, fn, NULL); +- assert (rc == 0); +- +- rc = pthread_join (thr, NULL); +- assert (rc == 0); ++ /* We create threads to force TLS allocation, which triggers ++ the original bug i.e. running out of surplus slotinfo entries ++ for TLS. */ ++ thr = xpthread_create (NULL, fn, NULL); ++ xpthread_join (thr); + } + + return 0; diff --git a/SOURCES/glibc-rh1817513-60.patch b/SOURCES/glibc-rh1817513-60.patch new file mode 100644 index 0000000..f6b4907 --- /dev/null +++ b/SOURCES/glibc-rh1817513-60.patch @@ -0,0 +1,151 @@ +commit 31563b68410ff8e9490c5aafca31ec71b38f87a5 +Author: Florian Weimer +Date: Thu May 28 10:21:17 2020 +0200 + + elf: Remove extra hwcap mechanism from ldconfig + + Historically, this mechanism was used to process "nosegneg" + subdirectories, and it is still used to include the "tls" + subdirectories. With nosegneg support gone from ld.so, this is part + no longer useful. + + The entire mechanism is not well-designed because it causes the + meaning of hwcap bits in ld.so.cache to depend on the kernel version + that was used to generate the cache, which makes it difficult to use + this mechanism for anything else in the future. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/ldconfig.c b/elf/ldconfig.c +index f31e10817dd5d665..7c8fd29387463a8a 100644 +--- a/elf/ldconfig.c ++++ b/elf/ldconfig.c +@@ -44,11 +44,15 @@ + + #include + +-#ifdef _DL_FIRST_PLATFORM +-# define _DL_FIRST_EXTRA (_DL_FIRST_PLATFORM + _DL_PLATFORMS_COUNT) +-#else +-# define _DL_FIRST_EXTRA _DL_HWCAP_COUNT +-#endif ++/* This subpath in search path entries is always supported and ++ included in the cache for backwards compatibility. */ ++#define TLS_SUBPATH "tls" ++ ++/* The MSB of the hwcap field is set for objects in TLS_SUBPATH ++ directories. There is always TLS support in glibc, so the dynamic ++ loader does not check the bit directly. But more hwcap bits make a ++ an object more preferred, so the bit still has meaning. */ ++#define TLS_HWCAP_BIT 63 + + #ifndef LD_SO_CONF + # define LD_SO_CONF SYSCONFDIR "/ld.so.conf" +@@ -127,9 +131,6 @@ static const char *config_file; + /* Mask to use for important hardware capabilities. */ + static unsigned long int hwcap_mask = HWCAP_IMPORTANT; + +-/* Configuration-defined capabilities defined in kernel vDSOs. */ +-static const char *hwcap_extra[64 - _DL_FIRST_EXTRA]; +- + /* Name and version of program. */ + static void print_version (FILE *stream, struct argp_state *state); + void (*argp_program_version_hook) (FILE *, struct argp_state *) +@@ -186,12 +187,9 @@ is_hwcap_platform (const char *name) + if (hwcap_idx != -1) + return 1; + +- /* Is this one of the extra pseudo-hwcaps that we map beyond +- _DL_FIRST_EXTRA like "tls", or "nosegneg?" */ +- for (hwcap_idx = _DL_FIRST_EXTRA; hwcap_idx < 64; ++hwcap_idx) +- if (hwcap_extra[hwcap_idx - _DL_FIRST_EXTRA] != NULL +- && !strcmp (name, hwcap_extra[hwcap_idx - _DL_FIRST_EXTRA])) +- return 1; ++ /* Backwards-compatibility for the "tls" subdirectory. */ ++ if (strcmp (name, TLS_SUBPATH) == 0) ++ return 1; + + return 0; + } +@@ -226,11 +224,9 @@ path_hwcap (const char *path) + h = _dl_string_platform (ptr + 1); + if (h == (uint64_t) -1) + { +- for (h = _DL_FIRST_EXTRA; h < 64; ++h) +- if (hwcap_extra[h - _DL_FIRST_EXTRA] != NULL +- && !strcmp (ptr + 1, hwcap_extra[h - _DL_FIRST_EXTRA])) +- break; +- if (h == 64) ++ if (strcmp (ptr + 1, TLS_SUBPATH) == 0) ++ h = TLS_HWCAP_BIT; ++ else + break; + } + } +@@ -1145,52 +1141,7 @@ Warning: ignoring configuration file that cannot be opened: %s"), + parse_conf_include (filename, lineno, do_chroot, dir); + } + else if (!strncasecmp (cp, "hwcap", 5) && isblank (cp[5])) +- { +- cp += 6; +- char *p, *name = NULL; +- unsigned long int n = strtoul (cp, &cp, 0); +- if (cp != NULL && isblank (*cp)) +- while ((p = strsep (&cp, " \t")) != NULL) +- if (p[0] != '\0') +- { +- if (name == NULL) +- name = p; +- else +- { +- name = NULL; +- break; +- } +- } +- if (name == NULL) +- { +- error (EXIT_FAILURE, 0, _("%s:%u: bad syntax in hwcap line"), +- filename, lineno); +- break; +- } +- if (n >= (64 - _DL_FIRST_EXTRA)) +- error (EXIT_FAILURE, 0, +- _("%s:%u: hwcap index %lu above maximum %u"), +- filename, lineno, n, 64 - _DL_FIRST_EXTRA - 1); +- if (hwcap_extra[n] == NULL) +- { +- for (unsigned long int h = 0; h < (64 - _DL_FIRST_EXTRA); ++h) +- if (hwcap_extra[h] != NULL && !strcmp (name, hwcap_extra[h])) +- error (EXIT_FAILURE, 0, +- _("%s:%u: hwcap index %lu already defined as %s"), +- filename, lineno, h, name); +- hwcap_extra[n] = xstrdup (name); +- } +- else +- { +- if (strcmp (name, hwcap_extra[n])) +- error (EXIT_FAILURE, 0, +- _("%s:%u: hwcap index %lu already defined as %s"), +- filename, lineno, n, hwcap_extra[n]); +- if (opt_verbose) +- error (0, 0, _("%s:%u: duplicate hwcap %lu %s"), +- filename, lineno, n, name); +- } +- } ++ error (0, 0, _("%s:%u: hwcap directive ignored"), filename, lineno); + else + add_dir_1 (cp, filename, lineno); + } +@@ -1303,12 +1254,6 @@ main (int argc, char **argv) + add_dir_1 (argv[i], "", 0); + } + +- /* The last entry in hwcap_extra is reserved for the "tls" pseudo-hwcap which +- indicates support for TLS. This pseudo-hwcap is only used by old versions +- under which TLS support was optional. The entry is no longer needed, but +- must remain for compatibility. */ +- hwcap_extra[63 - _DL_FIRST_EXTRA] = "tls"; +- + set_hwcap (); + + if (opt_chroot) diff --git a/SOURCES/glibc-rh1817513-61.patch b/SOURCES/glibc-rh1817513-61.patch new file mode 100644 index 0000000..87cf249 --- /dev/null +++ b/SOURCES/glibc-rh1817513-61.patch @@ -0,0 +1,21 @@ +commit 9e2dc874e62b0950891b319c000b009ea12ac8c2 +Author: Girish Joshi +Date: Fri May 29 10:11:24 2020 -0300 + + build: Use FAIL_EXIT1 () on failure to exec child [BZ #23990] + + Reviewed-by: Adhemerval Zanella + +diff --git a/support/test-container.c b/support/test-container.c +index d7ed073812305f71..9975c8cb7bc9a955 100644 +--- a/support/test-container.c ++++ b/support/test-container.c +@@ -392,7 +392,7 @@ recursive_remove (char *path) + /* "rm" would have already printed a suitable error message. */ + if (! WIFEXITED (status) + || WEXITSTATUS (status) != 0) +- exit (1); ++ FAIL_EXIT1 ("exec child returned status: %d", status); + + break; + } diff --git a/SOURCES/glibc-rh1817513-62.patch b/SOURCES/glibc-rh1817513-62.patch new file mode 100644 index 0000000..77f123a --- /dev/null +++ b/SOURCES/glibc-rh1817513-62.patch @@ -0,0 +1,67 @@ +commit 533dd2acf7eefa969fb770fa782b20519bd4bc0f +Author: H.J. Lu +Date: Tue Jun 9 12:15:01 2020 -0700 + + Add "%d" support to _dl_debug_vdprintf + + "%d" will be used to print out signed value. + +diff --git a/elf/dl-misc.c b/elf/dl-misc.c +index 2eb81eeb0231368d..3f28de3ee9d68368 100644 +--- a/elf/dl-misc.c ++++ b/elf/dl-misc.c +@@ -167,6 +167,7 @@ _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg) + switch (*fmt) + { + /* Integer formatting. */ ++ case 'd': + case 'u': + case 'x': + { +@@ -179,11 +180,34 @@ _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg) + #else + unsigned long int num = va_arg (arg, unsigned int); + #endif ++ bool negative = false; ++ if (*fmt == 'd') ++ { ++#if LONG_MAX != INT_MAX ++ if (long_mod) ++ { ++ if ((long int) num < 0) ++ negative = true; ++ } ++ else ++ { ++ if ((int) num < 0) ++ { ++ num = (unsigned int) num; ++ negative = true; ++ } ++ } ++#else ++ if ((int) num < 0) ++ negative = true; ++#endif ++ } ++ + /* We use alloca() to allocate the buffer with the most + pessimistic guess for the size. Using alloca() allows + having more than one integer formatting in a call. */ +- char *buf = (char *) alloca (3 * sizeof (unsigned long int)); +- char *endp = &buf[3 * sizeof (unsigned long int)]; ++ char *buf = (char *) alloca (1 + 3 * sizeof (unsigned long int)); ++ char *endp = &buf[1 + 3 * sizeof (unsigned long int)]; + char *cp = _itoa (num, endp, *fmt == 'x' ? 16 : 10, 0); + + /* Pad to the width the user specified. */ +@@ -191,6 +215,9 @@ _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg) + while (endp - cp < width) + *--cp = fill; + ++ if (negative) ++ *--cp = '-'; ++ + iov[niov].iov_base = cp; + iov[niov].iov_len = endp - cp; + ++niov; diff --git a/SOURCES/glibc-rh1817513-63.patch b/SOURCES/glibc-rh1817513-63.patch new file mode 100644 index 0000000..7e42638 --- /dev/null +++ b/SOURCES/glibc-rh1817513-63.patch @@ -0,0 +1,62 @@ +commit e221c512c74ec42fd47b71de2981a475b38110a4 +Author: Florian Weimer +Date: Mon Jun 15 09:50:14 2020 +0200 + + ld.so: Check for new cache format first and enhance corruption check + + Now that ldconfig defaults to the new format (only), check for it + first. Also apply the corruption check added in commit 2954daf00bb4d + ("Add more checks for valid ld.so.cache file (bug 18093)") to the + new-format-only case. + + Suggested-by: Josh Triplett + +diff --git a/elf/dl-cache.c b/elf/dl-cache.c +index 6dd99a35b9f97cfb..ef37ca18fa9fb6e0 100644 +--- a/elf/dl-cache.c ++++ b/elf/dl-cache.c +@@ -199,15 +199,25 @@ _dl_load_cache_lookup (const char *name) + PROT_READ); + + /* We can handle three different cache file formats here: ++ - only the new format + - the old libc5/glibc2.0/2.1 format + - the old format with the new format in it +- - only the new format + The following checks if the cache contains any of these formats. */ +- if (file != MAP_FAILED && cachesize > sizeof *cache +- && memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0 ++ if (file != MAP_FAILED && cachesize > sizeof *cache_new ++ && memcmp (file, CACHEMAGIC_VERSION_NEW, ++ sizeof CACHEMAGIC_VERSION_NEW - 1) == 0 + /* Check for corruption, avoiding overflow. */ +- && ((cachesize - sizeof *cache) / sizeof (struct file_entry) +- >= ((struct cache_file *) file)->nlibs)) ++ && ((cachesize - sizeof *cache_new) / sizeof (struct file_entry_new) ++ >= ((struct cache_file_new *) file)->nlibs)) ++ { ++ cache_new = file; ++ cache = file; ++ } ++ else if (file != MAP_FAILED && cachesize > sizeof *cache ++ && memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0 ++ /* Check for corruption, avoiding overflow. */ ++ && ((cachesize - sizeof *cache) / sizeof (struct file_entry) ++ >= ((struct cache_file *) file)->nlibs)) + { + size_t offset; + /* Looks ok. */ +@@ -223,13 +233,6 @@ _dl_load_cache_lookup (const char *name) + sizeof CACHEMAGIC_VERSION_NEW - 1) != 0) + cache_new = (void *) -1; + } +- else if (file != MAP_FAILED && cachesize > sizeof *cache_new +- && memcmp (file, CACHEMAGIC_VERSION_NEW, +- sizeof CACHEMAGIC_VERSION_NEW - 1) == 0) +- { +- cache_new = file; +- cache = file; +- } + else + { + if (file != MAP_FAILED) diff --git a/SOURCES/glibc-rh1817513-64.patch b/SOURCES/glibc-rh1817513-64.patch new file mode 100644 index 0000000..13fbc6c --- /dev/null +++ b/SOURCES/glibc-rh1817513-64.patch @@ -0,0 +1,21 @@ +commit b7c9bb183b799b10c09ec32e98d1843546ea4324 +Author: H.J. Lu +Date: Wed Jun 17 05:32:37 2020 -0700 + + x86: Correct bit_cpu_CLFLUSHOPT [BZ #26128] + + bit_cpu_CLFLUSHOPT should be (1u << 23), not (1u << 22). + +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 388172a1c07bf979..7abfa046c4b8f6ac 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -465,7 +465,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_ADX (1u << 19) + #define bit_cpu_SMAP (1u << 20) + #define bit_cpu_AVX512_IFMA (1u << 21) +-#define bit_cpu_CLFLUSHOPT (1u << 22) ++#define bit_cpu_CLFLUSHOPT (1u << 23) + #define bit_cpu_CLWB (1u << 24) + #define bit_cpu_TRACE (1u << 25) + #define bit_cpu_AVX512PF (1u << 26) diff --git a/SOURCES/glibc-rh1817513-65.patch b/SOURCES/glibc-rh1817513-65.patch new file mode 100644 index 0000000..14f1c78 --- /dev/null +++ b/SOURCES/glibc-rh1817513-65.patch @@ -0,0 +1,68 @@ +commit 27f8864bd41f0f1b61e8e947d9a030b1a0d23df9 +Author: H.J. Lu +Date: Thu Jun 18 05:34:15 2020 -0700 + + x86: Update F16C detection [BZ #26133] + + Since F16C requires AVX, set F16C usable only when AVX is usable. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 2a801e1856cfe1b3..37619c93f8dbcc5d 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -146,6 +146,10 @@ get_common_indices (struct cpu_features *cpu_features, + if (CPU_FEATURES_CPU_P (cpu_features, XOP)) + cpu_features->feature[index_arch_XOP_Usable] + |= bit_arch_XOP_Usable; ++ /* Determine if F16C is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, F16C)) ++ cpu_features->feature[index_arch_F16C_Usable] ++ |= bit_arch_F16C_Usable; + } + + /* Check if OPMASK state, upper 256-bit of ZMM0-ZMM15 and +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 7abfa046c4b8f6ac..f18f7520fcb7714a 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -142,6 +142,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_arch_VPCLMULQDQ_Usable (1u << 20) + #define bit_arch_XOP_Usable (1u << 21) + #define bit_arch_XSAVEC_Usable (1u << 22) ++#define bit_arch_F16C_Usable (1u << 23) + + #define index_arch_AVX_Usable FEATURE_INDEX_1 + #define index_arch_AVX2_Usable FEATURE_INDEX_1 +@@ -166,6 +167,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_arch_VPCLMULQDQ_Usable FEATURE_INDEX_1 + #define index_arch_XOP_Usable FEATURE_INDEX_1 + #define index_arch_XSAVEC_Usable FEATURE_INDEX_1 ++#define index_arch_F16C_Usable FEATURE_INDEX_1 + + /* Unused. Compiler will optimize them out. */ + #define bit_arch_SSE3_Usable (1u << 0) +@@ -179,7 +181,6 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_arch_AES_Usable (1u << 0) + #define bit_arch_XSAVE_Usable (1u << 0) + #define bit_arch_OSXSAVE_Usable (1u << 0) +-#define bit_arch_F16C_Usable (1u << 0) + #define bit_arch_RDRAND_Usable (1u << 0) + #define bit_arch_FPU_Usable (1u << 0) + #define bit_arch_TSC_Usable (1u << 0) +@@ -236,7 +237,6 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_arch_AES_Usable FEATURE_INDEX_1 + #define index_arch_XSAVE_Usable FEATURE_INDEX_1 + #define index_arch_OSXSAVE_Usable FEATURE_INDEX_1 +-#define index_arch_F16C_Usable FEATURE_INDEX_1 + #define index_arch_RDRAND_Usable FEATURE_INDEX_1 + #define index_arch_FPU_Usable FEATURE_INDEX_1 + #define index_arch_TSC_Usable FEATURE_INDEX_1 +@@ -296,7 +296,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define need_arch_feature_XSAVE 0 + #define need_arch_feature_OSXSAVE 0 + #define need_arch_feature_AVX 1 +-#define need_arch_feature_F16C 0 ++#define need_arch_feature_F16C 1 + #define need_arch_feature_RDRAND 0 + + /* EDX. */ diff --git a/SOURCES/glibc-rh1817513-66.patch b/SOURCES/glibc-rh1817513-66.patch new file mode 100644 index 0000000..04b83b4 --- /dev/null +++ b/SOURCES/glibc-rh1817513-66.patch @@ -0,0 +1,1123 @@ +commit ecbbadbf107ea1155ae5b71a8b7bd48f38c76731 +Author: H.J. Lu +Date: Wed Jun 17 06:34:46 2020 -0700 + + x86: Update CPU feature detection [BZ #26149] + + 1. Divide architecture features into the usable features and the preferred + features. The usable features are for correctness and can be exported in + a stable ABI. The preferred features are for performance and only for + glibc internal use. + 2. Change struct cpu_features to + + struct cpu_features + { + struct cpu_features_basic basic; + unsigned int *usable_p; + struct cpuid_registers cpuid[COMMON_CPUID_INDEX_MAX]; + unsigned int usable[USABLE_FEATURE_INDEX_MAX]; + unsigned int preferred[PREFERRED_FEATURE_INDEX_MAX]; + ... + }; + + and initialize usable_p to pointer to the usable arary so that + + struct cpu_features + { + struct cpu_features_basic basic; + unsigned int *usable_p; + struct cpuid_registers cpuid[COMMON_CPUID_INDEX_MAX]; + }; + + can be exported via a stable ABI. The cpuid and usable arrays can be + expanded with backward binary compatibility for both .o and .so files. + 3. Add COMMON_CPUID_INDEX_7_ECX_1 for AVX512_BF16. + 4. Detect ENQCMD, PKS, AVX512_VP2INTERSECT, MD_CLEAR, SERIALIZE, HYBRID, + TSXLDTRK, L1D_FLUSH, CORE_CAPABILITIES and AVX512_BF16. + 5. Rename CAPABILITIES to ARCH_CAPABILITIES. + 6. Check if AVX512_VP2INTERSECT, AVX512_BF16 and PKU are usable. + 7. Update CPU feature detection test. + +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h b/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h +index ac694c032e7baf87..32f93bb3773a318b 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h ++++ b/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h +@@ -33,7 +33,7 @@ + case 21: \ + if (!__libc_enable_secure \ + && memcmp (envline, "PREFER_MAP_32BIT_EXEC", 21) == 0) \ +- GLRO(dl_x86_cpu_features).feature[index_arch_Prefer_MAP_32BIT_EXEC] \ ++ GLRO(dl_x86_cpu_features).preferred[index_arch_Prefer_MAP_32BIT_EXEC] \ + |= bit_arch_Prefer_MAP_32BIT_EXEC; \ + break; + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 37619c93f8dbcc5d..7b2a5bc3ed27ec39 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -90,11 +90,18 @@ get_common_indices (struct cpu_features *cpu_features, + } + + if (cpu_features->basic.max_cpuid >= 7) +- __cpuid_count (7, 0, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7].eax, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7].ebx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7].ecx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7].edx); ++ { ++ __cpuid_count (7, 0, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_7].eax, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_7].ebx, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_7].ecx, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_7].edx); ++ __cpuid_count (7, 1, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_7_ECX_1].eax, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_7_ECX_1].ebx, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_7_ECX_1].ecx, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_7_ECX_1].edx); ++ } + + if (cpu_features->basic.max_cpuid >= 0xd) + __cpuid_count (0xd, 1, +@@ -116,39 +123,39 @@ get_common_indices (struct cpu_features *cpu_features, + /* Determine if AVX is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX)) + { +- cpu_features->feature[index_arch_AVX_Usable] ++ cpu_features->usable[index_arch_AVX_Usable] + |= bit_arch_AVX_Usable; + /* The following features depend on AVX being usable. */ + /* Determine if AVX2 is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX2)) + { +- cpu_features->feature[index_arch_AVX2_Usable] ++ cpu_features->usable[index_arch_AVX2_Usable] + |= bit_arch_AVX2_Usable; + + /* Unaligned load with 256-bit AVX registers are faster on + Intel/AMD processors with AVX2. */ +- cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load] ++ cpu_features->preferred[index_arch_AVX_Fast_Unaligned_Load] + |= bit_arch_AVX_Fast_Unaligned_Load; + } + /* Determine if FMA is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, FMA)) +- cpu_features->feature[index_arch_FMA_Usable] ++ cpu_features->usable[index_arch_FMA_Usable] + |= bit_arch_FMA_Usable; + /* Determine if VAES is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, VAES)) +- cpu_features->feature[index_arch_VAES_Usable] ++ cpu_features->usable[index_arch_VAES_Usable] + |= bit_arch_VAES_Usable; + /* Determine if VPCLMULQDQ is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, VPCLMULQDQ)) +- cpu_features->feature[index_arch_VPCLMULQDQ_Usable] ++ cpu_features->usable[index_arch_VPCLMULQDQ_Usable] + |= bit_arch_VPCLMULQDQ_Usable; + /* Determine if XOP is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, XOP)) +- cpu_features->feature[index_arch_XOP_Usable] ++ cpu_features->usable[index_arch_XOP_Usable] + |= bit_arch_XOP_Usable; + /* Determine if F16C is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, F16C)) +- cpu_features->feature[index_arch_F16C_Usable] ++ cpu_features->usable[index_arch_F16C_Usable] + |= bit_arch_F16C_Usable; + } + +@@ -161,64 +168,73 @@ get_common_indices (struct cpu_features *cpu_features, + /* Determine if AVX512F is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512F)) + { +- cpu_features->feature[index_arch_AVX512F_Usable] ++ cpu_features->usable[index_arch_AVX512F_Usable] + |= bit_arch_AVX512F_Usable; + /* Determine if AVX512CD is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512CD)) +- cpu_features->feature[index_arch_AVX512CD_Usable] ++ cpu_features->usable[index_arch_AVX512CD_Usable] + |= bit_arch_AVX512CD_Usable; + /* Determine if AVX512ER is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512ER)) +- cpu_features->feature[index_arch_AVX512ER_Usable] ++ cpu_features->usable[index_arch_AVX512ER_Usable] + |= bit_arch_AVX512ER_Usable; + /* Determine if AVX512PF is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512PF)) +- cpu_features->feature[index_arch_AVX512PF_Usable] ++ cpu_features->usable[index_arch_AVX512PF_Usable] + |= bit_arch_AVX512PF_Usable; + /* Determine if AVX512VL is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512VL)) +- cpu_features->feature[index_arch_AVX512VL_Usable] ++ cpu_features->usable[index_arch_AVX512VL_Usable] + |= bit_arch_AVX512VL_Usable; + /* Determine if AVX512DQ is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512DQ)) +- cpu_features->feature[index_arch_AVX512DQ_Usable] ++ cpu_features->usable[index_arch_AVX512DQ_Usable] + |= bit_arch_AVX512DQ_Usable; + /* Determine if AVX512BW is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512BW)) +- cpu_features->feature[index_arch_AVX512BW_Usable] ++ cpu_features->usable[index_arch_AVX512BW_Usable] + |= bit_arch_AVX512BW_Usable; + /* Determine if AVX512_4FMAPS is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512_4FMAPS)) +- cpu_features->feature[index_arch_AVX512_4FMAPS_Usable] ++ cpu_features->usable[index_arch_AVX512_4FMAPS_Usable] + |= bit_arch_AVX512_4FMAPS_Usable; + /* Determine if AVX512_4VNNIW is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512_4VNNIW)) +- cpu_features->feature[index_arch_AVX512_4VNNIW_Usable] ++ cpu_features->usable[index_arch_AVX512_4VNNIW_Usable] + |= bit_arch_AVX512_4VNNIW_Usable; + /* Determine if AVX512_BITALG is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512_BITALG)) +- cpu_features->feature[index_arch_AVX512_BITALG_Usable] ++ cpu_features->usable[index_arch_AVX512_BITALG_Usable] + |= bit_arch_AVX512_BITALG_Usable; + /* Determine if AVX512_IFMA is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512_IFMA)) +- cpu_features->feature[index_arch_AVX512_IFMA_Usable] ++ cpu_features->usable[index_arch_AVX512_IFMA_Usable] + |= bit_arch_AVX512_IFMA_Usable; + /* Determine if AVX512_VBMI is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VBMI)) +- cpu_features->feature[index_arch_AVX512_VBMI_Usable] ++ cpu_features->usable[index_arch_AVX512_VBMI_Usable] + |= bit_arch_AVX512_VBMI_Usable; + /* Determine if AVX512_VBMI2 is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VBMI2)) +- cpu_features->feature[index_arch_AVX512_VBMI2_Usable] ++ cpu_features->usable[index_arch_AVX512_VBMI2_Usable] + |= bit_arch_AVX512_VBMI2_Usable; + /* Determine if is AVX512_VNNI usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VNNI)) +- cpu_features->feature[index_arch_AVX512_VNNI_Usable] ++ cpu_features->usable[index_arch_AVX512_VNNI_Usable] + |= bit_arch_AVX512_VNNI_Usable; + /* Determine if AVX512_VPOPCNTDQ is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VPOPCNTDQ)) +- cpu_features->feature[index_arch_AVX512_VPOPCNTDQ_Usable] ++ cpu_features->usable[index_arch_AVX512_VPOPCNTDQ_Usable] + |= bit_arch_AVX512_VPOPCNTDQ_Usable; ++ /* Determine if AVX512_VP2INTERSECT is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, ++ AVX512_VP2INTERSECT)) ++ cpu_features->usable[index_arch_AVX512_VP2INTERSECT_Usable] ++ |= bit_arch_AVX512_VP2INTERSECT_Usable; ++ /* Determine if AVX512_BF16 is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512_BF16)) ++ cpu_features->usable[index_arch_AVX512_BF16_Usable] ++ |= bit_arch_AVX512_BF16_Usable; + } + } + } +@@ -284,13 +300,18 @@ get_common_indices (struct cpu_features *cpu_features, + { + cpu_features->xsave_state_size + = ALIGN_UP (size + STATE_SAVE_OFFSET, 64); +- cpu_features->feature[index_arch_XSAVEC_Usable] ++ cpu_features->usable[index_arch_XSAVEC_Usable] + |= bit_arch_XSAVEC_Usable; + } + } + } + } + } ++ ++ /* Determine if PKU is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, OSPKE)) ++ cpu_features->usable[index_arch_PKU_Usable] ++ |= bit_arch_PKU_Usable; + } + + _Static_assert (((index_arch_Fast_Unaligned_Load +@@ -314,6 +335,8 @@ init_cpu_features (struct cpu_features *cpu_features) + unsigned int stepping = 0; + enum cpu_features_kind kind; + ++ cpu_features->usable_p = cpu_features->usable; ++ + #if !HAS_CPUID + if (__get_cpuid_max (0, 0) == 0) + { +@@ -344,7 +367,7 @@ init_cpu_features (struct cpu_features *cpu_features) + case 0x1c: + case 0x26: + /* BSF is slow on Atom. */ +- cpu_features->feature[index_arch_Slow_BSF] ++ cpu_features->preferred[index_arch_Slow_BSF] + |= bit_arch_Slow_BSF; + break; + +@@ -371,7 +394,7 @@ init_cpu_features (struct cpu_features *cpu_features) + case 0x5d: + /* Unaligned load versions are faster than SSSE3 + on Silvermont. */ +- cpu_features->feature[index_arch_Fast_Unaligned_Load] ++ cpu_features->preferred[index_arch_Fast_Unaligned_Load] + |= (bit_arch_Fast_Unaligned_Load + | bit_arch_Fast_Unaligned_Copy + | bit_arch_Prefer_PMINUB_for_stringop +@@ -383,7 +406,7 @@ init_cpu_features (struct cpu_features *cpu_features) + case 0x9c: + /* Enable rep string instructions, unaligned load, unaligned + copy, pminub and avoid SSE 4.2 on Tremont. */ +- cpu_features->feature[index_arch_Fast_Rep_String] ++ cpu_features->preferred[index_arch_Fast_Rep_String] + |= (bit_arch_Fast_Rep_String + | bit_arch_Fast_Unaligned_Load + | bit_arch_Fast_Unaligned_Copy +@@ -407,7 +430,7 @@ init_cpu_features (struct cpu_features *cpu_features) + case 0x2f: + /* Rep string instructions, unaligned load, unaligned copy, + and pminub are fast on Intel Core i3, i5 and i7. */ +- cpu_features->feature[index_arch_Fast_Rep_String] ++ cpu_features->preferred[index_arch_Fast_Rep_String] + |= (bit_arch_Fast_Rep_String + | bit_arch_Fast_Unaligned_Load + | bit_arch_Fast_Unaligned_Copy +@@ -442,10 +465,10 @@ init_cpu_features (struct cpu_features *cpu_features) + if AVX512ER is available. Don't use AVX512 to avoid lower CPU + frequency if AVX512ER isn't available. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512ER)) +- cpu_features->feature[index_arch_Prefer_No_VZEROUPPER] ++ cpu_features->preferred[index_arch_Prefer_No_VZEROUPPER] + |= bit_arch_Prefer_No_VZEROUPPER; + else +- cpu_features->feature[index_arch_Prefer_No_AVX512] ++ cpu_features->preferred[index_arch_Prefer_No_AVX512] + |= bit_arch_Prefer_No_AVX512; + } + /* This spells out "AuthenticAMD". */ +@@ -467,7 +490,7 @@ init_cpu_features (struct cpu_features *cpu_features) + /* Since the FMA4 bit is in COMMON_CPUID_INDEX_80000001 and + FMA4 requires AVX, determine if FMA4 is usable here. */ + if (CPU_FEATURES_CPU_P (cpu_features, FMA4)) +- cpu_features->feature[index_arch_FMA4_Usable] ++ cpu_features->usable[index_arch_FMA4_Usable] + |= bit_arch_FMA4_Usable; + } + +@@ -476,13 +499,13 @@ init_cpu_features (struct cpu_features *cpu_features) + /* "Excavator" */ + if (model >= 0x60 && model <= 0x7f) + { +- cpu_features->feature[index_arch_Fast_Unaligned_Load] ++ cpu_features->preferred[index_arch_Fast_Unaligned_Load] + |= (bit_arch_Fast_Unaligned_Load + | bit_arch_Fast_Copy_Backward); + + /* Unaligned AVX loads are slower.*/ +- cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load] +- &= ~bit_arch_AVX_Fast_Unaligned_Load; ++ cpu_features->preferred[index_arch_AVX_Fast_Unaligned_Load] ++ &= ~bit_arch_AVX_Fast_Unaligned_Load; + } + } + } +@@ -504,41 +527,38 @@ init_cpu_features (struct cpu_features *cpu_features) + { + if (model == 0xf || model == 0x19) + { +- cpu_features->feature[index_arch_AVX_Usable] +- &= (~bit_arch_AVX_Usable +- & ~bit_arch_AVX2_Usable); ++ cpu_features->usable[index_arch_AVX_Usable] ++ &= ~(bit_arch_AVX_Usable | bit_arch_AVX2_Usable); + +- cpu_features->feature[index_arch_Slow_SSE4_2] +- |= (bit_arch_Slow_SSE4_2); ++ cpu_features->preferred[index_arch_Slow_SSE4_2] ++ |= bit_arch_Slow_SSE4_2; + +- cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load] +- &= ~bit_arch_AVX_Fast_Unaligned_Load; ++ cpu_features->preferred[index_arch_AVX_Fast_Unaligned_Load] ++ &= ~bit_arch_AVX_Fast_Unaligned_Load; + } + } + else if (family == 0x7) + { +- if (model == 0x1b) +- { +- cpu_features->feature[index_arch_AVX_Usable] +- &= (~bit_arch_AVX_Usable +- & ~bit_arch_AVX2_Usable); ++ if (model == 0x1b) ++ { ++ cpu_features->usable[index_arch_AVX_Usable] ++ &= ~(bit_arch_AVX_Usable | bit_arch_AVX2_Usable); + +- cpu_features->feature[index_arch_Slow_SSE4_2] +- |= bit_arch_Slow_SSE4_2; ++ cpu_features->preferred[index_arch_Slow_SSE4_2] ++ |= bit_arch_Slow_SSE4_2; ++ ++ cpu_features->preferred[index_arch_AVX_Fast_Unaligned_Load] ++ &= ~bit_arch_AVX_Fast_Unaligned_Load; ++ } ++ else if (model == 0x3b) ++ { ++ cpu_features->usable[index_arch_AVX_Usable] ++ &= ~(bit_arch_AVX_Usable | bit_arch_AVX2_Usable); + +- cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load] +- &= ~bit_arch_AVX_Fast_Unaligned_Load; +- } +- else if (model == 0x3b) +- { +- cpu_features->feature[index_arch_AVX_Usable] +- &= (~bit_arch_AVX_Usable +- & ~bit_arch_AVX2_Usable); +- +- cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load] +- &= ~bit_arch_AVX_Fast_Unaligned_Load; +- } +- } ++ cpu_features->preferred[index_arch_AVX_Fast_Unaligned_Load] ++ &= ~bit_arch_AVX_Fast_Unaligned_Load; ++ } ++ } + } + else + { +@@ -548,11 +568,11 @@ init_cpu_features (struct cpu_features *cpu_features) + + /* Support i586 if CX8 is available. */ + if (CPU_FEATURES_CPU_P (cpu_features, CX8)) +- cpu_features->feature[index_arch_I586] |= bit_arch_I586; ++ cpu_features->preferred[index_arch_I586] |= bit_arch_I586; + + /* Support i686 if CMOV is available. */ + if (CPU_FEATURES_CPU_P (cpu_features, CMOV)) +- cpu_features->feature[index_arch_I686] |= bit_arch_I686; ++ cpu_features->preferred[index_arch_I686] |= bit_arch_I686; + + #if !HAS_CPUID + no_cpuid: +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index f18f7520fcb7714a..41c3855e94d16b49 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -20,12 +20,20 @@ + + enum + { +- /* The integer bit array index for the first set of internal feature ++ /* The integer bit array index for the first set of usable feature + bits. */ +- FEATURE_INDEX_1 = 0, +- FEATURE_INDEX_2, ++ USABLE_FEATURE_INDEX_1 = 0, + /* The current maximum size of the feature integer bit array. */ +- FEATURE_INDEX_MAX ++ USABLE_FEATURE_INDEX_MAX ++}; ++ ++enum ++{ ++ /* The integer bit array index for the first set of preferred feature ++ bits. */ ++ PREFERRED_FEATURE_INDEX_1 = 0, ++ /* The current maximum size of the feature integer bit array. */ ++ PREFERRED_FEATURE_INDEX_MAX + }; + + enum +@@ -36,6 +44,7 @@ enum + COMMON_CPUID_INDEX_D_ECX_1, + COMMON_CPUID_INDEX_80000007, + COMMON_CPUID_INDEX_80000008, ++ COMMON_CPUID_INDEX_7_ECX_1, + /* Keep the following line at the end. */ + COMMON_CPUID_INDEX_MAX + }; +@@ -68,9 +77,11 @@ struct cpu_features_basic + + struct cpu_features + { +- struct cpuid_registers cpuid[COMMON_CPUID_INDEX_MAX]; +- unsigned int feature[FEATURE_INDEX_MAX]; + struct cpu_features_basic basic; ++ unsigned int *usable_p; ++ struct cpuid_registers cpuid[COMMON_CPUID_INDEX_MAX]; ++ unsigned int usable[USABLE_FEATURE_INDEX_MAX]; ++ unsigned int preferred[PREFERRED_FEATURE_INDEX_MAX]; + /* The state size for XSAVEC or XSAVE. The type must be unsigned long + int so that we use + +@@ -102,7 +113,7 @@ extern const struct cpu_features *__get_cpu_features (void) + # define CPU_FEATURES_CPU_P(ptr, name) \ + ((ptr->cpuid[index_cpu_##name].reg_##name & (bit_cpu_##name)) != 0) + # define CPU_FEATURES_ARCH_P(ptr, name) \ +- ((ptr->feature[index_arch_##name] & (bit_arch_##name)) != 0) ++ ((ptr->feature_##name[index_arch_##name] & (bit_arch_##name)) != 0) + + /* HAS_CPU_FEATURE evaluates to true if CPU supports the feature. */ + #define HAS_CPU_FEATURE(name) \ +@@ -112,13 +123,12 @@ extern const struct cpu_features *__get_cpu_features (void) + # define HAS_ARCH_FEATURE(name) \ + CPU_FEATURES_ARCH_P (__get_cpu_features (), name) + /* CPU_FEATURE_USABLE evaluates to true if the feature is usable. */ +-#define CPU_FEATURE_USABLE(name) \ +- ((need_arch_feature_##name && HAS_ARCH_FEATURE (name##_Usable)) \ +- || (!need_arch_feature_##name && HAS_CPU_FEATURE(name))) ++#define CPU_FEATURE_USABLE(name) \ ++ HAS_ARCH_FEATURE (name##_Usable) + + /* Architecture features. */ + +-/* FEATURE_INDEX_1. */ ++/* USABLE_FEATURE_INDEX_1. */ + #define bit_arch_AVX_Usable (1u << 0) + #define bit_arch_AVX2_Usable (1u << 1) + #define bit_arch_AVX512F_Usable (1u << 2) +@@ -143,237 +153,65 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_arch_XOP_Usable (1u << 21) + #define bit_arch_XSAVEC_Usable (1u << 22) + #define bit_arch_F16C_Usable (1u << 23) +- +-#define index_arch_AVX_Usable FEATURE_INDEX_1 +-#define index_arch_AVX2_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512F_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512CD_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512ER_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512PF_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512VL_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512BW_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512DQ_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512_4FMAPS_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512_4VNNIW_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512_BITALG_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512_IFMA_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512_VBMI_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512_VBMI2_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512_VNNI_Usable FEATURE_INDEX_1 +-#define index_arch_AVX512_VPOPCNTDQ_Usable FEATURE_INDEX_1 +-#define index_arch_FMA_Usable FEATURE_INDEX_1 +-#define index_arch_FMA4_Usable FEATURE_INDEX_1 +-#define index_arch_VAES_Usable FEATURE_INDEX_1 +-#define index_arch_VPCLMULQDQ_Usable FEATURE_INDEX_1 +-#define index_arch_XOP_Usable FEATURE_INDEX_1 +-#define index_arch_XSAVEC_Usable FEATURE_INDEX_1 +-#define index_arch_F16C_Usable FEATURE_INDEX_1 +- +-/* Unused. Compiler will optimize them out. */ +-#define bit_arch_SSE3_Usable (1u << 0) +-#define bit_arch_PCLMULQDQ_Usable (1u << 0) +-#define bit_arch_SSSE3_Usable (1u << 0) +-#define bit_arch_CMPXCHG16B_Usable (1u << 0) +-#define bit_arch_SSE4_1_Usable (1u << 0) +-#define bit_arch_SSE4_2_Usable (1u << 0) +-#define bit_arch_MOVBE_Usable (1u << 0) +-#define bit_arch_POPCNT_Usable (1u << 0) +-#define bit_arch_AES_Usable (1u << 0) +-#define bit_arch_XSAVE_Usable (1u << 0) +-#define bit_arch_OSXSAVE_Usable (1u << 0) +-#define bit_arch_RDRAND_Usable (1u << 0) +-#define bit_arch_FPU_Usable (1u << 0) +-#define bit_arch_TSC_Usable (1u << 0) +-#define bit_arch_MSR_Usable (1u << 0) +-#define bit_arch_CX8_Usable (1u << 0) +-#define bit_arch_SEP_Usable (1u << 0) +-#define bit_arch_CMOV_Usable (1u << 0) +-#define bit_arch_CLFSH_Usable (1u << 0) +-#define bit_arch_MMX_Usable (1u << 0) +-#define bit_arch_FXSR_Usable (1u << 0) +-#define bit_arch_SSE_Usable (1u << 0) +-#define bit_arch_SSE2_Usable (1u << 0) +-#define bit_arch_FSGSBASE_Usable (1u << 0) +-#define bit_arch_BMI1_Usable (1u << 0) +-#define bit_arch_HLE_Usable (1u << 0) +-#define bit_arch_BMI2_Usable (1u << 0) +-#define bit_arch_ERMS_Usable (1u << 0) +-#define bit_arch_RTM_Usable (1u << 0) +-#define bit_arch_RDSEED_Usable (1u << 0) +-#define bit_arch_ADX_Usable (1u << 0) +-#define bit_arch_CLFLUSHOPT_Usable (1u << 0) +-#define bit_arch_CLWB_Usable (1u << 0) +-#define bit_arch_SHA_Usable (1u << 0) +-#define bit_arch_PREFETCHWT1_Usable (1u << 0) +-#define bit_arch_GFNI_Usable (1u << 0) +-#define bit_arch_RDPID_Usable (1u << 0) +-#define bit_arch_CLDEMOTE_Usable (1u << 0) +-#define bit_arch_MOVDIRI_Usable (1u << 0) +-#define bit_arch_MOVDIR64B_Usable (1u << 0) +-#define bit_arch_FSRM_Usable (1u << 0) +-#define bit_arch_LAHF64_SAHF64_Usable (1u << 0) +-#define bit_arch_SVM_Usable (1u << 0) +-#define bit_arch_LZCNT_Usable (1u << 0) +-#define bit_arch_SSE4A_Usable (1u << 0) +-#define bit_arch_PREFETCHW_Usable (1u << 0) +-#define bit_arch_TBM_Usable (1u << 0) +-#define bit_arch_SYSCALL_SYSRET_Usable (1u << 0) +-#define bit_arch_RDTSCP_Usable (1u << 0) +-#define bit_arch_XSAVEOPT_Usable (1u << 0) +-#define bit_arch_XGETBV_ECX_1_Usable (1u << 0) +-#define bit_arch_XSAVES_Usable (1u << 0) +-#define bit_arch_INVARIANT_TSC_Usable (1u << 0) +-#define bit_arch_WBNOINVD_Usable (1u << 0) +- +-/* Unused. Compiler will optimize them out. */ +-#define index_arch_SSE3_Usable FEATURE_INDEX_1 +-#define index_arch_PCLMULQDQ_Usable FEATURE_INDEX_1 +-#define index_arch_SSSE3_Usable FEATURE_INDEX_1 +-#define index_arch_CMPXCHG16B_Usable FEATURE_INDEX_1 +-#define index_arch_SSE4_1_Usable FEATURE_INDEX_1 +-#define index_arch_SSE4_2_Usable FEATURE_INDEX_1 +-#define index_arch_MOVBE_Usable FEATURE_INDEX_1 +-#define index_arch_POPCNT_Usable FEATURE_INDEX_1 +-#define index_arch_AES_Usable FEATURE_INDEX_1 +-#define index_arch_XSAVE_Usable FEATURE_INDEX_1 +-#define index_arch_OSXSAVE_Usable FEATURE_INDEX_1 +-#define index_arch_RDRAND_Usable FEATURE_INDEX_1 +-#define index_arch_FPU_Usable FEATURE_INDEX_1 +-#define index_arch_TSC_Usable FEATURE_INDEX_1 +-#define index_arch_MSR_Usable FEATURE_INDEX_1 +-#define index_arch_CX8_Usable FEATURE_INDEX_1 +-#define index_arch_SEP_Usable FEATURE_INDEX_1 +-#define index_arch_CMOV_Usable FEATURE_INDEX_1 +-#define index_arch_CLFSH_Usable FEATURE_INDEX_1 +-#define index_arch_MMX_Usable FEATURE_INDEX_1 +-#define index_arch_FXSR_Usable FEATURE_INDEX_1 +-#define index_arch_SSE_Usable FEATURE_INDEX_1 +-#define index_arch_SSE2_Usable FEATURE_INDEX_1 +-#define index_arch_FSGSBASE_Usable FEATURE_INDEX_1 +-#define index_arch_BMI1_Usable FEATURE_INDEX_1 +-#define index_arch_HLE_Usable FEATURE_INDEX_1 +-#define index_arch_BMI2_Usable FEATURE_INDEX_1 +-#define index_arch_ERMS_Usable FEATURE_INDEX_1 +-#define index_arch_RTM_Usable FEATURE_INDEX_1 +-#define index_arch_RDSEED_Usable FEATURE_INDEX_1 +-#define index_arch_ADX_Usable FEATURE_INDEX_1 +-#define index_arch_CLFLUSHOPT_Usable FEATURE_INDEX_1 +-#define index_arch_CLWB_Usable FEATURE_INDEX_1 +-#define index_arch_SHA_Usable FEATURE_INDEX_1 +-#define index_arch_PREFETCHWT1_Usable FEATURE_INDEX_1 +-#define index_arch_GFNI_Usable FEATURE_INDEX_1 +-#define index_arch_RDPID_Usable FEATURE_INDEX_1 +-#define index_arch_CLDEMOTE_Usable FEATURE_INDEX_1 +-#define index_arch_MOVDIRI_Usable FEATURE_INDEX_1 +-#define index_arch_MOVDIR64B_Usable FEATURE_INDEX_1 +-#define index_arch_FSRM_Usable FEATURE_INDEX_1 +-#define index_arch_LAHF64_SAHF64_Usable FEATURE_INDEX_1 +-#define index_arch_LZCNT_Usable FEATURE_INDEX_1 +-#define index_arch_SSE4A_Usable FEATURE_INDEX_1 +-#define index_arch_PREFETCHW_Usable FEATURE_INDEX_1 +-#define index_arch_TBM_Usable FEATURE_INDEX_1 +-#define index_arch_SYSCALL_SYSRET_Usable FEATURE_INDEX_1 +-#define index_arch_RDTSCP_Usable FEATURE_INDEX_1 +-#define index_arch_XSAVEOPT_Usable FEATURE_INDEX_1 +-#define index_arch_XGETBV_ECX_1_Usable FEATURE_INDEX_1 +-#define index_arch_XSAVES_Usable FEATURE_INDEX_1 +-#define index_arch_INVARIANT_TSC_Usable FEATURE_INDEX_1 +-#define index_arch_WBNOINVD_Usable FEATURE_INDEX_1 +- +-/* COMMON_CPUID_INDEX_1. */ +- +-/* ECX. */ +-#define need_arch_feature_SSE3 0 +-#define need_arch_feature_PCLMULQDQ 0 +-#define need_arch_feature_SSSE3 0 +-#define need_arch_feature_FMA 1 +-#define need_arch_feature_CMPXCHG16B 0 +-#define need_arch_feature_SSE4_1 0 +-#define need_arch_feature_SSE4_2 0 +-#define need_arch_feature_MOVBE 0 +-#define need_arch_feature_POPCNT 0 +-#define need_arch_feature_AES 0 +-#define need_arch_feature_XSAVE 0 +-#define need_arch_feature_OSXSAVE 0 +-#define need_arch_feature_AVX 1 +-#define need_arch_feature_F16C 1 +-#define need_arch_feature_RDRAND 0 +- +-/* EDX. */ +-#define need_arch_feature_FPU 0 +-#define need_arch_feature_TSC 0 +-#define need_arch_feature_MSR 0 +-#define need_arch_feature_CX8 0 +-#define need_arch_feature_SEP 0 +-#define need_arch_feature_CMOV 0 +-#define need_arch_feature_CLFSH 0 +-#define need_arch_feature_MMX 0 +-#define need_arch_feature_FXSR 0 +-#define need_arch_feature_SSE 0 +-#define need_arch_feature_SSE2 0 +- +-/* COMMON_CPUID_INDEX_7. */ +- +-/* EBX. */ +-#define need_arch_feature_FSGSBASE 0 +-#define need_arch_feature_BMI1 0 +-#define need_arch_feature_HLE 0 +-#define need_arch_feature_AVX2 1 +-#define need_arch_feature_BMI2 0 +-#define need_arch_feature_ERMS 0 +-#define need_arch_feature_RTM 0 +-#define need_arch_feature_AVX512F 1 +-#define need_arch_feature_AVX512DQ 1 +-#define need_arch_feature_RDSEED 0 +-#define need_arch_feature_ADX 0 +-#define need_arch_feature_AVX512_IFMA 1 +-#define need_arch_feature_CLFLUSHOPT 0 +-#define need_arch_feature_CLWB 0 +-#define need_arch_feature_AVX512PF 1 +-#define need_arch_feature_AVX512ER 1 +-#define need_arch_feature_AVX512CD 1 +-#define need_arch_feature_SHA 0 +-#define need_arch_feature_AVX512BW 1 +-#define need_arch_feature_AVX512VL 1 +- +-/* ECX. */ +-#define need_arch_feature_PREFETCHWT1 0 +-#define need_arch_feature_AVX512_VBMI 1 +-#define need_arch_feature_AVX512_VBMI2 1 +-#define need_arch_feature_GFNI 0 +-#define need_arch_feature_VAES 1 +-#define need_arch_feature_VPCLMULQDQ 1 +-#define need_arch_feature_AVX512_VNNI 1 +-#define need_arch_feature_AVX512_BITALG 1 +-#define need_arch_feature_AVX512_VPOPCNTDQ 1 +-#define need_arch_feature_RDPID 0 +-#define need_arch_feature_CLDEMOTE 0 +-#define need_arch_feature_MOVDIRI 0 +-#define need_arch_feature_MOVDIR64B 0 +- +-/* EDX. */ +-#define need_arch_feature_AVX512_4VNNIW 1 +-#define need_arch_feature_AVX512_4FMAPS 1 +-#define need_arch_feature_FSRM 0 +- +-/* COMMON_CPUID_INDEX_80000001. */ +- +-/* ECX. */ +-#define need_arch_feature_LAHF64_SAHF64 0 +-#define need_arch_feature_LZCNT 0 +-#define need_arch_feature_SSE4A 0 +-#define need_arch_feature_PREFETCHW 0 +-#define need_arch_feature_XOP 1 +-#define need_arch_feature_FMA4 1 +-#define need_arch_feature_TBM 0 +-#define need_arch_feature_SYSCALL_SYSRET 0 +-#define need_arch_feature_RDTSCP 0 +-#define need_arch_feature_XSAVEOPT 0 +-#define need_arch_feature_XSAVEC 1 +-#define need_arch_feature_XGETBV_ECX_1 0 +-#define need_arch_feature_XSAVES 0 +-#define need_arch_feature_INVARIANT_TSC 0 +-#define need_arch_feature_WBNOINVD 0 ++#define bit_arch_AVX512_VP2INTERSECT_Usable (1u << 24) ++#define bit_arch_AVX512_BF16_Usable (1u << 25) ++#define bit_arch_PKU_Usable (1u << 26) ++ ++#define index_arch_AVX_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX2_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512F_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512CD_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512ER_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512PF_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512VL_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512BW_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512DQ_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512_4FMAPS_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512_4VNNIW_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512_BITALG_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512_IFMA_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512_VBMI_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512_VBMI2_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512_VNNI_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512_VPOPCNTDQ_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_FMA_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_FMA4_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_VAES_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_VPCLMULQDQ_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_XOP_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_XSAVEC_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_F16C_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512_VP2INTERSECT_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AVX512_BF16_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_PKU_Usable USABLE_FEATURE_INDEX_1 ++ ++#define feature_AVX_Usable usable ++#define feature_AVX2_Usable usable ++#define feature_AVX512F_Usable usable ++#define feature_AVX512CD_Usable usable ++#define feature_AVX512ER_Usable usable ++#define feature_AVX512PF_Usable usable ++#define feature_AVX512VL_Usable usable ++#define feature_AVX512BW_Usable usable ++#define feature_AVX512DQ_Usable usable ++#define feature_AVX512_4FMAPS_Usable usable ++#define feature_AVX512_4VNNIW_Usable usable ++#define feature_AVX512_BITALG_Usable usable ++#define feature_AVX512_IFMA_Usable usable ++#define feature_AVX512_VBMI_Usable usable ++#define feature_AVX512_VBMI2_Usable usable ++#define feature_AVX512_VNNI_Usable usable ++#define feature_AVX512_VPOPCNTDQ_Usable usable ++#define feature_FMA_Usable usable ++#define feature_FMA4_Usable usable ++#define feature_VAES_Usable usable ++#define feature_VPCLMULQDQ_Usable usable ++#define feature_XOP_Usable usable ++#define feature_XSAVEC_Usable usable ++#define feature_F16C_Usable usable ++#define feature_AVX512_VP2INTERSECT_Usable usable ++#define feature_AVX512_BF16_Usable usable ++#define feature_PKU_Usable usable + + /* CPU features. */ + +@@ -494,17 +332,26 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_CLDEMOTE (1u << 25) + #define bit_cpu_MOVDIRI (1u << 27) + #define bit_cpu_MOVDIR64B (1u << 28) ++#define bit_cpu_ENQCMD (1u << 29) + #define bit_cpu_SGX_LC (1u << 30) ++#define bit_cpu_PKS (1u << 31) + + /* EDX. */ + #define bit_cpu_AVX512_4VNNIW (1u << 2) + #define bit_cpu_AVX512_4FMAPS (1u << 3) + #define bit_cpu_FSRM (1u << 4) ++#define bit_cpu_AVX512_VP2INTERSECT (1u << 8) ++#define bit_cpu_MD_CLEAR (1u << 10) ++#define bit_cpu_SERIALIZE (1u << 14) ++#define bit_cpu_HYBRID (1u << 15) ++#define bit_cpu_TSXLDTRK (1u << 16) + #define bit_cpu_PCONFIG (1u << 18) + #define bit_cpu_IBT (1u << 20) + #define bit_cpu_IBRS_IBPB (1u << 26) + #define bit_cpu_STIBP (1u << 27) +-#define bit_cpu_CAPABILITIES (1u << 29) ++#define bit_cpu_L1D_FLUSH (1u << 28) ++#define bit_cpu_ARCH_CAPABILITIES (1u << 29) ++#define bit_cpu_CORE_CAPABILITIES (1u << 30) + #define bit_cpu_SSBD (1u << 31) + + /* COMMON_CPUID_INDEX_80000001. */ +@@ -545,6 +392,11 @@ extern const struct cpu_features *__get_cpu_features (void) + /* EBX. */ + #define bit_cpu_WBNOINVD (1u << 9) + ++/* COMMON_CPUID_INDEX_7_ECX_1. */ ++ ++/* EAX. */ ++#define bit_cpu_AVX512_BF16 (1u << 5) ++ + /* COMMON_CPUID_INDEX_1. */ + + /* ECX. */ +@@ -662,17 +514,26 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_CLDEMOTE COMMON_CPUID_INDEX_7 + #define index_cpu_MOVDIRI COMMON_CPUID_INDEX_7 + #define index_cpu_MOVDIR64B COMMON_CPUID_INDEX_7 ++#define index_cpu_ENQCMD COMMON_CPUID_INDEX_7 + #define index_cpu_SGX_LC COMMON_CPUID_INDEX_7 ++#define index_cpu_PKS COMMON_CPUID_INDEX_7 + + /* EDX. */ + #define index_cpu_AVX512_4VNNIW COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512_4FMAPS COMMON_CPUID_INDEX_7 + #define index_cpu_FSRM COMMON_CPUID_INDEX_7 ++#define index_cpu_AVX512_VP2INTERSECT COMMON_CPUID_INDEX_7 ++#define index_cpu_MD_CLEAR COMMON_CPUID_INDEX_7 ++#define index_cpu_SERIALIZE COMMON_CPUID_INDEX_7 ++#define index_cpu_HYBRID COMMON_CPUID_INDEX_7 ++#define index_cpu_TSXLDTRK COMMON_CPUID_INDEX_7 + #define index_cpu_PCONFIG COMMON_CPUID_INDEX_7 + #define index_cpu_IBT COMMON_CPUID_INDEX_7 + #define index_cpu_IBRS_IBPB COMMON_CPUID_INDEX_7 + #define index_cpu_STIBP COMMON_CPUID_INDEX_7 +-#define index_cpu_CAPABILITIES COMMON_CPUID_INDEX_7 ++#define index_cpu_L1D_FLUSH COMMON_CPUID_INDEX_7 ++#define index_cpu_ARCH_CAPABILITIES COMMON_CPUID_INDEX_7 ++#define index_cpu_CORE_CAPABILITIES COMMON_CPUID_INDEX_7 + #define index_cpu_SSBD COMMON_CPUID_INDEX_7 + + /* COMMON_CPUID_INDEX_80000001. */ +@@ -713,6 +574,11 @@ extern const struct cpu_features *__get_cpu_features (void) + /* EBX. */ + #define index_cpu_WBNOINVD COMMON_CPUID_INDEX_80000008 + ++/* COMMON_CPUID_INDEX_7_ECX_1. */ ++ ++/* EAX. */ ++#define index_cpu_AVX512_BF16 COMMON_CPUID_INDEX_7_ECX_1 ++ + /* COMMON_CPUID_INDEX_1. */ + + /* ECX. */ +@@ -830,17 +696,26 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_CLDEMOTE ecx + #define reg_MOVDIRI ecx + #define reg_MOVDIR64B ecx ++#define reg_ENQCMD ecx + #define reg_SGX_LC ecx ++#define reg_PKS ecx + + /* EDX. */ + #define reg_AVX512_4VNNIW edx + #define reg_AVX512_4FMAPS edx + #define reg_FSRM edx ++#define reg_AVX512_VP2INTERSECT edx ++#define reg_MD_CLEAR edx ++#define reg_SERIALIZE edx ++#define reg_HYBRID edx ++#define reg_TSXLDTRK edx + #define reg_PCONFIG edx + #define reg_IBT edx + #define reg_IBRS_IBPB edx + #define reg_STIBP edx +-#define reg_CAPABILITIES edx ++#define reg_L1D_FLUSH edx ++#define reg_ARCH_CAPABILITIES edx ++#define reg_CORE_CAPABILITIES edx + #define reg_SSBD edx + + /* COMMON_CPUID_INDEX_80000001. */ +@@ -881,6 +756,11 @@ extern const struct cpu_features *__get_cpu_features (void) + /* EBX. */ + #define reg_WBNOINVD ebx + ++/* COMMON_CPUID_INDEX_7_ECX_1. */ ++ ++/* EAX. */ ++#define reg_AVX512_BF16 eax ++ + /* FEATURE_INDEX_2. */ + #define bit_arch_I586 (1u << 0) + #define bit_arch_I686 (1u << 1) +@@ -899,22 +779,39 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_arch_Prefer_No_AVX512 (1u << 14) + #define bit_arch_MathVec_Prefer_No_AVX512 (1u << 15) + +-#define index_arch_Fast_Rep_String FEATURE_INDEX_2 +-#define index_arch_Fast_Copy_Backward FEATURE_INDEX_2 +-#define index_arch_Slow_BSF FEATURE_INDEX_2 +-#define index_arch_Fast_Unaligned_Load FEATURE_INDEX_2 +-#define index_arch_Prefer_PMINUB_for_stringop FEATURE_INDEX_2 +-#define index_arch_Fast_Unaligned_Copy FEATURE_INDEX_2 +-#define index_arch_I586 FEATURE_INDEX_2 +-#define index_arch_I686 FEATURE_INDEX_2 +-#define index_arch_Slow_SSE4_2 FEATURE_INDEX_2 +-#define index_arch_AVX_Fast_Unaligned_Load FEATURE_INDEX_2 +-#define index_arch_Prefer_MAP_32BIT_EXEC FEATURE_INDEX_2 +-#define index_arch_Prefer_No_VZEROUPPER FEATURE_INDEX_2 +-#define index_arch_Prefer_ERMS FEATURE_INDEX_2 +-#define index_arch_Prefer_No_AVX512 FEATURE_INDEX_2 +-#define index_arch_MathVec_Prefer_No_AVX512 FEATURE_INDEX_2 +-#define index_arch_Prefer_FSRM FEATURE_INDEX_2 ++#define index_arch_Fast_Rep_String PREFERRED_FEATURE_INDEX_1 ++#define index_arch_Fast_Copy_Backward PREFERRED_FEATURE_INDEX_1 ++#define index_arch_Slow_BSF PREFERRED_FEATURE_INDEX_1 ++#define index_arch_Fast_Unaligned_Load PREFERRED_FEATURE_INDEX_1 ++#define index_arch_Prefer_PMINUB_for_stringop PREFERRED_FEATURE_INDEX_1 ++#define index_arch_Fast_Unaligned_Copy PREFERRED_FEATURE_INDEX_1 ++#define index_arch_I586 PREFERRED_FEATURE_INDEX_1 ++#define index_arch_I686 PREFERRED_FEATURE_INDEX_1 ++#define index_arch_Slow_SSE4_2 PREFERRED_FEATURE_INDEX_1 ++#define index_arch_AVX_Fast_Unaligned_Load PREFERRED_FEATURE_INDEX_1 ++#define index_arch_Prefer_MAP_32BIT_EXEC PREFERRED_FEATURE_INDEX_1 ++#define index_arch_Prefer_No_VZEROUPPER PREFERRED_FEATURE_INDEX_1 ++#define index_arch_Prefer_ERMS PREFERRED_FEATURE_INDEX_1 ++#define index_arch_Prefer_No_AVX512 PREFERRED_FEATURE_INDEX_1 ++#define index_arch_MathVec_Prefer_No_AVX512 PREFERRED_FEATURE_INDEX_1 ++#define index_arch_Prefer_FSRM PREFERRED_FEATURE_INDEX_1 ++ ++#define feature_Fast_Rep_String preferred ++#define feature_Fast_Copy_Backward preferred ++#define feature_Slow_BSF preferred ++#define feature_Fast_Unaligned_Load preferred ++#define feature_Prefer_PMINUB_for_stringop preferred ++#define feature_Fast_Unaligned_Copy preferred ++#define feature_I586 preferred ++#define feature_I686 preferred ++#define feature_Slow_SSE4_2 preferred ++#define feature_AVX_Fast_Unaligned_Load preferred ++#define feature_Prefer_MAP_32BIT_EXEC preferred ++#define feature_Prefer_No_VZEROUPPER preferred ++#define feature_Prefer_ERMS preferred ++#define feature_Prefer_No_AVX512 preferred ++#define feature_MathVec_Prefer_No_AVX512 preferred ++#define feature_Prefer_FSRM preferred + + /* XCR0 Feature flags. */ + #define bit_XMM_state (1u << 1) +diff --git a/sysdeps/x86/cpu-tunables.c b/sysdeps/x86/cpu-tunables.c +index 2e5d37753713e975..012ae48933055eaa 100644 +--- a/sysdeps/x86/cpu-tunables.c ++++ b/sysdeps/x86/cpu-tunables.c +@@ -54,7 +54,7 @@ extern __typeof (memcmp) DEFAULT_MEMCMP; + _Static_assert (sizeof (#name) - 1 == len, #name " != " #len); \ + if (!DEFAULT_MEMCMP (f, #name, len)) \ + { \ +- cpu_features->feature[index_arch_##name] \ ++ cpu_features->feature_##name[index_arch_##name] \ + &= ~bit_arch_##name; \ + break; \ + } +@@ -66,10 +66,10 @@ extern __typeof (memcmp) DEFAULT_MEMCMP; + if (!DEFAULT_MEMCMP (f, #name, len)) \ + { \ + if (disable) \ +- cpu_features->feature[index_arch_##name] \ ++ cpu_features->feature_##name[index_arch_##name] \ + &= ~bit_arch_##name; \ + else \ +- cpu_features->feature[index_arch_##name] \ ++ cpu_features->feature_##name[index_arch_##name] \ + |= bit_arch_##name; \ + break; \ + } +@@ -82,10 +82,10 @@ extern __typeof (memcmp) DEFAULT_MEMCMP; + if (!DEFAULT_MEMCMP (f, #name, len)) \ + { \ + if (disable) \ +- cpu_features->feature[index_arch_##name] \ ++ cpu_features->feature_##name[index_arch_##name] \ + &= ~bit_arch_##name; \ + else if (CPU_FEATURES_ARCH_P (cpu_features, need)) \ +- cpu_features->feature[index_arch_##name] \ ++ cpu_features->feature_##name[index_arch_##name] \ + |= bit_arch_##name; \ + break; \ + } +@@ -98,10 +98,10 @@ extern __typeof (memcmp) DEFAULT_MEMCMP; + if (!DEFAULT_MEMCMP (f, #name, len)) \ + { \ + if (disable) \ +- cpu_features->feature[index_arch_##name] \ ++ cpu_features->feature_##name[index_arch_##name] \ + &= ~bit_arch_##name; \ + else if (CPU_FEATURES_CPU_P (cpu_features, need)) \ +- cpu_features->feature[index_arch_##name] \ ++ cpu_features->feature_##name[index_arch_##name] \ + |= bit_arch_##name; \ + break; \ + } +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index 64a7fd6157242bdd..08688ace2a0ae35e 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -172,15 +172,24 @@ do_test (void) + CHECK_CPU_FEATURE (CLDEMOTE); + CHECK_CPU_FEATURE (MOVDIRI); + CHECK_CPU_FEATURE (MOVDIR64B); ++ CHECK_CPU_FEATURE (ENQCMD); + CHECK_CPU_FEATURE (SGX_LC); ++ CHECK_CPU_FEATURE (PKS); + CHECK_CPU_FEATURE (AVX512_4VNNIW); + CHECK_CPU_FEATURE (AVX512_4FMAPS); + CHECK_CPU_FEATURE (FSRM); ++ CHECK_CPU_FEATURE (AVX512_VP2INTERSECT); ++ CHECK_CPU_FEATURE (MD_CLEAR); ++ CHECK_CPU_FEATURE (SERIALIZE); ++ CHECK_CPU_FEATURE (HYBRID); ++ CHECK_CPU_FEATURE (TSXLDTRK); + CHECK_CPU_FEATURE (PCONFIG); + CHECK_CPU_FEATURE (IBT); + CHECK_CPU_FEATURE (IBRS_IBPB); + CHECK_CPU_FEATURE (STIBP); +- CHECK_CPU_FEATURE (CAPABILITIES); ++ CHECK_CPU_FEATURE (L1D_FLUSH); ++ CHECK_CPU_FEATURE (ARCH_CAPABILITIES); ++ CHECK_CPU_FEATURE (CORE_CAPABILITIES); + CHECK_CPU_FEATURE (SSBD); + CHECK_CPU_FEATURE (LAHF64_SAHF64); + CHECK_CPU_FEATURE (SVM); +@@ -202,84 +211,36 @@ do_test (void) + CHECK_CPU_FEATURE (XSAVES); + CHECK_CPU_FEATURE (INVARIANT_TSC); + CHECK_CPU_FEATURE (WBNOINVD); ++ CHECK_CPU_FEATURE (AVX512_BF16); + + printf ("Usable CPU features:\n"); +- CHECK_CPU_FEATURE_USABLE (SSE3); +- CHECK_CPU_FEATURE_USABLE (PCLMULQDQ); +- CHECK_CPU_FEATURE_USABLE (SSSE3); + CHECK_CPU_FEATURE_USABLE (FMA); +- CHECK_CPU_FEATURE_USABLE (CMPXCHG16B); +- CHECK_CPU_FEATURE_USABLE (SSE4_1); +- CHECK_CPU_FEATURE_USABLE (SSE4_2); +- CHECK_CPU_FEATURE_USABLE (MOVBE); +- CHECK_CPU_FEATURE_USABLE (POPCNT); +- CHECK_CPU_FEATURE_USABLE (AES); +- CHECK_CPU_FEATURE_USABLE (XSAVE); +- CHECK_CPU_FEATURE_USABLE (OSXSAVE); + CHECK_CPU_FEATURE_USABLE (AVX); + CHECK_CPU_FEATURE_USABLE (F16C); +- CHECK_CPU_FEATURE_USABLE (RDRAND); +- CHECK_CPU_FEATURE_USABLE (FPU); +- CHECK_CPU_FEATURE_USABLE (TSC); +- CHECK_CPU_FEATURE_USABLE (MSR); +- CHECK_CPU_FEATURE_USABLE (CX8); +- CHECK_CPU_FEATURE_USABLE (SEP); +- CHECK_CPU_FEATURE_USABLE (CMOV); +- CHECK_CPU_FEATURE_USABLE (CLFSH); +- CHECK_CPU_FEATURE_USABLE (MMX); +- CHECK_CPU_FEATURE_USABLE (FXSR); +- CHECK_CPU_FEATURE_USABLE (SSE); +- CHECK_CPU_FEATURE_USABLE (SSE2); +- CHECK_CPU_FEATURE_USABLE (FSGSBASE); +- CHECK_CPU_FEATURE_USABLE (BMI1); +- CHECK_CPU_FEATURE_USABLE (HLE); + CHECK_CPU_FEATURE_USABLE (AVX2); +- CHECK_CPU_FEATURE_USABLE (BMI2); +- CHECK_CPU_FEATURE_USABLE (ERMS); + CHECK_CPU_FEATURE_USABLE (AVX512F); + CHECK_CPU_FEATURE_USABLE (AVX512DQ); +- CHECK_CPU_FEATURE_USABLE (RDSEED); +- CHECK_CPU_FEATURE_USABLE (ADX); + CHECK_CPU_FEATURE_USABLE (AVX512_IFMA); +- CHECK_CPU_FEATURE_USABLE (CLFLUSHOPT); +- CHECK_CPU_FEATURE_USABLE (CLWB); + CHECK_CPU_FEATURE_USABLE (AVX512PF); + CHECK_CPU_FEATURE_USABLE (AVX512ER); + CHECK_CPU_FEATURE_USABLE (AVX512CD); +- CHECK_CPU_FEATURE_USABLE (SHA); + CHECK_CPU_FEATURE_USABLE (AVX512BW); + CHECK_CPU_FEATURE_USABLE (AVX512VL); +- CHECK_CPU_FEATURE_USABLE (PREFETCHWT1); + CHECK_CPU_FEATURE_USABLE (AVX512_VBMI); ++ CHECK_CPU_FEATURE_USABLE (PKU); + CHECK_CPU_FEATURE_USABLE (AVX512_VBMI2); +- CHECK_CPU_FEATURE_USABLE (GFNI); + CHECK_CPU_FEATURE_USABLE (VAES); + CHECK_CPU_FEATURE_USABLE (VPCLMULQDQ); + CHECK_CPU_FEATURE_USABLE (AVX512_VNNI); + CHECK_CPU_FEATURE_USABLE (AVX512_BITALG); + CHECK_CPU_FEATURE_USABLE (AVX512_VPOPCNTDQ); +- CHECK_CPU_FEATURE_USABLE (RDPID); +- CHECK_CPU_FEATURE_USABLE (CLDEMOTE); +- CHECK_CPU_FEATURE_USABLE (MOVDIRI); +- CHECK_CPU_FEATURE_USABLE (MOVDIR64B); + CHECK_CPU_FEATURE_USABLE (AVX512_4VNNIW); + CHECK_CPU_FEATURE_USABLE (AVX512_4FMAPS); +- CHECK_CPU_FEATURE_USABLE (FSRM); +- CHECK_CPU_FEATURE_USABLE (LAHF64_SAHF64); +- CHECK_CPU_FEATURE_USABLE (LZCNT); +- CHECK_CPU_FEATURE_USABLE (SSE4A); +- CHECK_CPU_FEATURE_USABLE (PREFETCHW); ++ CHECK_CPU_FEATURE_USABLE (AVX512_VP2INTERSECT); + CHECK_CPU_FEATURE_USABLE (XOP); + CHECK_CPU_FEATURE_USABLE (FMA4); +- CHECK_CPU_FEATURE_USABLE (TBM); +- CHECK_CPU_FEATURE_USABLE (SYSCALL_SYSRET); +- CHECK_CPU_FEATURE_USABLE (RDTSCP); +- CHECK_CPU_FEATURE_USABLE (XSAVEOPT); + CHECK_CPU_FEATURE_USABLE (XSAVEC); +- CHECK_CPU_FEATURE_USABLE (XGETBV_ECX_1); +- CHECK_CPU_FEATURE_USABLE (XSAVES); +- CHECK_CPU_FEATURE_USABLE (INVARIANT_TSC); +- CHECK_CPU_FEATURE_USABLE (WBNOINVD); ++ CHECK_CPU_FEATURE_USABLE (AVX512_BF16); + + return 0; + } diff --git a/SOURCES/glibc-rh1817513-67.patch b/SOURCES/glibc-rh1817513-67.patch new file mode 100644 index 0000000..9e331ec --- /dev/null +++ b/SOURCES/glibc-rh1817513-67.patch @@ -0,0 +1,19 @@ +commit 6f3331f26d2ee5d210ba768389828c391750f7a0 +Author: Florian Weimer +Date: Wed Jun 24 11:02:33 2020 +0200 + + elf: Include in because bool is used + +diff --git a/elf/dl-tunables.h b/elf/dl-tunables.h +index 928b30dde9fa0489..7f181f3316cd9fc1 100644 +--- a/elf/dl-tunables.h ++++ b/elf/dl-tunables.h +@@ -21,6 +21,8 @@ + #ifndef _TUNABLES_H_ + #define _TUNABLES_H_ + ++#include ++ + #if !HAVE_TUNABLES + static inline void + __always_inline diff --git a/SOURCES/glibc-rh1817513-68.patch b/SOURCES/glibc-rh1817513-68.patch new file mode 100644 index 0000000..5ba0d6a --- /dev/null +++ b/SOURCES/glibc-rh1817513-68.patch @@ -0,0 +1,22 @@ +commit 2034c70e64b31e48140c8e31c5ae839af5ccb6eb +Author: Florian Weimer +Date: Thu Jun 25 16:51:03 2020 +0200 + + elf: Include (for size_t), in + + Reviewed-by: Carlos O'Donell + +diff --git a/sysdeps/generic/ldconfig.h b/sysdeps/generic/ldconfig.h +index 59e20dc3ef790125..6774212110d23eae 100644 +--- a/sysdeps/generic/ldconfig.h ++++ b/sysdeps/generic/ldconfig.h +@@ -19,7 +19,9 @@ + #ifndef _LDCONFIG_H + #define _LDCONFIG_H + ++#include + #include ++#include + + #define FLAG_ANY -1 + #define FLAG_TYPE_MASK 0x00ff diff --git a/SOURCES/glibc-rh1817513-69.patch b/SOURCES/glibc-rh1817513-69.patch new file mode 100644 index 0000000..9d668b3 --- /dev/null +++ b/SOURCES/glibc-rh1817513-69.patch @@ -0,0 +1,144 @@ +commit 4fdd4d41a17dda26c854ed935658154a17d4b906 +Author: H.J. Lu +Date: Thu Jun 25 15:12:57 2020 -0700 + + x86: Detect Intel Advanced Matrix Extensions + + Intel Advanced Matrix Extensions (Intel AMX) is a new programming + paradigm consisting of two components: a set of 2-dimensional registers + (tiles) representing sub-arrays from a larger 2-dimensional memory image, + and accelerators able to operate on tiles. Intel AMX is an extensible + architecture. New accelerators can be added and the existing accelerator + may be enhanced to provide higher performance. The initial features are + AMX-BF16, AMX-TILE and AMX-INT8, which are usable only if the operating + system supports both XTILECFG state and XTILEDATA state. + + Add AMX-BF16, AMX-TILE and AMX-INT8 support to HAS_CPU_FEATURE and + CPU_FEATURE_USABLE. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 7b2a5bc3ed27ec39..21565474839efffc 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -239,6 +239,24 @@ get_common_indices (struct cpu_features *cpu_features, + } + } + ++ /* Are XTILECFG and XTILEDATA states usable? */ ++ if ((xcrlow & (bit_XTILECFG_state | bit_XTILEDATA_state)) ++ == (bit_XTILECFG_state | bit_XTILEDATA_state)) ++ { ++ /* Determine if AMX_BF16 is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AMX_BF16)) ++ cpu_features->usable[index_arch_AMX_BF16_Usable] ++ |= bit_arch_AMX_BF16_Usable; ++ /* Determine if AMX_TILE is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AMX_TILE)) ++ cpu_features->usable[index_arch_AMX_TILE_Usable] ++ |= bit_arch_AMX_TILE_Usable; ++ /* Determine if AMX_INT8 is usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AMX_INT8)) ++ cpu_features->usable[index_arch_AMX_INT8_Usable] ++ |= bit_arch_AMX_INT8_Usable; ++ } ++ + /* For _dl_runtime_resolve, set xsave_state_size to xsave area + size + integer register save size and align it to 64 bytes. */ + if (cpu_features->basic.max_cpuid >= 0xd) +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 41c3855e94d16b49..7c46242aad69d427 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -156,6 +156,9 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_arch_AVX512_VP2INTERSECT_Usable (1u << 24) + #define bit_arch_AVX512_BF16_Usable (1u << 25) + #define bit_arch_PKU_Usable (1u << 26) ++#define bit_arch_AMX_BF16_Usable (1u << 27) ++#define bit_arch_AMX_TILE_Usable (1u << 28) ++#define bit_arch_AMX_INT8_Usable (1u << 29) + + #define index_arch_AVX_Usable USABLE_FEATURE_INDEX_1 + #define index_arch_AVX2_Usable USABLE_FEATURE_INDEX_1 +@@ -184,6 +187,9 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_arch_AVX512_VP2INTERSECT_Usable USABLE_FEATURE_INDEX_1 + #define index_arch_AVX512_BF16_Usable USABLE_FEATURE_INDEX_1 + #define index_arch_PKU_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AMX_BF16_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AMX_TILE_Usable USABLE_FEATURE_INDEX_1 ++#define index_arch_AMX_INT8_Usable USABLE_FEATURE_INDEX_1 + + #define feature_AVX_Usable usable + #define feature_AVX2_Usable usable +@@ -212,6 +218,9 @@ extern const struct cpu_features *__get_cpu_features (void) + #define feature_AVX512_VP2INTERSECT_Usable usable + #define feature_AVX512_BF16_Usable usable + #define feature_PKU_Usable usable ++#define feature_AMX_BF16_Usable usable ++#define feature_AMX_TILE_Usable usable ++#define feature_AMX_INT8_Usable usable + + /* CPU features. */ + +@@ -347,6 +356,9 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_TSXLDTRK (1u << 16) + #define bit_cpu_PCONFIG (1u << 18) + #define bit_cpu_IBT (1u << 20) ++#define bit_cpu_AMX_BF16 (1u << 22) ++#define bit_cpu_AMX_TILE (1u << 24) ++#define bit_cpu_AMX_INT8 (1u << 25) + #define bit_cpu_IBRS_IBPB (1u << 26) + #define bit_cpu_STIBP (1u << 27) + #define bit_cpu_L1D_FLUSH (1u << 28) +@@ -529,6 +541,9 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_TSXLDTRK COMMON_CPUID_INDEX_7 + #define index_cpu_PCONFIG COMMON_CPUID_INDEX_7 + #define index_cpu_IBT COMMON_CPUID_INDEX_7 ++#define index_cpu_AMX_BF16 COMMON_CPUID_INDEX_7 ++#define index_cpu_AMX_TILE COMMON_CPUID_INDEX_7 ++#define index_cpu_AMX_INT8 COMMON_CPUID_INDEX_7 + #define index_cpu_IBRS_IBPB COMMON_CPUID_INDEX_7 + #define index_cpu_STIBP COMMON_CPUID_INDEX_7 + #define index_cpu_L1D_FLUSH COMMON_CPUID_INDEX_7 +@@ -711,6 +726,9 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_TSXLDTRK edx + #define reg_PCONFIG edx + #define reg_IBT edx ++#define reg_AMX_BF16 edx ++#define reg_AMX_TILE edx ++#define reg_AMX_INT8 edx + #define reg_IBRS_IBPB edx + #define reg_STIBP edx + #define reg_L1D_FLUSH edx +@@ -819,6 +837,8 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_Opmask_state (1u << 5) + #define bit_ZMM0_15_state (1u << 6) + #define bit_ZMM16_31_state (1u << 7) ++#define bit_XTILECFG_state (1u << 17) ++#define bit_XTILEDATA_state (1u << 18) + + # if defined (_LIBC) && !IS_IN (nonlib) + /* Unused for x86. */ +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index 08688ace2a0ae35e..c4d91be3a48de886 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -185,6 +185,9 @@ do_test (void) + CHECK_CPU_FEATURE (TSXLDTRK); + CHECK_CPU_FEATURE (PCONFIG); + CHECK_CPU_FEATURE (IBT); ++ CHECK_CPU_FEATURE (AMX_BF16); ++ CHECK_CPU_FEATURE (AMX_TILE); ++ CHECK_CPU_FEATURE (AMX_INT8); + CHECK_CPU_FEATURE (IBRS_IBPB); + CHECK_CPU_FEATURE (STIBP); + CHECK_CPU_FEATURE (L1D_FLUSH); +@@ -237,6 +240,9 @@ do_test (void) + CHECK_CPU_FEATURE_USABLE (AVX512_4VNNIW); + CHECK_CPU_FEATURE_USABLE (AVX512_4FMAPS); + CHECK_CPU_FEATURE_USABLE (AVX512_VP2INTERSECT); ++ CHECK_CPU_FEATURE_USABLE (AMX_BF16); ++ CHECK_CPU_FEATURE_USABLE (AMX_TILE); ++ CHECK_CPU_FEATURE_USABLE (AMX_INT8); + CHECK_CPU_FEATURE_USABLE (XOP); + CHECK_CPU_FEATURE_USABLE (FMA4); + CHECK_CPU_FEATURE_USABLE (XSAVEC); diff --git a/SOURCES/glibc-rh1817513-7.patch b/SOURCES/glibc-rh1817513-7.patch new file mode 100644 index 0000000..57228a8 --- /dev/null +++ b/SOURCES/glibc-rh1817513-7.patch @@ -0,0 +1,54 @@ +commit 221e4babca17b363df2c56e839572e9f7ab7d127 +Author: Joseph Myers +Date: Wed Sep 12 20:31:24 2018 +0000 + + Include most of elf/ modules-names in modules-names-tests. + + I'm testing a patch to let the compiler expand calls to floor in libm + as built-in function calls as much as possible, instead of calling + __floor, so that no architecture-specific __floor inlines are needed, + and then to arrange for non-inlined calls to end up calling __floor, + as done with sqrt and __ieee754_sqrt. + + This shows up elf/tst-relsort1mod2.c calling floor, which must not be + converted to a call to __floor. Now, while an IS_IN (libm) + conditional could be added to the existing conditionals on such + redirections in include/math.h, the _ISOMAC conditional ought to + suffice (code in other glibc libraries shouldn't be calling floor or + sqrt anyway, as they aren't provided in libc and the other libraries + don't link with libm). But while tests are mostly now built with + _ISOMAC defined, test modules in modules-names aren't unless also + listed in modules-names-tests. + + As far as I can see, all the modules in modules-names in elf/ are in + fact parts of tests and so listing them in modules-names-tests is + appropriate, so they get built with something closer to the headers + used for user code, except in a few cases that actually rely on + something from internal headers. This patch duly sets + modules-names-tests there accordingly (filtering out those tests that + fail to build without internal headers). + + Tested for x86_64, and with build-many-glibcs.py. + + * elf/Makefile (modules-names-tests): New variable. + +Conflicts: + elf/Makefile + (Different backport order for tests.) + +diff --git a/elf/Makefile b/elf/Makefile +index b4b618ce62a9e6df..89dff92adfc417f5 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -306,6 +306,11 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-dlopenfailmod3 \ + tst-filterobj-flt tst-filterobj-aux tst-filterobj-filtee + ++# Most modules build with _ISOMAC defined, but those filtered out ++# depend on internal headers. ++modules-names-tests = $(filter-out ifuncmod% tst-libc_dlvsym-dso tst-tlsmod%,\ ++ $(modules-names)) ++ + ifeq (yes,$(have-mtls-dialect-gnu2)) + tests += tst-gnu2-tls1 + modules-names += tst-gnu2-tls1mod diff --git a/SOURCES/glibc-rh1817513-70.patch b/SOURCES/glibc-rh1817513-70.patch new file mode 100644 index 0000000..8960178 --- /dev/null +++ b/SOURCES/glibc-rh1817513-70.patch @@ -0,0 +1,21 @@ +commit f8b4630ef673486c2c77bd291a08ef132981e149 +Author: H.J. Lu +Date: Mon Jul 6 06:38:05 2020 -0700 + + x86: Correct bit_cpu_CLFSH [BZ #26208] + + bit_cpu_CLFSH should be (1u << 19), not (1u << 20). + +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 7c46242aad69d427..535b3cb2d25b245b 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -277,7 +277,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_PAT (1u << 16) + #define bit_cpu_PSE_36 (1u << 17) + #define bit_cpu_PSN (1u << 18) +-#define bit_cpu_CLFSH (1u << 20) ++#define bit_cpu_CLFSH (1u << 19) + #define bit_cpu_DS (1u << 21) + #define bit_cpu_ACPI (1u << 22) + #define bit_cpu_MMX (1u << 23) diff --git a/SOURCES/glibc-rh1817513-71.patch b/SOURCES/glibc-rh1817513-71.patch new file mode 100644 index 0000000..1a5fcdd --- /dev/null +++ b/SOURCES/glibc-rh1817513-71.patch @@ -0,0 +1,51 @@ +commit 28c13ae5bbc81aa2ae67890ce53e65257d4703a4 +Author: H.J. Lu +Date: Mon Jul 6 06:57:08 2020 -0700 + + x86: Detect Extended Feature Disable (XFD) + + An extension called extended feature disable (XFD) is an extension added + for Intel AMX to the XSAVE feature set that allows an operating system + to enable a feature while preventing specific user threads from using + the feature. + +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 535b3cb2d25b245b..e7ea9e8ece3e8211 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -393,6 +393,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_XSAVEC (1u << 1) + #define bit_cpu_XGETBV_ECX_1 (1u << 2) + #define bit_cpu_XSAVES (1u << 3) ++#define bit_cpu_XFD (1u << 4) + + /* COMMON_CPUID_INDEX_80000007. */ + +@@ -578,6 +579,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_XSAVEC COMMON_CPUID_INDEX_D_ECX_1 + #define index_cpu_XGETBV_ECX_1 COMMON_CPUID_INDEX_D_ECX_1 + #define index_cpu_XSAVES COMMON_CPUID_INDEX_D_ECX_1 ++#define index_cpu_XFD COMMON_CPUID_INDEX_D_ECX_1 + + /* COMMON_CPUID_INDEX_80000007. */ + +@@ -763,6 +765,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_XSAVEC eax + #define reg_XGETBV_ECX_1 eax + #define reg_XSAVES eax ++#define reg_XFD eax + + /* COMMON_CPUID_INDEX_80000007. */ + +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index c4d91be3a48de886..c56f309ba0736c0d 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -212,6 +212,7 @@ do_test (void) + CHECK_CPU_FEATURE (XSAVEC); + CHECK_CPU_FEATURE (XGETBV_ECX_1); + CHECK_CPU_FEATURE (XSAVES); ++ CHECK_CPU_FEATURE (XFD); + CHECK_CPU_FEATURE (INVARIANT_TSC); + CHECK_CPU_FEATURE (WBNOINVD); + CHECK_CPU_FEATURE (AVX512_BF16); diff --git a/SOURCES/glibc-rh1817513-72.patch b/SOURCES/glibc-rh1817513-72.patch new file mode 100644 index 0000000..fde1130 --- /dev/null +++ b/SOURCES/glibc-rh1817513-72.patch @@ -0,0 +1,235 @@ +commit 3f4b61a0b8de67ef9f20737919c713ddfc4bd620 +Author: H.J. Lu +Date: Mon Jul 6 11:48:09 2020 -0700 + + x86: Add thresholds for "rep movsb/stosb" to tunables + + Add x86_rep_movsb_threshold and x86_rep_stosb_threshold to tunables + to update thresholds for "rep movsb" and "rep stosb" at run-time. + + Note that the user specified threshold for "rep movsb" smaller than + the minimum threshold will be ignored. + + Reviewed-by: Carlos O'Donell + +Conflicts: + sysdeps/x86/cacheinfo.c + (Previous backport of the shared cache computation fix.) + +diff --git a/manual/tunables.texi b/manual/tunables.texi +index ef10d2872cfc244e..55d5dfb14db4dfb8 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -373,6 +373,22 @@ like memmove and memcpy. + This tunable is specific to i386 and x86-64. + @end deftp + ++@deftp Tunable glibc.cpu.x86_rep_movsb_threshold ++The @code{glibc.cpu.x86_rep_movsb_threshold} tunable allows the user to ++set threshold in bytes to start using "rep movsb". The value must be ++greater than zero, and currently defaults to 2048 bytes. ++ ++This tunable is specific to i386 and x86-64. ++@end deftp ++ ++@deftp Tunable glibc.cpu.x86_rep_stosb_threshold ++The @code{glibc.cpu.x86_rep_stosb_threshold} tunable allows the user to ++set threshold in bytes to start using "rep stosb". The value must be ++greater than zero, and currently defaults to 2048 bytes. ++ ++This tunable is specific to i386 and x86-64. ++@end deftp ++ + @deftp Tunable glibc.cpu.x86_ibt + The @code{glibc.cpu.x86_ibt} tunable allows the user to control how + indirect branch tracking (IBT) should be enabled. Accepted values are +diff --git a/sysdeps/x86/cacheinfo.c b/sysdeps/x86/cacheinfo.c +index aa7cb705d546bcd0..c741a69fb19a1e95 100644 +--- a/sysdeps/x86/cacheinfo.c ++++ b/sysdeps/x86/cacheinfo.c +@@ -530,6 +530,12 @@ long int __x86_raw_shared_cache_size attribute_hidden = 1024 * 1024; + /* Threshold to use non temporal store. */ + long int __x86_shared_non_temporal_threshold attribute_hidden; + ++/* Threshold to use Enhanced REP MOVSB. */ ++long int __x86_rep_movsb_threshold attribute_hidden = 2048; ++ ++/* Threshold to use Enhanced REP STOSB. */ ++long int __x86_rep_stosb_threshold attribute_hidden = 2048; ++ + #ifndef DISABLE_PREFETCHW + /* PREFETCHW support flag for use in memory and string routines. */ + int __x86_prefetchw attribute_hidden; +@@ -892,6 +898,36 @@ init_cacheinfo (void) + = (cpu_features->non_temporal_threshold != 0 + ? cpu_features->non_temporal_threshold + : __x86_shared_cache_size * 3 / 4); ++ ++ /* NB: The REP MOVSB threshold must be greater than VEC_SIZE * 8. */ ++ unsigned int minimum_rep_movsb_threshold; ++ /* NB: The default REP MOVSB threshold is 2048 * (VEC_SIZE / 16). */ ++ unsigned int rep_movsb_threshold; ++ if (CPU_FEATURES_ARCH_P (cpu_features, AVX512F_Usable) ++ && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_AVX512)) ++ { ++ rep_movsb_threshold = 2048 * (64 / 16); ++ minimum_rep_movsb_threshold = 64 * 8; ++ } ++ else if (CPU_FEATURES_ARCH_P (cpu_features, ++ AVX_Fast_Unaligned_Load)) ++ { ++ rep_movsb_threshold = 2048 * (32 / 16); ++ minimum_rep_movsb_threshold = 32 * 8; ++ } ++ else ++ { ++ rep_movsb_threshold = 2048 * (16 / 16); ++ minimum_rep_movsb_threshold = 16 * 8; ++ } ++ if (cpu_features->rep_movsb_threshold > minimum_rep_movsb_threshold) ++ __x86_rep_movsb_threshold = cpu_features->rep_movsb_threshold; ++ else ++ __x86_rep_movsb_threshold = rep_movsb_threshold; ++ ++# if HAVE_TUNABLES ++ __x86_rep_stosb_threshold = cpu_features->rep_stosb_threshold; ++# endif + } + + #endif +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 21565474839efffc..ad470f79ef7769fc 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -605,6 +605,10 @@ no_cpuid: + TUNABLE_GET (hwcaps, tunable_val_t *, TUNABLE_CALLBACK (set_hwcaps)); + cpu_features->non_temporal_threshold + = TUNABLE_GET (x86_non_temporal_threshold, long int, NULL); ++ cpu_features->rep_movsb_threshold ++ = TUNABLE_GET (x86_rep_movsb_threshold, long int, NULL); ++ cpu_features->rep_stosb_threshold ++ = TUNABLE_GET (x86_rep_stosb_threshold, long int, NULL); + cpu_features->data_cache_size + = TUNABLE_GET (x86_data_cache_size, long int, NULL); + cpu_features->shared_cache_size +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index e7ea9e8ece3e8211..0f19c64352c4d7f1 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -102,6 +102,10 @@ struct cpu_features + unsigned long int shared_cache_size; + /* Threshold to use non temporal store. */ + unsigned long int non_temporal_threshold; ++ /* Threshold to use "rep movsb". */ ++ unsigned long int rep_movsb_threshold; ++ /* Threshold to use "rep stosb". */ ++ unsigned long int rep_stosb_threshold; + }; + + /* Used from outside of glibc to get access to the CPU features +diff --git a/sysdeps/x86/dl-tunables.list b/sysdeps/x86/dl-tunables.list +index 2a457d0eec9c3122..e066313a1d1dd009 100644 +--- a/sysdeps/x86/dl-tunables.list ++++ b/sysdeps/x86/dl-tunables.list +@@ -30,6 +30,30 @@ glibc { + x86_non_temporal_threshold { + type: SIZE_T + } ++ x86_rep_movsb_threshold { ++ type: SIZE_T ++ # Since there is overhead to set up REP MOVSB operation, REP MOVSB ++ # isn't faster on short data. The memcpy micro benchmark in glibc ++ # shows that 2KB is the approximate value above which REP MOVSB ++ # becomes faster than SSE2 optimization on processors with Enhanced ++ # REP MOVSB. Since larger register size can move more data with a ++ # single load and store, the threshold is higher with larger register ++ # size. Note: Since the REP MOVSB threshold must be greater than 8 ++ # times of vector size, the minium value must be updated at run-time. ++ minval: 1 ++ default: 2048 ++ } ++ x86_rep_stosb_threshold { ++ type: SIZE_T ++ # Since there is overhead to set up REP STOSB operation, REP STOSB ++ # isn't faster on short data. The memset micro benchmark in glibc ++ # shows that 2KB is the approximate value above which REP STOSB ++ # becomes faster on processors with Enhanced REP STOSB. Since the ++ # stored value is fixed, larger register size has minimal impact ++ # on threshold. ++ minval: 1 ++ default: 2048 ++ } + x86_data_cache_size { + type: SIZE_T + } +diff --git a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +index e2ede45e9f68791b..c952576cfdf6e3e6 100644 +--- a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +@@ -56,17 +56,6 @@ + # endif + #endif + +-/* Threshold to use Enhanced REP MOVSB. Since there is overhead to set +- up REP MOVSB operation, REP MOVSB isn't faster on short data. The +- memcpy micro benchmark in glibc shows that 2KB is the approximate +- value above which REP MOVSB becomes faster than SSE2 optimization +- on processors with Enhanced REP MOVSB. Since larger register size +- can move more data with a single load and store, the threshold is +- higher with larger register size. */ +-#ifndef REP_MOVSB_THRESHOLD +-# define REP_MOVSB_THRESHOLD (2048 * (VEC_SIZE / 16)) +-#endif +- + #ifndef PREFETCH + # define PREFETCH(addr) prefetcht0 addr + #endif +@@ -245,9 +234,6 @@ L(movsb): + leaq (%rsi,%rdx), %r9 + cmpq %r9, %rdi + /* Avoid slow backward REP MOVSB. */ +-# if REP_MOVSB_THRESHOLD <= (VEC_SIZE * 8) +-# error Unsupported REP_MOVSB_THRESHOLD and VEC_SIZE! +-# endif + jb L(more_8x_vec_backward) + 1: + movq %rdx, %rcx +@@ -323,7 +309,7 @@ L(between_2_3): + + #if defined USE_MULTIARCH && IS_IN (libc) + L(movsb_more_2x_vec): +- cmpq $REP_MOVSB_THRESHOLD, %rdx ++ cmp __x86_rep_movsb_threshold(%rip), %RDX_LP + ja L(movsb) + #endif + L(more_2x_vec): +diff --git a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +index dc9cb88b37a5477a..270a1d49b34be9f5 100644 +--- a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +@@ -58,16 +58,6 @@ + # endif + #endif + +-/* Threshold to use Enhanced REP STOSB. Since there is overhead to set +- up REP STOSB operation, REP STOSB isn't faster on short data. The +- memset micro benchmark in glibc shows that 2KB is the approximate +- value above which REP STOSB becomes faster on processors with +- Enhanced REP STOSB. Since the stored value is fixed, larger register +- size has minimal impact on threshold. */ +-#ifndef REP_STOSB_THRESHOLD +-# define REP_STOSB_THRESHOLD 2048 +-#endif +- + #ifndef SECTION + # error SECTION is not defined! + #endif +@@ -173,7 +163,7 @@ ENTRY (MEMSET_SYMBOL (__memset, unaligned_erms)) + ret + + L(stosb_more_2x_vec): +- cmpq $REP_STOSB_THRESHOLD, %rdx ++ cmp __x86_rep_stosb_threshold(%rip), %RDX_LP + ja L(stosb) + #endif + L(more_2x_vec): diff --git a/SOURCES/glibc-rh1817513-73.patch b/SOURCES/glibc-rh1817513-73.patch new file mode 100644 index 0000000..adb3c93 --- /dev/null +++ b/SOURCES/glibc-rh1817513-73.patch @@ -0,0 +1,289 @@ +commit 0c7b002fac12dcb2f53ba83ee56bb3b5d2439447 +Author: Szabolcs Nagy +Date: Tue Jun 9 09:57:28 2020 +0100 + + rtld: Add rtld.nns tunable for the number of supported namespaces + + TLS_STATIC_SURPLUS is 1664 bytes currently which is not enough to + support DL_NNS (== 16) number of dynamic link namespaces, if we + assume 192 bytes of TLS are reserved for libc use and 144 bytes + are reserved for other system libraries that use IE TLS. + + A new tunable is introduced to control the number of supported + namespaces and to adjust the surplus static TLS size as follows: + + surplus_tls = 192 * (rtld.nns-1) + 144 * rtld.nns + 512 + + The default is rtld.nns == 4 and then the surplus TLS size is the + same as before, so the behaviour is unchanged by default. If an + application creates more namespaces than the rtld.nns setting + allows, then it is not guaranteed to work, but the limit is not + checked. So existing usage will continue to work, but in the + future if an application creates more than 4 dynamic link + namespaces then the tunable will need to be set. + + In this patch DL_NNS is a fixed value and provides a maximum to + the rtld.nns setting. + + Static linking used fixed 2048 bytes surplus TLS, this is changed + so the same contract is used as for dynamic linking. With static + linking DL_NNS == 1 so rtld.nns tunable is forced to 1, so by + default the surplus TLS is reduced to 144 + 512 = 656 bytes. This + change is not expected to cause problems. + + Tested on aarch64-linux-gnu and x86_64-linux-gnu. + + Reviewed-by: Carlos O'Donell + +Conflicts: + elf/dl-tls.c + (Different per-namespace TLS reservation defaults before + this backport.) + +diff --git a/csu/libc-tls.c b/csu/libc-tls.c +index 28a79441cde379f7..08ed2b988b58ac6c 100644 +--- a/csu/libc-tls.c ++++ b/csu/libc-tls.c +@@ -52,13 +52,16 @@ bool _dl_tls_dtv_gaps; + struct dtv_slotinfo_list *_dl_tls_dtv_slotinfo_list; + /* Number of modules in the static TLS block. */ + size_t _dl_tls_static_nelem; +-/* Size of the static TLS block. Giving this initialized value +- preallocates some surplus bytes in the static TLS area. */ +-size_t _dl_tls_static_size = 2048; ++/* Size of the static TLS block. */ ++size_t _dl_tls_static_size; + /* Size actually allocated in the static TLS block. */ + size_t _dl_tls_static_used; + /* Alignment requirement of the static TLS block. */ + size_t _dl_tls_static_align; ++/* Size of surplus space in the static TLS area for dynamically ++ loaded modules with IE-model TLS or for TLSDESC optimization. ++ See comments in elf/dl-tls.c where it is initialized. */ ++size_t _dl_tls_static_surplus; + + /* Generation counter for the dtv. */ + size_t _dl_tls_generation; +@@ -87,10 +90,8 @@ init_slotinfo (void) + static void + init_static_tls (size_t memsz, size_t align) + { +- /* That is the size of the TLS memory for this object. The initialized +- value of _dl_tls_static_size is provided by dl-open.c to request some +- surplus that permits dynamic loading of modules with IE-model TLS. */ +- GL(dl_tls_static_size) = roundup (memsz + GL(dl_tls_static_size), ++ /* That is the size of the TLS memory for this object. */ ++ GL(dl_tls_static_size) = roundup (memsz + GLRO(dl_tls_static_surplus), + TLS_TCB_ALIGN); + #if TLS_TCB_AT_TP + GL(dl_tls_static_size) += TLS_TCB_SIZE; +@@ -131,25 +132,24 @@ __libc_setup_tls (void) + break; + } + ++ /* Calculate the size of the static TLS surplus. */ ++ _dl_tls_static_surplus_init (); ++ + /* We have to set up the TCB block which also (possibly) contains + 'errno'. Therefore we avoid 'malloc' which might touch 'errno'. + Instead we use 'sbrk' which would only uses 'errno' if it fails. + In this case we are right away out of memory and the user gets +- what she/he deserves. +- +- The initialized value of _dl_tls_static_size is provided by dl-open.c +- to request some surplus that permits dynamic loading of modules with +- IE-model TLS. */ ++ what she/he deserves. */ + #if TLS_TCB_AT_TP + /* Align the TCB offset to the maximum alignment, as + _dl_allocate_tls_storage (in elf/dl-tls.c) does using __libc_memalign + and dl_tls_static_align. */ +- tcb_offset = roundup (memsz + GL(dl_tls_static_size), max_align); ++ tcb_offset = roundup (memsz + GLRO(dl_tls_static_surplus), max_align); + tlsblock = __sbrk (tcb_offset + TLS_INIT_TCB_SIZE + max_align); + #elif TLS_DTV_AT_TP + tcb_offset = roundup (TLS_INIT_TCB_SIZE, align ?: 1); + tlsblock = __sbrk (tcb_offset + memsz + max_align +- + TLS_PRE_TCB_SIZE + GL(dl_tls_static_size)); ++ + TLS_PRE_TCB_SIZE + GLRO(dl_tls_static_surplus)); + tlsblock += TLS_PRE_TCB_SIZE; + #else + /* In case a model with a different layout for the TCB and DTV +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index a2def280b7096960..ef57a21391bb36fa 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -29,10 +29,54 @@ + #include + #include + +-/* Amount of excess space to allocate in the static TLS area +- to allow dynamic loading of modules defining IE-model TLS data. */ +-#define TLS_STATIC_SURPLUS 64 + DL_NNS * 100 ++#define TUNABLE_NAMESPACE rtld ++#include ++ ++/* Surplus static TLS, GLRO(dl_tls_static_surplus), is used for ++ ++ - IE TLS in libc.so for all dlmopen namespaces except in the initial ++ one where libc.so is not loaded dynamically but at startup time, ++ - IE TLS in other libraries which may be dynamically loaded even in the ++ initial namespace, ++ - and optionally for optimizing dynamic TLS access. ++ ++ The maximum number of namespaces is DL_NNS, but to support that many ++ namespaces correctly the static TLS allocation should be significantly ++ increased, which may cause problems with small thread stacks due to the ++ way static TLS is accounted (bug 11787). ++ ++ So there is a rtld.nns tunable limit on the number of supported namespaces ++ that affects the size of the static TLS and by default it's small enough ++ not to cause problems with existing applications. The limit is not ++ enforced or checked: it is the user's responsibility to increase rtld.nns ++ if more dlmopen namespaces are used. */ ++ ++/* Size of initial-exec TLS in libc.so. */ ++#define LIBC_IE_TLS 192 ++/* Size of initial-exec TLS in libraries other than libc.so. ++ This should be large enough to cover runtime libraries of the ++ compiler such as libgomp and libraries in libc other than libc.so. */ ++#define OTHER_IE_TLS 144 ++/* Size of additional surplus TLS, placeholder for TLS optimizations. */ ++#define OPT_SURPLUS_TLS 512 + ++void ++_dl_tls_static_surplus_init (void) ++{ ++ size_t nns; ++ ++#if HAVE_TUNABLES ++ nns = TUNABLE_GET (nns, size_t, NULL); ++#else ++ /* Default values of the tunables. */ ++ nns = 4; ++#endif ++ if (nns > DL_NNS) ++ nns = DL_NNS; ++ GLRO(dl_tls_static_surplus) = ((nns - 1) * LIBC_IE_TLS ++ + nns * OTHER_IE_TLS ++ + OPT_SURPLUS_TLS); ++} + + /* Out-of-memory handler. */ + static void +@@ -218,7 +262,8 @@ _dl_determine_tlsoffset (void) + } + + GL(dl_tls_static_used) = offset; +- GL(dl_tls_static_size) = (roundup (offset + TLS_STATIC_SURPLUS, max_align) ++ GL(dl_tls_static_size) = (roundup (offset + GLRO(dl_tls_static_surplus), ++ max_align) + + TLS_TCB_SIZE); + #elif TLS_DTV_AT_TP + /* The TLS blocks start right after the TCB. */ +@@ -262,7 +307,7 @@ _dl_determine_tlsoffset (void) + } + + GL(dl_tls_static_used) = offset; +- GL(dl_tls_static_size) = roundup (offset + TLS_STATIC_SURPLUS, ++ GL(dl_tls_static_size) = roundup (offset + GLRO(dl_tls_static_surplus), + TLS_TCB_ALIGN); + #else + # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list +index b7cc79f8bfe0a7c6..7337fb85062c91a7 100644 +--- a/elf/dl-tunables.list ++++ b/elf/dl-tunables.list +@@ -126,4 +126,13 @@ glibc { + default: 3 + } + } ++ ++ rtld { ++ nns { ++ type: SIZE_T ++ minval: 1 ++ maxval: 16 ++ default: 4 ++ } ++ } + } +diff --git a/elf/rtld.c b/elf/rtld.c +index 772aff5160359b7b..a440741f4c1b3c91 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -776,6 +776,9 @@ init_tls (void) + } + assert (i == GL(dl_tls_max_dtv_idx)); + ++ /* Calculate the size of the static TLS surplus. */ ++ _dl_tls_static_surplus_init (); ++ + /* Compute the TLS offsets for the various blocks. */ + _dl_determine_tlsoffset (); + +diff --git a/manual/tunables.texi b/manual/tunables.texi +index 55d5dfb14db4dfb8..e092b8e81a18d739 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -31,6 +31,7 @@ their own namespace. + @menu + * Tunable names:: The structure of a tunable name + * Memory Allocation Tunables:: Tunables in the memory allocation subsystem ++* Dynamic Linking Tunables:: Tunables in the dynamic linking subsystem + * Elision Tunables:: Tunables in elision subsystem + * Hardware Capability Tunables:: Tunables that modify the hardware + capabilities seen by @theglibc{} +@@ -225,6 +226,26 @@ pointer, so add 4 on 32-bit systems or 8 on 64-bit systems to the size + passed to @code{malloc} for the largest bin size to enable. + @end deftp + ++@node Dynamic Linking Tunables ++@section Dynamic Linking Tunables ++@cindex dynamic linking tunables ++@cindex rtld tunables ++ ++@deftp {Tunable namespace} glibc.rtld ++Dynamic linker behavior can be modified by setting the ++following tunables in the @code{rtld} namespace: ++@end deftp ++ ++@deftp Tunable glibc.rtld.nns ++Sets the number of supported dynamic link namespaces (see @code{dlmopen}). ++Currently this limit can be set between 1 and 16 inclusive, the default is 4. ++Each link namespace consumes some memory in all thread, and thus raising the ++limit will increase the amount of memory each thread uses. Raising the limit ++is useful when your application uses more than 4 dynamic linker audit modules ++e.g. @env{LD_AUDIT}, or will use more than 4 dynamic link namespaces as created ++by @code{dlmopen} with an lmid argument of @code{LM_ID_NEWLM}. ++@end deftp ++ + @node Elision Tunables + @section Elision Tunables + @cindex elision tunables +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index ccec08929e4ad4e7..e54105848c3cb7d1 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -582,6 +582,11 @@ struct rtld_global_ro + binaries, don't honor for PIEs). */ + EXTERN ElfW(Addr) _dl_use_load_bias; + ++ /* Size of surplus space in the static TLS area for dynamically ++ loaded modules with IE-model TLS or for TLSDESC optimization. ++ See comments in elf/dl-tls.c where it is initialized. */ ++ EXTERN size_t _dl_tls_static_surplus; ++ + /* Name of the shared object to be profiled (if any). */ + EXTERN const char *_dl_profile; + /* Filename of the output file. */ +@@ -1099,6 +1104,9 @@ extern size_t _dl_count_modids (void) attribute_hidden; + /* Calculate offset of the TLS blocks in the static TLS block. */ + extern void _dl_determine_tlsoffset (void) attribute_hidden; + ++/* Calculate the size of the static TLS surplus. */ ++void _dl_tls_static_surplus_init (void) attribute_hidden; ++ + #ifndef SHARED + /* Set up the TCB for statically linked applications. This is called + early during startup because we always use TLS (for errno and the diff --git a/SOURCES/glibc-rh1817513-74.patch b/SOURCES/glibc-rh1817513-74.patch new file mode 100644 index 0000000..8281192 --- /dev/null +++ b/SOURCES/glibc-rh1817513-74.patch @@ -0,0 +1,205 @@ +commit 17796419b5fd694348cceb65c3f77601faae082c +Author: Szabolcs Nagy +Date: Tue Jul 7 10:49:11 2020 +0100 + + rtld: Account static TLS surplus for audit modules + + The new static TLS surplus size computation is + + surplus_tls = 192 * (nns-1) + 144 * nns + 512 + + where nns is controlled via the rtld.nns tunable. This commit + accounts audit modules too so nns = rtld.nns + audit modules. + + rtld.nns should only include the namespaces required by the + application, namespaces for audit modules are accounted on top + of that so audit modules don't use up the static TLS that is + reserved for the application. This allows loading many audit + modules without tuning rtld.nns or using up static TLS, and it + fixes + + FAIL: elf/tst-auditmany + + Note that DL_NNS is currently a hard upper limit for nns, and + if rtld.nns + audit modules go over the limit that's a fatal + error. By default rtld.nns is 4 which allows 12 audit modules. + + Counting the audit modules is based on existing audit string + parsing code, we cannot use GLRO(dl_naudit) before the modules + are actually loaded. + +Conflicts: + elf/rtld.c + (Caused by glibc-fedora-__libc_multiple_libcs.patch.) + +diff --git a/csu/libc-tls.c b/csu/libc-tls.c +index 08ed2b988b58ac6c..6f2a47dc86222407 100644 +--- a/csu/libc-tls.c ++++ b/csu/libc-tls.c +@@ -132,8 +132,8 @@ __libc_setup_tls (void) + break; + } + +- /* Calculate the size of the static TLS surplus. */ +- _dl_tls_static_surplus_init (); ++ /* Calculate the size of the static TLS surplus, with 0 auditors. */ ++ _dl_tls_static_surplus_init (0); + + /* We have to set up the TCB block which also (possibly) contains + 'errno'. Therefore we avoid 'malloc' which might touch 'errno'. +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index ef57a21391bb36fa..cfda76f6de96df57 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -49,7 +49,10 @@ + that affects the size of the static TLS and by default it's small enough + not to cause problems with existing applications. The limit is not + enforced or checked: it is the user's responsibility to increase rtld.nns +- if more dlmopen namespaces are used. */ ++ if more dlmopen namespaces are used. ++ ++ Audit modules use their own namespaces, they are not included in rtld.nns, ++ but come on top when computing the number of namespaces. */ + + /* Size of initial-exec TLS in libc.so. */ + #define LIBC_IE_TLS 192 +@@ -60,8 +63,11 @@ + /* Size of additional surplus TLS, placeholder for TLS optimizations. */ + #define OPT_SURPLUS_TLS 512 + ++/* Calculate the size of the static TLS surplus, when the given ++ number of audit modules are loaded. Must be called after the ++ number of audit modules is known and before static TLS allocation. */ + void +-_dl_tls_static_surplus_init (void) ++_dl_tls_static_surplus_init (size_t naudit) + { + size_t nns; + +@@ -73,6 +79,11 @@ _dl_tls_static_surplus_init (void) + #endif + if (nns > DL_NNS) + nns = DL_NNS; ++ if (DL_NNS - nns < naudit) ++ _dl_fatal_printf ("Failed loading %lu audit modules, %lu are supported.\n", ++ (unsigned long) naudit, (unsigned long) (DL_NNS - nns)); ++ nns += naudit; ++ + GLRO(dl_tls_static_surplus) = ((nns - 1) * LIBC_IE_TLS + + nns * OTHER_IE_TLS + + OPT_SURPLUS_TLS); +diff --git a/elf/rtld.c b/elf/rtld.c +index a440741f4c1b3c91..67441ac6f252350e 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -297,6 +297,23 @@ audit_list_next (struct audit_list *list) + } + } + ++/* Count audit modules before they are loaded so GLRO(dl_naudit) ++ is not yet usable. */ ++static size_t ++audit_list_count (struct audit_list *list) ++{ ++ /* Restore the audit_list iterator state at the end. */ ++ const char *saved_tail = list->current_tail; ++ size_t naudit = 0; ++ ++ assert (list->current_index == 0); ++ while (audit_list_next (list) != NULL) ++ naudit++; ++ list->current_tail = saved_tail; ++ list->current_index = 0; ++ return naudit; ++} ++ + /* Set nonzero during loading and initialization of executable and + libraries, cleared before the executable's entry point runs. This + must not be initialized to nonzero, because the unused dynamic +@@ -734,7 +751,7 @@ match_version (const char *string, struct link_map *map) + static bool tls_init_tp_called; + + static void * +-init_tls (void) ++init_tls (size_t naudit) + { + /* Number of elements in the static TLS block. */ + GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx); +@@ -777,7 +794,7 @@ init_tls (void) + assert (i == GL(dl_tls_max_dtv_idx)); + + /* Calculate the size of the static TLS surplus. */ +- _dl_tls_static_surplus_init (); ++ _dl_tls_static_surplus_init (naudit); + + /* Compute the TLS offsets for the various blocks. */ + _dl_determine_tlsoffset (); +@@ -1659,9 +1676,11 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + bool need_security_init = true; + if (audit_list.length > 0) + { ++ size_t naudit = audit_list_count (&audit_list); ++ + /* Since we start using the auditing DSOs right away we need to + initialize the data structures now. */ +- tcbp = init_tls (); ++ tcbp = init_tls (naudit); + + /* Initialize security features. We need to do it this early + since otherwise the constructors of the audit libraries will +@@ -1671,6 +1690,10 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + need_security_init = false; + + load_audit_modules (main_map, &audit_list); ++ ++ /* The count based on audit strings may overestimate the number ++ of audit modules that got loaded, but not underestimate. */ ++ assert (GLRO(dl_naudit) <= naudit); + } + + /* Keep track of the currently loaded modules to count how many +@@ -1914,7 +1937,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + multiple threads (from a non-TLS-using libpthread). */ + bool was_tls_init_tp_called = tls_init_tp_called; + if (tcbp == NULL) +- tcbp = init_tls (); ++ tcbp = init_tls (0); + + if (__glibc_likely (need_security_init)) + /* Initialize security features. But only if we have not done it +diff --git a/manual/tunables.texi b/manual/tunables.texi +index e092b8e81a18d739..e6a3e9a2cf5c959c 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -241,9 +241,12 @@ Sets the number of supported dynamic link namespaces (see @code{dlmopen}). + Currently this limit can be set between 1 and 16 inclusive, the default is 4. + Each link namespace consumes some memory in all thread, and thus raising the + limit will increase the amount of memory each thread uses. Raising the limit +-is useful when your application uses more than 4 dynamic linker audit modules +-e.g. @env{LD_AUDIT}, or will use more than 4 dynamic link namespaces as created +-by @code{dlmopen} with an lmid argument of @code{LM_ID_NEWLM}. ++is useful when your application uses more than 4 dynamic link namespaces as ++created by @code{dlmopen} with an lmid argument of @code{LM_ID_NEWLM}. ++Dynamic linker audit modules are loaded in their own dynamic link namespaces, ++but they are not accounted for in @code{glibc.rtld.nns}. They implicitly ++increase the per-thread memory usage as necessary, so this tunable does ++not need to be changed to allow many audit modules e.g. via @env{LD_AUDIT}. + @end deftp + + @node Elision Tunables +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index e54105848c3cb7d1..293f3ab5a496afdf 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1104,8 +1104,9 @@ extern size_t _dl_count_modids (void) attribute_hidden; + /* Calculate offset of the TLS blocks in the static TLS block. */ + extern void _dl_determine_tlsoffset (void) attribute_hidden; + +-/* Calculate the size of the static TLS surplus. */ +-void _dl_tls_static_surplus_init (void) attribute_hidden; ++/* Calculate the size of the static TLS surplus, when the given ++ number of audit modules are loaded. */ ++void _dl_tls_static_surplus_init (size_t naudit) attribute_hidden; + + #ifndef SHARED + /* Set up the TCB for statically linked applications. This is called diff --git a/SOURCES/glibc-rh1817513-75.patch b/SOURCES/glibc-rh1817513-75.patch new file mode 100644 index 0000000..1c9577d --- /dev/null +++ b/SOURCES/glibc-rh1817513-75.patch @@ -0,0 +1,115 @@ +commit 9016b6f3893789ddfbd978aa572b46b3d3ce762f +Author: H.J. Lu +Date: Sat Jul 11 09:04:34 2020 -0700 + + x86: Remove the unused __x86_prefetchw + + Since + + commit c867597bff2562180a18da4b8dba89d24e8b65c4 + Author: H.J. Lu + Date: Wed Jun 8 13:57:50 2016 -0700 + + X86-64: Remove previous default/SSE2/AVX2 memcpy/memmove + + removed the only usage of __x86_prefetchw, we can remove the unused + __x86_prefetchw. + +Conflicts: + sysdeps/x86/cacheinfo.c + (Different backport order downstream, related to cache + comptuation. Also had to remove the now-unused eax variable.) + +diff --git a/sysdeps/i386/Makefile b/sysdeps/i386/Makefile +index c0a4fe15d47bff1c..41b345c6c6274c01 100644 +--- a/sysdeps/i386/Makefile ++++ b/sysdeps/i386/Makefile +@@ -13,10 +13,6 @@ ifeq ($(subdir),math) + CFLAGS-e_gamma_r.c += -DMATH_SET_BOTH_ROUNDING_MODES + endif + +-ifeq ($(subdir),string) +-sysdep_routines += cacheinfo +-endif +- + ifeq ($(subdir),gmon) + sysdep_routines += i386-mcount + endif +diff --git a/sysdeps/i386/cacheinfo.c b/sysdeps/i386/cacheinfo.c +deleted file mode 100644 +index f15fe0779afebb8f..0000000000000000 +--- a/sysdeps/i386/cacheinfo.c ++++ /dev/null +@@ -1,3 +0,0 @@ +-#define DISABLE_PREFETCHW +- +-#include +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index a936134a577e42a5..962bbcb07eba1259 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -14,6 +14,10 @@ gen-as-const-headers += jmp_buf-ssp.sym + sysdep_routines += __longjmp_cancel + endif + ++ifeq ($(subdir),string) ++sysdep_routines += cacheinfo ++endif ++ + ifneq ($(enable-cet),no) + ifeq ($(subdir),elf) + sysdep-dl-routines += dl-cet +diff --git a/sysdeps/x86/cacheinfo.c b/sysdeps/x86/cacheinfo.c +index c741a69fb19a1e95..f4edbc0103beb435 100644 +--- a/sysdeps/x86/cacheinfo.c ++++ b/sysdeps/x86/cacheinfo.c +@@ -536,11 +536,6 @@ long int __x86_rep_movsb_threshold attribute_hidden = 2048; + /* Threshold to use Enhanced REP STOSB. */ + long int __x86_rep_stosb_threshold attribute_hidden = 2048; + +-#ifndef DISABLE_PREFETCHW +-/* PREFETCHW support flag for use in memory and string routines. */ +-int __x86_prefetchw attribute_hidden; +-#endif +- + + static void + get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, +@@ -765,7 +760,6 @@ __attribute__((constructor)) + init_cacheinfo (void) + { + /* Find out what brand of processor. */ +- unsigned int eax; + unsigned int ebx; + unsigned int ecx; + unsigned int edx; +@@ -846,16 +840,6 @@ init_cacheinfo (void) + shared += core; + } + } +- +-#ifndef DISABLE_PREFETCHW +- if (max_cpuid_ex >= 0x80000001) +- { +- __cpuid (0x80000001, eax, ebx, ecx, edx); +- /* PREFETCHW || 3DNow! */ +- if ((ecx & 0x100) || (edx & 0x80000000)) +- __x86_prefetchw = -1; +- } +-#endif + } + + if (cpu_features->data_cache_size != 0) +diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile +index d51cf03ac92ebcc2..e3bb45d78811d70f 100644 +--- a/sysdeps/x86_64/Makefile ++++ b/sysdeps/x86_64/Makefile +@@ -18,7 +18,7 @@ tests += tst-mallocalign1 + endif + + ifeq ($(subdir),string) +-sysdep_routines += cacheinfo strcasecmp_l-nonascii strncase_l-nonascii ++sysdep_routines += strcasecmp_l-nonascii strncase_l-nonascii + gen-as-const-headers += locale-defines.sym + endif + diff --git a/SOURCES/glibc-rh1817513-76.patch b/SOURCES/glibc-rh1817513-76.patch new file mode 100644 index 0000000..c241cbf --- /dev/null +++ b/SOURCES/glibc-rh1817513-76.patch @@ -0,0 +1,34 @@ +commit 43530ba1dc4fccd438fefa26f50977ff6bf284c7 +Author: H.J. Lu +Date: Sat Jul 11 10:03:05 2020 -0700 + + x86: Remove __ASSEMBLER__ check in init-arch.h + + Since + + commit 430388d5dc0e1861b869096f4f5d946d7d74232a + Author: H.J. Lu + Date: Fri Aug 3 08:04:49 2018 -0700 + + x86: Don't include in assembly codes + + removed all usages of from assembly codes, we can remove + __ASSEMBLER__ check in init-arch.h. + +diff --git a/sysdeps/x86/init-arch.h b/sysdeps/x86/init-arch.h +index bc860fcd69a605b3..63a7f8562010e5e2 100644 +--- a/sysdeps/x86/init-arch.h ++++ b/sysdeps/x86/init-arch.h +@@ -15,11 +15,7 @@ + License along with the GNU C Library; if not, see + . */ + +-#ifdef __ASSEMBLER__ +-# include +-#else +-# include +-#endif ++#include + #include + #include + diff --git a/SOURCES/glibc-rh1817513-77.patch b/SOURCES/glibc-rh1817513-77.patch new file mode 100644 index 0000000..10ed7a3 --- /dev/null +++ b/SOURCES/glibc-rh1817513-77.patch @@ -0,0 +1,3679 @@ +commit 107e6a3c2212ba7a3a4ec7cae8d82d73f7c95d0b +Author: H.J. Lu +Date: Mon Jun 29 16:36:08 2020 -0700 + + x86: Support usable check for all CPU features + + Support usable check for all CPU features with the following changes: + + 1. Change struct cpu_features to + + struct cpuid_features + { + struct cpuid_registers cpuid; + struct cpuid_registers usable; + }; + + struct cpu_features + { + struct cpu_features_basic basic; + struct cpuid_features features[COMMON_CPUID_INDEX_MAX]; + unsigned int preferred[PREFERRED_FEATURE_INDEX_MAX]; + ... + }; + + so that there is a usable bit for each cpuid bit. + 2. After the cpuid bits have been initialized, copy the known bits to the + usable bits. EAX/EBX from INDEX_1 and EAX from INDEX_7 aren't used for + CPU feature detection. + 3. Clear the usable bits which require OS support. + 4. If the feature is supported by OS, copy its cpuid bit to its usable + bit. + 5. Replace HAS_CPU_FEATURE and CPU_FEATURES_CPU_P with CPU_FEATURE_USABLE + and CPU_FEATURE_USABLE_P to check if a feature is usable. + 6. Add DEPR_FPU_CS_DS for INDEX_7_EBX_13. + 7. Unset MPX feature since it has been deprecated. + + The results are + + 1. If the feature is known and doesn't requre OS support, its usable bit + is copied from the cpuid bit. + 2. Otherwise, its usable bit is copied from the cpuid bit only if the + feature is known to supported by OS. + 3. CPU_FEATURE_USABLE/CPU_FEATURE_USABLE_P are used to check if the + feature can be used. + 4. HAS_CPU_FEATURE/CPU_FEATURE_CPU_P are used to check if CPU supports + the feature. + +diff --git a/sysdeps/i386/fpu/fclrexcpt.c b/sysdeps/i386/fpu/fclrexcpt.c +index 8463b102e7b79f07..9eff917e88235c64 100644 +--- a/sysdeps/i386/fpu/fclrexcpt.c ++++ b/sysdeps/i386/fpu/fclrexcpt.c +@@ -41,7 +41,7 @@ __feclearexcept (int excepts) + __asm__ ("fldenv %0" : : "m" (*&temp)); + + /* If the CPU supports SSE, we clear the MXCSR as well. */ +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + { + unsigned int xnew_exc; + +diff --git a/sysdeps/i386/fpu/fedisblxcpt.c b/sysdeps/i386/fpu/fedisblxcpt.c +index e2738e6d6c8304fe..3b5436018d08a269 100644 +--- a/sysdeps/i386/fpu/fedisblxcpt.c ++++ b/sysdeps/i386/fpu/fedisblxcpt.c +@@ -38,7 +38,7 @@ fedisableexcept (int excepts) + __asm__ ("fldcw %0" : : "m" (*&new_exc)); + + /* If the CPU supports SSE we set the MXCSR as well. */ +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + { + unsigned int xnew_exc; + +diff --git a/sysdeps/i386/fpu/feenablxcpt.c b/sysdeps/i386/fpu/feenablxcpt.c +index a4d986266636835b..88f46f6078e12e2c 100644 +--- a/sysdeps/i386/fpu/feenablxcpt.c ++++ b/sysdeps/i386/fpu/feenablxcpt.c +@@ -38,7 +38,7 @@ feenableexcept (int excepts) + __asm__ ("fldcw %0" : : "m" (*&new_exc)); + + /* If the CPU supports SSE we set the MXCSR as well. */ +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + { + unsigned int xnew_exc; + +diff --git a/sysdeps/i386/fpu/fegetenv.c b/sysdeps/i386/fpu/fegetenv.c +index 2a1a8507bac9bfa5..2a800fb6d6e856f3 100644 +--- a/sysdeps/i386/fpu/fegetenv.c ++++ b/sysdeps/i386/fpu/fegetenv.c +@@ -31,7 +31,7 @@ __fegetenv (fenv_t *envp) + would block all exceptions. */ + __asm__ ("fldenv %0" : : "m" (*envp)); + +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + __asm__ ("stmxcsr %0" : "=m" (envp->__eip)); + + /* Success. */ +diff --git a/sysdeps/i386/fpu/fegetmode.c b/sysdeps/i386/fpu/fegetmode.c +index 86de9f5548f4b0b4..b01ca64fc9187b10 100644 +--- a/sysdeps/i386/fpu/fegetmode.c ++++ b/sysdeps/i386/fpu/fegetmode.c +@@ -26,7 +26,7 @@ int + fegetmode (femode_t *modep) + { + _FPU_GETCW (modep->__control_word); +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + __asm__ ("stmxcsr %0" : "=m" (modep->__mxcsr)); + return 0; + } +diff --git a/sysdeps/i386/fpu/feholdexcpt.c b/sysdeps/i386/fpu/feholdexcpt.c +index 270554df31928cda..e2f3f97b9494f900 100644 +--- a/sysdeps/i386/fpu/feholdexcpt.c ++++ b/sysdeps/i386/fpu/feholdexcpt.c +@@ -30,7 +30,7 @@ __feholdexcept (fenv_t *envp) + __asm__ volatile ("fnstenv %0; fnclex" : "=m" (*envp)); + + /* If the CPU supports SSE we set the MXCSR as well. */ +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + { + unsigned int xwork; + +diff --git a/sysdeps/i386/fpu/fesetenv.c b/sysdeps/i386/fpu/fesetenv.c +index 6df6849da4007a45..5c8bf1f71a474aa9 100644 +--- a/sysdeps/i386/fpu/fesetenv.c ++++ b/sysdeps/i386/fpu/fesetenv.c +@@ -79,7 +79,7 @@ __fesetenv (const fenv_t *envp) + + __asm__ ("fldenv %0" : : "m" (temp)); + +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + { + unsigned int mxcsr; + __asm__ ("stmxcsr %0" : "=m" (mxcsr)); +diff --git a/sysdeps/i386/fpu/fesetmode.c b/sysdeps/i386/fpu/fesetmode.c +index 9aad6ea99f810786..35881b6adf5b0aed 100644 +--- a/sysdeps/i386/fpu/fesetmode.c ++++ b/sysdeps/i386/fpu/fesetmode.c +@@ -35,7 +35,7 @@ fesetmode (const femode_t *modep) + else + cw = modep->__control_word; + _FPU_SETCW (cw); +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + { + unsigned int mxcsr; + __asm__ ("stmxcsr %0" : "=m" (mxcsr)); +diff --git a/sysdeps/i386/fpu/fesetround.c b/sysdeps/i386/fpu/fesetround.c +index d260046c65d0aba0..5d38b6b8624bdaef 100644 +--- a/sysdeps/i386/fpu/fesetround.c ++++ b/sysdeps/i386/fpu/fesetround.c +@@ -37,7 +37,7 @@ __fesetround (int round) + __asm__ ("fldcw %0" : : "m" (*&cw)); + + /* If the CPU supports SSE we set the MXCSR as well. */ +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + { + unsigned int xcw; + +diff --git a/sysdeps/i386/fpu/feupdateenv.c b/sysdeps/i386/fpu/feupdateenv.c +index db3ff96dfa8336ec..1246b21e30740922 100644 +--- a/sysdeps/i386/fpu/feupdateenv.c ++++ b/sysdeps/i386/fpu/feupdateenv.c +@@ -32,7 +32,7 @@ __feupdateenv (const fenv_t *envp) + __asm__ ("fnstsw %0" : "=m" (*&temp)); + + /* If the CPU supports SSE we test the MXCSR as well. */ +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + __asm__ ("stmxcsr %0" : "=m" (*&xtemp)); + + temp = (temp | xtemp) & FE_ALL_EXCEPT; +diff --git a/sysdeps/i386/fpu/fgetexcptflg.c b/sysdeps/i386/fpu/fgetexcptflg.c +index 39d1f7df3aa24b25..acb2ae15ea681c13 100644 +--- a/sysdeps/i386/fpu/fgetexcptflg.c ++++ b/sysdeps/i386/fpu/fgetexcptflg.c +@@ -34,7 +34,7 @@ __fegetexceptflag (fexcept_t *flagp, int excepts) + *flagp = temp & excepts & FE_ALL_EXCEPT; + + /* If the CPU supports SSE, we clear the MXCSR as well. */ +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + { + unsigned int sse_exc; + +diff --git a/sysdeps/i386/fpu/fsetexcptflg.c b/sysdeps/i386/fpu/fsetexcptflg.c +index 21e70251cfbf8a73..caa15c0cf105a9bc 100644 +--- a/sysdeps/i386/fpu/fsetexcptflg.c ++++ b/sysdeps/i386/fpu/fsetexcptflg.c +@@ -41,7 +41,7 @@ __fesetexceptflag (const fexcept_t *flagp, int excepts) + __asm__ ("fldenv %0" : : "m" (*&temp)); + + /* If the CPU supports SSE, we set the MXCSR as well. */ +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + { + unsigned int xnew_exc; + +diff --git a/sysdeps/i386/fpu/ftestexcept.c b/sysdeps/i386/fpu/ftestexcept.c +index c1b5e90356bae9da..06d6134e0d85eeef 100644 +--- a/sysdeps/i386/fpu/ftestexcept.c ++++ b/sysdeps/i386/fpu/ftestexcept.c +@@ -32,7 +32,7 @@ fetestexcept (int excepts) + __asm__ ("fnstsw %0" : "=a" (temp)); + + /* If the CPU supports SSE we test the MXCSR as well. */ +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + __asm__ ("stmxcsr %0" : "=m" (*&xtemp)); + + return (temp | xtemp) & excepts & FE_ALL_EXCEPT; +diff --git a/sysdeps/i386/i686/fpu/multiarch/s_cosf.c b/sysdeps/i386/i686/fpu/multiarch/s_cosf.c +index a4556a478d16974a..c31592f238d67916 100644 +--- a/sysdeps/i386/i686/fpu/multiarch/s_cosf.c ++++ b/sysdeps/i386/i686/fpu/multiarch/s_cosf.c +@@ -23,7 +23,7 @@ extern float __cosf_sse2 (float); + extern float __cosf_ia32 (float); + float __cosf (float); + +-libm_ifunc (__cosf, HAS_CPU_FEATURE (SSE2) ? __cosf_sse2 : __cosf_ia32); ++libm_ifunc (__cosf, CPU_FEATURE_USABLE (SSE2) ? __cosf_sse2 : __cosf_ia32); + libm_alias_float (__cos, cos); + + #define COSF __cosf_ia32 +diff --git a/sysdeps/i386/i686/fpu/multiarch/s_sincosf.c b/sysdeps/i386/i686/fpu/multiarch/s_sincosf.c +index 5f21f5c0eda20fd1..116c541dba54dd16 100644 +--- a/sysdeps/i386/i686/fpu/multiarch/s_sincosf.c ++++ b/sysdeps/i386/i686/fpu/multiarch/s_sincosf.c +@@ -24,7 +24,7 @@ extern void __sincosf_ia32 (float, float *, float *); + void __sincosf (float, float *, float *); + + libm_ifunc (__sincosf, +- HAS_CPU_FEATURE (SSE2) ? __sincosf_sse2 : __sincosf_ia32); ++ CPU_FEATURE_USABLE (SSE2) ? __sincosf_sse2 : __sincosf_ia32); + libm_alias_float (__sincos, sincos); + + #define SINCOSF __sincosf_ia32 +diff --git a/sysdeps/i386/i686/fpu/multiarch/s_sinf.c b/sysdeps/i386/i686/fpu/multiarch/s_sinf.c +index 80a7ffaa1e36b492..63abd34c21a1c83f 100644 +--- a/sysdeps/i386/i686/fpu/multiarch/s_sinf.c ++++ b/sysdeps/i386/i686/fpu/multiarch/s_sinf.c +@@ -23,7 +23,7 @@ extern float __sinf_sse2 (float); + extern float __sinf_ia32 (float); + float __sinf (float); + +-libm_ifunc (__sinf, HAS_CPU_FEATURE (SSE2) ? __sinf_sse2 : __sinf_ia32); ++libm_ifunc (__sinf, CPU_FEATURE_USABLE (SSE2) ? __sinf_sse2 : __sinf_ia32); + libm_alias_float (__sin, sin); + #define SINF __sinf_ia32 + #include +diff --git a/sysdeps/i386/i686/multiarch/ifunc-impl-list.c b/sysdeps/i386/i686/multiarch/ifunc-impl-list.c +index a926b04acdfbb889..06e7231d94e21c02 100644 +--- a/sysdeps/i386/i686/multiarch/ifunc-impl-list.c ++++ b/sysdeps/i386/i686/multiarch/ifunc-impl-list.c +@@ -38,35 +38,35 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/i386/i686/multiarch/bcopy.S. */ + IFUNC_IMPL (i, name, bcopy, +- IFUNC_IMPL_ADD (array, i, bcopy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, bcopy, CPU_FEATURE_USABLE (SSSE3), + __bcopy_ssse3_rep) +- IFUNC_IMPL_ADD (array, i, bcopy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, bcopy, CPU_FEATURE_USABLE (SSSE3), + __bcopy_ssse3) +- IFUNC_IMPL_ADD (array, i, bcopy, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, bcopy, CPU_FEATURE_USABLE (SSE2), + __bcopy_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, bcopy, 1, __bcopy_ia32)) + + /* Support sysdeps/i386/i686/multiarch/bzero.S. */ + IFUNC_IMPL (i, name, bzero, +- IFUNC_IMPL_ADD (array, i, bzero, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, bzero, CPU_FEATURE_USABLE (SSE2), + __bzero_sse2_rep) +- IFUNC_IMPL_ADD (array, i, bzero, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, bzero, CPU_FEATURE_USABLE (SSE2), + __bzero_sse2) + IFUNC_IMPL_ADD (array, i, bzero, 1, __bzero_ia32)) + + /* Support sysdeps/i386/i686/multiarch/memchr.S. */ + IFUNC_IMPL (i, name, memchr, +- IFUNC_IMPL_ADD (array, i, memchr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, memchr, CPU_FEATURE_USABLE (SSE2), + __memchr_sse2_bsf) +- IFUNC_IMPL_ADD (array, i, memchr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, memchr, CPU_FEATURE_USABLE (SSE2), + __memchr_sse2) + IFUNC_IMPL_ADD (array, i, memchr, 1, __memchr_ia32)) + + /* Support sysdeps/i386/i686/multiarch/memcmp.S. */ + IFUNC_IMPL (i, name, memcmp, +- IFUNC_IMPL_ADD (array, i, memcmp, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, memcmp, CPU_FEATURE_USABLE (SSE4_2), + __memcmp_sse4_2) +- IFUNC_IMPL_ADD (array, i, memcmp, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, memcmp, CPU_FEATURE_USABLE (SSSE3), + __memcmp_ssse3) + IFUNC_IMPL_ADD (array, i, memcmp, 1, __memcmp_ia32)) + +@@ -74,13 +74,13 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/i386/i686/multiarch/memmove_chk.S. */ + IFUNC_IMPL (i, name, __memmove_chk, + IFUNC_IMPL_ADD (array, i, __memmove_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __memmove_chk_ssse3_rep) + IFUNC_IMPL_ADD (array, i, __memmove_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __memmove_chk_ssse3) + IFUNC_IMPL_ADD (array, i, __memmove_chk, +- HAS_CPU_FEATURE (SSE2), ++ CPU_FEATURE_USABLE (SSE2), + __memmove_chk_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, __memmove_chk, 1, + __memmove_chk_ia32)) +@@ -88,19 +88,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/i386/i686/multiarch/memmove.S. */ + IFUNC_IMPL (i, name, memmove, +- IFUNC_IMPL_ADD (array, i, memmove, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, memmove, CPU_FEATURE_USABLE (SSSE3), + __memmove_ssse3_rep) +- IFUNC_IMPL_ADD (array, i, memmove, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, memmove, CPU_FEATURE_USABLE (SSSE3), + __memmove_ssse3) +- IFUNC_IMPL_ADD (array, i, memmove, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, memmove, CPU_FEATURE_USABLE (SSE2), + __memmove_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_ia32)) + + /* Support sysdeps/i386/i686/multiarch/memrchr.S. */ + IFUNC_IMPL (i, name, memrchr, +- IFUNC_IMPL_ADD (array, i, memrchr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, memrchr, CPU_FEATURE_USABLE (SSE2), + __memrchr_sse2_bsf) +- IFUNC_IMPL_ADD (array, i, memrchr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, memrchr, CPU_FEATURE_USABLE (SSE2), + __memrchr_sse2) + IFUNC_IMPL_ADD (array, i, memrchr, 1, __memrchr_ia32)) + +@@ -108,10 +108,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/i386/i686/multiarch/memset_chk.S. */ + IFUNC_IMPL (i, name, __memset_chk, + IFUNC_IMPL_ADD (array, i, __memset_chk, +- HAS_CPU_FEATURE (SSE2), ++ CPU_FEATURE_USABLE (SSE2), + __memset_chk_sse2_rep) + IFUNC_IMPL_ADD (array, i, __memset_chk, +- HAS_CPU_FEATURE (SSE2), ++ CPU_FEATURE_USABLE (SSE2), + __memset_chk_sse2) + IFUNC_IMPL_ADD (array, i, __memset_chk, 1, + __memset_chk_ia32)) +@@ -119,102 +119,102 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/i386/i686/multiarch/memset.S. */ + IFUNC_IMPL (i, name, memset, +- IFUNC_IMPL_ADD (array, i, memset, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, memset, CPU_FEATURE_USABLE (SSE2), + __memset_sse2_rep) +- IFUNC_IMPL_ADD (array, i, memset, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, memset, CPU_FEATURE_USABLE (SSE2), + __memset_sse2) + IFUNC_IMPL_ADD (array, i, memset, 1, __memset_ia32)) + + /* Support sysdeps/i386/i686/multiarch/rawmemchr.S. */ + IFUNC_IMPL (i, name, rawmemchr, +- IFUNC_IMPL_ADD (array, i, rawmemchr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, rawmemchr, CPU_FEATURE_USABLE (SSE2), + __rawmemchr_sse2_bsf) +- IFUNC_IMPL_ADD (array, i, rawmemchr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, rawmemchr, CPU_FEATURE_USABLE (SSE2), + __rawmemchr_sse2) + IFUNC_IMPL_ADD (array, i, rawmemchr, 1, __rawmemchr_ia32)) + + /* Support sysdeps/i386/i686/multiarch/stpncpy.S. */ + IFUNC_IMPL (i, name, stpncpy, +- IFUNC_IMPL_ADD (array, i, stpncpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, stpncpy, CPU_FEATURE_USABLE (SSSE3), + __stpncpy_ssse3) +- IFUNC_IMPL_ADD (array, i, stpncpy, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, stpncpy, CPU_FEATURE_USABLE (SSE2), + __stpncpy_sse2) + IFUNC_IMPL_ADD (array, i, stpncpy, 1, __stpncpy_ia32)) + + /* Support sysdeps/i386/i686/multiarch/stpcpy.S. */ + IFUNC_IMPL (i, name, stpcpy, +- IFUNC_IMPL_ADD (array, i, stpcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, stpcpy, CPU_FEATURE_USABLE (SSSE3), + __stpcpy_ssse3) +- IFUNC_IMPL_ADD (array, i, stpcpy, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, stpcpy, CPU_FEATURE_USABLE (SSE2), + __stpcpy_sse2) + IFUNC_IMPL_ADD (array, i, stpcpy, 1, __stpcpy_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strcasecmp.S. */ + IFUNC_IMPL (i, name, strcasecmp, + IFUNC_IMPL_ADD (array, i, strcasecmp, +- HAS_CPU_FEATURE (SSE4_2), ++ CPU_FEATURE_USABLE (SSE4_2), + __strcasecmp_sse4_2) + IFUNC_IMPL_ADD (array, i, strcasecmp, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __strcasecmp_ssse3) + IFUNC_IMPL_ADD (array, i, strcasecmp, 1, __strcasecmp_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strcasecmp_l.S. */ + IFUNC_IMPL (i, name, strcasecmp_l, + IFUNC_IMPL_ADD (array, i, strcasecmp_l, +- HAS_CPU_FEATURE (SSE4_2), ++ CPU_FEATURE_USABLE (SSE4_2), + __strcasecmp_l_sse4_2) + IFUNC_IMPL_ADD (array, i, strcasecmp_l, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __strcasecmp_l_ssse3) + IFUNC_IMPL_ADD (array, i, strcasecmp_l, 1, + __strcasecmp_l_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strcat.S. */ + IFUNC_IMPL (i, name, strcat, +- IFUNC_IMPL_ADD (array, i, strcat, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strcat, CPU_FEATURE_USABLE (SSSE3), + __strcat_ssse3) +- IFUNC_IMPL_ADD (array, i, strcat, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, strcat, CPU_FEATURE_USABLE (SSE2), + __strcat_sse2) + IFUNC_IMPL_ADD (array, i, strcat, 1, __strcat_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strchr.S. */ + IFUNC_IMPL (i, name, strchr, +- IFUNC_IMPL_ADD (array, i, strchr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, strchr, CPU_FEATURE_USABLE (SSE2), + __strchr_sse2_bsf) +- IFUNC_IMPL_ADD (array, i, strchr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, strchr, CPU_FEATURE_USABLE (SSE2), + __strchr_sse2) + IFUNC_IMPL_ADD (array, i, strchr, 1, __strchr_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strcmp.S. */ + IFUNC_IMPL (i, name, strcmp, +- IFUNC_IMPL_ADD (array, i, strcmp, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, strcmp, CPU_FEATURE_USABLE (SSE4_2), + __strcmp_sse4_2) +- IFUNC_IMPL_ADD (array, i, strcmp, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strcmp, CPU_FEATURE_USABLE (SSSE3), + __strcmp_ssse3) + IFUNC_IMPL_ADD (array, i, strcmp, 1, __strcmp_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strcpy.S. */ + IFUNC_IMPL (i, name, strcpy, +- IFUNC_IMPL_ADD (array, i, strcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strcpy, CPU_FEATURE_USABLE (SSSE3), + __strcpy_ssse3) +- IFUNC_IMPL_ADD (array, i, strcpy, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, strcpy, CPU_FEATURE_USABLE (SSE2), + __strcpy_sse2) + IFUNC_IMPL_ADD (array, i, strcpy, 1, __strcpy_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strcspn.S. */ + IFUNC_IMPL (i, name, strcspn, +- IFUNC_IMPL_ADD (array, i, strcspn, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, strcspn, CPU_FEATURE_USABLE (SSE4_2), + __strcspn_sse42) + IFUNC_IMPL_ADD (array, i, strcspn, 1, __strcspn_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strncase.S. */ + IFUNC_IMPL (i, name, strncasecmp, + IFUNC_IMPL_ADD (array, i, strncasecmp, +- HAS_CPU_FEATURE (SSE4_2), ++ CPU_FEATURE_USABLE (SSE4_2), + __strncasecmp_sse4_2) + IFUNC_IMPL_ADD (array, i, strncasecmp, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __strncasecmp_ssse3) + IFUNC_IMPL_ADD (array, i, strncasecmp, 1, + __strncasecmp_ia32)) +@@ -222,91 +222,91 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/i386/i686/multiarch/strncase_l.S. */ + IFUNC_IMPL (i, name, strncasecmp_l, + IFUNC_IMPL_ADD (array, i, strncasecmp_l, +- HAS_CPU_FEATURE (SSE4_2), ++ CPU_FEATURE_USABLE (SSE4_2), + __strncasecmp_l_sse4_2) + IFUNC_IMPL_ADD (array, i, strncasecmp_l, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __strncasecmp_l_ssse3) + IFUNC_IMPL_ADD (array, i, strncasecmp_l, 1, + __strncasecmp_l_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strncat.S. */ + IFUNC_IMPL (i, name, strncat, +- IFUNC_IMPL_ADD (array, i, strncat, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strncat, CPU_FEATURE_USABLE (SSSE3), + __strncat_ssse3) +- IFUNC_IMPL_ADD (array, i, strncat, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, strncat, CPU_FEATURE_USABLE (SSE2), + __strncat_sse2) + IFUNC_IMPL_ADD (array, i, strncat, 1, __strncat_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strncpy.S. */ + IFUNC_IMPL (i, name, strncpy, +- IFUNC_IMPL_ADD (array, i, strncpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strncpy, CPU_FEATURE_USABLE (SSSE3), + __strncpy_ssse3) +- IFUNC_IMPL_ADD (array, i, strncpy, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, strncpy, CPU_FEATURE_USABLE (SSE2), + __strncpy_sse2) + IFUNC_IMPL_ADD (array, i, strncpy, 1, __strncpy_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strnlen.S. */ + IFUNC_IMPL (i, name, strnlen, +- IFUNC_IMPL_ADD (array, i, strnlen, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, strnlen, CPU_FEATURE_USABLE (SSE2), + __strnlen_sse2) + IFUNC_IMPL_ADD (array, i, strnlen, 1, __strnlen_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strpbrk.S. */ + IFUNC_IMPL (i, name, strpbrk, +- IFUNC_IMPL_ADD (array, i, strpbrk, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, strpbrk, CPU_FEATURE_USABLE (SSE4_2), + __strpbrk_sse42) + IFUNC_IMPL_ADD (array, i, strpbrk, 1, __strpbrk_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strrchr.S. */ + IFUNC_IMPL (i, name, strrchr, +- IFUNC_IMPL_ADD (array, i, strrchr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, strrchr, CPU_FEATURE_USABLE (SSE2), + __strrchr_sse2_bsf) +- IFUNC_IMPL_ADD (array, i, strrchr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, strrchr, CPU_FEATURE_USABLE (SSE2), + __strrchr_sse2) + IFUNC_IMPL_ADD (array, i, strrchr, 1, __strrchr_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strspn.S. */ + IFUNC_IMPL (i, name, strspn, +- IFUNC_IMPL_ADD (array, i, strspn, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, strspn, CPU_FEATURE_USABLE (SSE4_2), + __strspn_sse42) + IFUNC_IMPL_ADD (array, i, strspn, 1, __strspn_ia32)) + + /* Support sysdeps/i386/i686/multiarch/wcschr.S. */ + IFUNC_IMPL (i, name, wcschr, +- IFUNC_IMPL_ADD (array, i, wcschr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, wcschr, CPU_FEATURE_USABLE (SSE2), + __wcschr_sse2) + IFUNC_IMPL_ADD (array, i, wcschr, 1, __wcschr_ia32)) + + /* Support sysdeps/i386/i686/multiarch/wcscmp.S. */ + IFUNC_IMPL (i, name, wcscmp, +- IFUNC_IMPL_ADD (array, i, wcscmp, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, wcscmp, CPU_FEATURE_USABLE (SSE2), + __wcscmp_sse2) + IFUNC_IMPL_ADD (array, i, wcscmp, 1, __wcscmp_ia32)) + + /* Support sysdeps/i386/i686/multiarch/wcscpy.S. */ + IFUNC_IMPL (i, name, wcscpy, +- IFUNC_IMPL_ADD (array, i, wcscpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, wcscpy, CPU_FEATURE_USABLE (SSSE3), + __wcscpy_ssse3) + IFUNC_IMPL_ADD (array, i, wcscpy, 1, __wcscpy_ia32)) + + /* Support sysdeps/i386/i686/multiarch/wcslen.S. */ + IFUNC_IMPL (i, name, wcslen, +- IFUNC_IMPL_ADD (array, i, wcslen, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, wcslen, CPU_FEATURE_USABLE (SSE2), + __wcslen_sse2) + IFUNC_IMPL_ADD (array, i, wcslen, 1, __wcslen_ia32)) + + /* Support sysdeps/i386/i686/multiarch/wcsrchr.S. */ + IFUNC_IMPL (i, name, wcsrchr, +- IFUNC_IMPL_ADD (array, i, wcsrchr, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, wcsrchr, CPU_FEATURE_USABLE (SSE2), + __wcsrchr_sse2) + IFUNC_IMPL_ADD (array, i, wcsrchr, 1, __wcsrchr_ia32)) + + /* Support sysdeps/i386/i686/multiarch/wmemcmp.S. */ + IFUNC_IMPL (i, name, wmemcmp, +- IFUNC_IMPL_ADD (array, i, wmemcmp, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, wmemcmp, CPU_FEATURE_USABLE (SSE4_2), + __wmemcmp_sse4_2) +- IFUNC_IMPL_ADD (array, i, wmemcmp, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, wmemcmp, CPU_FEATURE_USABLE (SSSE3), + __wmemcmp_ssse3) + IFUNC_IMPL_ADD (array, i, wmemcmp, 1, __wmemcmp_ia32)) + +@@ -314,64 +314,64 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/i386/i686/multiarch/memcpy_chk.S. */ + IFUNC_IMPL (i, name, __memcpy_chk, + IFUNC_IMPL_ADD (array, i, __memcpy_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __memcpy_chk_ssse3_rep) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __memcpy_chk_ssse3) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, +- HAS_CPU_FEATURE (SSE2), ++ CPU_FEATURE_USABLE (SSE2), + __memcpy_chk_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, 1, + __memcpy_chk_ia32)) + + /* Support sysdeps/i386/i686/multiarch/memcpy.S. */ + IFUNC_IMPL (i, name, memcpy, +- IFUNC_IMPL_ADD (array, i, memcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, memcpy, CPU_FEATURE_USABLE (SSSE3), + __memcpy_ssse3_rep) +- IFUNC_IMPL_ADD (array, i, memcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, memcpy, CPU_FEATURE_USABLE (SSSE3), + __memcpy_ssse3) +- IFUNC_IMPL_ADD (array, i, memcpy, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, memcpy, CPU_FEATURE_USABLE (SSE2), + __memcpy_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_ia32)) + + /* Support sysdeps/i386/i686/multiarch/mempcpy_chk.S. */ + IFUNC_IMPL (i, name, __mempcpy_chk, + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __mempcpy_chk_ssse3_rep) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __mempcpy_chk_ssse3) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, +- HAS_CPU_FEATURE (SSE2), ++ CPU_FEATURE_USABLE (SSE2), + __mempcpy_chk_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, 1, + __mempcpy_chk_ia32)) + + /* Support sysdeps/i386/i686/multiarch/mempcpy.S. */ + IFUNC_IMPL (i, name, mempcpy, +- IFUNC_IMPL_ADD (array, i, mempcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, mempcpy, CPU_FEATURE_USABLE (SSSE3), + __mempcpy_ssse3_rep) +- IFUNC_IMPL_ADD (array, i, mempcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, mempcpy, CPU_FEATURE_USABLE (SSSE3), + __mempcpy_ssse3) +- IFUNC_IMPL_ADD (array, i, mempcpy, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, mempcpy, CPU_FEATURE_USABLE (SSE2), + __mempcpy_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, mempcpy, 1, __mempcpy_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strlen.S. */ + IFUNC_IMPL (i, name, strlen, +- IFUNC_IMPL_ADD (array, i, strlen, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, strlen, CPU_FEATURE_USABLE (SSE2), + __strlen_sse2_bsf) +- IFUNC_IMPL_ADD (array, i, strlen, HAS_CPU_FEATURE (SSE2), ++ IFUNC_IMPL_ADD (array, i, strlen, CPU_FEATURE_USABLE (SSE2), + __strlen_sse2) + IFUNC_IMPL_ADD (array, i, strlen, 1, __strlen_ia32)) + + /* Support sysdeps/i386/i686/multiarch/strncmp.S. */ + IFUNC_IMPL (i, name, strncmp, +- IFUNC_IMPL_ADD (array, i, strncmp, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, strncmp, CPU_FEATURE_USABLE (SSE4_2), + __strncmp_sse4_2) +- IFUNC_IMPL_ADD (array, i, strncmp, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strncmp, CPU_FEATURE_USABLE (SSSE3), + __strncmp_ssse3) + IFUNC_IMPL_ADD (array, i, strncmp, 1, __strncmp_ia32)) + #endif +diff --git a/sysdeps/i386/i686/multiarch/ifunc-memmove.h b/sysdeps/i386/i686/multiarch/ifunc-memmove.h +index f0e97561784a82d5..cd4333f84b114552 100644 +--- a/sysdeps/i386/i686/multiarch/ifunc-memmove.h ++++ b/sysdeps/i386/i686/multiarch/ifunc-memmove.h +@@ -33,7 +33,7 @@ IFUNC_SELECTOR (void) + if (CPU_FEATURES_ARCH_P (cpu_features, Fast_Unaligned_Load)) + return OPTIMIZE (sse2_unaligned); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSSE3)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSSE3)) + { + if (CPU_FEATURES_ARCH_P (cpu_features, Fast_Rep_String)) + return OPTIMIZE (ssse3_rep); +diff --git a/sysdeps/i386/i686/multiarch/ifunc-memset.h b/sysdeps/i386/i686/multiarch/ifunc-memset.h +index e96609439aef30d1..6cf96ebcd480dba4 100644 +--- a/sysdeps/i386/i686/multiarch/ifunc-memset.h ++++ b/sysdeps/i386/i686/multiarch/ifunc-memset.h +@@ -28,7 +28,7 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE2)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE2)) + { + if (CPU_FEATURES_ARCH_P (cpu_features, Fast_Rep_String)) + return OPTIMIZE (sse2_rep); +diff --git a/sysdeps/i386/i686/multiarch/ifunc-sse2-bsf.h b/sysdeps/i386/i686/multiarch/ifunc-sse2-bsf.h +index f5e7f1b846c28454..de30f004db53f227 100644 +--- a/sysdeps/i386/i686/multiarch/ifunc-sse2-bsf.h ++++ b/sysdeps/i386/i686/multiarch/ifunc-sse2-bsf.h +@@ -28,7 +28,7 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE2)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE2)) + { + if (CPU_FEATURES_ARCH_P (cpu_features, Slow_BSF)) + return OPTIMIZE (sse2); +diff --git a/sysdeps/i386/i686/multiarch/ifunc-sse2-ssse3.h b/sysdeps/i386/i686/multiarch/ifunc-sse2-ssse3.h +index a33fe44f504bd178..299d73e3144698d7 100644 +--- a/sysdeps/i386/i686/multiarch/ifunc-sse2-ssse3.h ++++ b/sysdeps/i386/i686/multiarch/ifunc-sse2-ssse3.h +@@ -29,11 +29,11 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE2) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE2) + && CPU_FEATURES_ARCH_P (cpu_features, Fast_Rep_String)) + return OPTIMIZE (sse2); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSSE3)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSSE3)) + return OPTIMIZE (ssse3); + + return OPTIMIZE (ia32); +diff --git a/sysdeps/i386/i686/multiarch/ifunc-sse2.h b/sysdeps/i386/i686/multiarch/ifunc-sse2.h +index 706c0329c9a76573..e1ba025299037bfb 100644 +--- a/sysdeps/i386/i686/multiarch/ifunc-sse2.h ++++ b/sysdeps/i386/i686/multiarch/ifunc-sse2.h +@@ -27,7 +27,7 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE2)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE2)) + return OPTIMIZE (sse2); + + return OPTIMIZE (ia32); +diff --git a/sysdeps/i386/i686/multiarch/ifunc-sse4_2.h b/sysdeps/i386/i686/multiarch/ifunc-sse4_2.h +index de7fa2f185ad9a59..641cec2ced510524 100644 +--- a/sysdeps/i386/i686/multiarch/ifunc-sse4_2.h ++++ b/sysdeps/i386/i686/multiarch/ifunc-sse4_2.h +@@ -27,7 +27,7 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE4_2)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_2)) + return OPTIMIZE (sse42); + + return OPTIMIZE (ia32); +diff --git a/sysdeps/i386/i686/multiarch/ifunc-ssse3-sse4_2.h b/sysdeps/i386/i686/multiarch/ifunc-ssse3-sse4_2.h +index bd772a9298ab7d6b..6b2b461e47e94b66 100644 +--- a/sysdeps/i386/i686/multiarch/ifunc-ssse3-sse4_2.h ++++ b/sysdeps/i386/i686/multiarch/ifunc-ssse3-sse4_2.h +@@ -29,10 +29,10 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE4_2)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_2)) + return OPTIMIZE (sse4_2); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSSE3)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSSE3)) + return OPTIMIZE (ssse3); + + return OPTIMIZE (ia32); +diff --git a/sysdeps/i386/i686/multiarch/s_fma.c b/sysdeps/i386/i686/multiarch/s_fma.c +index 7f39f5fdc972fcc7..0cf6e41b03043911 100644 +--- a/sysdeps/i386/i686/multiarch/s_fma.c ++++ b/sysdeps/i386/i686/multiarch/s_fma.c +@@ -27,7 +27,7 @@ extern double __fma_ia32 (double x, double y, double z) attribute_hidden; + extern double __fma_fma (double x, double y, double z) attribute_hidden; + + libm_ifunc (__fma, +- HAS_ARCH_FEATURE (FMA_Usable) ? __fma_fma : __fma_ia32); ++ CPU_FEATURE_USABLE (FMA) ? __fma_fma : __fma_ia32); + libm_alias_double (__fma, fma) + + #define __fma __fma_ia32 +diff --git a/sysdeps/i386/i686/multiarch/s_fmaf.c b/sysdeps/i386/i686/multiarch/s_fmaf.c +index 1ebb6e975ee86f54..638cd5b10ba57592 100644 +--- a/sysdeps/i386/i686/multiarch/s_fmaf.c ++++ b/sysdeps/i386/i686/multiarch/s_fmaf.c +@@ -27,7 +27,7 @@ extern float __fmaf_ia32 (float x, float y, float z) attribute_hidden; + extern float __fmaf_fma (float x, float y, float z) attribute_hidden; + + libm_ifunc (__fmaf, +- HAS_ARCH_FEATURE (FMA_Usable) ? __fmaf_fma : __fmaf_ia32); ++ CPU_FEATURE_USABLE (FMA) ? __fmaf_fma : __fmaf_ia32); + libm_alias_float (__fma, fma) + + #define __fmaf __fmaf_ia32 +diff --git a/sysdeps/i386/i686/multiarch/wcscpy.c b/sysdeps/i386/i686/multiarch/wcscpy.c +index be89ab81b066d463..ea149b0d3af357f2 100644 +--- a/sysdeps/i386/i686/multiarch/wcscpy.c ++++ b/sysdeps/i386/i686/multiarch/wcscpy.c +@@ -34,7 +34,7 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSSE3)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSSE3)) + return OPTIMIZE (ssse3); + + return OPTIMIZE (ia32); +diff --git a/sysdeps/i386/setfpucw.c b/sysdeps/i386/setfpucw.c +index 931302bcd03d221b..3fa2651d46a70ab6 100644 +--- a/sysdeps/i386/setfpucw.c ++++ b/sysdeps/i386/setfpucw.c +@@ -39,7 +39,7 @@ __setfpucw (fpu_control_t set) + __asm__ ("fldcw %0" : : "m" (*&cw)); + + /* If the CPU supports SSE, we set the MXCSR as well. */ +- if (HAS_CPU_FEATURE (SSE)) ++ if (CPU_FEATURE_USABLE (SSE)) + { + unsigned int xnew_exc; + +diff --git a/sysdeps/unix/sysv/linux/x86/elision-conf.c b/sysdeps/unix/sysv/linux/x86/elision-conf.c +index 22af294426596add..bdfc514a238f92a8 100644 +--- a/sysdeps/unix/sysv/linux/x86/elision-conf.c ++++ b/sysdeps/unix/sysv/linux/x86/elision-conf.c +@@ -64,7 +64,7 @@ do_set_elision_enable (int32_t elision_enable) + if __libc_enable_secure isn't enabled since elision_enable will be set + according to the default, which is disabled. */ + if (elision_enable == 1) +- __pthread_force_elision = HAS_CPU_FEATURE (RTM) ? 1 : 0; ++ __pthread_force_elision = CPU_FEATURE_USABLE (RTM) ? 1 : 0; + } + + /* The pthread->elision_enable tunable is 0 or 1 indicating that elision +diff --git a/sysdeps/x86/cacheinfo.c b/sysdeps/x86/cacheinfo.c +index f4edbc0103beb435..fdfe2684759d968c 100644 +--- a/sysdeps/x86/cacheinfo.c ++++ b/sysdeps/x86/cacheinfo.c +@@ -583,7 +583,7 @@ get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, + + /* A value of 0 for the HTT bit indicates there is only a single + logical processor. */ +- if (HAS_CPU_FEATURE (HTT)) ++ if (CPU_FEATURE_USABLE (HTT)) + { + /* Figure out the number of logical threads that share the + highest cache level. */ +@@ -732,7 +732,7 @@ intel_bug_no_cache_info: + /* Assume that all logical threads share the highest cache + level. */ + threads +- = ((cpu_features->cpuid[COMMON_CPUID_INDEX_1].ebx ++ = ((cpu_features->features[COMMON_CPUID_INDEX_1].cpuid.ebx + >> 16) & 0xff); + } + +@@ -887,14 +887,14 @@ init_cacheinfo (void) + unsigned int minimum_rep_movsb_threshold; + /* NB: The default REP MOVSB threshold is 2048 * (VEC_SIZE / 16). */ + unsigned int rep_movsb_threshold; +- if (CPU_FEATURES_ARCH_P (cpu_features, AVX512F_Usable) +- && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_AVX512)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F) ++ && !CPU_FEATURE_PREFERRED_P (cpu_features, Prefer_No_AVX512)) + { + rep_movsb_threshold = 2048 * (64 / 16); + minimum_rep_movsb_threshold = 64 * 8; + } +- else if (CPU_FEATURES_ARCH_P (cpu_features, +- AVX_Fast_Unaligned_Load)) ++ else if (CPU_FEATURE_PREFERRED_P (cpu_features, ++ AVX_Fast_Unaligned_Load)) + { + rep_movsb_threshold = 2048 * (32 / 16); + minimum_rep_movsb_threshold = 32 * 8; +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index ad470f79ef7769fc..f13a1df4555c7000 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -42,73 +42,109 @@ extern void TUNABLE_CALLBACK (set_x86_shstk) (tunable_val_t *) + #endif + + static void +-get_extended_indices (struct cpu_features *cpu_features) ++update_usable (struct cpu_features *cpu_features) + { +- unsigned int eax, ebx, ecx, edx; +- __cpuid (0x80000000, eax, ebx, ecx, edx); +- if (eax >= 0x80000001) +- __cpuid (0x80000001, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].eax, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].ebx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].ecx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].edx); +- if (eax >= 0x80000007) +- __cpuid (0x80000007, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000007].eax, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000007].ebx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000007].ecx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000007].edx); +- if (eax >= 0x80000008) +- __cpuid (0x80000008, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000008].eax, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000008].ebx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000008].ecx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000008].edx); +-} +- +-static void +-get_common_indices (struct cpu_features *cpu_features, +- unsigned int *family, unsigned int *model, +- unsigned int *extended_model, unsigned int *stepping) +-{ +- if (family) +- { +- unsigned int eax; +- __cpuid (1, eax, cpu_features->cpuid[COMMON_CPUID_INDEX_1].ebx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_1].ecx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_1].edx); +- cpu_features->cpuid[COMMON_CPUID_INDEX_1].eax = eax; +- *family = (eax >> 8) & 0x0f; +- *model = (eax >> 4) & 0x0f; +- *extended_model = (eax >> 12) & 0xf0; +- *stepping = eax & 0x0f; +- if (*family == 0x0f) +- { +- *family += (eax >> 20) & 0xff; +- *model += *extended_model; +- } +- } +- +- if (cpu_features->basic.max_cpuid >= 7) +- { +- __cpuid_count (7, 0, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7].eax, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7].ebx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7].ecx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7].edx); +- __cpuid_count (7, 1, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7_ECX_1].eax, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7_ECX_1].ebx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7_ECX_1].ecx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_7_ECX_1].edx); +- } +- +- if (cpu_features->basic.max_cpuid >= 0xd) +- __cpuid_count (0xd, 1, +- cpu_features->cpuid[COMMON_CPUID_INDEX_D_ECX_1].eax, +- cpu_features->cpuid[COMMON_CPUID_INDEX_D_ECX_1].ebx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_D_ECX_1].ecx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_D_ECX_1].edx); ++ /* Before COMMON_CPUID_INDEX_80000001, copy the cpuid array elements to ++ the usable array. */ ++ unsigned int i; ++ for (i = 0; i < COMMON_CPUID_INDEX_80000001; i++) ++ cpu_features->features[i].usable = cpu_features->features[i].cpuid; ++ ++ /* Before COMMON_CPUID_INDEX_80000001, clear the unknown usable bits ++ and the always zero bits. */ ++ CPU_FEATURE_UNSET (cpu_features, INDEX_1_ECX_16); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_1_ECX_31); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_1_EDX_10); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_1_EDX_20); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_1_EDX_30); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EBX_6); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EBX_22); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_13); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_15); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_16); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_23); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_24); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_26); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_0); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_1); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_5); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_6); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_7); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_9); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_11); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_12); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_13); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_17); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_19); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_21); ++ CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_23); ++ ++ /* EAX/EBX from COMMON_CPUID_INDEX_1 and EAX from COMMON_CPUID_INDEX_7 ++ aren't used for CPU feature detection. */ ++ cpu_features->features[COMMON_CPUID_INDEX_1].usable.eax = 0; ++ cpu_features->features[COMMON_CPUID_INDEX_1].usable.ebx = 0; ++ cpu_features->features[COMMON_CPUID_INDEX_7].usable.eax = 0; ++ ++ /* Starting from COMMON_CPUID_INDEX_80000001, copy the cpuid bits to ++ usable bits. */ ++ CPU_FEATURE_SET_USABLE (cpu_features, LAHF64_SAHF64); ++ CPU_FEATURE_SET_USABLE (cpu_features, SVM); ++ CPU_FEATURE_SET_USABLE (cpu_features, LZCNT); ++ CPU_FEATURE_SET_USABLE (cpu_features, SSE4A); ++ CPU_FEATURE_SET_USABLE (cpu_features, PREFETCHW); ++ CPU_FEATURE_SET_USABLE (cpu_features, XOP); ++ CPU_FEATURE_SET_USABLE (cpu_features, LWP); ++ CPU_FEATURE_SET_USABLE (cpu_features, FMA4); ++ CPU_FEATURE_SET_USABLE (cpu_features, TBM); ++ CPU_FEATURE_SET_USABLE (cpu_features, SYSCALL_SYSRET); ++ CPU_FEATURE_SET_USABLE (cpu_features, NX); ++ CPU_FEATURE_SET_USABLE (cpu_features, PAGE1GB); ++ CPU_FEATURE_SET_USABLE (cpu_features, RDTSCP); ++ CPU_FEATURE_SET_USABLE (cpu_features, LM); ++ CPU_FEATURE_SET_USABLE (cpu_features, XSAVEOPT); ++ CPU_FEATURE_SET_USABLE (cpu_features, XSAVEC); ++ CPU_FEATURE_SET_USABLE (cpu_features, XGETBV_ECX_1); ++ CPU_FEATURE_SET_USABLE (cpu_features, XSAVES); ++ CPU_FEATURE_SET_USABLE (cpu_features, XFD); ++ CPU_FEATURE_SET_USABLE (cpu_features, INVARIANT_TSC); ++ CPU_FEATURE_SET_USABLE (cpu_features, WBNOINVD); ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512_BF16); ++ ++ /* MPX has been deprecated. */ ++ CPU_FEATURE_UNSET (cpu_features, MPX); ++ ++ /* Clear the usable bits which require OS support. */ ++ CPU_FEATURE_UNSET (cpu_features, FMA); ++ CPU_FEATURE_UNSET (cpu_features, AVX); ++ CPU_FEATURE_UNSET (cpu_features, F16C); ++ CPU_FEATURE_UNSET (cpu_features, AVX2); ++ CPU_FEATURE_UNSET (cpu_features, AVX512F); ++ CPU_FEATURE_UNSET (cpu_features, AVX512DQ); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_IFMA); ++ CPU_FEATURE_UNSET (cpu_features, AVX512PF); ++ CPU_FEATURE_UNSET (cpu_features, AVX512ER); ++ CPU_FEATURE_UNSET (cpu_features, AVX512CD); ++ CPU_FEATURE_UNSET (cpu_features, AVX512BW); ++ CPU_FEATURE_UNSET (cpu_features, AVX512VL); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_VBMI); ++ CPU_FEATURE_UNSET (cpu_features, PKU); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_VBMI2); ++ CPU_FEATURE_UNSET (cpu_features, VAES); ++ CPU_FEATURE_UNSET (cpu_features, VPCLMULQDQ); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_VNNI); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_BITALG); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_VPOPCNTDQ); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_4VNNIW); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_4FMAPS); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_VP2INTERSECT); ++ CPU_FEATURE_UNSET (cpu_features, AMX_BF16); ++ CPU_FEATURE_UNSET (cpu_features, AMX_TILE); ++ CPU_FEATURE_UNSET (cpu_features, AMX_INT8); ++ CPU_FEATURE_UNSET (cpu_features, XOP); ++ CPU_FEATURE_UNSET (cpu_features, FMA4); ++ CPU_FEATURE_UNSET (cpu_features, XSAVEC); ++ CPU_FEATURE_UNSET (cpu_features, XFD); ++ CPU_FEATURE_UNSET (cpu_features, AVX512_BF16); + + /* Can we call xgetbv? */ + if (CPU_FEATURES_CPU_P (cpu_features, OSXSAVE)) +@@ -123,40 +159,28 @@ get_common_indices (struct cpu_features *cpu_features, + /* Determine if AVX is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX)) + { +- cpu_features->usable[index_arch_AVX_Usable] +- |= bit_arch_AVX_Usable; ++ CPU_FEATURE_SET (cpu_features, AVX); + /* The following features depend on AVX being usable. */ + /* Determine if AVX2 is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX2)) +- { +- cpu_features->usable[index_arch_AVX2_Usable] +- |= bit_arch_AVX2_Usable; +- +- /* Unaligned load with 256-bit AVX registers are faster on +- Intel/AMD processors with AVX2. */ +- cpu_features->preferred[index_arch_AVX_Fast_Unaligned_Load] +- |= bit_arch_AVX_Fast_Unaligned_Load; +- } ++ { ++ CPU_FEATURE_SET (cpu_features, AVX2); ++ ++ /* Unaligned load with 256-bit AVX registers are faster ++ on Intel/AMD processors with AVX2. */ ++ cpu_features->preferred[index_arch_AVX_Fast_Unaligned_Load] ++ |= bit_arch_AVX_Fast_Unaligned_Load; ++ } + /* Determine if FMA is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, FMA)) +- cpu_features->usable[index_arch_FMA_Usable] +- |= bit_arch_FMA_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, FMA); + /* Determine if VAES is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, VAES)) +- cpu_features->usable[index_arch_VAES_Usable] +- |= bit_arch_VAES_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, VAES); + /* Determine if VPCLMULQDQ is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, VPCLMULQDQ)) +- cpu_features->usable[index_arch_VPCLMULQDQ_Usable] +- |= bit_arch_VPCLMULQDQ_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, VPCLMULQDQ); + /* Determine if XOP is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, XOP)) +- cpu_features->usable[index_arch_XOP_Usable] +- |= bit_arch_XOP_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, XOP); + /* Determine if F16C is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, F16C)) +- cpu_features->usable[index_arch_F16C_Usable] +- |= bit_arch_F16C_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, F16C); + } + + /* Check if OPMASK state, upper 256-bit of ZMM0-ZMM15 and +@@ -168,73 +192,41 @@ get_common_indices (struct cpu_features *cpu_features, + /* Determine if AVX512F is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512F)) + { +- cpu_features->usable[index_arch_AVX512F_Usable] +- |= bit_arch_AVX512F_Usable; ++ CPU_FEATURE_SET (cpu_features, AVX512F); + /* Determine if AVX512CD is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512CD)) +- cpu_features->usable[index_arch_AVX512CD_Usable] +- |= bit_arch_AVX512CD_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512CD); + /* Determine if AVX512ER is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512ER)) +- cpu_features->usable[index_arch_AVX512ER_Usable] +- |= bit_arch_AVX512ER_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512ER); + /* Determine if AVX512PF is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512PF)) +- cpu_features->usable[index_arch_AVX512PF_Usable] +- |= bit_arch_AVX512PF_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512PF); + /* Determine if AVX512VL is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512VL)) +- cpu_features->usable[index_arch_AVX512VL_Usable] +- |= bit_arch_AVX512VL_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512VL); + /* Determine if AVX512DQ is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512DQ)) +- cpu_features->usable[index_arch_AVX512DQ_Usable] +- |= bit_arch_AVX512DQ_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512DQ); + /* Determine if AVX512BW is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512BW)) +- cpu_features->usable[index_arch_AVX512BW_Usable] +- |= bit_arch_AVX512BW_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512BW); + /* Determine if AVX512_4FMAPS is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512_4FMAPS)) +- cpu_features->usable[index_arch_AVX512_4FMAPS_Usable] +- |= bit_arch_AVX512_4FMAPS_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512_4FMAPS); + /* Determine if AVX512_4VNNIW is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512_4VNNIW)) +- cpu_features->usable[index_arch_AVX512_4VNNIW_Usable] +- |= bit_arch_AVX512_4VNNIW_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512_4VNNIW); + /* Determine if AVX512_BITALG is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512_BITALG)) +- cpu_features->usable[index_arch_AVX512_BITALG_Usable] +- |= bit_arch_AVX512_BITALG_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512_BITALG); + /* Determine if AVX512_IFMA is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512_IFMA)) +- cpu_features->usable[index_arch_AVX512_IFMA_Usable] +- |= bit_arch_AVX512_IFMA_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512_IFMA); + /* Determine if AVX512_VBMI is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VBMI)) +- cpu_features->usable[index_arch_AVX512_VBMI_Usable] +- |= bit_arch_AVX512_VBMI_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512_VBMI); + /* Determine if AVX512_VBMI2 is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VBMI2)) +- cpu_features->usable[index_arch_AVX512_VBMI2_Usable] +- |= bit_arch_AVX512_VBMI2_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512_VBMI2); + /* Determine if is AVX512_VNNI usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VNNI)) +- cpu_features->usable[index_arch_AVX512_VNNI_Usable] +- |= bit_arch_AVX512_VNNI_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512_VNNI); + /* Determine if AVX512_VPOPCNTDQ is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512_VPOPCNTDQ)) +- cpu_features->usable[index_arch_AVX512_VPOPCNTDQ_Usable] +- |= bit_arch_AVX512_VPOPCNTDQ_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, ++ AVX512_VPOPCNTDQ); + /* Determine if AVX512_VP2INTERSECT is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, +- AVX512_VP2INTERSECT)) +- cpu_features->usable[index_arch_AVX512_VP2INTERSECT_Usable] +- |= bit_arch_AVX512_VP2INTERSECT_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, ++ AVX512_VP2INTERSECT); + /* Determine if AVX512_BF16 is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512_BF16)) +- cpu_features->usable[index_arch_AVX512_BF16_Usable] +- |= bit_arch_AVX512_BF16_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AVX512_BF16); + } + } + } +@@ -244,19 +236,17 @@ get_common_indices (struct cpu_features *cpu_features, + == (bit_XTILECFG_state | bit_XTILEDATA_state)) + { + /* Determine if AMX_BF16 is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AMX_BF16)) +- cpu_features->usable[index_arch_AMX_BF16_Usable] +- |= bit_arch_AMX_BF16_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AMX_BF16); + /* Determine if AMX_TILE is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AMX_TILE)) +- cpu_features->usable[index_arch_AMX_TILE_Usable] +- |= bit_arch_AMX_TILE_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AMX_TILE); + /* Determine if AMX_INT8 is usable. */ +- if (CPU_FEATURES_CPU_P (cpu_features, AMX_INT8)) +- cpu_features->usable[index_arch_AMX_INT8_Usable] +- |= bit_arch_AMX_INT8_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, AMX_INT8); + } + ++ ++ /* XFD is usable only when OSXSAVE is enabled. */ ++ CPU_FEATURE_SET_USABLE (cpu_features, XFD); ++ + /* For _dl_runtime_resolve, set xsave_state_size to xsave area + size + integer register save size and align it to 64 bytes. */ + if (cpu_features->basic.max_cpuid >= 0xd) +@@ -318,8 +308,7 @@ get_common_indices (struct cpu_features *cpu_features, + { + cpu_features->xsave_state_size + = ALIGN_UP (size + STATE_SAVE_OFFSET, 64); +- cpu_features->usable[index_arch_XSAVEC_Usable] +- |= bit_arch_XSAVEC_Usable; ++ CPU_FEATURE_SET (cpu_features, XSAVEC); + } + } + } +@@ -328,8 +317,79 @@ get_common_indices (struct cpu_features *cpu_features, + + /* Determine if PKU is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, OSPKE)) +- cpu_features->usable[index_arch_PKU_Usable] +- |= bit_arch_PKU_Usable; ++ CPU_FEATURE_SET (cpu_features, PKU); ++} ++ ++static void ++get_extended_indices (struct cpu_features *cpu_features) ++{ ++ unsigned int eax, ebx, ecx, edx; ++ __cpuid (0x80000000, eax, ebx, ecx, edx); ++ if (eax >= 0x80000001) ++ __cpuid (0x80000001, ++ cpu_features->features[COMMON_CPUID_INDEX_80000001].cpuid.eax, ++ cpu_features->features[COMMON_CPUID_INDEX_80000001].cpuid.ebx, ++ cpu_features->features[COMMON_CPUID_INDEX_80000001].cpuid.ecx, ++ cpu_features->features[COMMON_CPUID_INDEX_80000001].cpuid.edx); ++ if (eax >= 0x80000007) ++ __cpuid (0x80000007, ++ cpu_features->features[COMMON_CPUID_INDEX_80000007].cpuid.eax, ++ cpu_features->features[COMMON_CPUID_INDEX_80000007].cpuid.ebx, ++ cpu_features->features[COMMON_CPUID_INDEX_80000007].cpuid.ecx, ++ cpu_features->features[COMMON_CPUID_INDEX_80000007].cpuid.edx); ++ if (eax >= 0x80000008) ++ __cpuid (0x80000008, ++ cpu_features->features[COMMON_CPUID_INDEX_80000008].cpuid.eax, ++ cpu_features->features[COMMON_CPUID_INDEX_80000008].cpuid.ebx, ++ cpu_features->features[COMMON_CPUID_INDEX_80000008].cpuid.ecx, ++ cpu_features->features[COMMON_CPUID_INDEX_80000008].cpuid.edx); ++} ++ ++static void ++get_common_indices (struct cpu_features *cpu_features, ++ unsigned int *family, unsigned int *model, ++ unsigned int *extended_model, unsigned int *stepping) ++{ ++ if (family) ++ { ++ unsigned int eax; ++ __cpuid (1, eax, ++ cpu_features->features[COMMON_CPUID_INDEX_1].cpuid.ebx, ++ cpu_features->features[COMMON_CPUID_INDEX_1].cpuid.ecx, ++ cpu_features->features[COMMON_CPUID_INDEX_1].cpuid.edx); ++ cpu_features->features[COMMON_CPUID_INDEX_1].cpuid.eax = eax; ++ *family = (eax >> 8) & 0x0f; ++ *model = (eax >> 4) & 0x0f; ++ *extended_model = (eax >> 12) & 0xf0; ++ *stepping = eax & 0x0f; ++ if (*family == 0x0f) ++ { ++ *family += (eax >> 20) & 0xff; ++ *model += *extended_model; ++ } ++ } ++ ++ if (cpu_features->basic.max_cpuid >= 7) ++ { ++ __cpuid_count (7, 0, ++ cpu_features->features[COMMON_CPUID_INDEX_7].cpuid.eax, ++ cpu_features->features[COMMON_CPUID_INDEX_7].cpuid.ebx, ++ cpu_features->features[COMMON_CPUID_INDEX_7].cpuid.ecx, ++ cpu_features->features[COMMON_CPUID_INDEX_7].cpuid.edx); ++ __cpuid_count (7, 1, ++ cpu_features->features[COMMON_CPUID_INDEX_7_ECX_1].cpuid.eax, ++ cpu_features->features[COMMON_CPUID_INDEX_7_ECX_1].cpuid.ebx, ++ cpu_features->features[COMMON_CPUID_INDEX_7_ECX_1].cpuid.ecx, ++ cpu_features->features[COMMON_CPUID_INDEX_7_ECX_1].cpuid.edx); ++ } ++ ++ if (cpu_features->basic.max_cpuid >= 0xd) ++ __cpuid_count (0xd, 1, ++ cpu_features->features[COMMON_CPUID_INDEX_D_ECX_1].cpuid.eax, ++ cpu_features->features[COMMON_CPUID_INDEX_D_ECX_1].cpuid.ebx, ++ cpu_features->features[COMMON_CPUID_INDEX_D_ECX_1].cpuid.ecx, ++ cpu_features->features[COMMON_CPUID_INDEX_D_ECX_1].cpuid.edx); ++ + } + + _Static_assert (((index_arch_Fast_Unaligned_Load +@@ -353,8 +413,6 @@ init_cpu_features (struct cpu_features *cpu_features) + unsigned int stepping = 0; + enum cpu_features_kind kind; + +- cpu_features->usable_p = cpu_features->usable; +- + #if !HAS_CPUID + if (__get_cpuid_max (0, 0) == 0) + { +@@ -377,6 +435,8 @@ init_cpu_features (struct cpu_features *cpu_features) + + get_extended_indices (cpu_features); + ++ update_usable (cpu_features); ++ + if (family == 0x06) + { + model += extended_model; +@@ -473,7 +533,7 @@ init_cpu_features (struct cpu_features *cpu_features) + with stepping >= 4) to avoid TSX on kernels that weren't + updated with the latest microcode package (which disables + broken feature by default). */ +- cpu_features->cpuid[index_cpu_RTM].reg_RTM &= ~bit_cpu_RTM; ++ CPU_FEATURE_UNSET (cpu_features, RTM); + break; + } + } +@@ -501,15 +561,15 @@ init_cpu_features (struct cpu_features *cpu_features) + + get_extended_indices (cpu_features); + +- ecx = cpu_features->cpuid[COMMON_CPUID_INDEX_1].ecx; ++ update_usable (cpu_features); + +- if (HAS_ARCH_FEATURE (AVX_Usable)) ++ ecx = cpu_features->features[COMMON_CPUID_INDEX_1].cpuid.ecx; ++ ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX)) + { + /* Since the FMA4 bit is in COMMON_CPUID_INDEX_80000001 and + FMA4 requires AVX, determine if FMA4 is usable here. */ +- if (CPU_FEATURES_CPU_P (cpu_features, FMA4)) +- cpu_features->usable[index_arch_FMA4_Usable] +- |= bit_arch_FMA4_Usable; ++ CPU_FEATURE_SET_USABLE (cpu_features, FMA4); + } + + if (family == 0x15) +@@ -540,13 +600,15 @@ init_cpu_features (struct cpu_features *cpu_features) + + get_extended_indices (cpu_features); + ++ update_usable (cpu_features); ++ + model += extended_model; + if (family == 0x6) + { + if (model == 0xf || model == 0x19) + { +- cpu_features->usable[index_arch_AVX_Usable] +- &= ~(bit_arch_AVX_Usable | bit_arch_AVX2_Usable); ++ CPU_FEATURE_UNSET (cpu_features, AVX); ++ CPU_FEATURE_UNSET (cpu_features, AVX2); + + cpu_features->preferred[index_arch_Slow_SSE4_2] + |= bit_arch_Slow_SSE4_2; +@@ -559,8 +621,8 @@ init_cpu_features (struct cpu_features *cpu_features) + { + if (model == 0x1b) + { +- cpu_features->usable[index_arch_AVX_Usable] +- &= ~(bit_arch_AVX_Usable | bit_arch_AVX2_Usable); ++ CPU_FEATURE_UNSET (cpu_features, AVX); ++ CPU_FEATURE_UNSET (cpu_features, AVX2); + + cpu_features->preferred[index_arch_Slow_SSE4_2] + |= bit_arch_Slow_SSE4_2; +@@ -570,8 +632,8 @@ init_cpu_features (struct cpu_features *cpu_features) + } + else if (model == 0x3b) + { +- cpu_features->usable[index_arch_AVX_Usable] +- &= ~(bit_arch_AVX_Usable | bit_arch_AVX2_Usable); ++ CPU_FEATURE_UNSET (cpu_features, AVX); ++ CPU_FEATURE_UNSET (cpu_features, AVX2); + + cpu_features->preferred[index_arch_AVX_Fast_Unaligned_Load] + &= ~bit_arch_AVX_Fast_Unaligned_Load; +@@ -582,6 +644,7 @@ init_cpu_features (struct cpu_features *cpu_features) + { + kind = arch_kind_other; + get_common_indices (cpu_features, NULL, NULL, NULL, NULL); ++ update_usable (cpu_features); + } + + /* Support i586 if CX8 is available. */ +@@ -628,31 +691,30 @@ no_cpuid: + { + const char *platform = NULL; + +- if (CPU_FEATURES_ARCH_P (cpu_features, AVX512F_Usable) +- && CPU_FEATURES_CPU_P (cpu_features, AVX512CD)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512CD)) + { +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512ER)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512ER)) + { +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512PF)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512PF)) + platform = "xeon_phi"; + } + else + { +- if (CPU_FEATURES_CPU_P (cpu_features, AVX512BW) +- && CPU_FEATURES_CPU_P (cpu_features, AVX512DQ) +- && CPU_FEATURES_CPU_P (cpu_features, AVX512VL)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512DQ) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512VL)) + GLRO(dl_hwcap) |= HWCAP_X86_AVX512_1; + } + } + + if (platform == NULL +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable) +- && CPU_FEATURES_ARCH_P (cpu_features, FMA_Usable) +- && CPU_FEATURES_CPU_P (cpu_features, BMI1) +- && CPU_FEATURES_CPU_P (cpu_features, BMI2) +- && CPU_FEATURES_CPU_P (cpu_features, LZCNT) +- && CPU_FEATURES_CPU_P (cpu_features, MOVBE) +- && CPU_FEATURES_CPU_P (cpu_features, POPCNT)) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && CPU_FEATURE_USABLE_P (cpu_features, FMA) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI1) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2) ++ && CPU_FEATURE_USABLE_P (cpu_features, LZCNT) ++ && CPU_FEATURE_USABLE_P (cpu_features, MOVBE) ++ && CPU_FEATURE_USABLE_P (cpu_features, POPCNT)) + platform = "haswell"; + + if (platform != NULL) +@@ -660,7 +722,7 @@ no_cpuid: + } + #else + GLRO(dl_hwcap) = 0; +- if (CPU_FEATURES_CPU_P (cpu_features, SSE2)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE2)) + GLRO(dl_hwcap) |= HWCAP_X86_SSE2; + + if (CPU_FEATURES_ARCH_P (cpu_features, I686)) +@@ -695,9 +757,9 @@ no_cpuid: + GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK + */ + unsigned int cet_feature = 0; +- if (!HAS_CPU_FEATURE (IBT)) ++ if (!CPU_FEATURE_USABLE (IBT)) + cet_feature |= GNU_PROPERTY_X86_FEATURE_1_IBT; +- if (!HAS_CPU_FEATURE (SHSTK)) ++ if (!CPU_FEATURE_USABLE (SHSTK)) + cet_feature |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; + + if (cet_feature) +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 0f19c64352c4d7f1..21708c028a12dbb2 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -18,15 +18,6 @@ + #ifndef cpu_features_h + #define cpu_features_h + +-enum +-{ +- /* The integer bit array index for the first set of usable feature +- bits. */ +- USABLE_FEATURE_INDEX_1 = 0, +- /* The current maximum size of the feature integer bit array. */ +- USABLE_FEATURE_INDEX_MAX +-}; +- + enum + { + /* The integer bit array index for the first set of preferred feature +@@ -57,6 +48,12 @@ struct cpuid_registers + unsigned int edx; + }; + ++struct cpuid_features ++{ ++ struct cpuid_registers cpuid; ++ struct cpuid_registers usable; ++}; ++ + enum cpu_features_kind + { + arch_kind_unknown = 0, +@@ -78,9 +75,7 @@ struct cpu_features_basic + struct cpu_features + { + struct cpu_features_basic basic; +- unsigned int *usable_p; +- struct cpuid_registers cpuid[COMMON_CPUID_INDEX_MAX]; +- unsigned int usable[USABLE_FEATURE_INDEX_MAX]; ++ struct cpuid_features features[COMMON_CPUID_INDEX_MAX]; + unsigned int preferred[PREFERRED_FEATURE_INDEX_MAX]; + /* The state size for XSAVEC or XSAVE. The type must be unsigned long + int so that we use +@@ -91,7 +86,7 @@ struct cpu_features + unsigned long int xsave_state_size; + /* The full state size for XSAVE when XSAVEC is disabled by + +- GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC_Usable ++ GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC + */ + unsigned int xsave_state_full_size; + /* Data cache size for use in memory and string routines, typically +@@ -114,117 +109,40 @@ extern const struct cpu_features *__get_cpu_features (void) + __attribute__ ((const)); + + /* Only used directly in cpu-features.c. */ +-# define CPU_FEATURES_CPU_P(ptr, name) \ +- ((ptr->cpuid[index_cpu_##name].reg_##name & (bit_cpu_##name)) != 0) +-# define CPU_FEATURES_ARCH_P(ptr, name) \ +- ((ptr->feature_##name[index_arch_##name] & (bit_arch_##name)) != 0) ++#define CPU_FEATURE_CHECK_P(ptr, name, check) \ ++ ((ptr->features[index_cpu_##name].check.reg_##name \ ++ & bit_cpu_##name) != 0) ++#define CPU_FEATURE_SET(ptr, name) \ ++ ptr->features[index_cpu_##name].usable.reg_##name |= bit_cpu_##name; ++#define CPU_FEATURE_UNSET(ptr, name) \ ++ ptr->features[index_cpu_##name].usable.reg_##name &= ~bit_cpu_##name; ++#define CPU_FEATURE_SET_USABLE(ptr, name) \ ++ ptr->features[index_cpu_##name].usable.reg_##name \ ++ |= ptr->features[index_cpu_##name].cpuid.reg_##name & bit_cpu_##name; ++#define CPU_FEATURE_PREFERRED_P(ptr, name) \ ++ ((ptr->preferred[index_arch_##name] & bit_arch_##name) != 0) ++#define CPU_FEATURE_CPU_P(ptr, name) \ ++ CPU_FEATURE_CHECK_P (ptr, name, cpuid) ++#define CPU_FEATURE_USABLE_P(ptr, name) \ ++ CPU_FEATURE_CHECK_P (ptr, name, usable) + + /* HAS_CPU_FEATURE evaluates to true if CPU supports the feature. */ + #define HAS_CPU_FEATURE(name) \ +- CPU_FEATURES_CPU_P (__get_cpu_features (), name) +-/* HAS_ARCH_FEATURE evaluates to true if we may use the feature at +- runtime. */ +-# define HAS_ARCH_FEATURE(name) \ +- CPU_FEATURES_ARCH_P (__get_cpu_features (), name) ++ CPU_FEATURE_CPU_P (__get_cpu_features (), name) + /* CPU_FEATURE_USABLE evaluates to true if the feature is usable. */ + #define CPU_FEATURE_USABLE(name) \ +- HAS_ARCH_FEATURE (name##_Usable) +- +-/* Architecture features. */ +- +-/* USABLE_FEATURE_INDEX_1. */ +-#define bit_arch_AVX_Usable (1u << 0) +-#define bit_arch_AVX2_Usable (1u << 1) +-#define bit_arch_AVX512F_Usable (1u << 2) +-#define bit_arch_AVX512CD_Usable (1u << 3) +-#define bit_arch_AVX512ER_Usable (1u << 4) +-#define bit_arch_AVX512PF_Usable (1u << 5) +-#define bit_arch_AVX512VL_Usable (1u << 6) +-#define bit_arch_AVX512DQ_Usable (1u << 7) +-#define bit_arch_AVX512BW_Usable (1u << 8) +-#define bit_arch_AVX512_4FMAPS_Usable (1u << 9) +-#define bit_arch_AVX512_4VNNIW_Usable (1u << 10) +-#define bit_arch_AVX512_BITALG_Usable (1u << 11) +-#define bit_arch_AVX512_IFMA_Usable (1u << 12) +-#define bit_arch_AVX512_VBMI_Usable (1u << 13) +-#define bit_arch_AVX512_VBMI2_Usable (1u << 14) +-#define bit_arch_AVX512_VNNI_Usable (1u << 15) +-#define bit_arch_AVX512_VPOPCNTDQ_Usable (1u << 16) +-#define bit_arch_FMA_Usable (1u << 17) +-#define bit_arch_FMA4_Usable (1u << 18) +-#define bit_arch_VAES_Usable (1u << 19) +-#define bit_arch_VPCLMULQDQ_Usable (1u << 20) +-#define bit_arch_XOP_Usable (1u << 21) +-#define bit_arch_XSAVEC_Usable (1u << 22) +-#define bit_arch_F16C_Usable (1u << 23) +-#define bit_arch_AVX512_VP2INTERSECT_Usable (1u << 24) +-#define bit_arch_AVX512_BF16_Usable (1u << 25) +-#define bit_arch_PKU_Usable (1u << 26) +-#define bit_arch_AMX_BF16_Usable (1u << 27) +-#define bit_arch_AMX_TILE_Usable (1u << 28) +-#define bit_arch_AMX_INT8_Usable (1u << 29) +- +-#define index_arch_AVX_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX2_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512F_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512CD_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512ER_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512PF_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512VL_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512BW_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512DQ_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512_4FMAPS_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512_4VNNIW_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512_BITALG_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512_IFMA_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512_VBMI_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512_VBMI2_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512_VNNI_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512_VPOPCNTDQ_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_FMA_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_FMA4_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_VAES_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_VPCLMULQDQ_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_XOP_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_XSAVEC_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_F16C_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512_VP2INTERSECT_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AVX512_BF16_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_PKU_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AMX_BF16_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AMX_TILE_Usable USABLE_FEATURE_INDEX_1 +-#define index_arch_AMX_INT8_Usable USABLE_FEATURE_INDEX_1 +- +-#define feature_AVX_Usable usable +-#define feature_AVX2_Usable usable +-#define feature_AVX512F_Usable usable +-#define feature_AVX512CD_Usable usable +-#define feature_AVX512ER_Usable usable +-#define feature_AVX512PF_Usable usable +-#define feature_AVX512VL_Usable usable +-#define feature_AVX512BW_Usable usable +-#define feature_AVX512DQ_Usable usable +-#define feature_AVX512_4FMAPS_Usable usable +-#define feature_AVX512_4VNNIW_Usable usable +-#define feature_AVX512_BITALG_Usable usable +-#define feature_AVX512_IFMA_Usable usable +-#define feature_AVX512_VBMI_Usable usable +-#define feature_AVX512_VBMI2_Usable usable +-#define feature_AVX512_VNNI_Usable usable +-#define feature_AVX512_VPOPCNTDQ_Usable usable +-#define feature_FMA_Usable usable +-#define feature_FMA4_Usable usable +-#define feature_VAES_Usable usable +-#define feature_VPCLMULQDQ_Usable usable +-#define feature_XOP_Usable usable +-#define feature_XSAVEC_Usable usable +-#define feature_F16C_Usable usable +-#define feature_AVX512_VP2INTERSECT_Usable usable +-#define feature_AVX512_BF16_Usable usable +-#define feature_PKU_Usable usable +-#define feature_AMX_BF16_Usable usable +-#define feature_AMX_TILE_Usable usable +-#define feature_AMX_INT8_Usable usable ++ CPU_FEATURE_USABLE_P (__get_cpu_features (), name) ++/* CPU_FEATURE_PREFER evaluates to true if we prefer the feature at ++ runtime. */ ++#define CPU_FEATURE_PREFERRED(name) \ ++ CPU_FEATURE_PREFERRED_P(__get_cpu_features (), name) ++ ++#define CPU_FEATURES_CPU_P(ptr, name) \ ++ CPU_FEATURE_CPU_P (ptr, name) ++#define CPU_FEATURES_ARCH_P(ptr, name) \ ++ CPU_FEATURE_PREFERRED_P (ptr, name) ++#define HAS_ARCH_FEATURE(name) \ ++ CPU_FEATURE_PREFERRED (name) + + /* CPU features. */ + +@@ -247,6 +165,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_CMPXCHG16B (1u << 13) + #define bit_cpu_XTPRUPDCTRL (1u << 14) + #define bit_cpu_PDCM (1u << 15) ++#define bit_cpu_INDEX_1_ECX_16 (1u << 16) + #define bit_cpu_PCID (1u << 17) + #define bit_cpu_DCA (1u << 18) + #define bit_cpu_SSE4_1 (1u << 19) +@@ -261,6 +180,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_AVX (1u << 28) + #define bit_cpu_F16C (1u << 29) + #define bit_cpu_RDRAND (1u << 30) ++#define bit_cpu_INDEX_1_ECX_31 (1u << 31) + + /* EDX. */ + #define bit_cpu_FPU (1u << 0) +@@ -273,6 +193,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_MCE (1u << 7) + #define bit_cpu_CX8 (1u << 8) + #define bit_cpu_APIC (1u << 9) ++#define bit_cpu_INDEX_1_EDX_10 (1u << 10) + #define bit_cpu_SEP (1u << 11) + #define bit_cpu_MTRR (1u << 12) + #define bit_cpu_PGE (1u << 13) +@@ -282,6 +203,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_PSE_36 (1u << 17) + #define bit_cpu_PSN (1u << 18) + #define bit_cpu_CLFSH (1u << 19) ++#define bit_cpu_INDEX_1_EDX_20 (1u << 20) + #define bit_cpu_DS (1u << 21) + #define bit_cpu_ACPI (1u << 22) + #define bit_cpu_MMX (1u << 23) +@@ -291,6 +213,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_SS (1u << 27) + #define bit_cpu_HTT (1u << 28) + #define bit_cpu_TM (1u << 29) ++#define bit_cpu_INDEX_1_EDX_30 (1u << 30) + #define bit_cpu_PBE (1u << 31) + + /* COMMON_CPUID_INDEX_7. */ +@@ -302,12 +225,14 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_BMI1 (1u << 3) + #define bit_cpu_HLE (1u << 4) + #define bit_cpu_AVX2 (1u << 5) ++#define bit_cpu_INDEX_7_EBX_6 (1u << 6) + #define bit_cpu_SMEP (1u << 7) + #define bit_cpu_BMI2 (1u << 8) + #define bit_cpu_ERMS (1u << 9) + #define bit_cpu_INVPCID (1u << 10) + #define bit_cpu_RTM (1u << 11) + #define bit_cpu_PQM (1u << 12) ++#define bit_cpu_DEPR_FPU_CS_DS (1u << 13) + #define bit_cpu_MPX (1u << 14) + #define bit_cpu_PQE (1u << 15) + #define bit_cpu_AVX512F (1u << 16) +@@ -316,6 +241,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_ADX (1u << 19) + #define bit_cpu_SMAP (1u << 20) + #define bit_cpu_AVX512_IFMA (1u << 21) ++#define bit_cpu_INDEX_7_EBX_22 (1u << 22) + #define bit_cpu_CLFLUSHOPT (1u << 23) + #define bit_cpu_CLWB (1u << 24) + #define bit_cpu_TRACE (1u << 25) +@@ -340,9 +266,17 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_VPCLMULQDQ (1u << 10) + #define bit_cpu_AVX512_VNNI (1u << 11) + #define bit_cpu_AVX512_BITALG (1u << 12) ++#define bit_cpu_INDEX_7_ECX_13 (1u << 13) + #define bit_cpu_AVX512_VPOPCNTDQ (1u << 14) ++#define bit_cpu_INDEX_7_ECX_15 (1u << 15) ++#define bit_cpu_INDEX_7_ECX_16 (1u << 16) ++/* Note: Bits 17-21: The value of MAWAU used by the BNDLDX and BNDSTX ++ instructions in 64-bit mode. */ + #define bit_cpu_RDPID (1u << 22) ++#define bit_cpu_INDEX_7_ECX_23 (1u << 23) ++#define bit_cpu_INDEX_7_ECX_24 (1u << 24) + #define bit_cpu_CLDEMOTE (1u << 25) ++#define bit_cpu_INDEX_7_ECX_26 (1u << 26) + #define bit_cpu_MOVDIRI (1u << 27) + #define bit_cpu_MOVDIR64B (1u << 28) + #define bit_cpu_ENQCMD (1u << 29) +@@ -350,17 +284,30 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_PKS (1u << 31) + + /* EDX. */ ++#define bit_cpu_INDEX_7_EDX_0 (1u << 0) ++#define bit_cpu_INDEX_7_EDX_1 (1u << 1) + #define bit_cpu_AVX512_4VNNIW (1u << 2) + #define bit_cpu_AVX512_4FMAPS (1u << 3) + #define bit_cpu_FSRM (1u << 4) ++#define bit_cpu_INDEX_7_EDX_5 (1u << 5) ++#define bit_cpu_INDEX_7_EDX_6 (1u << 6) ++#define bit_cpu_INDEX_7_EDX_7 (1u << 7) + #define bit_cpu_AVX512_VP2INTERSECT (1u << 8) ++#define bit_cpu_INDEX_7_EDX_9 (1u << 9) + #define bit_cpu_MD_CLEAR (1u << 10) ++#define bit_cpu_INDEX_7_EDX_11 (1u << 11) ++#define bit_cpu_INDEX_7_EDX_12 (1u << 12) ++#define bit_cpu_INDEX_7_EDX_13 (1u << 13) + #define bit_cpu_SERIALIZE (1u << 14) + #define bit_cpu_HYBRID (1u << 15) + #define bit_cpu_TSXLDTRK (1u << 16) ++#define bit_cpu_INDEX_7_EDX_17 (1u << 17) + #define bit_cpu_PCONFIG (1u << 18) ++#define bit_cpu_INDEX_7_EDX_19 (1u << 19) + #define bit_cpu_IBT (1u << 20) ++#define bit_cpu_INDEX_7_EDX_21 (1u << 21) + #define bit_cpu_AMX_BF16 (1u << 22) ++#define bit_cpu_INDEX_7_EDX_23 (1u << 23) + #define bit_cpu_AMX_TILE (1u << 24) + #define bit_cpu_AMX_INT8 (1u << 25) + #define bit_cpu_IBRS_IBPB (1u << 26) +@@ -433,6 +380,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_CMPXCHG16B COMMON_CPUID_INDEX_1 + #define index_cpu_XTPRUPDCTRL COMMON_CPUID_INDEX_1 + #define index_cpu_PDCM COMMON_CPUID_INDEX_1 ++#define index_cpu_INDEX_1_ECX_16 COMMON_CPUID_INDEX_1 + #define index_cpu_PCID COMMON_CPUID_INDEX_1 + #define index_cpu_DCA COMMON_CPUID_INDEX_1 + #define index_cpu_SSE4_1 COMMON_CPUID_INDEX_1 +@@ -447,6 +395,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_AVX COMMON_CPUID_INDEX_1 + #define index_cpu_F16C COMMON_CPUID_INDEX_1 + #define index_cpu_RDRAND COMMON_CPUID_INDEX_1 ++#define index_cpu_INDEX_1_ECX_31 COMMON_CPUID_INDEX_1 + + /* ECX. */ + #define index_cpu_FPU COMMON_CPUID_INDEX_1 +@@ -459,6 +408,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_MCE COMMON_CPUID_INDEX_1 + #define index_cpu_CX8 COMMON_CPUID_INDEX_1 + #define index_cpu_APIC COMMON_CPUID_INDEX_1 ++#define index_cpu_INDEX_1_EDX_10 COMMON_CPUID_INDEX_1 + #define index_cpu_SEP COMMON_CPUID_INDEX_1 + #define index_cpu_MTRR COMMON_CPUID_INDEX_1 + #define index_cpu_PGE COMMON_CPUID_INDEX_1 +@@ -468,6 +418,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_PSE_36 COMMON_CPUID_INDEX_1 + #define index_cpu_PSN COMMON_CPUID_INDEX_1 + #define index_cpu_CLFSH COMMON_CPUID_INDEX_1 ++#define index_cpu_INDEX_1_EDX_20 COMMON_CPUID_INDEX_1 + #define index_cpu_DS COMMON_CPUID_INDEX_1 + #define index_cpu_ACPI COMMON_CPUID_INDEX_1 + #define index_cpu_MMX COMMON_CPUID_INDEX_1 +@@ -477,6 +428,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_SS COMMON_CPUID_INDEX_1 + #define index_cpu_HTT COMMON_CPUID_INDEX_1 + #define index_cpu_TM COMMON_CPUID_INDEX_1 ++#define index_cpu_INDEX_1_EDX_30 COMMON_CPUID_INDEX_1 + #define index_cpu_PBE COMMON_CPUID_INDEX_1 + + /* COMMON_CPUID_INDEX_7. */ +@@ -488,12 +440,14 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_BMI1 COMMON_CPUID_INDEX_7 + #define index_cpu_HLE COMMON_CPUID_INDEX_7 + #define index_cpu_AVX2 COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EBX_6 COMMON_CPUID_INDEX_7 + #define index_cpu_SMEP COMMON_CPUID_INDEX_7 + #define index_cpu_BMI2 COMMON_CPUID_INDEX_7 + #define index_cpu_ERMS COMMON_CPUID_INDEX_7 + #define index_cpu_INVPCID COMMON_CPUID_INDEX_7 + #define index_cpu_RTM COMMON_CPUID_INDEX_7 + #define index_cpu_PQM COMMON_CPUID_INDEX_7 ++#define index_cpu_DEPR_FPU_CS_DS COMMON_CPUID_INDEX_7 + #define index_cpu_MPX COMMON_CPUID_INDEX_7 + #define index_cpu_PQE COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512F COMMON_CPUID_INDEX_7 +@@ -502,6 +456,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_ADX COMMON_CPUID_INDEX_7 + #define index_cpu_SMAP COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512_IFMA COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EBX_22 COMMON_CPUID_INDEX_7 + #define index_cpu_CLFLUSHOPT COMMON_CPUID_INDEX_7 + #define index_cpu_CLWB COMMON_CPUID_INDEX_7 + #define index_cpu_TRACE COMMON_CPUID_INDEX_7 +@@ -526,9 +481,15 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_VPCLMULQDQ COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512_VNNI COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512_BITALG COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_ECX_13 COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512_VPOPCNTDQ COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_ECX_15 COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_ECX_16 COMMON_CPUID_INDEX_7 + #define index_cpu_RDPID COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_ECX_23 COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_ECX_24 COMMON_CPUID_INDEX_7 + #define index_cpu_CLDEMOTE COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_ECX_26 COMMON_CPUID_INDEX_7 + #define index_cpu_MOVDIRI COMMON_CPUID_INDEX_7 + #define index_cpu_MOVDIR64B COMMON_CPUID_INDEX_7 + #define index_cpu_ENQCMD COMMON_CPUID_INDEX_7 +@@ -536,17 +497,30 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_PKS COMMON_CPUID_INDEX_7 + + /* EDX. */ ++#define index_cpu_INDEX_7_EDX_0 COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_1 COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512_4VNNIW COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512_4FMAPS COMMON_CPUID_INDEX_7 + #define index_cpu_FSRM COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_5 COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_6 COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_7 COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512_VP2INTERSECT COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_9 COMMON_CPUID_INDEX_7 + #define index_cpu_MD_CLEAR COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_11 COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_12 COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_13 COMMON_CPUID_INDEX_7 + #define index_cpu_SERIALIZE COMMON_CPUID_INDEX_7 + #define index_cpu_HYBRID COMMON_CPUID_INDEX_7 + #define index_cpu_TSXLDTRK COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_17 COMMON_CPUID_INDEX_7 + #define index_cpu_PCONFIG COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_19 COMMON_CPUID_INDEX_7 + #define index_cpu_IBT COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_21 COMMON_CPUID_INDEX_7 + #define index_cpu_AMX_BF16 COMMON_CPUID_INDEX_7 ++#define index_cpu_INDEX_7_EDX_23 COMMON_CPUID_INDEX_7 + #define index_cpu_AMX_TILE COMMON_CPUID_INDEX_7 + #define index_cpu_AMX_INT8 COMMON_CPUID_INDEX_7 + #define index_cpu_IBRS_IBPB COMMON_CPUID_INDEX_7 +@@ -619,6 +593,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_CMPXCHG16B ecx + #define reg_XTPRUPDCTRL ecx + #define reg_PDCM ecx ++#define reg_INDEX_1_ECX_16 ecx + #define reg_PCID ecx + #define reg_DCA ecx + #define reg_SSE4_1 ecx +@@ -633,6 +608,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_AVX ecx + #define reg_F16C ecx + #define reg_RDRAND ecx ++#define reg_INDEX_1_ECX_31 ecx + + /* EDX. */ + #define reg_FPU edx +@@ -645,6 +621,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_MCE edx + #define reg_CX8 edx + #define reg_APIC edx ++#define reg_INDEX_1_EDX_10 edx + #define reg_SEP edx + #define reg_MTRR edx + #define reg_PGE edx +@@ -654,6 +631,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_PSE_36 edx + #define reg_PSN edx + #define reg_CLFSH edx ++#define reg_INDEX_1_EDX_20 edx + #define reg_DS edx + #define reg_ACPI edx + #define reg_MMX edx +@@ -663,6 +641,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_SS edx + #define reg_HTT edx + #define reg_TM edx ++#define reg_INDEX_1_EDX_30 edx + #define reg_PBE edx + + /* COMMON_CPUID_INDEX_7. */ +@@ -675,11 +654,13 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_HLE ebx + #define reg_BMI2 ebx + #define reg_AVX2 ebx ++#define reg_INDEX_7_EBX_6 ebx + #define reg_SMEP ebx + #define reg_ERMS ebx + #define reg_INVPCID ebx + #define reg_RTM ebx + #define reg_PQM ebx ++#define reg_DEPR_FPU_CS_DS ebx + #define reg_MPX ebx + #define reg_PQE ebx + #define reg_AVX512F ebx +@@ -688,6 +669,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_ADX ebx + #define reg_SMAP ebx + #define reg_AVX512_IFMA ebx ++#define reg_INDEX_7_EBX_22 ebx + #define reg_CLFLUSHOPT ebx + #define reg_CLWB ebx + #define reg_TRACE ebx +@@ -712,9 +694,15 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_VPCLMULQDQ ecx + #define reg_AVX512_VNNI ecx + #define reg_AVX512_BITALG ecx ++#define reg_INDEX_7_ECX_13 ecx + #define reg_AVX512_VPOPCNTDQ ecx ++#define reg_INDEX_7_ECX_15 ecx ++#define reg_INDEX_7_ECX_16 ecx + #define reg_RDPID ecx ++#define reg_INDEX_7_ECX_23 ecx ++#define reg_INDEX_7_ECX_24 ecx + #define reg_CLDEMOTE ecx ++#define reg_INDEX_7_ECX_26 ecx + #define reg_MOVDIRI ecx + #define reg_MOVDIR64B ecx + #define reg_ENQCMD ecx +@@ -722,17 +710,30 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_PKS ecx + + /* EDX. */ ++#define reg_INDEX_7_EDX_0 edx ++#define reg_INDEX_7_EDX_1 edx + #define reg_AVX512_4VNNIW edx + #define reg_AVX512_4FMAPS edx + #define reg_FSRM edx ++#define reg_INDEX_7_EDX_5 edx ++#define reg_INDEX_7_EDX_6 edx ++#define reg_INDEX_7_EDX_7 edx + #define reg_AVX512_VP2INTERSECT edx ++#define reg_INDEX_7_EDX_9 edx + #define reg_MD_CLEAR edx ++#define reg_INDEX_7_EDX_11 edx ++#define reg_INDEX_7_EDX_12 edx ++#define reg_INDEX_7_EDX_13 edx + #define reg_SERIALIZE edx + #define reg_HYBRID edx + #define reg_TSXLDTRK edx ++#define reg_INDEX_7_EDX_17 edx + #define reg_PCONFIG edx ++#define reg_INDEX_7_EDX_19 edx + #define reg_IBT edx ++#define reg_INDEX_7_EDX_21 edx + #define reg_AMX_BF16 edx ++#define reg_INDEX_7_EDX_23 edx + #define reg_AMX_TILE edx + #define reg_AMX_INT8 edx + #define reg_IBRS_IBPB edx +@@ -821,23 +822,6 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_arch_MathVec_Prefer_No_AVX512 PREFERRED_FEATURE_INDEX_1 + #define index_arch_Prefer_FSRM PREFERRED_FEATURE_INDEX_1 + +-#define feature_Fast_Rep_String preferred +-#define feature_Fast_Copy_Backward preferred +-#define feature_Slow_BSF preferred +-#define feature_Fast_Unaligned_Load preferred +-#define feature_Prefer_PMINUB_for_stringop preferred +-#define feature_Fast_Unaligned_Copy preferred +-#define feature_I586 preferred +-#define feature_I686 preferred +-#define feature_Slow_SSE4_2 preferred +-#define feature_AVX_Fast_Unaligned_Load preferred +-#define feature_Prefer_MAP_32BIT_EXEC preferred +-#define feature_Prefer_No_VZEROUPPER preferred +-#define feature_Prefer_ERMS preferred +-#define feature_Prefer_No_AVX512 preferred +-#define feature_MathVec_Prefer_No_AVX512 preferred +-#define feature_Prefer_FSRM preferred +- + /* XCR0 Feature flags. */ + #define bit_XMM_state (1u << 1) + #define bit_YMM_state (1u << 2) +@@ -851,8 +835,6 @@ extern const struct cpu_features *__get_cpu_features (void) + /* Unused for x86. */ + # define INIT_ARCH() + # define __get_cpu_features() (&GLRO(dl_x86_cpu_features)) +-# define x86_get_cpuid_registers(i) \ +- (&(GLRO(dl_x86_cpu_features).cpuid[i])) + # endif + + #ifdef __x86_64__ +diff --git a/sysdeps/x86/cpu-tunables.c b/sysdeps/x86/cpu-tunables.c +index 012ae48933055eaa..0728023007a0f423 100644 +--- a/sysdeps/x86/cpu-tunables.c ++++ b/sysdeps/x86/cpu-tunables.c +@@ -43,66 +43,45 @@ extern __typeof (memcmp) DEFAULT_MEMCMP; + _Static_assert (sizeof (#name) - 1 == len, #name " != " #len); \ + if (!DEFAULT_MEMCMP (f, #name, len)) \ + { \ +- cpu_features->cpuid[index_cpu_##name].reg_##name \ +- &= ~bit_cpu_##name; \ ++ CPU_FEATURE_UNSET (cpu_features, name) \ + break; \ + } + +-/* Disable an ARCH feature NAME. We don't enable an ARCH feature which +- isn't available. */ +-# define CHECK_GLIBC_IFUNC_ARCH_OFF(f, cpu_features, name, len) \ ++/* Disable a preferred feature NAME. We don't enable a preferred feature ++ which isn't available. */ ++# define CHECK_GLIBC_IFUNC_PREFERRED_OFF(f, cpu_features, name, len) \ + _Static_assert (sizeof (#name) - 1 == len, #name " != " #len); \ + if (!DEFAULT_MEMCMP (f, #name, len)) \ + { \ +- cpu_features->feature_##name[index_arch_##name] \ ++ cpu_features->preferred[index_arch_##name] \ + &= ~bit_arch_##name; \ + break; \ + } + +-/* Enable/disable an ARCH feature NAME. */ +-# define CHECK_GLIBC_IFUNC_ARCH_BOTH(f, cpu_features, name, disable, \ +- len) \ ++/* Enable/disable a preferred feature NAME. */ ++# define CHECK_GLIBC_IFUNC_PREFERRED_BOTH(f, cpu_features, name, \ ++ disable, len) \ + _Static_assert (sizeof (#name) - 1 == len, #name " != " #len); \ + if (!DEFAULT_MEMCMP (f, #name, len)) \ + { \ + if (disable) \ +- cpu_features->feature_##name[index_arch_##name] \ +- &= ~bit_arch_##name; \ ++ cpu_features->preferred[index_arch_##name] &= ~bit_arch_##name; \ + else \ +- cpu_features->feature_##name[index_arch_##name] \ +- |= bit_arch_##name; \ ++ cpu_features->preferred[index_arch_##name] |= bit_arch_##name; \ + break; \ + } + +-/* Enable/disable an ARCH feature NAME. Enable an ARCH feature only +- if the ARCH feature NEED is also enabled. */ +-# define CHECK_GLIBC_IFUNC_ARCH_NEED_ARCH_BOTH(f, cpu_features, name, \ ++/* Enable/disable a preferred feature NAME. Enable a preferred feature ++ only if the feature NEED is usable. */ ++# define CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH(f, cpu_features, name, \ + need, disable, len) \ + _Static_assert (sizeof (#name) - 1 == len, #name " != " #len); \ + if (!DEFAULT_MEMCMP (f, #name, len)) \ + { \ + if (disable) \ +- cpu_features->feature_##name[index_arch_##name] \ +- &= ~bit_arch_##name; \ +- else if (CPU_FEATURES_ARCH_P (cpu_features, need)) \ +- cpu_features->feature_##name[index_arch_##name] \ +- |= bit_arch_##name; \ +- break; \ +- } +- +-/* Enable/disable an ARCH feature NAME. Enable an ARCH feature only +- if the CPU feature NEED is also enabled. */ +-# define CHECK_GLIBC_IFUNC_ARCH_NEED_CPU_BOTH(f, cpu_features, name, \ +- need, disable, len) \ +- _Static_assert (sizeof (#name) - 1 == len, #name " != " #len); \ +- if (!DEFAULT_MEMCMP (f, #name, len)) \ +- { \ +- if (disable) \ +- cpu_features->feature_##name[index_arch_##name] \ +- &= ~bit_arch_##name; \ +- else if (CPU_FEATURES_CPU_P (cpu_features, need)) \ +- cpu_features->feature_##name[index_arch_##name] \ +- |= bit_arch_##name; \ ++ cpu_features->preferred[index_arch_##name] &= ~bit_arch_##name; \ ++ else if (CPU_FEATURE_USABLE_P (cpu_features, need)) \ ++ cpu_features->preferred[index_arch_##name] |= bit_arch_##name; \ + break; \ + } + +@@ -178,8 +157,8 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp) + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, ERMS, 4); + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, FMA4, 4); + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, SSE2, 4); +- CHECK_GLIBC_IFUNC_ARCH_OFF (n, cpu_features, I586, 4); +- CHECK_GLIBC_IFUNC_ARCH_OFF (n, cpu_features, I686, 4); ++ CHECK_GLIBC_IFUNC_PREFERRED_OFF (n, cpu_features, I586, 4); ++ CHECK_GLIBC_IFUNC_PREFERRED_OFF (n, cpu_features, I686, 4); + } + break; + case 5: +@@ -197,6 +176,13 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp) + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, POPCNT, 6); + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, SSE4_1, 6); + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, SSE4_2, 6); ++ if (!DEFAULT_MEMCMP (n, "XSAVEC", 6)) ++ { ++ /* Update xsave_state_size to XSAVE state size. */ ++ cpu_features->xsave_state_size ++ = cpu_features->xsave_state_full_size; ++ CPU_FEATURE_UNSET (cpu_features, XSAVEC); ++ } + } + break; + case 7: +@@ -216,115 +202,85 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp) + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, AVX512PF, 8); + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, AVX512VL, 8); + } +- CHECK_GLIBC_IFUNC_ARCH_BOTH (n, cpu_features, Slow_BSF, +- disable, 8); +- break; +- case 10: +- if (disable) +- { +- CHECK_GLIBC_IFUNC_ARCH_OFF (n, cpu_features, AVX_Usable, +- 10); +- CHECK_GLIBC_IFUNC_ARCH_OFF (n, cpu_features, FMA_Usable, +- 10); +- } ++ CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n, cpu_features, Slow_BSF, ++ disable, 8); + break; + case 11: +- if (disable) + { +- CHECK_GLIBC_IFUNC_ARCH_OFF (n, cpu_features, AVX2_Usable, +- 11); +- CHECK_GLIBC_IFUNC_ARCH_OFF (n, cpu_features, FMA4_Usable, +- 11); +- } +- CHECK_GLIBC_IFUNC_ARCH_BOTH (n, cpu_features, Prefer_ERMS, +- disable, 11); +- CHECK_GLIBC_IFUNC_ARCH_NEED_CPU_BOTH (n, cpu_features, +- Slow_SSE4_2, SSE4_2, ++ CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n, cpu_features, ++ Prefer_ERMS, + disable, 11); +- CHECK_GLIBC_IFUNC_ARCH_BOTH (n, cpu_features, Prefer_FSRM, +- disable, 11); +- break; +- case 13: +- if (disable) +- { +- /* Update xsave_state_size to XSAVE state size. */ +- cpu_features->xsave_state_size +- = cpu_features->xsave_state_full_size; +- CHECK_GLIBC_IFUNC_ARCH_OFF (n, cpu_features, +- XSAVEC_Usable, 13); +- } +- break; +- case 14: +- if (disable) +- { +- CHECK_GLIBC_IFUNC_ARCH_OFF (n, cpu_features, +- AVX512F_Usable, 14); ++ CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n, cpu_features, ++ Prefer_FSRM, ++ disable, 11); ++ CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH (n, cpu_features, ++ Slow_SSE4_2, ++ SSE4_2, ++ disable, 11); + } + break; + case 15: +- if (disable) + { +- CHECK_GLIBC_IFUNC_ARCH_OFF (n, cpu_features, +- AVX512DQ_Usable, 15); ++ CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n, cpu_features, ++ Fast_Rep_String, ++ disable, 15); + } +- CHECK_GLIBC_IFUNC_ARCH_BOTH (n, cpu_features, Fast_Rep_String, +- disable, 15); + break; + case 16: + { +- CHECK_GLIBC_IFUNC_ARCH_NEED_ARCH_BOTH +- (n, cpu_features, Prefer_No_AVX512, AVX512F_Usable, ++ CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH ++ (n, cpu_features, Prefer_No_AVX512, AVX512F, + disable, 16); + } + break; + case 18: + { +- CHECK_GLIBC_IFUNC_ARCH_BOTH (n, cpu_features, +- Fast_Copy_Backward, disable, +- 18); ++ CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n, cpu_features, ++ Fast_Copy_Backward, ++ disable, 18); + } + break; + case 19: + { +- CHECK_GLIBC_IFUNC_ARCH_BOTH (n, cpu_features, +- Fast_Unaligned_Load, disable, +- 19); +- CHECK_GLIBC_IFUNC_ARCH_BOTH (n, cpu_features, +- Fast_Unaligned_Copy, disable, +- 19); ++ CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n, cpu_features, ++ Fast_Unaligned_Load, ++ disable, 19); ++ CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n, cpu_features, ++ Fast_Unaligned_Copy, ++ disable, 19); + } + break; + case 20: + { +- CHECK_GLIBC_IFUNC_ARCH_NEED_ARCH_BOTH +- (n, cpu_features, Prefer_No_VZEROUPPER, AVX_Usable, +- disable, 20); ++ CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH ++ (n, cpu_features, Prefer_No_VZEROUPPER, AVX, disable, ++ 20); + } + break; + case 21: + { +- CHECK_GLIBC_IFUNC_ARCH_BOTH (n, cpu_features, +- Prefer_MAP_32BIT_EXEC, disable, +- 21); ++ CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n, cpu_features, ++ Prefer_MAP_32BIT_EXEC, ++ disable, 21); + } + break; + case 23: + { +- CHECK_GLIBC_IFUNC_ARCH_NEED_ARCH_BOTH +- (n, cpu_features, AVX_Fast_Unaligned_Load, AVX_Usable, ++ CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH ++ (n, cpu_features, AVX_Fast_Unaligned_Load, AVX, + disable, 23); + } + break; + case 24: + { +- CHECK_GLIBC_IFUNC_ARCH_NEED_ARCH_BOTH +- (n, cpu_features, MathVec_Prefer_No_AVX512, +- AVX512F_Usable, disable, 24); ++ CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH ++ (n, cpu_features, MathVec_Prefer_No_AVX512, AVX512F, ++ disable, 24); + } + break; + case 26: + { +- CHECK_GLIBC_IFUNC_ARCH_NEED_CPU_BOTH ++ CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH + (n, cpu_features, Prefer_PMINUB_for_stringop, SSE2, + disable, 26); + } +diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c +index d481bddc27e5d7cc..11ff0618fae7230f 100644 +--- a/sysdeps/x86/dl-cet.c ++++ b/sysdeps/x86/dl-cet.c +@@ -74,10 +74,10 @@ dl_cet_check (struct link_map *m, const char *program) + + GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK + */ +- enable_ibt &= (HAS_CPU_FEATURE (IBT) ++ enable_ibt &= (CPU_FEATURE_USABLE (IBT) + && (enable_ibt_type == cet_always_on + || (m->l_cet & lc_ibt) != 0)); +- enable_shstk &= (HAS_CPU_FEATURE (SHSTK) ++ enable_shstk &= (CPU_FEATURE_USABLE (SHSTK) + && (enable_shstk_type == cet_always_on + || (m->l_cet & lc_shstk) != 0)); + } +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index c56f309ba0736c0d..85ec9d5a091e2c88 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -137,6 +137,7 @@ do_test (void) + CHECK_CPU_FEATURE (INVPCID); + CHECK_CPU_FEATURE (RTM); + CHECK_CPU_FEATURE (PQM); ++ CHECK_CPU_FEATURE (DEPR_FPU_CS_DS); + CHECK_CPU_FEATURE (MPX); + CHECK_CPU_FEATURE (PQE); + CHECK_CPU_FEATURE (AVX512F); +@@ -218,35 +219,156 @@ do_test (void) + CHECK_CPU_FEATURE (AVX512_BF16); + + printf ("Usable CPU features:\n"); ++ CHECK_CPU_FEATURE_USABLE (SSE3); ++ CHECK_CPU_FEATURE_USABLE (PCLMULQDQ); ++ CHECK_CPU_FEATURE_USABLE (DTES64); ++ CHECK_CPU_FEATURE_USABLE (MONITOR); ++ CHECK_CPU_FEATURE_USABLE (DS_CPL); ++ CHECK_CPU_FEATURE_USABLE (VMX); ++ CHECK_CPU_FEATURE_USABLE (SMX); ++ CHECK_CPU_FEATURE_USABLE (EST); ++ CHECK_CPU_FEATURE_USABLE (TM2); ++ CHECK_CPU_FEATURE_USABLE (SSSE3); ++ CHECK_CPU_FEATURE_USABLE (CNXT_ID); ++ CHECK_CPU_FEATURE_USABLE (SDBG); + CHECK_CPU_FEATURE_USABLE (FMA); ++ CHECK_CPU_FEATURE_USABLE (CMPXCHG16B); ++ CHECK_CPU_FEATURE_USABLE (XTPRUPDCTRL); ++ CHECK_CPU_FEATURE_USABLE (PDCM); ++ CHECK_CPU_FEATURE_USABLE (PCID); ++ CHECK_CPU_FEATURE_USABLE (DCA); ++ CHECK_CPU_FEATURE_USABLE (SSE4_1); ++ CHECK_CPU_FEATURE_USABLE (SSE4_2); ++ CHECK_CPU_FEATURE_USABLE (X2APIC); ++ CHECK_CPU_FEATURE_USABLE (MOVBE); ++ CHECK_CPU_FEATURE_USABLE (POPCNT); ++ CHECK_CPU_FEATURE_USABLE (TSC_DEADLINE); ++ CHECK_CPU_FEATURE_USABLE (AES); ++ CHECK_CPU_FEATURE_USABLE (XSAVE); ++ CHECK_CPU_FEATURE_USABLE (OSXSAVE); + CHECK_CPU_FEATURE_USABLE (AVX); + CHECK_CPU_FEATURE_USABLE (F16C); ++ CHECK_CPU_FEATURE_USABLE (RDRAND); ++ CHECK_CPU_FEATURE_USABLE (FPU); ++ CHECK_CPU_FEATURE_USABLE (VME); ++ CHECK_CPU_FEATURE_USABLE (DE); ++ CHECK_CPU_FEATURE_USABLE (PSE); ++ CHECK_CPU_FEATURE_USABLE (TSC); ++ CHECK_CPU_FEATURE_USABLE (MSR); ++ CHECK_CPU_FEATURE_USABLE (PAE); ++ CHECK_CPU_FEATURE_USABLE (MCE); ++ CHECK_CPU_FEATURE_USABLE (CX8); ++ CHECK_CPU_FEATURE_USABLE (APIC); ++ CHECK_CPU_FEATURE_USABLE (SEP); ++ CHECK_CPU_FEATURE_USABLE (MTRR); ++ CHECK_CPU_FEATURE_USABLE (PGE); ++ CHECK_CPU_FEATURE_USABLE (MCA); ++ CHECK_CPU_FEATURE_USABLE (CMOV); ++ CHECK_CPU_FEATURE_USABLE (PAT); ++ CHECK_CPU_FEATURE_USABLE (PSE_36); ++ CHECK_CPU_FEATURE_USABLE (PSN); ++ CHECK_CPU_FEATURE_USABLE (CLFSH); ++ CHECK_CPU_FEATURE_USABLE (DS); ++ CHECK_CPU_FEATURE_USABLE (ACPI); ++ CHECK_CPU_FEATURE_USABLE (MMX); ++ CHECK_CPU_FEATURE_USABLE (FXSR); ++ CHECK_CPU_FEATURE_USABLE (SSE); ++ CHECK_CPU_FEATURE_USABLE (SSE2); ++ CHECK_CPU_FEATURE_USABLE (SS); ++ CHECK_CPU_FEATURE_USABLE (HTT); ++ CHECK_CPU_FEATURE_USABLE (TM); ++ CHECK_CPU_FEATURE_USABLE (PBE); ++ CHECK_CPU_FEATURE_USABLE (FSGSBASE); ++ CHECK_CPU_FEATURE_USABLE (TSC_ADJUST); ++ CHECK_CPU_FEATURE_USABLE (SGX); ++ CHECK_CPU_FEATURE_USABLE (BMI1); ++ CHECK_CPU_FEATURE_USABLE (HLE); + CHECK_CPU_FEATURE_USABLE (AVX2); ++ CHECK_CPU_FEATURE_USABLE (SMEP); ++ CHECK_CPU_FEATURE_USABLE (BMI2); ++ CHECK_CPU_FEATURE_USABLE (ERMS); ++ CHECK_CPU_FEATURE_USABLE (INVPCID); ++ CHECK_CPU_FEATURE_USABLE (RTM); ++ CHECK_CPU_FEATURE_USABLE (PQM); ++ CHECK_CPU_FEATURE_USABLE (DEPR_FPU_CS_DS); ++ CHECK_CPU_FEATURE_USABLE (MPX); ++ CHECK_CPU_FEATURE_USABLE (PQE); + CHECK_CPU_FEATURE_USABLE (AVX512F); + CHECK_CPU_FEATURE_USABLE (AVX512DQ); ++ CHECK_CPU_FEATURE_USABLE (RDSEED); ++ CHECK_CPU_FEATURE_USABLE (ADX); ++ CHECK_CPU_FEATURE_USABLE (SMAP); + CHECK_CPU_FEATURE_USABLE (AVX512_IFMA); ++ CHECK_CPU_FEATURE_USABLE (CLFLUSHOPT); ++ CHECK_CPU_FEATURE_USABLE (CLWB); ++ CHECK_CPU_FEATURE_USABLE (TRACE); + CHECK_CPU_FEATURE_USABLE (AVX512PF); + CHECK_CPU_FEATURE_USABLE (AVX512ER); + CHECK_CPU_FEATURE_USABLE (AVX512CD); ++ CHECK_CPU_FEATURE_USABLE (SHA); + CHECK_CPU_FEATURE_USABLE (AVX512BW); + CHECK_CPU_FEATURE_USABLE (AVX512VL); ++ CHECK_CPU_FEATURE_USABLE (PREFETCHWT1); + CHECK_CPU_FEATURE_USABLE (AVX512_VBMI); ++ CHECK_CPU_FEATURE_USABLE (UMIP); + CHECK_CPU_FEATURE_USABLE (PKU); ++ CHECK_CPU_FEATURE_USABLE (OSPKE); ++ CHECK_CPU_FEATURE_USABLE (WAITPKG); + CHECK_CPU_FEATURE_USABLE (AVX512_VBMI2); ++ CHECK_CPU_FEATURE_USABLE (SHSTK); ++ CHECK_CPU_FEATURE_USABLE (GFNI); + CHECK_CPU_FEATURE_USABLE (VAES); + CHECK_CPU_FEATURE_USABLE (VPCLMULQDQ); + CHECK_CPU_FEATURE_USABLE (AVX512_VNNI); + CHECK_CPU_FEATURE_USABLE (AVX512_BITALG); + CHECK_CPU_FEATURE_USABLE (AVX512_VPOPCNTDQ); ++ CHECK_CPU_FEATURE_USABLE (RDPID); ++ CHECK_CPU_FEATURE_USABLE (CLDEMOTE); ++ CHECK_CPU_FEATURE_USABLE (MOVDIRI); ++ CHECK_CPU_FEATURE_USABLE (MOVDIR64B); ++ CHECK_CPU_FEATURE_USABLE (ENQCMD); ++ CHECK_CPU_FEATURE_USABLE (SGX_LC); ++ CHECK_CPU_FEATURE_USABLE (PKS); + CHECK_CPU_FEATURE_USABLE (AVX512_4VNNIW); + CHECK_CPU_FEATURE_USABLE (AVX512_4FMAPS); ++ CHECK_CPU_FEATURE_USABLE (FSRM); + CHECK_CPU_FEATURE_USABLE (AVX512_VP2INTERSECT); ++ CHECK_CPU_FEATURE_USABLE (MD_CLEAR); ++ CHECK_CPU_FEATURE_USABLE (SERIALIZE); ++ CHECK_CPU_FEATURE_USABLE (HYBRID); ++ CHECK_CPU_FEATURE_USABLE (TSXLDTRK); ++ CHECK_CPU_FEATURE_USABLE (PCONFIG); ++ CHECK_CPU_FEATURE_USABLE (IBT); + CHECK_CPU_FEATURE_USABLE (AMX_BF16); + CHECK_CPU_FEATURE_USABLE (AMX_TILE); + CHECK_CPU_FEATURE_USABLE (AMX_INT8); ++ CHECK_CPU_FEATURE_USABLE (IBRS_IBPB); ++ CHECK_CPU_FEATURE_USABLE (STIBP); ++ CHECK_CPU_FEATURE_USABLE (L1D_FLUSH); ++ CHECK_CPU_FEATURE_USABLE (ARCH_CAPABILITIES); ++ CHECK_CPU_FEATURE_USABLE (CORE_CAPABILITIES); ++ CHECK_CPU_FEATURE_USABLE (SSBD); ++ CHECK_CPU_FEATURE_USABLE (LAHF64_SAHF64); ++ CHECK_CPU_FEATURE_USABLE (SVM); ++ CHECK_CPU_FEATURE_USABLE (LZCNT); ++ CHECK_CPU_FEATURE_USABLE (SSE4A); ++ CHECK_CPU_FEATURE_USABLE (PREFETCHW); + CHECK_CPU_FEATURE_USABLE (XOP); ++ CHECK_CPU_FEATURE_USABLE (LWP); + CHECK_CPU_FEATURE_USABLE (FMA4); ++ CHECK_CPU_FEATURE_USABLE (TBM); ++ CHECK_CPU_FEATURE_USABLE (SYSCALL_SYSRET); ++ CHECK_CPU_FEATURE_USABLE (NX); ++ CHECK_CPU_FEATURE_USABLE (PAGE1GB); ++ CHECK_CPU_FEATURE_USABLE (RDTSCP); ++ CHECK_CPU_FEATURE_USABLE (LM); ++ CHECK_CPU_FEATURE_USABLE (XSAVEOPT); + CHECK_CPU_FEATURE_USABLE (XSAVEC); ++ CHECK_CPU_FEATURE_USABLE (XGETBV_ECX_1); ++ CHECK_CPU_FEATURE_USABLE (XSAVES); ++ CHECK_CPU_FEATURE_USABLE (XFD); ++ CHECK_CPU_FEATURE_USABLE (INVARIANT_TSC); ++ CHECK_CPU_FEATURE_USABLE (WBNOINVD); + CHECK_CPU_FEATURE_USABLE (AVX512_BF16); + + return 0; +diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile +index e3bb45d78811d70f..42b97c5cc73892cc 100644 +--- a/sysdeps/x86_64/Makefile ++++ b/sysdeps/x86_64/Makefile +@@ -57,7 +57,7 @@ modules-names += x86_64/tst-x86_64mod-1 + LDFLAGS-tst-x86_64mod-1.so = -Wl,-soname,tst-x86_64mod-1.so + ifneq (no,$(have-tunables)) + # Test the state size for XSAVE when XSAVEC is disabled. +-tst-x86_64-1-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC_Usable ++tst-x86_64-1-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC + endif + + $(objpfx)tst-x86_64-1: $(objpfx)x86_64/tst-x86_64mod-1.so +@@ -71,10 +71,10 @@ CFLAGS-tst-platformmod-2.c = -mno-avx + LDFLAGS-tst-platformmod-2.so = -Wl,-soname,tst-platformmod-2.so + $(objpfx)tst-platform-1: $(objpfx)tst-platformmod-1.so + $(objpfx)tst-platform-1.out: $(objpfx)x86_64/tst-platformmod-2.so +-# Turn off AVX512F_Usable and AVX2_Usable so that GLRO(dl_platform) is ++# Turn off AVX512F and AVX2 so that GLRO(dl_platform) is + # always set to x86_64. + tst-platform-1-ENV = LD_PRELOAD=$(objpfx)\$$PLATFORM/tst-platformmod-2.so \ +- GLIBC_TUNABLES=glibc.cpu.hwcaps=-AVX512F_Usable,-AVX2_Usable ++ GLIBC_TUNABLES=glibc.cpu.hwcaps=-AVX512F,-AVX2 + endif + + tests += tst-audit3 tst-audit4 tst-audit5 tst-audit6 tst-audit7 \ +diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h +index 23afb3c05dbe17d6..d58298d787ef352c 100644 +--- a/sysdeps/x86_64/dl-machine.h ++++ b/sysdeps/x86_64/dl-machine.h +@@ -99,9 +99,9 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) + end in this function. */ + if (__glibc_unlikely (profile)) + { +- if (HAS_ARCH_FEATURE (AVX512F_Usable)) ++ if (CPU_FEATURE_USABLE (AVX512F)) + *(ElfW(Addr) *) (got + 2) = (ElfW(Addr)) &_dl_runtime_profile_avx512; +- else if (HAS_ARCH_FEATURE (AVX_Usable)) ++ else if (CPU_FEATURE_USABLE (AVX)) + *(ElfW(Addr) *) (got + 2) = (ElfW(Addr)) &_dl_runtime_profile_avx; + else + *(ElfW(Addr) *) (got + 2) = (ElfW(Addr)) &_dl_runtime_profile_sse; +@@ -119,7 +119,7 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) + the resolved address. */ + if (GLRO(dl_x86_cpu_features).xsave_state_size != 0) + *(ElfW(Addr) *) (got + 2) +- = (HAS_ARCH_FEATURE (XSAVEC_Usable) ++ = (CPU_FEATURE_USABLE (XSAVEC) + ? (ElfW(Addr)) &_dl_runtime_resolve_xsavec + : (ElfW(Addr)) &_dl_runtime_resolve_xsave); + else +diff --git a/sysdeps/x86_64/fpu/math-tests-arch.h b/sysdeps/x86_64/fpu/math-tests-arch.h +index a5df133292ce39b0..61955d70863321fd 100644 +--- a/sysdeps/x86_64/fpu/math-tests-arch.h ++++ b/sysdeps/x86_64/fpu/math-tests-arch.h +@@ -24,7 +24,7 @@ + # define CHECK_ARCH_EXT \ + do \ + { \ +- if (!HAS_ARCH_FEATURE (AVX_Usable)) return; \ ++ if (!CPU_FEATURE_USABLE (AVX)) return; \ + } \ + while (0) + +@@ -34,7 +34,7 @@ + # define CHECK_ARCH_EXT \ + do \ + { \ +- if (!HAS_ARCH_FEATURE (AVX2_Usable)) return; \ ++ if (!CPU_FEATURE_USABLE (AVX2)) return; \ + } \ + while (0) + +@@ -44,7 +44,7 @@ + # define CHECK_ARCH_EXT \ + do \ + { \ +- if (!HAS_ARCH_FEATURE (AVX512F_Usable)) return; \ ++ if (!CPU_FEATURE_USABLE (AVX512F)) return; \ + } \ + while (0) + +diff --git a/sysdeps/x86_64/fpu/multiarch/ifunc-avx-fma4.h b/sysdeps/x86_64/fpu/multiarch/ifunc-avx-fma4.h +index a5f9375afc683663..399ed90362f476b7 100644 +--- a/sysdeps/x86_64/fpu/multiarch/ifunc-avx-fma4.h ++++ b/sysdeps/x86_64/fpu/multiarch/ifunc-avx-fma4.h +@@ -29,14 +29,14 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_ARCH_P (cpu_features, FMA_Usable) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, FMA) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2)) + return OPTIMIZE (fma); + +- if (CPU_FEATURES_ARCH_P (cpu_features, FMA4_Usable)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, FMA4)) + return OPTIMIZE (fma4); + +- if (CPU_FEATURES_ARCH_P (cpu_features, AVX_Usable)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX)) + return OPTIMIZE (avx); + + return OPTIMIZE (sse2); +diff --git a/sysdeps/x86_64/fpu/multiarch/ifunc-fma.h b/sysdeps/x86_64/fpu/multiarch/ifunc-fma.h +index 63a8cd221fb34e28..c6717d65dfd160e7 100644 +--- a/sysdeps/x86_64/fpu/multiarch/ifunc-fma.h ++++ b/sysdeps/x86_64/fpu/multiarch/ifunc-fma.h +@@ -26,8 +26,8 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_ARCH_P (cpu_features, FMA_Usable) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, FMA) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2)) + return OPTIMIZE (fma); + + return OPTIMIZE (sse2); +diff --git a/sysdeps/x86_64/fpu/multiarch/ifunc-fma4.h b/sysdeps/x86_64/fpu/multiarch/ifunc-fma4.h +index a2526a2ee0e55e18..76c677198dac5cb0 100644 +--- a/sysdeps/x86_64/fpu/multiarch/ifunc-fma4.h ++++ b/sysdeps/x86_64/fpu/multiarch/ifunc-fma4.h +@@ -28,11 +28,11 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_ARCH_P (cpu_features, FMA_Usable) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, FMA) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2)) + return OPTIMIZE (fma); + +- if (CPU_FEATURES_ARCH_P (cpu_features, FMA4_Usable)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, FMA)) + return OPTIMIZE (fma4); + + return OPTIMIZE (sse2); +diff --git a/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-avx2.h b/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-avx2.h +index bd2d32e4186c11e3..d84d82a3a22f0e86 100644 +--- a/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-avx2.h ++++ b/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-avx2.h +@@ -31,8 +31,8 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_ARCH_P (cpu_features, FMA_Usable) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, FMA) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2)) + return OPTIMIZE (avx2); + + return OPTIMIZE (sse_wrapper); +diff --git a/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-avx512.h b/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-avx512.h +index 174e462cfbcfa0a5..a2d9972e5a02b87c 100644 +--- a/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-avx512.h ++++ b/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-avx512.h +@@ -34,10 +34,10 @@ IFUNC_SELECTOR (void) + + if (!CPU_FEATURES_ARCH_P (cpu_features, MathVec_Prefer_No_AVX512)) + { +- if (CPU_FEATURES_ARCH_P (cpu_features, AVX512DQ_Usable)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512DQ)) + return OPTIMIZE (skx); + +- if (CPU_FEATURES_ARCH_P (cpu_features, AVX512F_Usable)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F)) + return OPTIMIZE (knl); + } + +diff --git a/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-sse4_1.h b/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-sse4_1.h +index c1e70ebfc1b424e6..64d03f6cb1caa9b7 100644 +--- a/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-sse4_1.h ++++ b/sysdeps/x86_64/fpu/multiarch/ifunc-mathvec-sse4_1.h +@@ -31,7 +31,7 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE4_1)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_1)) + return OPTIMIZE (sse4); + + return OPTIMIZE (sse2); +diff --git a/sysdeps/x86_64/fpu/multiarch/ifunc-sse4_1.h b/sysdeps/x86_64/fpu/multiarch/ifunc-sse4_1.h +index a8710ba80226f13f..81bca1c9ecde9fb7 100644 +--- a/sysdeps/x86_64/fpu/multiarch/ifunc-sse4_1.h ++++ b/sysdeps/x86_64/fpu/multiarch/ifunc-sse4_1.h +@@ -26,7 +26,7 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE4_1)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_1)) + return OPTIMIZE (sse41); + + return OPTIMIZE (c); +diff --git a/sysdeps/x86_64/fpu/multiarch/s_fma.c b/sysdeps/x86_64/fpu/multiarch/s_fma.c +index 875c76d3727e6d3c..9ea8d368d08220a9 100644 +--- a/sysdeps/x86_64/fpu/multiarch/s_fma.c ++++ b/sysdeps/x86_64/fpu/multiarch/s_fma.c +@@ -41,8 +41,8 @@ __fma_fma4 (double x, double y, double z) + } + + +-libm_ifunc (__fma, HAS_ARCH_FEATURE (FMA_Usable) +- ? __fma_fma3 : (HAS_ARCH_FEATURE (FMA4_Usable) ++libm_ifunc (__fma, CPU_FEATURE_USABLE (FMA) ++ ? __fma_fma3 : (CPU_FEATURE_USABLE (FMA4) + ? __fma_fma4 : __fma_sse2)); + libm_alias_double (__fma, fma) + +diff --git a/sysdeps/x86_64/fpu/multiarch/s_fmaf.c b/sysdeps/x86_64/fpu/multiarch/s_fmaf.c +index 5f4c2ec0be15c2dc..33e64ef8d1a03269 100644 +--- a/sysdeps/x86_64/fpu/multiarch/s_fmaf.c ++++ b/sysdeps/x86_64/fpu/multiarch/s_fmaf.c +@@ -40,8 +40,8 @@ __fmaf_fma4 (float x, float y, float z) + } + + +-libm_ifunc (__fmaf, HAS_ARCH_FEATURE (FMA_Usable) +- ? __fmaf_fma3 : (HAS_ARCH_FEATURE (FMA4_Usable) ++libm_ifunc (__fmaf, CPU_FEATURE_USABLE (FMA) ++ ? __fmaf_fma3 : (CPU_FEATURE_USABLE (FMA4) + ? __fmaf_fma4 : __fmaf_sse2)); + libm_alias_float (__fma, fma) + +diff --git a/sysdeps/x86_64/multiarch/ifunc-avx2.h b/sysdeps/x86_64/multiarch/ifunc-avx2.h +index 9cab837642b7af21..5c88640a2d901ec6 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-avx2.h ++++ b/sysdeps/x86_64/multiarch/ifunc-avx2.h +@@ -28,7 +28,7 @@ IFUNC_SELECTOR (void) + const struct cpu_features* cpu_features = __get_cpu_features (); + + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + return OPTIMIZE (avx2); + +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index 8b55bb6954000cc2..fe13505ca1ac7ef0 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -41,19 +41,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/memchr.c. */ + IFUNC_IMPL (i, name, memchr, + IFUNC_IMPL_ADD (array, i, memchr, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __memchr_avx2) + IFUNC_IMPL_ADD (array, i, memchr, 1, __memchr_sse2)) + + /* Support sysdeps/x86_64/multiarch/memcmp.c. */ + IFUNC_IMPL (i, name, memcmp, + IFUNC_IMPL_ADD (array, i, memcmp, +- (HAS_ARCH_FEATURE (AVX2_Usable) +- && HAS_CPU_FEATURE (MOVBE)), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (MOVBE)), + __memcmp_avx2_movbe) +- IFUNC_IMPL_ADD (array, i, memcmp, HAS_CPU_FEATURE (SSE4_1), ++ IFUNC_IMPL_ADD (array, i, memcmp, CPU_FEATURE_USABLE (SSE4_1), + __memcmp_sse4_1) +- IFUNC_IMPL_ADD (array, i, memcmp, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, memcmp, CPU_FEATURE_USABLE (SSSE3), + __memcmp_ssse3) + IFUNC_IMPL_ADD (array, i, memcmp, 1, __memcmp_sse2)) + +@@ -61,25 +61,25 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/memmove_chk.c. */ + IFUNC_IMPL (i, name, __memmove_chk, + IFUNC_IMPL_ADD (array, i, __memmove_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memmove_chk_avx512_no_vzeroupper) + IFUNC_IMPL_ADD (array, i, __memmove_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memmove_chk_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, __memmove_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memmove_chk_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memmove_chk, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __memmove_chk_avx_unaligned) + IFUNC_IMPL_ADD (array, i, __memmove_chk, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __memmove_chk_avx_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memmove_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __memmove_chk_ssse3_back) + IFUNC_IMPL_ADD (array, i, __memmove_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __memmove_chk_ssse3) + IFUNC_IMPL_ADD (array, i, __memmove_chk, 1, + __memmove_chk_sse2_unaligned) +@@ -92,23 +92,23 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/memmove.c. */ + IFUNC_IMPL (i, name, memmove, + IFUNC_IMPL_ADD (array, i, memmove, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __memmove_avx_unaligned) + IFUNC_IMPL_ADD (array, i, memmove, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __memmove_avx_unaligned_erms) + IFUNC_IMPL_ADD (array, i, memmove, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memmove_avx512_no_vzeroupper) + IFUNC_IMPL_ADD (array, i, memmove, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memmove_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, memmove, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memmove_avx512_unaligned_erms) +- IFUNC_IMPL_ADD (array, i, memmove, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, memmove, CPU_FEATURE_USABLE (SSSE3), + __memmove_ssse3_back) +- IFUNC_IMPL_ADD (array, i, memmove, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, memmove, CPU_FEATURE_USABLE (SSSE3), + __memmove_ssse3) + IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_erms) + IFUNC_IMPL_ADD (array, i, memmove, 1, +@@ -119,7 +119,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/memrchr.c. */ + IFUNC_IMPL (i, name, memrchr, + IFUNC_IMPL_ADD (array, i, memrchr, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __memrchr_avx2) + IFUNC_IMPL_ADD (array, i, memrchr, 1, __memrchr_sse2)) + +@@ -133,19 +133,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, __memset_chk, 1, + __memset_chk_sse2_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memset_chk, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __memset_chk_avx2_unaligned) + IFUNC_IMPL_ADD (array, i, __memset_chk, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __memset_chk_avx2_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memset_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memset_chk_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memset_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memset_chk_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, __memset_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memset_chk_avx512_no_vzeroupper) + ) + #endif +@@ -158,48 +158,48 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __memset_sse2_unaligned_erms) + IFUNC_IMPL_ADD (array, i, memset, 1, __memset_erms) + IFUNC_IMPL_ADD (array, i, memset, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __memset_avx2_unaligned) + IFUNC_IMPL_ADD (array, i, memset, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __memset_avx2_unaligned_erms) + IFUNC_IMPL_ADD (array, i, memset, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memset_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, memset, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memset_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, memset, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memset_avx512_no_vzeroupper) + ) + + /* Support sysdeps/x86_64/multiarch/rawmemchr.c. */ + IFUNC_IMPL (i, name, rawmemchr, + IFUNC_IMPL_ADD (array, i, rawmemchr, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __rawmemchr_avx2) + IFUNC_IMPL_ADD (array, i, rawmemchr, 1, __rawmemchr_sse2)) + + /* Support sysdeps/x86_64/multiarch/strlen.c. */ + IFUNC_IMPL (i, name, strlen, + IFUNC_IMPL_ADD (array, i, strlen, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __strlen_avx2) + IFUNC_IMPL_ADD (array, i, strlen, 1, __strlen_sse2)) + + /* Support sysdeps/x86_64/multiarch/strnlen.c. */ + IFUNC_IMPL (i, name, strnlen, + IFUNC_IMPL_ADD (array, i, strnlen, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __strnlen_avx2) + IFUNC_IMPL_ADD (array, i, strnlen, 1, __strnlen_sse2)) + + /* Support sysdeps/x86_64/multiarch/stpncpy.c. */ + IFUNC_IMPL (i, name, stpncpy, +- IFUNC_IMPL_ADD (array, i, stpncpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, stpncpy, CPU_FEATURE_USABLE (SSSE3), + __stpncpy_ssse3) +- IFUNC_IMPL_ADD (array, i, stpncpy, HAS_ARCH_FEATURE (AVX2_Usable), ++ IFUNC_IMPL_ADD (array, i, stpncpy, CPU_FEATURE_USABLE (AVX2), + __stpncpy_avx2) + IFUNC_IMPL_ADD (array, i, stpncpy, 1, + __stpncpy_sse2_unaligned) +@@ -207,9 +207,9 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/x86_64/multiarch/stpcpy.c. */ + IFUNC_IMPL (i, name, stpcpy, +- IFUNC_IMPL_ADD (array, i, stpcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, stpcpy, CPU_FEATURE_USABLE (SSSE3), + __stpcpy_ssse3) +- IFUNC_IMPL_ADD (array, i, stpcpy, HAS_ARCH_FEATURE (AVX2_Usable), ++ IFUNC_IMPL_ADD (array, i, stpcpy, CPU_FEATURE_USABLE (AVX2), + __stpcpy_avx2) + IFUNC_IMPL_ADD (array, i, stpcpy, 1, __stpcpy_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, stpcpy, 1, __stpcpy_sse2)) +@@ -217,35 +217,35 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/strcasecmp_l.c. */ + IFUNC_IMPL (i, name, strcasecmp, + IFUNC_IMPL_ADD (array, i, strcasecmp, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __strcasecmp_avx) + IFUNC_IMPL_ADD (array, i, strcasecmp, +- HAS_CPU_FEATURE (SSE4_2), ++ CPU_FEATURE_USABLE (SSE4_2), + __strcasecmp_sse42) + IFUNC_IMPL_ADD (array, i, strcasecmp, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __strcasecmp_ssse3) + IFUNC_IMPL_ADD (array, i, strcasecmp, 1, __strcasecmp_sse2)) + + /* Support sysdeps/x86_64/multiarch/strcasecmp_l.c. */ + IFUNC_IMPL (i, name, strcasecmp_l, + IFUNC_IMPL_ADD (array, i, strcasecmp_l, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __strcasecmp_l_avx) + IFUNC_IMPL_ADD (array, i, strcasecmp_l, +- HAS_CPU_FEATURE (SSE4_2), ++ CPU_FEATURE_USABLE (SSE4_2), + __strcasecmp_l_sse42) + IFUNC_IMPL_ADD (array, i, strcasecmp_l, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __strcasecmp_l_ssse3) + IFUNC_IMPL_ADD (array, i, strcasecmp_l, 1, + __strcasecmp_l_sse2)) + + /* Support sysdeps/x86_64/multiarch/strcat.c. */ + IFUNC_IMPL (i, name, strcat, +- IFUNC_IMPL_ADD (array, i, strcat, HAS_ARCH_FEATURE (AVX2_Usable), ++ IFUNC_IMPL_ADD (array, i, strcat, CPU_FEATURE_USABLE (AVX2), + __strcat_avx2) +- IFUNC_IMPL_ADD (array, i, strcat, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strcat, CPU_FEATURE_USABLE (SSSE3), + __strcat_ssse3) + IFUNC_IMPL_ADD (array, i, strcat, 1, __strcat_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, strcat, 1, __strcat_sse2)) +@@ -253,7 +253,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/strchr.c. */ + IFUNC_IMPL (i, name, strchr, + IFUNC_IMPL_ADD (array, i, strchr, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __strchr_avx2) + IFUNC_IMPL_ADD (array, i, strchr, 1, __strchr_sse2_no_bsf) + IFUNC_IMPL_ADD (array, i, strchr, 1, __strchr_sse2)) +@@ -261,54 +261,54 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/strchrnul.c. */ + IFUNC_IMPL (i, name, strchrnul, + IFUNC_IMPL_ADD (array, i, strchrnul, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __strchrnul_avx2) + IFUNC_IMPL_ADD (array, i, strchrnul, 1, __strchrnul_sse2)) + + /* Support sysdeps/x86_64/multiarch/strrchr.c. */ + IFUNC_IMPL (i, name, strrchr, + IFUNC_IMPL_ADD (array, i, strrchr, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __strrchr_avx2) + IFUNC_IMPL_ADD (array, i, strrchr, 1, __strrchr_sse2)) + + /* Support sysdeps/x86_64/multiarch/strcmp.c. */ + IFUNC_IMPL (i, name, strcmp, + IFUNC_IMPL_ADD (array, i, strcmp, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __strcmp_avx2) +- IFUNC_IMPL_ADD (array, i, strcmp, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, strcmp, CPU_FEATURE_USABLE (SSE4_2), + __strcmp_sse42) +- IFUNC_IMPL_ADD (array, i, strcmp, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strcmp, CPU_FEATURE_USABLE (SSSE3), + __strcmp_ssse3) + IFUNC_IMPL_ADD (array, i, strcmp, 1, __strcmp_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, strcmp, 1, __strcmp_sse2)) + + /* Support sysdeps/x86_64/multiarch/strcpy.c. */ + IFUNC_IMPL (i, name, strcpy, +- IFUNC_IMPL_ADD (array, i, strcpy, HAS_ARCH_FEATURE (AVX2_Usable), ++ IFUNC_IMPL_ADD (array, i, strcpy, CPU_FEATURE_USABLE (AVX2), + __strcpy_avx2) +- IFUNC_IMPL_ADD (array, i, strcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strcpy, CPU_FEATURE_USABLE (SSSE3), + __strcpy_ssse3) + IFUNC_IMPL_ADD (array, i, strcpy, 1, __strcpy_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, strcpy, 1, __strcpy_sse2)) + + /* Support sysdeps/x86_64/multiarch/strcspn.c. */ + IFUNC_IMPL (i, name, strcspn, +- IFUNC_IMPL_ADD (array, i, strcspn, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, strcspn, CPU_FEATURE_USABLE (SSE4_2), + __strcspn_sse42) + IFUNC_IMPL_ADD (array, i, strcspn, 1, __strcspn_sse2)) + + /* Support sysdeps/x86_64/multiarch/strncase_l.c. */ + IFUNC_IMPL (i, name, strncasecmp, + IFUNC_IMPL_ADD (array, i, strncasecmp, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __strncasecmp_avx) + IFUNC_IMPL_ADD (array, i, strncasecmp, +- HAS_CPU_FEATURE (SSE4_2), ++ CPU_FEATURE_USABLE (SSE4_2), + __strncasecmp_sse42) + IFUNC_IMPL_ADD (array, i, strncasecmp, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __strncasecmp_ssse3) + IFUNC_IMPL_ADD (array, i, strncasecmp, 1, + __strncasecmp_sse2)) +@@ -316,22 +316,22 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/strncase_l.c. */ + IFUNC_IMPL (i, name, strncasecmp_l, + IFUNC_IMPL_ADD (array, i, strncasecmp_l, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __strncasecmp_l_avx) + IFUNC_IMPL_ADD (array, i, strncasecmp_l, +- HAS_CPU_FEATURE (SSE4_2), ++ CPU_FEATURE_USABLE (SSE4_2), + __strncasecmp_l_sse42) + IFUNC_IMPL_ADD (array, i, strncasecmp_l, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __strncasecmp_l_ssse3) + IFUNC_IMPL_ADD (array, i, strncasecmp_l, 1, + __strncasecmp_l_sse2)) + + /* Support sysdeps/x86_64/multiarch/strncat.c. */ + IFUNC_IMPL (i, name, strncat, +- IFUNC_IMPL_ADD (array, i, strncat, HAS_ARCH_FEATURE (AVX2_Usable), ++ IFUNC_IMPL_ADD (array, i, strncat, CPU_FEATURE_USABLE (AVX2), + __strncat_avx2) +- IFUNC_IMPL_ADD (array, i, strncat, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strncat, CPU_FEATURE_USABLE (SSSE3), + __strncat_ssse3) + IFUNC_IMPL_ADD (array, i, strncat, 1, + __strncat_sse2_unaligned) +@@ -339,9 +339,9 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/x86_64/multiarch/strncpy.c. */ + IFUNC_IMPL (i, name, strncpy, +- IFUNC_IMPL_ADD (array, i, strncpy, HAS_ARCH_FEATURE (AVX2_Usable), ++ IFUNC_IMPL_ADD (array, i, strncpy, CPU_FEATURE_USABLE (AVX2), + __strncpy_avx2) +- IFUNC_IMPL_ADD (array, i, strncpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strncpy, CPU_FEATURE_USABLE (SSSE3), + __strncpy_ssse3) + IFUNC_IMPL_ADD (array, i, strncpy, 1, + __strncpy_sse2_unaligned) +@@ -349,14 +349,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + + /* Support sysdeps/x86_64/multiarch/strpbrk.c. */ + IFUNC_IMPL (i, name, strpbrk, +- IFUNC_IMPL_ADD (array, i, strpbrk, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, strpbrk, CPU_FEATURE_USABLE (SSE4_2), + __strpbrk_sse42) + IFUNC_IMPL_ADD (array, i, strpbrk, 1, __strpbrk_sse2)) + + + /* Support sysdeps/x86_64/multiarch/strspn.c. */ + IFUNC_IMPL (i, name, strspn, +- IFUNC_IMPL_ADD (array, i, strspn, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, strspn, CPU_FEATURE_USABLE (SSE4_2), + __strspn_sse42) + IFUNC_IMPL_ADD (array, i, strspn, 1, __strspn_sse2)) + +@@ -368,70 +368,70 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/wcschr.c. */ + IFUNC_IMPL (i, name, wcschr, + IFUNC_IMPL_ADD (array, i, wcschr, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __wcschr_avx2) + IFUNC_IMPL_ADD (array, i, wcschr, 1, __wcschr_sse2)) + + /* Support sysdeps/x86_64/multiarch/wcsrchr.c. */ + IFUNC_IMPL (i, name, wcsrchr, + IFUNC_IMPL_ADD (array, i, wcsrchr, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __wcsrchr_avx2) + IFUNC_IMPL_ADD (array, i, wcsrchr, 1, __wcsrchr_sse2)) + + /* Support sysdeps/x86_64/multiarch/wcscmp.c. */ + IFUNC_IMPL (i, name, wcscmp, + IFUNC_IMPL_ADD (array, i, wcscmp, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __wcscmp_avx2) + IFUNC_IMPL_ADD (array, i, wcscmp, 1, __wcscmp_sse2)) + + /* Support sysdeps/x86_64/multiarch/wcsncmp.c. */ + IFUNC_IMPL (i, name, wcsncmp, + IFUNC_IMPL_ADD (array, i, wcsncmp, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __wcsncmp_avx2) + IFUNC_IMPL_ADD (array, i, wcsncmp, 1, __wcsncmp_sse2)) + + /* Support sysdeps/x86_64/multiarch/wcscpy.c. */ + IFUNC_IMPL (i, name, wcscpy, +- IFUNC_IMPL_ADD (array, i, wcscpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, wcscpy, CPU_FEATURE_USABLE (SSSE3), + __wcscpy_ssse3) + IFUNC_IMPL_ADD (array, i, wcscpy, 1, __wcscpy_sse2)) + + /* Support sysdeps/x86_64/multiarch/wcslen.c. */ + IFUNC_IMPL (i, name, wcslen, + IFUNC_IMPL_ADD (array, i, wcslen, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __wcslen_avx2) + IFUNC_IMPL_ADD (array, i, wcslen, 1, __wcslen_sse2)) + + /* Support sysdeps/x86_64/multiarch/wcsnlen.c. */ + IFUNC_IMPL (i, name, wcsnlen, + IFUNC_IMPL_ADD (array, i, wcsnlen, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __wcsnlen_avx2) + IFUNC_IMPL_ADD (array, i, wcsnlen, +- HAS_CPU_FEATURE (SSE4_1), ++ CPU_FEATURE_USABLE (SSE4_1), + __wcsnlen_sse4_1) + IFUNC_IMPL_ADD (array, i, wcsnlen, 1, __wcsnlen_sse2)) + + /* Support sysdeps/x86_64/multiarch/wmemchr.c. */ + IFUNC_IMPL (i, name, wmemchr, + IFUNC_IMPL_ADD (array, i, wmemchr, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __wmemchr_avx2) + IFUNC_IMPL_ADD (array, i, wmemchr, 1, __wmemchr_sse2)) + + /* Support sysdeps/x86_64/multiarch/wmemcmp.c. */ + IFUNC_IMPL (i, name, wmemcmp, + IFUNC_IMPL_ADD (array, i, wmemcmp, +- (HAS_ARCH_FEATURE (AVX2_Usable) +- && HAS_CPU_FEATURE (MOVBE)), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (MOVBE)), + __wmemcmp_avx2_movbe) +- IFUNC_IMPL_ADD (array, i, wmemcmp, HAS_CPU_FEATURE (SSE4_1), ++ IFUNC_IMPL_ADD (array, i, wmemcmp, CPU_FEATURE_USABLE (SSE4_1), + __wmemcmp_sse4_1) +- IFUNC_IMPL_ADD (array, i, wmemcmp, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, wmemcmp, CPU_FEATURE_USABLE (SSSE3), + __wmemcmp_ssse3) + IFUNC_IMPL_ADD (array, i, wmemcmp, 1, __wmemcmp_sse2)) + +@@ -440,35 +440,35 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, wmemset, 1, + __wmemset_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, wmemset, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __wmemset_avx2_unaligned) + IFUNC_IMPL_ADD (array, i, wmemset, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __wmemset_avx512_unaligned)) + + #ifdef SHARED + /* Support sysdeps/x86_64/multiarch/memcpy_chk.c. */ + IFUNC_IMPL (i, name, __memcpy_chk, + IFUNC_IMPL_ADD (array, i, __memcpy_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memcpy_chk_avx512_no_vzeroupper) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memcpy_chk_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memcpy_chk_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __memcpy_chk_avx_unaligned) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __memcpy_chk_avx_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __memcpy_chk_ssse3_back) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __memcpy_chk_ssse3) + IFUNC_IMPL_ADD (array, i, __memcpy_chk, 1, + __memcpy_chk_sse2_unaligned) +@@ -481,23 +481,23 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/memcpy.c. */ + IFUNC_IMPL (i, name, memcpy, + IFUNC_IMPL_ADD (array, i, memcpy, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __memcpy_avx_unaligned) + IFUNC_IMPL_ADD (array, i, memcpy, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __memcpy_avx_unaligned_erms) +- IFUNC_IMPL_ADD (array, i, memcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, memcpy, CPU_FEATURE_USABLE (SSSE3), + __memcpy_ssse3_back) +- IFUNC_IMPL_ADD (array, i, memcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, memcpy, CPU_FEATURE_USABLE (SSSE3), + __memcpy_ssse3) + IFUNC_IMPL_ADD (array, i, memcpy, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memcpy_avx512_no_vzeroupper) + IFUNC_IMPL_ADD (array, i, memcpy, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memcpy_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, memcpy, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __memcpy_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, memcpy, 1, +@@ -508,25 +508,25 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/mempcpy_chk.c. */ + IFUNC_IMPL (i, name, __mempcpy_chk, + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __mempcpy_chk_avx512_no_vzeroupper) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __mempcpy_chk_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __mempcpy_chk_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __mempcpy_chk_avx_unaligned) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __mempcpy_chk_avx_unaligned_erms) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __mempcpy_chk_ssse3_back) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, +- HAS_CPU_FEATURE (SSSE3), ++ CPU_FEATURE_USABLE (SSSE3), + __mempcpy_chk_ssse3) + IFUNC_IMPL_ADD (array, i, __mempcpy_chk, 1, + __mempcpy_chk_sse2_unaligned) +@@ -539,23 +539,23 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/mempcpy.c. */ + IFUNC_IMPL (i, name, mempcpy, + IFUNC_IMPL_ADD (array, i, mempcpy, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __mempcpy_avx512_no_vzeroupper) + IFUNC_IMPL_ADD (array, i, mempcpy, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __mempcpy_avx512_unaligned) + IFUNC_IMPL_ADD (array, i, mempcpy, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __mempcpy_avx512_unaligned_erms) + IFUNC_IMPL_ADD (array, i, mempcpy, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __mempcpy_avx_unaligned) + IFUNC_IMPL_ADD (array, i, mempcpy, +- HAS_ARCH_FEATURE (AVX_Usable), ++ CPU_FEATURE_USABLE (AVX), + __mempcpy_avx_unaligned_erms) +- IFUNC_IMPL_ADD (array, i, mempcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, mempcpy, CPU_FEATURE_USABLE (SSSE3), + __mempcpy_ssse3_back) +- IFUNC_IMPL_ADD (array, i, mempcpy, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, mempcpy, CPU_FEATURE_USABLE (SSSE3), + __mempcpy_ssse3) + IFUNC_IMPL_ADD (array, i, mempcpy, 1, + __mempcpy_sse2_unaligned) +@@ -566,11 +566,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/strncmp.c. */ + IFUNC_IMPL (i, name, strncmp, + IFUNC_IMPL_ADD (array, i, strncmp, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __strncmp_avx2) +- IFUNC_IMPL_ADD (array, i, strncmp, HAS_CPU_FEATURE (SSE4_2), ++ IFUNC_IMPL_ADD (array, i, strncmp, CPU_FEATURE_USABLE (SSE4_2), + __strncmp_sse42) +- IFUNC_IMPL_ADD (array, i, strncmp, HAS_CPU_FEATURE (SSSE3), ++ IFUNC_IMPL_ADD (array, i, strncmp, CPU_FEATURE_USABLE (SSSE3), + __strncmp_ssse3) + IFUNC_IMPL_ADD (array, i, strncmp, 1, __strncmp_sse2)) + +@@ -580,10 +580,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL_ADD (array, i, __wmemset_chk, 1, + __wmemset_chk_sse2_unaligned) + IFUNC_IMPL_ADD (array, i, __wmemset_chk, +- HAS_ARCH_FEATURE (AVX2_Usable), ++ CPU_FEATURE_USABLE (AVX2), + __wmemset_chk_avx2_unaligned) + IFUNC_IMPL_ADD (array, i, __wmemset_chk, +- HAS_ARCH_FEATURE (AVX512F_Usable), ++ CPU_FEATURE_USABLE (AVX512F), + __wmemset_chk_avx512_unaligned)) + #endif + +diff --git a/sysdeps/x86_64/multiarch/ifunc-memcmp.h b/sysdeps/x86_64/multiarch/ifunc-memcmp.h +index bf5ab8eb7ffd0002..6c1f3153579d19c4 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-memcmp.h ++++ b/sysdeps/x86_64/multiarch/ifunc-memcmp.h +@@ -30,15 +30,15 @@ IFUNC_SELECTOR (void) + const struct cpu_features* cpu_features = __get_cpu_features (); + + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable) +- && CPU_FEATURES_CPU_P (cpu_features, MOVBE) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && CPU_FEATURE_USABLE_P (cpu_features, MOVBE) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + return OPTIMIZE (avx2_movbe); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE4_1)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_1)) + return OPTIMIZE (sse4_1); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSSE3)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSSE3)) + return OPTIMIZE (ssse3); + + return OPTIMIZE (sse2); +diff --git a/sysdeps/x86_64/multiarch/ifunc-memmove.h b/sysdeps/x86_64/multiarch/ifunc-memmove.h +index 5b1eb1c92c2f199b..5e5f02994531ec14 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-memmove.h ++++ b/sysdeps/x86_64/multiarch/ifunc-memmove.h +@@ -45,13 +45,13 @@ IFUNC_SELECTOR (void) + || CPU_FEATURES_ARCH_P (cpu_features, Prefer_FSRM)) + return OPTIMIZE (erms); + +- if (CPU_FEATURES_ARCH_P (cpu_features, AVX512F_Usable) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F) + && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_AVX512)) + { + if (CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) + return OPTIMIZE (avx512_no_vzeroupper); + +- if (CPU_FEATURES_CPU_P (cpu_features, ERMS)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) + return OPTIMIZE (avx512_unaligned_erms); + + return OPTIMIZE (avx512_unaligned); +@@ -59,16 +59,16 @@ IFUNC_SELECTOR (void) + + if (CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + { +- if (CPU_FEATURES_CPU_P (cpu_features, ERMS)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) + return OPTIMIZE (avx_unaligned_erms); + + return OPTIMIZE (avx_unaligned); + } + +- if (!CPU_FEATURES_CPU_P (cpu_features, SSSE3) ++ if (!CPU_FEATURE_USABLE_P (cpu_features, SSSE3) + || CPU_FEATURES_ARCH_P (cpu_features, Fast_Unaligned_Copy)) + { +- if (CPU_FEATURES_CPU_P (cpu_features, ERMS)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) + return OPTIMIZE (sse2_unaligned_erms); + + return OPTIMIZE (sse2_unaligned); +diff --git a/sysdeps/x86_64/multiarch/ifunc-memset.h b/sysdeps/x86_64/multiarch/ifunc-memset.h +index 19b5ae676c2d5d53..708bd72e2c3d3963 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-memset.h ++++ b/sysdeps/x86_64/multiarch/ifunc-memset.h +@@ -42,27 +42,27 @@ IFUNC_SELECTOR (void) + if (CPU_FEATURES_ARCH_P (cpu_features, Prefer_ERMS)) + return OPTIMIZE (erms); + +- if (CPU_FEATURES_ARCH_P (cpu_features, AVX512F_Usable) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F) + && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_AVX512)) + { + if (CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)) + return OPTIMIZE (avx512_no_vzeroupper); + +- if (CPU_FEATURES_CPU_P (cpu_features, ERMS)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) + return OPTIMIZE (avx512_unaligned_erms); + + return OPTIMIZE (avx512_unaligned); + } + +- if (CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX2)) + { +- if (CPU_FEATURES_CPU_P (cpu_features, ERMS)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) + return OPTIMIZE (avx2_unaligned_erms); + else + return OPTIMIZE (avx2_unaligned); + } + +- if (CPU_FEATURES_CPU_P (cpu_features, ERMS)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)) + return OPTIMIZE (sse2_unaligned_erms); + + return OPTIMIZE (sse2_unaligned); +diff --git a/sysdeps/x86_64/multiarch/ifunc-sse4_2.h b/sysdeps/x86_64/multiarch/ifunc-sse4_2.h +index f2b791cccf12c425..73383f4b583b29c8 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-sse4_2.h ++++ b/sysdeps/x86_64/multiarch/ifunc-sse4_2.h +@@ -27,7 +27,7 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE4_2)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_2)) + return OPTIMIZE (sse42); + + return OPTIMIZE (sse2); +diff --git a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h +index 1ca170b663a4e65c..6a4bb07849a11f51 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h ++++ b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h +@@ -29,14 +29,14 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_ARCH_P (cpu_features, AVX_Usable)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX)) + return OPTIMIZE (avx); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE4_2) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_2) + && !CPU_FEATURES_ARCH_P (cpu_features, Slow_SSE4_2)) + return OPTIMIZE (sse42); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSSE3)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSSE3)) + return OPTIMIZE (ssse3); + + return OPTIMIZE (sse2); +diff --git a/sysdeps/x86_64/multiarch/ifunc-strcpy.h b/sysdeps/x86_64/multiarch/ifunc-strcpy.h +index 4f2286fefccda069..100dca5cde0ecac5 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-strcpy.h ++++ b/sysdeps/x86_64/multiarch/ifunc-strcpy.h +@@ -32,14 +32,14 @@ IFUNC_SELECTOR (void) + const struct cpu_features* cpu_features = __get_cpu_features (); + + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + return OPTIMIZE (avx2); + + if (CPU_FEATURES_ARCH_P (cpu_features, Fast_Unaligned_Load)) + return OPTIMIZE (sse2_unaligned); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSSE3)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSSE3)) + return OPTIMIZE (ssse3); + + return OPTIMIZE (sse2); +diff --git a/sysdeps/x86_64/multiarch/ifunc-wmemset.h b/sysdeps/x86_64/multiarch/ifunc-wmemset.h +index 2f1085f5fc483c70..eb2422104751b235 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-wmemset.h ++++ b/sysdeps/x86_64/multiarch/ifunc-wmemset.h +@@ -28,10 +28,10 @@ IFUNC_SELECTOR (void) + const struct cpu_features* cpu_features = __get_cpu_features (); + + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + { +- if (CPU_FEATURES_ARCH_P (cpu_features, AVX512F_Usable) ++ if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F) + && !CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_AVX512)) + return OPTIMIZE (avx512_unaligned); + else +diff --git a/sysdeps/x86_64/multiarch/sched_cpucount.c b/sysdeps/x86_64/multiarch/sched_cpucount.c +index 7949119dcdb5a94b..b38ff37c6511ca1b 100644 +--- a/sysdeps/x86_64/multiarch/sched_cpucount.c ++++ b/sysdeps/x86_64/multiarch/sched_cpucount.c +@@ -33,4 +33,4 @@ + #undef __sched_cpucount + + libc_ifunc (__sched_cpucount, +- HAS_CPU_FEATURE (POPCNT) ? popcount_cpucount : generic_cpucount); ++ CPU_FEATURE_USABLE (POPCNT) ? popcount_cpucount : generic_cpucount); +diff --git a/sysdeps/x86_64/multiarch/strchr.c b/sysdeps/x86_64/multiarch/strchr.c +index 76d64fb378e9bbac..329547132c3a301b 100644 +--- a/sysdeps/x86_64/multiarch/strchr.c ++++ b/sysdeps/x86_64/multiarch/strchr.c +@@ -36,7 +36,7 @@ IFUNC_SELECTOR (void) + const struct cpu_features* cpu_features = __get_cpu_features (); + + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + return OPTIMIZE (avx2); + +diff --git a/sysdeps/x86_64/multiarch/strcmp.c b/sysdeps/x86_64/multiarch/strcmp.c +index b903e418df151ec1..3f433fbccf9e7121 100644 +--- a/sysdeps/x86_64/multiarch/strcmp.c ++++ b/sysdeps/x86_64/multiarch/strcmp.c +@@ -37,14 +37,14 @@ IFUNC_SELECTOR (void) + const struct cpu_features* cpu_features = __get_cpu_features (); + + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + return OPTIMIZE (avx2); + + if (CPU_FEATURES_ARCH_P (cpu_features, Fast_Unaligned_Load)) + return OPTIMIZE (sse2_unaligned); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSSE3)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSSE3)) + return OPTIMIZE (ssse3); + + return OPTIMIZE (sse2); +diff --git a/sysdeps/x86_64/multiarch/strncmp.c b/sysdeps/x86_64/multiarch/strncmp.c +index 02b6d0b6f5717e2a..686d654f3da84379 100644 +--- a/sysdeps/x86_64/multiarch/strncmp.c ++++ b/sysdeps/x86_64/multiarch/strncmp.c +@@ -37,15 +37,15 @@ IFUNC_SELECTOR (void) + const struct cpu_features* cpu_features = __get_cpu_features (); + + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + return OPTIMIZE (avx2); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE4_2) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_2) + && !CPU_FEATURES_ARCH_P (cpu_features, Slow_SSE4_2)) + return OPTIMIZE (sse42); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSSE3)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSSE3)) + return OPTIMIZE (ssse3); + + return OPTIMIZE (sse2); +diff --git a/sysdeps/x86_64/multiarch/test-multiarch.c b/sysdeps/x86_64/multiarch/test-multiarch.c +index 417147c3d5f325a5..cc2ea56a6753402d 100644 +--- a/sysdeps/x86_64/multiarch/test-multiarch.c ++++ b/sysdeps/x86_64/multiarch/test-multiarch.c +@@ -75,18 +75,18 @@ do_test (int argc, char **argv) + int fails; + + get_cpuinfo (); +- fails = check_proc ("avx", HAS_ARCH_FEATURE (AVX_Usable), +- "HAS_ARCH_FEATURE (AVX_Usable)"); +- fails += check_proc ("fma4", HAS_ARCH_FEATURE (FMA4_Usable), +- "HAS_ARCH_FEATURE (FMA4_Usable)"); +- fails += check_proc ("sse4_2", HAS_CPU_FEATURE (SSE4_2), +- "HAS_CPU_FEATURE (SSE4_2)"); +- fails += check_proc ("sse4_1", HAS_CPU_FEATURE (SSE4_1) +- , "HAS_CPU_FEATURE (SSE4_1)"); +- fails += check_proc ("ssse3", HAS_CPU_FEATURE (SSSE3), +- "HAS_CPU_FEATURE (SSSE3)"); +- fails += check_proc ("popcnt", HAS_CPU_FEATURE (POPCNT), +- "HAS_CPU_FEATURE (POPCNT)"); ++ fails = check_proc ("avx", CPU_FEATURE_USABLE (AVX), ++ "CPU_FEATURE_USABLE (AVX)"); ++ fails += check_proc ("fma4", CPU_FEATURE_USABLE (FMA4), ++ "CPU_FEATURE_USABLE (FMA4)"); ++ fails += check_proc ("sse4_2", CPU_FEATURE_USABLE (SSE4_2), ++ "CPU_FEATURE_USABLE (SSE4_2)"); ++ fails += check_proc ("sse4_1", CPU_FEATURE_USABLE (SSE4_1) ++ , "CPU_FEATURE_USABLE (SSE4_1)"); ++ fails += check_proc ("ssse3", CPU_FEATURE_USABLE (SSSE3), ++ "CPU_FEATURE_USABLE (SSSE3)"); ++ fails += check_proc ("popcnt", CPU_FEATURE_USABLE (POPCNT), ++ "CPU_FEATURE_USABLE (POPCNT)"); + + printf ("%d differences between /proc/cpuinfo and glibc code.\n", fails); + +diff --git a/sysdeps/x86_64/multiarch/wcscpy.c b/sysdeps/x86_64/multiarch/wcscpy.c +index f23b1fd853a4dcb4..8fffb5c3163ab3e4 100644 +--- a/sysdeps/x86_64/multiarch/wcscpy.c ++++ b/sysdeps/x86_64/multiarch/wcscpy.c +@@ -34,7 +34,7 @@ IFUNC_SELECTOR (void) + { + const struct cpu_features* cpu_features = __get_cpu_features (); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSSE3)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSSE3)) + return OPTIMIZE (ssse3); + + return OPTIMIZE (sse2); +diff --git a/sysdeps/x86_64/multiarch/wcsnlen.c b/sysdeps/x86_64/multiarch/wcsnlen.c +index bd376057e3e26ed6..b3144c938df70b1e 100644 +--- a/sysdeps/x86_64/multiarch/wcsnlen.c ++++ b/sysdeps/x86_64/multiarch/wcsnlen.c +@@ -36,11 +36,11 @@ IFUNC_SELECTOR (void) + const struct cpu_features* cpu_features = __get_cpu_features (); + + if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER) +- && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + return OPTIMIZE (avx2); + +- if (CPU_FEATURES_CPU_P (cpu_features, SSE4_1)) ++ if (CPU_FEATURE_USABLE_P (cpu_features, SSE4_1)) + return OPTIMIZE (sse4_1); + + return OPTIMIZE (sse2); diff --git a/SOURCES/glibc-rh1817513-78.patch b/SOURCES/glibc-rh1817513-78.patch new file mode 100644 index 0000000..2395513 --- /dev/null +++ b/SOURCES/glibc-rh1817513-78.patch @@ -0,0 +1,75 @@ +commit 94b63e66206a9ad38872a9136a623ce73cf7c858 +Author: Florian Weimer +Date: Thu Feb 7 09:02:00 2019 +0100 + + support: Implement xdlmopen + + Put xdlmopen into its own file, to avoid disturbing static linking + tests (where dlmopen pulls in additional code). + +diff --git a/support/Makefile b/support/Makefile +index 5808a42dce87151f..895b83a426369b0c 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -86,6 +86,7 @@ libsupport-routines = \ + xconnect \ + xcopy_file_range \ + xdlfcn \ ++ xdlmopen \ + xdup2 \ + xfclose \ + xfopen \ +diff --git a/support/xdlfcn.h b/support/xdlfcn.h +index ab1cbb3cb9bb1cc7..a53fb61b133af5c3 100644 +--- a/support/xdlfcn.h ++++ b/support/xdlfcn.h +@@ -25,11 +25,11 @@ __BEGIN_DECLS + + /* Each of these terminates process on failure with relevant error message. */ + void *xdlopen (const char *filename, int flags); ++void *xdlmopen (Lmid_t lmid, const char *filename, int flags); + void *xdlsym (void *handle, const char *symbol); + void *xdlvsym (void *handle, const char *symbol, const char *version); + void xdlclose (void *handle); + +- + __END_DECLS + + #endif /* SUPPORT_DLOPEN_H */ +diff --git a/support/xdlmopen.c b/support/xdlmopen.c +new file mode 100644 +index 0000000000000000..9a39ba8801eb1617 +--- /dev/null ++++ b/support/xdlmopen.c +@@ -0,0 +1,31 @@ ++/* dlmopen with error checking. ++ Copyright (C) 2017-2019 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 ++ ++void * ++xdlmopen (Lmid_t lmid, const char *filename, int flags) ++{ ++ void *dso = dlmopen (lmid, filename, flags); ++ ++ if (dso == NULL) ++ FAIL_EXIT1 ("error: dlmopen: %s\n", dlerror ()); ++ ++ return dso; ++} diff --git a/SOURCES/glibc-rh1817513-79.patch b/SOURCES/glibc-rh1817513-79.patch new file mode 100644 index 0000000..5b1cb3a --- /dev/null +++ b/SOURCES/glibc-rh1817513-79.patch @@ -0,0 +1,642 @@ +commit ffb17e7ba3a5ba9632cee97330b325072fbe41dd +Author: Szabolcs Nagy +Date: Wed Jun 10 13:40:40 2020 +0100 + + rtld: Avoid using up static TLS surplus for optimizations [BZ #25051] + + On some targets static TLS surplus area can be used opportunistically + for dynamically loaded modules such that the TLS access then becomes + faster (TLSDESC and powerpc TLS optimization). However we don't want + all surplus TLS to be used for this optimization because dynamically + loaded modules with initial-exec model TLS can only use surplus TLS. + + The new contract for surplus static TLS use is: + + - libc.so can have up to 192 bytes of IE TLS, + - other system libraries together can have up to 144 bytes of IE TLS. + - Some "optional" static TLS is available for opportunistic use. + + The optional TLS is now tunable: rtld.optional_static_tls, so users + can directly affect the allocated static TLS size. (Note that module + unloading with dlclose does not reclaim static TLS. After the optional + TLS runs out, TLS access is no longer optimized to use static TLS.) + + The default setting of rtld.optional_static_tls is 512 so the surplus + TLS is 3*192 + 4*144 + 512 = 1664 by default, the same as before. + + Fixes BZ #25051. + + Tested on aarch64-linux-gnu and x86_64-linux-gnu. + + Reviewed-by: Carlos O'Donell + +Conflicts: + elf/Makefile + (Missing __libc_single_threaded downstream.) + +diff --git a/csu/libc-tls.c b/csu/libc-tls.c +index 6f2a47dc86222407..76aa1b98ea059a43 100644 +--- a/csu/libc-tls.c ++++ b/csu/libc-tls.c +@@ -62,6 +62,9 @@ size_t _dl_tls_static_align; + loaded modules with IE-model TLS or for TLSDESC optimization. + See comments in elf/dl-tls.c where it is initialized. */ + size_t _dl_tls_static_surplus; ++/* Remaining amount of static TLS that may be used for optimizing ++ dynamic TLS access (e.g. with TLSDESC). */ ++size_t _dl_tls_static_optional; + + /* Generation counter for the dtv. */ + size_t _dl_tls_generation; +diff --git a/elf/Makefile b/elf/Makefile +index cbced7605ebe2443..8b96bfefd852b79f 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -197,7 +197,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-auditmany tst-initfinilazyfail \ + tst-dlopenfail tst-dlopenfail-2 \ + tst-filterobj tst-filterobj-dlopen tst-auxobj tst-auxobj-dlopen \ +- tst-audit14 tst-audit15 tst-audit16 ++ tst-audit14 tst-audit15 tst-audit16 \ ++ tst-tls-ie tst-tls-ie-dlmopen + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -313,7 +314,10 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 \ + tst-dlopenfailmod3 \ + tst-filterobj-flt tst-filterobj-aux tst-filterobj-filtee \ +- tst-auditlogmod-1 tst-auditlogmod-2 tst-auditlogmod-3 ++ tst-auditlogmod-1 tst-auditlogmod-2 tst-auditlogmod-3 \ ++ tst-tls-ie-mod0 tst-tls-ie-mod1 tst-tls-ie-mod2 \ ++ tst-tls-ie-mod3 tst-tls-ie-mod4 tst-tls-ie-mod5 \ ++ tst-tls-ie-mod6 + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +@@ -1690,3 +1694,23 @@ $(objpfx)tst-auxobj: $(objpfx)tst-filterobj-aux.so + $(objpfx)tst-auxobj-dlopen: $(libdl) + $(objpfx)tst-auxobj.out: $(objpfx)tst-filterobj-filtee.so + $(objpfx)tst-auxobj-dlopen.out: $(objpfx)tst-filterobj-filtee.so ++ ++$(objpfx)tst-tls-ie: $(libdl) $(shared-thread-library) ++$(objpfx)tst-tls-ie.out: \ ++ $(objpfx)tst-tls-ie-mod0.so \ ++ $(objpfx)tst-tls-ie-mod1.so \ ++ $(objpfx)tst-tls-ie-mod2.so \ ++ $(objpfx)tst-tls-ie-mod3.so \ ++ $(objpfx)tst-tls-ie-mod4.so \ ++ $(objpfx)tst-tls-ie-mod5.so \ ++ $(objpfx)tst-tls-ie-mod6.so ++ ++$(objpfx)tst-tls-ie-dlmopen: $(libdl) $(shared-thread-library) ++$(objpfx)tst-tls-ie-dlmopen.out: \ ++ $(objpfx)tst-tls-ie-mod0.so \ ++ $(objpfx)tst-tls-ie-mod1.so \ ++ $(objpfx)tst-tls-ie-mod2.so \ ++ $(objpfx)tst-tls-ie-mod3.so \ ++ $(objpfx)tst-tls-ie-mod4.so \ ++ $(objpfx)tst-tls-ie-mod5.so \ ++ $(objpfx)tst-tls-ie-mod6.so +diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c +index afeace4d3e49180c..c6139b89d4ecddc8 100644 +--- a/elf/dl-reloc.c ++++ b/elf/dl-reloc.c +@@ -39,13 +39,16 @@ + /* We are trying to perform a static TLS relocation in MAP, but it was + dynamically loaded. This can only work if there is enough surplus in + the static TLS area already allocated for each running thread. If this +- object's TLS segment is too big to fit, we fail. If it fits, +- we set MAP->l_tls_offset and return. +- This function intentionally does not return any value but signals error +- directly, as static TLS should be rare and code handling it should +- not be inlined as much as possible. */ ++ object's TLS segment is too big to fit, we fail with -1. If it fits, ++ we set MAP->l_tls_offset and return 0. ++ A portion of the surplus static TLS can be optionally used to optimize ++ dynamic TLS access (with TLSDESC or powerpc TLS optimizations). ++ If OPTIONAL is true then TLS is allocated for such optimization and ++ the caller must have a fallback in case the optional portion of surplus ++ TLS runs out. If OPTIONAL is false then the entire surplus TLS area is ++ considered and the allocation only fails if that runs out. */ + int +-_dl_try_allocate_static_tls (struct link_map *map) ++_dl_try_allocate_static_tls (struct link_map *map, bool optional) + { + /* If we've already used the variable with dynamic access, or if the + alignment requirements are too high, fail. */ +@@ -68,8 +71,14 @@ _dl_try_allocate_static_tls (struct link_map *map) + + size_t n = (freebytes - blsize) / map->l_tls_align; + +- size_t offset = GL(dl_tls_static_used) + (freebytes - n * map->l_tls_align +- - map->l_tls_firstbyte_offset); ++ /* Account optional static TLS surplus usage. */ ++ size_t use = freebytes - n * map->l_tls_align - map->l_tls_firstbyte_offset; ++ if (optional && use > GL(dl_tls_static_optional)) ++ goto fail; ++ else if (optional) ++ GL(dl_tls_static_optional) -= use; ++ ++ size_t offset = GL(dl_tls_static_used) + use; + + map->l_tls_offset = GL(dl_tls_static_used) = offset; + #elif TLS_DTV_AT_TP +@@ -83,6 +92,13 @@ _dl_try_allocate_static_tls (struct link_map *map) + if (used > GL(dl_tls_static_size)) + goto fail; + ++ /* Account optional static TLS surplus usage. */ ++ size_t use = used - GL(dl_tls_static_used); ++ if (optional && use > GL(dl_tls_static_optional)) ++ goto fail; ++ else if (optional) ++ GL(dl_tls_static_optional) -= use; ++ + map->l_tls_offset = offset; + map->l_tls_firstbyte_offset = GL(dl_tls_static_used); + GL(dl_tls_static_used) = used; +@@ -110,12 +126,15 @@ _dl_try_allocate_static_tls (struct link_map *map) + return 0; + } + ++/* This function intentionally does not return any value but signals error ++ directly, as static TLS should be rare and code handling it should ++ not be inlined as much as possible. */ + void + __attribute_noinline__ + _dl_allocate_static_tls (struct link_map *map) + { + if (map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET +- || _dl_try_allocate_static_tls (map)) ++ || _dl_try_allocate_static_tls (map, false)) + { + _dl_signal_error (0, map->l_name, NULL, N_("\ + cannot allocate memory in static TLS block")); +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index cfda76f6de96df57..4f8c35b7d37bfc18 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -60,8 +60,6 @@ + This should be large enough to cover runtime libraries of the + compiler such as libgomp and libraries in libc other than libc.so. */ + #define OTHER_IE_TLS 144 +-/* Size of additional surplus TLS, placeholder for TLS optimizations. */ +-#define OPT_SURPLUS_TLS 512 + + /* Calculate the size of the static TLS surplus, when the given + number of audit modules are loaded. Must be called after the +@@ -69,13 +67,15 @@ + void + _dl_tls_static_surplus_init (size_t naudit) + { +- size_t nns; ++ size_t nns, opt_tls; + + #if HAVE_TUNABLES + nns = TUNABLE_GET (nns, size_t, NULL); ++ opt_tls = TUNABLE_GET (optional_static_tls, size_t, NULL); + #else + /* Default values of the tunables. */ + nns = 4; ++ opt_tls = 512; + #endif + if (nns > DL_NNS) + nns = DL_NNS; +@@ -84,9 +84,10 @@ _dl_tls_static_surplus_init (size_t naudit) + (unsigned long) naudit, (unsigned long) (DL_NNS - nns)); + nns += naudit; + ++ GL(dl_tls_static_optional) = opt_tls; + GLRO(dl_tls_static_surplus) = ((nns - 1) * LIBC_IE_TLS + + nns * OTHER_IE_TLS +- + OPT_SURPLUS_TLS); ++ + opt_tls); + } + + /* Out-of-memory handler. */ +diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list +index 7337fb85062c91a7..6408a8e5ae92d2c6 100644 +--- a/elf/dl-tunables.list ++++ b/elf/dl-tunables.list +@@ -134,5 +134,10 @@ glibc { + maxval: 16 + default: 4 + } ++ optional_static_tls { ++ type: SIZE_T ++ minval: 0 ++ default: 512 ++ } + } + } +diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h +index 9e9d5a3b28bc06c5..2fc3c91b7defe84e 100644 +--- a/elf/dynamic-link.h ++++ b/elf/dynamic-link.h +@@ -40,9 +40,10 @@ + (__builtin_expect ((sym_map)->l_tls_offset \ + != FORCED_DYNAMIC_TLS_OFFSET, 1) \ + && (__builtin_expect ((sym_map)->l_tls_offset != NO_TLS_OFFSET, 1) \ +- || _dl_try_allocate_static_tls (sym_map) == 0)) ++ || _dl_try_allocate_static_tls (sym_map, true) == 0)) + +-int _dl_try_allocate_static_tls (struct link_map *map) attribute_hidden; ++int _dl_try_allocate_static_tls (struct link_map *map, bool optional) ++ attribute_hidden; + + #include + +diff --git a/elf/tst-tls-ie-dlmopen.c b/elf/tst-tls-ie-dlmopen.c +new file mode 100644 +index 0000000000000000..c7b5c688e362c861 +--- /dev/null ++++ b/elf/tst-tls-ie-dlmopen.c +@@ -0,0 +1,112 @@ ++/* Test dlopen of modules with initial-exec TLS after dlmopen. ++ Copyright (C) 2016-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 test tries to check that surplus static TLS is not used up for ++ dynamic TLS optimizations and 4*144 = 576 bytes of static TLS is ++ still available for dlopening modules with initial-exec TLS after 3 ++ new dlmopen namespaces are created. It depends on rtld.nns=4 and ++ rtld.optional_static_tls=512 tunable settings. */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static int do_test (void); ++#include ++#include ++#include ++#include ++ ++/* Have some big TLS in the main exe: should not use surplus TLS. */ ++__thread char maintls[1000]; ++ ++static pthread_barrier_t barrier; ++ ++/* Forces multi-threaded behaviour. */ ++static void * ++blocked_thread_func (void *closure) ++{ ++ xpthread_barrier_wait (&barrier); ++ /* TLS load and access tests run here in the main thread. */ ++ xpthread_barrier_wait (&barrier); ++ return NULL; ++} ++ ++static void * ++load_and_access (Lmid_t lmid, const char *mod, const char *func) ++{ ++ /* Load module with TLS. */ ++ void *p = xdlmopen (lmid, mod, RTLD_NOW); ++ /* Access the TLS variable to ensure it is allocated. */ ++ void (*f) (void) = (void (*) (void))xdlsym (p, func); ++ f (); ++ return p; ++} ++ ++static int ++do_test (void) ++{ ++ void *mods[5]; ++ ++ { ++ int ret = pthread_barrier_init (&barrier, NULL, 2); ++ if (ret != 0) ++ { ++ errno = ret; ++ printf ("error: pthread_barrier_init: %m\n"); ++ exit (1); ++ } ++ } ++ ++ pthread_t blocked_thread = xpthread_create (NULL, blocked_thread_func, NULL); ++ xpthread_barrier_wait (&barrier); ++ ++ printf ("maintls[%zu]:\t %p .. %p\n", ++ sizeof maintls, maintls, maintls + sizeof maintls); ++ memset (maintls, 1, sizeof maintls); ++ ++ /* Load modules with dynamic TLS (use surplus static TLS for libc ++ in new namespaces and may be for TLS optimizations too). */ ++ mods[0] = load_and_access (LM_ID_BASE, "tst-tls-ie-mod0.so", "access0"); ++ mods[1] = load_and_access (LM_ID_NEWLM, "tst-tls-ie-mod1.so", "access1"); ++ mods[2] = load_and_access (LM_ID_NEWLM, "tst-tls-ie-mod2.so", "access2"); ++ mods[3] = load_and_access (LM_ID_NEWLM, "tst-tls-ie-mod3.so", "access3"); ++ /* Load modules with initial-exec TLS (can only use surplus static TLS). */ ++ mods[4] = load_and_access (LM_ID_BASE, "tst-tls-ie-mod6.so", "access6"); ++ ++ /* Here 576 bytes + 3 * libc use of surplus static TLS is in use so less ++ than 1024 bytes are available (exact number depends on TLS optimizations ++ and the libc TLS use). */ ++ printf ("The next dlmopen should fail...\n"); ++ void *p = dlmopen (LM_ID_BASE, "tst-tls-ie-mod4.so", RTLD_NOW); ++ if (p != NULL) ++ FAIL_EXIT1 ("error: expected dlmopen to fail because there is " ++ "not enough surplus static TLS.\n"); ++ printf ("...OK failed with: %s.\n", dlerror ()); ++ ++ xpthread_barrier_wait (&barrier); ++ xpthread_join (blocked_thread); ++ ++ /* Close the modules. */ ++ for (int i = 0; i < 5; ++i) ++ xdlclose (mods[i]); ++ ++ return 0; ++} +diff --git a/elf/tst-tls-ie-mod.h b/elf/tst-tls-ie-mod.h +new file mode 100644 +index 0000000000000000..46b362a9b783d214 +--- /dev/null ++++ b/elf/tst-tls-ie-mod.h +@@ -0,0 +1,40 @@ ++/* Module with specified TLS size and model. ++ 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 file is parameterized by macros N, SIZE and MODEL. */ ++ ++#include ++#include ++ ++#define CONCATX(x, y) x ## y ++#define CONCAT(x, y) CONCATX (x, y) ++#define STRX(x) #x ++#define STR(x) STRX (x) ++ ++#define VAR CONCAT (var, N) ++ ++__attribute__ ((aligned (8), tls_model (MODEL))) ++__thread char VAR[SIZE]; ++ ++void ++CONCAT (access, N) (void) ++{ ++ printf (STR (VAR) "[%d]:\t %p .. %p " MODEL "\n", SIZE, VAR, VAR + SIZE); ++ fflush (stdout); ++ memset (VAR, 1, SIZE); ++} +diff --git a/elf/tst-tls-ie-mod0.c b/elf/tst-tls-ie-mod0.c +new file mode 100644 +index 0000000000000000..2450686e400e1141 +--- /dev/null ++++ b/elf/tst-tls-ie-mod0.c +@@ -0,0 +1,4 @@ ++#define N 0 ++#define SIZE 480 ++#define MODEL "global-dynamic" ++#include "tst-tls-ie-mod.h" +diff --git a/elf/tst-tls-ie-mod1.c b/elf/tst-tls-ie-mod1.c +new file mode 100644 +index 0000000000000000..849ff91e53b0a518 +--- /dev/null ++++ b/elf/tst-tls-ie-mod1.c +@@ -0,0 +1,4 @@ ++#define N 1 ++#define SIZE 120 ++#define MODEL "global-dynamic" ++#include "tst-tls-ie-mod.h" +diff --git a/elf/tst-tls-ie-mod2.c b/elf/tst-tls-ie-mod2.c +new file mode 100644 +index 0000000000000000..23915ab67bab0ada +--- /dev/null ++++ b/elf/tst-tls-ie-mod2.c +@@ -0,0 +1,4 @@ ++#define N 2 ++#define SIZE 24 ++#define MODEL "global-dynamic" ++#include "tst-tls-ie-mod.h" +diff --git a/elf/tst-tls-ie-mod3.c b/elf/tst-tls-ie-mod3.c +new file mode 100644 +index 0000000000000000..5395f844a5999ea9 +--- /dev/null ++++ b/elf/tst-tls-ie-mod3.c +@@ -0,0 +1,4 @@ ++#define N 3 ++#define SIZE 16 ++#define MODEL "global-dynamic" ++#include "tst-tls-ie-mod.h" +diff --git a/elf/tst-tls-ie-mod4.c b/elf/tst-tls-ie-mod4.c +new file mode 100644 +index 0000000000000000..93ac2eacae292d86 +--- /dev/null ++++ b/elf/tst-tls-ie-mod4.c +@@ -0,0 +1,4 @@ ++#define N 4 ++#define SIZE 1024 ++#define MODEL "initial-exec" ++#include "tst-tls-ie-mod.h" +diff --git a/elf/tst-tls-ie-mod5.c b/elf/tst-tls-ie-mod5.c +new file mode 100644 +index 0000000000000000..84b3fd285b5b5a3e +--- /dev/null ++++ b/elf/tst-tls-ie-mod5.c +@@ -0,0 +1,4 @@ ++#define N 5 ++#define SIZE 128 ++#define MODEL "initial-exec" ++#include "tst-tls-ie-mod.h" +diff --git a/elf/tst-tls-ie-mod6.c b/elf/tst-tls-ie-mod6.c +new file mode 100644 +index 0000000000000000..c736bf0684f3b08f +--- /dev/null ++++ b/elf/tst-tls-ie-mod6.c +@@ -0,0 +1,4 @@ ++#define N 6 ++#define SIZE 576 ++#define MODEL "initial-exec" ++#include "tst-tls-ie-mod.h" +diff --git a/elf/tst-tls-ie.c b/elf/tst-tls-ie.c +new file mode 100644 +index 0000000000000000..2dc0894480417389 +--- /dev/null ++++ b/elf/tst-tls-ie.c +@@ -0,0 +1,111 @@ ++/* Test dlopen of modules with initial-exec TLS. ++ Copyright (C) 2016-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 test tries to check that surplus static TLS is not used up for ++ dynamic TLS optimizations and 3*192 + 4*144 = 1152 bytes of static ++ TLS is available for dlopening modules with initial-exec TLS. It ++ depends on rtld.nns=4 and rtld.optional_static_tls=512 tunable setting. */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static int do_test (void); ++#include ++#include ++#include ++#include ++ ++/* Have some big TLS in the main exe: should not use surplus TLS. */ ++__thread char maintls[1000]; ++ ++static pthread_barrier_t barrier; ++ ++/* Forces multi-threaded behaviour. */ ++static void * ++blocked_thread_func (void *closure) ++{ ++ xpthread_barrier_wait (&barrier); ++ /* TLS load and access tests run here in the main thread. */ ++ xpthread_barrier_wait (&barrier); ++ return NULL; ++} ++ ++static void * ++load_and_access (const char *mod, const char *func) ++{ ++ /* Load module with TLS. */ ++ void *p = xdlopen (mod, RTLD_NOW); ++ /* Access the TLS variable to ensure it is allocated. */ ++ void (*f) (void) = (void (*) (void))xdlsym (p, func); ++ f (); ++ return p; ++} ++ ++static int ++do_test (void) ++{ ++ void *mods[6]; ++ ++ { ++ int ret = pthread_barrier_init (&barrier, NULL, 2); ++ if (ret != 0) ++ { ++ errno = ret; ++ printf ("error: pthread_barrier_init: %m\n"); ++ exit (1); ++ } ++ } ++ ++ pthread_t blocked_thread = xpthread_create (NULL, blocked_thread_func, NULL); ++ xpthread_barrier_wait (&barrier); ++ ++ printf ("maintls[%zu]:\t %p .. %p\n", ++ sizeof maintls, maintls, maintls + sizeof maintls); ++ memset (maintls, 1, sizeof maintls); ++ ++ /* Load modules with dynamic TLS (may use surplus static TLS ++ opportunistically). */ ++ mods[0] = load_and_access ("tst-tls-ie-mod0.so", "access0"); ++ mods[1] = load_and_access ("tst-tls-ie-mod1.so", "access1"); ++ mods[2] = load_and_access ("tst-tls-ie-mod2.so", "access2"); ++ mods[3] = load_and_access ("tst-tls-ie-mod3.so", "access3"); ++ /* Load modules with initial-exec TLS (can only use surplus static TLS). */ ++ mods[4] = load_and_access ("tst-tls-ie-mod4.so", "access4"); ++ mods[5] = load_and_access ("tst-tls-ie-mod5.so", "access5"); ++ ++ /* Here 1152 bytes of surplus static TLS is in use and at most 512 bytes ++ are available (depending on TLS optimizations). */ ++ printf ("The next dlopen should fail...\n"); ++ void *p = dlopen ("tst-tls-ie-mod6.so", RTLD_NOW); ++ if (p != NULL) ++ FAIL_EXIT1 ("error: expected dlopen to fail because there is " ++ "not enough surplus static TLS.\n"); ++ printf ("...OK failed with: %s.\n", dlerror ()); ++ ++ xpthread_barrier_wait (&barrier); ++ xpthread_join (blocked_thread); ++ ++ /* Close the modules. */ ++ for (int i = 0; i < 6; ++i) ++ xdlclose (mods[i]); ++ ++ return 0; ++} +diff --git a/manual/tunables.texi b/manual/tunables.texi +index e6a3e9a2cf5c959c..bd737b5d57080462 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -249,6 +249,23 @@ increase the per-thread memory usage as necessary, so this tunable does + not need to be changed to allow many audit modules e.g. via @env{LD_AUDIT}. + @end deftp + ++@deftp Tunable glibc.rtld.optional_static_tls ++Sets the amount of surplus static TLS in bytes to allocate at program ++startup. Every thread created allocates this amount of specified surplus ++static TLS. This is a minimum value and additional space may be allocated ++for internal purposes including alignment. Optional static TLS is used for ++optimizing dynamic TLS access for platforms that support such optimizations ++e.g. TLS descriptors or optimized TLS access for POWER (@code{DT_PPC64_OPT} ++and @code{DT_PPC_OPT}). In order to make the best use of such optimizations ++the value should be as many bytes as would be required to hold all TLS ++variables in all dynamic loaded shared libraries. The value cannot be known ++by the dynamic loader because it doesn't know the expected set of shared ++libraries which will be loaded. The existing static TLS space cannot be ++changed once allocated at process startup. The default allocation of ++optional static TLS is 512 bytes and is allocated in every thread. ++@end deftp ++ ++ + @node Elision Tunables + @section Elision Tunables + @cindex elision tunables +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 293f3ab5a496afdf..37f1915b0c75a020 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -441,6 +441,9 @@ struct rtld_global + EXTERN size_t _dl_tls_static_used; + /* Alignment requirement of the static TLS block. */ + EXTERN size_t _dl_tls_static_align; ++ /* Remaining amount of static TLS that may be used for optimizing ++ dynamic TLS access (e.g. with TLSDESC). */ ++ EXTERN size_t _dl_tls_static_optional; + + /* Number of additional entries in the slotinfo array of each slotinfo + list element. A large number makes it almost certain take we never diff --git a/SOURCES/glibc-rh1817513-8.patch b/SOURCES/glibc-rh1817513-8.patch new file mode 100644 index 0000000..5f82d23 --- /dev/null +++ b/SOURCES/glibc-rh1817513-8.patch @@ -0,0 +1,74 @@ +commit d90c9b1a121295a5e31810b899ab637f68898857 +Author: Joseph Myers +Date: Thu Sep 20 12:43:41 2018 +0000 + + Invert sense of list of i686-class processors in sysdeps/x86/cpu-features.h. + + I noticed that sysdeps/x86/cpu-features.h had conditionals on whether + to define HAS_CPUID, HAS_I586 and HAS_I686 with a long list of + preprocessor macros for i686-and-later processors which however was + out of date. This patch avoids the problem of the list getting out of + date by instead having conditionals on all the (few, old) pre-i686 + processors for which GCC has preprocessor macros, rather than the + (many, expanding list) i686-and-later processors. It seems HAS_I586 + and HAS_I686 are unused so the only effect of these macros being + missing is that 32-bit glibc built for one of these processors would + end up doing runtime detection of CPUID availability. + + i386 builds are prevented by a configure test so there is no need to + allow for them here. __geode__ (no long nops?) and __k6__ (no CMOV, + at least according to GCC) are conservatively handled as i586, not + i686, here (as noted above, this is a theoretical distinction at + present in that only HAS_CPUID appears to be used). + + Tested for x86. + + * sysdeps/x86/cpu-features.h [__geode__ || __k6__]: Handle like + [__i586__ || __pentium__]. + [__i486__]: Handle explicitly. + (HAS_CPUID): Define to 1 if above macros are undefined. + (HAS_I586): Likewise. + (HAS_I686): Likewise. + +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index d342664c64ab7aa1..fb22d7b9d6226a92 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -257,30 +257,19 @@ extern const struct cpu_features *__get_cpu_features (void) + + #ifdef __x86_64__ + # define HAS_CPUID 1 +-#elif defined __i586__ || defined __pentium__ ++#elif (defined __i586__ || defined __pentium__ \ ++ || defined __geode__ || defined __k6__) + # define HAS_CPUID 1 + # define HAS_I586 1 + # define HAS_I686 HAS_ARCH_FEATURE (I686) +-#elif (defined __i686__ || defined __pentiumpro__ \ +- || defined __pentium4__ || defined __nocona__ \ +- || defined __atom__ || defined __core2__ \ +- || defined __corei7__ || defined __corei7_avx__ \ +- || defined __core_avx2__ || defined __nehalem__ \ +- || defined __sandybridge__ || defined __haswell__ \ +- || defined __knl__ || defined __bonnell__ \ +- || defined __silvermont__ \ +- || defined __k6__ || defined __k8__ \ +- || defined __athlon__ || defined __amdfam10__ \ +- || defined __bdver1__ || defined __bdver2__ \ +- || defined __bdver3__ || defined __bdver4__ \ +- || defined __btver1__ || defined __btver2__) +-# define HAS_CPUID 1 +-# define HAS_I586 1 +-# define HAS_I686 1 +-#else ++#elif defined __i486__ + # define HAS_CPUID 0 + # define HAS_I586 HAS_ARCH_FEATURE (I586) + # define HAS_I686 HAS_ARCH_FEATURE (I686) ++#else ++# define HAS_CPUID 1 ++# define HAS_I586 1 ++# define HAS_I686 1 + #endif + + #endif /* cpu_features_h */ diff --git a/SOURCES/glibc-rh1817513-80.patch b/SOURCES/glibc-rh1817513-80.patch new file mode 100644 index 0000000..1f83e15 --- /dev/null +++ b/SOURCES/glibc-rh1817513-80.patch @@ -0,0 +1,151 @@ +commit 07ed32f920f0bcb1ddb400e4ed606104756dee32 +Author: Florian Weimer +Date: Mon Jul 20 13:30:45 2020 +0200 + + elf: Change TLS static surplus default back to 1664 + + Make the computation in elf/dl-tls.c more transparent, and add + an explicit test for the historic value. + + Reviewed-by: Carlos O'Donell + +Conflicts: + elf/Makefile + (Missing test backports.) + elf/dl-tls.c + (Missing backport of rseq and its revert.) + +diff --git a/elf/Makefile b/elf/Makefile +index 8b96bfefd852b79f..82b5b4a07495c805 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -204,7 +204,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-create_format1 tst-tls-surplus + tests-container += tst-pldd + ifeq ($(build-hardcoded-path-in-tests),yes) + tests += tst-dlopen-aout +@@ -1714,3 +1714,5 @@ $(objpfx)tst-tls-ie-dlmopen.out: \ + $(objpfx)tst-tls-ie-mod4.so \ + $(objpfx)tst-tls-ie-mod5.so \ + $(objpfx)tst-tls-ie-mod6.so ++ ++$(objpfx)tst-tls-surplus: $(libdl) +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index 4f8c35b7d37bfc18..cccf74b33481b866 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -54,13 +54,37 @@ + Audit modules use their own namespaces, they are not included in rtld.nns, + but come on top when computing the number of namespaces. */ + +-/* Size of initial-exec TLS in libc.so. */ +-#define LIBC_IE_TLS 192 ++/* Size of initial-exec TLS in libc.so. This should be the maximum of ++ observed PT_GNU_TLS sizes across all architectures. Some ++ architectures have lower values due to differences in type sizes ++ and link editor capabilities. */ ++#define LIBC_IE_TLS 144 ++ + /* Size of initial-exec TLS in libraries other than libc.so. + This should be large enough to cover runtime libraries of the + compiler such as libgomp and libraries in libc other than libc.so. */ + #define OTHER_IE_TLS 144 + ++/* Default number of namespaces. */ ++#define DEFAULT_NNS 4 ++ ++/* Default for dl_tls_static_optional. */ ++#define OPTIONAL_TLS 512 ++ ++/* Compute the static TLS surplus based on the namespace count and the ++ TLS space that can be used for optimizations. */ ++static inline int ++tls_static_surplus (int nns, int opt_tls) ++{ ++ return (nns - 1) * LIBC_IE_TLS + nns * OTHER_IE_TLS + opt_tls; ++} ++ ++/* This value is chosen so that with default values for the tunables, ++ the computation of dl_tls_static_surplus in ++ _dl_tls_static_surplus_init yields the historic value 1664, for ++ backwards compatibility. */ ++#define LEGACY_TLS (1664 - tls_static_surplus (DEFAULT_NNS, OPTIONAL_TLS)) ++ + /* Calculate the size of the static TLS surplus, when the given + number of audit modules are loaded. Must be called after the + number of audit modules is known and before static TLS allocation. */ +@@ -74,8 +98,8 @@ _dl_tls_static_surplus_init (size_t naudit) + opt_tls = TUNABLE_GET (optional_static_tls, size_t, NULL); + #else + /* Default values of the tunables. */ +- nns = 4; +- opt_tls = 512; ++ nns = DEFAULT_NNS; ++ opt_tls = OPTIONAL_TLS; + #endif + if (nns > DL_NNS) + nns = DL_NNS; +@@ -85,9 +109,8 @@ _dl_tls_static_surplus_init (size_t naudit) + nns += naudit; + + GL(dl_tls_static_optional) = opt_tls; +- GLRO(dl_tls_static_surplus) = ((nns - 1) * LIBC_IE_TLS +- + nns * OTHER_IE_TLS +- + opt_tls); ++ assert (LEGACY_TLS >= 0); ++ GLRO(dl_tls_static_surplus) = tls_static_surplus (nns, opt_tls) + LEGACY_TLS; + } + + /* Out-of-memory handler. */ +diff --git a/elf/tst-tls-surplus.c b/elf/tst-tls-surplus.c +new file mode 100644 +index 0000000000000000..b0dea0b5ee178ddd +--- /dev/null ++++ b/elf/tst-tls-surplus.c +@@ -0,0 +1,42 @@ ++/* Test size of the static TLS surplus reservation for backwards compatibility. ++ 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 ++ ++static int do_test (void); ++#include ++ ++/* This hack results in a definition of struct rtld_global_ro. Do ++ this after all the other header inclusions, to minimize the ++ impact. */ ++#define SHARED ++#include ++ ++static ++int do_test (void) ++{ ++ /* Avoid introducing a copy relocation due to the hidden alias in ++ ld.so. */ ++ struct rtld_global_ro *glro = xdlsym (NULL, "_rtld_global_ro"); ++ printf ("info: _dl_tls_static_surplus: %zu\n", glro->_dl_tls_static_surplus); ++ /* Hisoric value: 16 * 100 + 64. */ ++ TEST_VERIFY (glro->_dl_tls_static_surplus >= 1664); ++ return 0; ++} diff --git a/SOURCES/glibc-rh1817513-81.patch b/SOURCES/glibc-rh1817513-81.patch new file mode 100644 index 0000000..1a035bc --- /dev/null +++ b/SOURCES/glibc-rh1817513-81.patch @@ -0,0 +1,137 @@ +commit ac3bda9a251f1512650f7b2c10d711c740ee0b78 +Author: H.J. Lu +Date: Wed Aug 5 08:20:52 2020 -0700 + + x86: Rename Intel CPU feature names + + Intel64 and IA-32 Architectures Software Developer’s Manual has changed + the following CPU feature names: + + 1. The CPU feature of Enhanced Intel SpeedStep Technology is renamed + from EST to EIST. + 2. The CPU feature which supports Platform Quality of Service Monitoring + (PQM) capability is changed to Intel Resource Director Technology + (Intel RDT) Monitoring capability, i.e. PQM is renamed to RDT_M. + 3. The CPU feature which supports Platform Quality of Service + Enforcement (PQE) capability is changed to Intel Resource Director + Technology (Intel RDT) Allocation capability, i.e. PQE is renamed to + RDT_A. + +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 21708c028a12dbb2..3b401d441b8d370a 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -156,7 +156,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_DS_CPL (1u << 4) + #define bit_cpu_VMX (1u << 5) + #define bit_cpu_SMX (1u << 6) +-#define bit_cpu_EST (1u << 7) ++#define bit_cpu_EIST (1u << 7) + #define bit_cpu_TM2 (1u << 8) + #define bit_cpu_SSSE3 (1u << 9) + #define bit_cpu_CNXT_ID (1u << 10) +@@ -231,10 +231,10 @@ extern const struct cpu_features *__get_cpu_features (void) + #define bit_cpu_ERMS (1u << 9) + #define bit_cpu_INVPCID (1u << 10) + #define bit_cpu_RTM (1u << 11) +-#define bit_cpu_PQM (1u << 12) ++#define bit_cpu_RDT_M (1u << 12) + #define bit_cpu_DEPR_FPU_CS_DS (1u << 13) + #define bit_cpu_MPX (1u << 14) +-#define bit_cpu_PQE (1u << 15) ++#define bit_cpu_RDT_A (1u << 15) + #define bit_cpu_AVX512F (1u << 16) + #define bit_cpu_AVX512DQ (1u << 17) + #define bit_cpu_RDSEED (1u << 18) +@@ -371,7 +371,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_DS_CPL COMMON_CPUID_INDEX_1 + #define index_cpu_VMX COMMON_CPUID_INDEX_1 + #define index_cpu_SMX COMMON_CPUID_INDEX_1 +-#define index_cpu_EST COMMON_CPUID_INDEX_1 ++#define index_cpu_EIST COMMON_CPUID_INDEX_1 + #define index_cpu_TM2 COMMON_CPUID_INDEX_1 + #define index_cpu_SSSE3 COMMON_CPUID_INDEX_1 + #define index_cpu_CNXT_ID COMMON_CPUID_INDEX_1 +@@ -446,10 +446,10 @@ extern const struct cpu_features *__get_cpu_features (void) + #define index_cpu_ERMS COMMON_CPUID_INDEX_7 + #define index_cpu_INVPCID COMMON_CPUID_INDEX_7 + #define index_cpu_RTM COMMON_CPUID_INDEX_7 +-#define index_cpu_PQM COMMON_CPUID_INDEX_7 ++#define index_cpu_RDT_M COMMON_CPUID_INDEX_7 + #define index_cpu_DEPR_FPU_CS_DS COMMON_CPUID_INDEX_7 + #define index_cpu_MPX COMMON_CPUID_INDEX_7 +-#define index_cpu_PQE COMMON_CPUID_INDEX_7 ++#define index_cpu_RDT_A COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512F COMMON_CPUID_INDEX_7 + #define index_cpu_AVX512DQ COMMON_CPUID_INDEX_7 + #define index_cpu_RDSEED COMMON_CPUID_INDEX_7 +@@ -584,7 +584,7 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_DS_CPL ecx + #define reg_VMX ecx + #define reg_SMX ecx +-#define reg_EST ecx ++#define reg_EIST ecx + #define reg_TM2 ecx + #define reg_SSSE3 ecx + #define reg_CNXT_ID ecx +@@ -659,10 +659,10 @@ extern const struct cpu_features *__get_cpu_features (void) + #define reg_ERMS ebx + #define reg_INVPCID ebx + #define reg_RTM ebx +-#define reg_PQM ebx ++#define reg_RDT_M ebx + #define reg_DEPR_FPU_CS_DS ebx + #define reg_MPX ebx +-#define reg_PQE ebx ++#define reg_RDT_A ebx + #define reg_AVX512F ebx + #define reg_AVX512DQ ebx + #define reg_RDSEED ebx +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index 85ec9d5a091e2c88..582b125a2dad3f21 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -73,7 +73,7 @@ do_test (void) + CHECK_CPU_FEATURE (DS_CPL); + CHECK_CPU_FEATURE (VMX); + CHECK_CPU_FEATURE (SMX); +- CHECK_CPU_FEATURE (EST); ++ CHECK_CPU_FEATURE (EIST); + CHECK_CPU_FEATURE (TM2); + CHECK_CPU_FEATURE (SSSE3); + CHECK_CPU_FEATURE (CNXT_ID); +@@ -136,10 +136,10 @@ do_test (void) + CHECK_CPU_FEATURE (ERMS); + CHECK_CPU_FEATURE (INVPCID); + CHECK_CPU_FEATURE (RTM); +- CHECK_CPU_FEATURE (PQM); ++ CHECK_CPU_FEATURE (RDT_M); + CHECK_CPU_FEATURE (DEPR_FPU_CS_DS); + CHECK_CPU_FEATURE (MPX); +- CHECK_CPU_FEATURE (PQE); ++ CHECK_CPU_FEATURE (RDT_A); + CHECK_CPU_FEATURE (AVX512F); + CHECK_CPU_FEATURE (AVX512DQ); + CHECK_CPU_FEATURE (RDSEED); +@@ -226,7 +226,7 @@ do_test (void) + CHECK_CPU_FEATURE_USABLE (DS_CPL); + CHECK_CPU_FEATURE_USABLE (VMX); + CHECK_CPU_FEATURE_USABLE (SMX); +- CHECK_CPU_FEATURE_USABLE (EST); ++ CHECK_CPU_FEATURE_USABLE (EIST); + CHECK_CPU_FEATURE_USABLE (TM2); + CHECK_CPU_FEATURE_USABLE (SSSE3); + CHECK_CPU_FEATURE_USABLE (CNXT_ID); +@@ -289,10 +289,10 @@ do_test (void) + CHECK_CPU_FEATURE_USABLE (ERMS); + CHECK_CPU_FEATURE_USABLE (INVPCID); + CHECK_CPU_FEATURE_USABLE (RTM); +- CHECK_CPU_FEATURE_USABLE (PQM); ++ CHECK_CPU_FEATURE_USABLE (RDT_M); + CHECK_CPU_FEATURE_USABLE (DEPR_FPU_CS_DS); + CHECK_CPU_FEATURE_USABLE (MPX); +- CHECK_CPU_FEATURE_USABLE (PQE); ++ CHECK_CPU_FEATURE_USABLE (RDT_A); + CHECK_CPU_FEATURE_USABLE (AVX512F); + CHECK_CPU_FEATURE_USABLE (AVX512DQ); + CHECK_CPU_FEATURE_USABLE (RDSEED); diff --git a/SOURCES/glibc-rh1817513-82.patch b/SOURCES/glibc-rh1817513-82.patch new file mode 100644 index 0000000..6a04b8c --- /dev/null +++ b/SOURCES/glibc-rh1817513-82.patch @@ -0,0 +1,178 @@ +commit 04bba1e5d84b6fd8d3a3b006bc240cd5d241ee30 +Author: H.J. Lu +Date: Wed Aug 5 13:51:56 2020 -0700 + + x86: Set CPU usable feature bits conservatively [BZ #26552] + + Set CPU usable feature bits only for CPU features which are usable in + user space and whose usability can be detected from user space, excluding + features like FSGSBASE whose enable bit can only be checked in the kernel. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index f13a1df4555c7000..6954728c47d0126b 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -44,107 +44,55 @@ extern void TUNABLE_CALLBACK (set_x86_shstk) (tunable_val_t *) + static void + update_usable (struct cpu_features *cpu_features) + { +- /* Before COMMON_CPUID_INDEX_80000001, copy the cpuid array elements to +- the usable array. */ +- unsigned int i; +- for (i = 0; i < COMMON_CPUID_INDEX_80000001; i++) +- cpu_features->features[i].usable = cpu_features->features[i].cpuid; +- +- /* Before COMMON_CPUID_INDEX_80000001, clear the unknown usable bits +- and the always zero bits. */ +- CPU_FEATURE_UNSET (cpu_features, INDEX_1_ECX_16); +- CPU_FEATURE_UNSET (cpu_features, INDEX_1_ECX_31); +- CPU_FEATURE_UNSET (cpu_features, INDEX_1_EDX_10); +- CPU_FEATURE_UNSET (cpu_features, INDEX_1_EDX_20); +- CPU_FEATURE_UNSET (cpu_features, INDEX_1_EDX_30); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EBX_6); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EBX_22); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_13); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_15); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_16); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_23); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_24); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_ECX_26); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_0); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_1); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_5); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_6); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_7); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_9); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_11); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_12); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_13); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_17); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_19); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_21); +- CPU_FEATURE_UNSET (cpu_features, INDEX_7_EDX_23); +- +- /* EAX/EBX from COMMON_CPUID_INDEX_1 and EAX from COMMON_CPUID_INDEX_7 +- aren't used for CPU feature detection. */ +- cpu_features->features[COMMON_CPUID_INDEX_1].usable.eax = 0; +- cpu_features->features[COMMON_CPUID_INDEX_1].usable.ebx = 0; +- cpu_features->features[COMMON_CPUID_INDEX_7].usable.eax = 0; +- +- /* Starting from COMMON_CPUID_INDEX_80000001, copy the cpuid bits to +- usable bits. */ ++ /* Copy the cpuid bits to usable bits for CPU featuress whose usability ++ in user space can be detected without additonal OS support. */ ++ CPU_FEATURE_SET_USABLE (cpu_features, SSE3); ++ CPU_FEATURE_SET_USABLE (cpu_features, PCLMULQDQ); ++ CPU_FEATURE_SET_USABLE (cpu_features, SSSE3); ++ CPU_FEATURE_SET_USABLE (cpu_features, CMPXCHG16B); ++ CPU_FEATURE_SET_USABLE (cpu_features, SSE4_1); ++ CPU_FEATURE_SET_USABLE (cpu_features, SSE4_2); ++ CPU_FEATURE_SET_USABLE (cpu_features, MOVBE); ++ CPU_FEATURE_SET_USABLE (cpu_features, POPCNT); ++ CPU_FEATURE_SET_USABLE (cpu_features, AES); ++ CPU_FEATURE_SET_USABLE (cpu_features, OSXSAVE); ++ CPU_FEATURE_SET_USABLE (cpu_features, TSC); ++ CPU_FEATURE_SET_USABLE (cpu_features, CX8); ++ CPU_FEATURE_SET_USABLE (cpu_features, CMOV); ++ CPU_FEATURE_SET_USABLE (cpu_features, CLFSH); ++ CPU_FEATURE_SET_USABLE (cpu_features, MMX); ++ CPU_FEATURE_SET_USABLE (cpu_features, FXSR); ++ CPU_FEATURE_SET_USABLE (cpu_features, SSE); ++ CPU_FEATURE_SET_USABLE (cpu_features, SSE2); ++ CPU_FEATURE_SET_USABLE (cpu_features, HTT); ++ CPU_FEATURE_SET_USABLE (cpu_features, BMI1); ++ CPU_FEATURE_SET_USABLE (cpu_features, HLE); ++ CPU_FEATURE_SET_USABLE (cpu_features, BMI2); ++ CPU_FEATURE_SET_USABLE (cpu_features, ERMS); ++ CPU_FEATURE_SET_USABLE (cpu_features, RTM); ++ CPU_FEATURE_SET_USABLE (cpu_features, RDSEED); ++ CPU_FEATURE_SET_USABLE (cpu_features, ADX); ++ CPU_FEATURE_SET_USABLE (cpu_features, CLFLUSHOPT); ++ CPU_FEATURE_SET_USABLE (cpu_features, CLWB); ++ CPU_FEATURE_SET_USABLE (cpu_features, SHA); ++ CPU_FEATURE_SET_USABLE (cpu_features, PREFETCHWT1); ++ CPU_FEATURE_SET_USABLE (cpu_features, OSPKE); ++ CPU_FEATURE_SET_USABLE (cpu_features, WAITPKG); ++ CPU_FEATURE_SET_USABLE (cpu_features, GFNI); ++ CPU_FEATURE_SET_USABLE (cpu_features, RDPID); ++ CPU_FEATURE_SET_USABLE (cpu_features, CLDEMOTE); ++ CPU_FEATURE_SET_USABLE (cpu_features, MOVDIRI); ++ CPU_FEATURE_SET_USABLE (cpu_features, MOVDIR64B); ++ CPU_FEATURE_SET_USABLE (cpu_features, FSRM); ++ CPU_FEATURE_SET_USABLE (cpu_features, SERIALIZE); ++ CPU_FEATURE_SET_USABLE (cpu_features, TSXLDTRK); + CPU_FEATURE_SET_USABLE (cpu_features, LAHF64_SAHF64); +- CPU_FEATURE_SET_USABLE (cpu_features, SVM); + CPU_FEATURE_SET_USABLE (cpu_features, LZCNT); + CPU_FEATURE_SET_USABLE (cpu_features, SSE4A); + CPU_FEATURE_SET_USABLE (cpu_features, PREFETCHW); +- CPU_FEATURE_SET_USABLE (cpu_features, XOP); +- CPU_FEATURE_SET_USABLE (cpu_features, LWP); +- CPU_FEATURE_SET_USABLE (cpu_features, FMA4); + CPU_FEATURE_SET_USABLE (cpu_features, TBM); +- CPU_FEATURE_SET_USABLE (cpu_features, SYSCALL_SYSRET); +- CPU_FEATURE_SET_USABLE (cpu_features, NX); +- CPU_FEATURE_SET_USABLE (cpu_features, PAGE1GB); + CPU_FEATURE_SET_USABLE (cpu_features, RDTSCP); +- CPU_FEATURE_SET_USABLE (cpu_features, LM); +- CPU_FEATURE_SET_USABLE (cpu_features, XSAVEOPT); +- CPU_FEATURE_SET_USABLE (cpu_features, XSAVEC); +- CPU_FEATURE_SET_USABLE (cpu_features, XGETBV_ECX_1); +- CPU_FEATURE_SET_USABLE (cpu_features, XSAVES); +- CPU_FEATURE_SET_USABLE (cpu_features, XFD); +- CPU_FEATURE_SET_USABLE (cpu_features, INVARIANT_TSC); + CPU_FEATURE_SET_USABLE (cpu_features, WBNOINVD); +- CPU_FEATURE_SET_USABLE (cpu_features, AVX512_BF16); +- +- /* MPX has been deprecated. */ +- CPU_FEATURE_UNSET (cpu_features, MPX); +- +- /* Clear the usable bits which require OS support. */ +- CPU_FEATURE_UNSET (cpu_features, FMA); +- CPU_FEATURE_UNSET (cpu_features, AVX); +- CPU_FEATURE_UNSET (cpu_features, F16C); +- CPU_FEATURE_UNSET (cpu_features, AVX2); +- CPU_FEATURE_UNSET (cpu_features, AVX512F); +- CPU_FEATURE_UNSET (cpu_features, AVX512DQ); +- CPU_FEATURE_UNSET (cpu_features, AVX512_IFMA); +- CPU_FEATURE_UNSET (cpu_features, AVX512PF); +- CPU_FEATURE_UNSET (cpu_features, AVX512ER); +- CPU_FEATURE_UNSET (cpu_features, AVX512CD); +- CPU_FEATURE_UNSET (cpu_features, AVX512BW); +- CPU_FEATURE_UNSET (cpu_features, AVX512VL); +- CPU_FEATURE_UNSET (cpu_features, AVX512_VBMI); +- CPU_FEATURE_UNSET (cpu_features, PKU); +- CPU_FEATURE_UNSET (cpu_features, AVX512_VBMI2); +- CPU_FEATURE_UNSET (cpu_features, VAES); +- CPU_FEATURE_UNSET (cpu_features, VPCLMULQDQ); +- CPU_FEATURE_UNSET (cpu_features, AVX512_VNNI); +- CPU_FEATURE_UNSET (cpu_features, AVX512_BITALG); +- CPU_FEATURE_UNSET (cpu_features, AVX512_VPOPCNTDQ); +- CPU_FEATURE_UNSET (cpu_features, AVX512_4VNNIW); +- CPU_FEATURE_UNSET (cpu_features, AVX512_4FMAPS); +- CPU_FEATURE_UNSET (cpu_features, AVX512_VP2INTERSECT); +- CPU_FEATURE_UNSET (cpu_features, AMX_BF16); +- CPU_FEATURE_UNSET (cpu_features, AMX_TILE); +- CPU_FEATURE_UNSET (cpu_features, AMX_INT8); +- CPU_FEATURE_UNSET (cpu_features, XOP); +- CPU_FEATURE_UNSET (cpu_features, FMA4); +- CPU_FEATURE_UNSET (cpu_features, XSAVEC); +- CPU_FEATURE_UNSET (cpu_features, XFD); +- CPU_FEATURE_UNSET (cpu_features, AVX512_BF16); + + /* Can we call xgetbv? */ + if (CPU_FEATURES_CPU_P (cpu_features, OSXSAVE)) +@@ -243,8 +191,11 @@ update_usable (struct cpu_features *cpu_features) + CPU_FEATURE_SET_USABLE (cpu_features, AMX_INT8); + } + +- +- /* XFD is usable only when OSXSAVE is enabled. */ ++ /* These features are usable only when OSXSAVE is enabled. */ ++ CPU_FEATURE_SET (cpu_features, XSAVE); ++ CPU_FEATURE_SET_USABLE (cpu_features, XSAVEOPT); ++ CPU_FEATURE_SET_USABLE (cpu_features, XSAVEC); ++ CPU_FEATURE_SET_USABLE (cpu_features, XGETBV_ECX_1); + CPU_FEATURE_SET_USABLE (cpu_features, XFD); + + /* For _dl_runtime_resolve, set xsave_state_size to xsave area diff --git a/SOURCES/glibc-rh1817513-83.patch b/SOURCES/glibc-rh1817513-83.patch new file mode 100644 index 0000000..f3b8f3a --- /dev/null +++ b/SOURCES/glibc-rh1817513-83.patch @@ -0,0 +1,1664 @@ +commit 9620398097de3981c1adf5233e2b3478d36bc1b3 +Author: H.J. Lu +Date: Mon Jun 29 18:30:54 2020 -0700 + + x86: Install [BZ #26124] + + Install so that programmers can do + + #if __has_include() + #include + #endif + ... + + if (CPU_FEATURE_USABLE (SSE2)) + ... + if (CPU_FEATURE_USABLE (AVX2)) + ... + + exports only: + + enum + { + COMMON_CPUID_INDEX_1 = 0, + COMMON_CPUID_INDEX_7, + COMMON_CPUID_INDEX_80000001, + COMMON_CPUID_INDEX_D_ECX_1, + COMMON_CPUID_INDEX_80000007, + COMMON_CPUID_INDEX_80000008, + COMMON_CPUID_INDEX_7_ECX_1, + /* Keep the following line at the end. */ + COMMON_CPUID_INDEX_MAX + }; + + struct cpuid_features + { + struct cpuid_registers cpuid; + struct cpuid_registers usable; + }; + + struct cpu_features + { + struct cpu_features_basic basic; + struct cpuid_features features[COMMON_CPUID_INDEX_MAX]; + }; + + /* Get a pointer to the CPU features structure. */ + extern const struct cpu_features *__x86_get_cpu_features + (unsigned int max) __attribute__ ((const)); + + Since all feature checks are done through macros, programs compiled with + a newer are compatible with the older glibc binaries + as long as the layout of struct cpu_features is identical. The features + array can be expanded with backward binary compatibility for both .o and + .so files. When COMMON_CPUID_INDEX_MAX is increased to support new + processor features, __x86_get_cpu_features in the older glibc binaries + returns NULL and HAS_CPU_FEATURE/CPU_FEATURE_USABLE return false on the + new processor feature. No new symbol version is neeeded. + + Both CPU_FEATURE_USABLE and HAS_CPU_FEATURE are provided. HAS_CPU_FEATURE + can be used to identify processor features. + + Note: Although GCC has __builtin_cpu_supports, it only supports a subset + of and it is equivalent to CPU_FEATURE_USABLE. It + doesn't support HAS_CPU_FEATURE. + +Conflicts: + sysdeps/x86/sys/platform/x86.h + sysdeps/x86/tst-get-cpu-features.c + sysdeps/x86_64/multiarch/test-multiarch.c + (Copyright year, URL differences.) + +Downstream changes: Do not install , +and use a GLIBC_PRIVATE symbol for __x86_get_cpu_features. + +diff --git a/manual/platform.texi b/manual/platform.texi +index 504addc956086820..2c145acdc3564cbb 100644 +--- a/manual/platform.texi ++++ b/manual/platform.texi +@@ -7,6 +7,7 @@ + @menu + * PowerPC:: Facilities Specific to the PowerPC Architecture + * RISC-V:: Facilities Specific to the RISC-V Architecture ++* X86:: Facilities Specific to the X86 Architecture + @end menu + + @node PowerPC +@@ -134,3 +135,519 @@ all threads in the current process. Setting the + ordering on only the current thread is necessary. All other flag bits are + reserved. + @end deftypefun ++ ++@node X86 ++@appendixsec X86-specific Facilities ++ ++Facilities specific to X86 that are not specific to a particular ++operating system are declared in @file{sys/platform/x86.h}. ++ ++@deftypefun {const struct cpu_features *} __x86_get_cpu_features (unsigned int @var{max}) ++@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} ++Return a pointer to x86 CPU feature structure used by query macros for x86 ++CPU features. If @var{max} exceeds @code{COMMON_CPUID_INDEX_MAX} which ++is the limit of the CPUID leaves supported by @Theglibc{}, the function ++returns @code{NULL}, indicating that the queried processor feature is ++unsupported by @Theglibc{} run-time. ++@end deftypefun ++ ++@deftypefn Macro int HAS_CPU_FEATURE (@var{name}) ++This macro returns a nonzero value (true) if the processor has the feature ++@var{name}. ++@end deftypefn ++ ++@deftypefn Macro int CPU_FEATURE_USABLE (@var{name}) ++This macro returns a nonzero value (true) if the processor has the feature ++@var{name} and the feature is supported by the operating system. ++@end deftypefn ++ ++The supported processor features are: ++ ++@itemize @bullet ++ ++@item ++@code{ACPI} -- Thermal Monitor and Software Controlled Clock Facilities. ++ ++@item ++@code{ADX} -- ADX instruction extensions. ++ ++@item ++@code{APIC} -- APIC On-Chip. ++ ++@item ++@code{AES} -- The AES instruction extensions. ++ ++@item ++@code{AMX_BF16} -- Tile computational operations on bfloat16 numbers. ++ ++@item ++@code{AMX_INT8} -- Tile computational operations on 8-bit numbers. ++ ++@item ++@code{AMX_TILE} -- Tile architecture. ++ ++@item ++@code{ARCH_CAPABILITIES} -- IA32_ARCH_CAPABILITIES MSR. ++ ++@item ++@code{AVX} -- The AVX instruction extensions. ++ ++@item ++@code{AVX2} -- The AVX2 instruction extensions. ++ ++@item ++@code{AVX512_4FMAPS} -- The AVX512_4FMAPS instruction extensions. ++ ++@item ++@code{AVX512_4VNNIW} -- The AVX512_4VNNIW instruction extensions. ++ ++@item ++@code{AVX512_BF16} -- The AVX512_BF16 instruction extensions. ++ ++@item ++@code{AVX512_BITALG} -- The AVX512_BITALG instruction extensions. ++ ++@item ++@code{AVX512_IFMA} -- The AVX512_IFMA instruction extensions. ++ ++@item ++@code{AVX512_VBMI} -- The AVX512_VBMI instruction extensions. ++ ++@item ++@code{AVX512_VBMI2} -- The AVX512_VBMI2 instruction extensions. ++ ++@item ++@code{AVX512_VNNI} -- The AVX512_VNNI instruction extensions. ++ ++@item ++@code{AVX512_VP2INTERSECT} -- The AVX512_VP2INTERSECT instruction ++extensions. ++ ++@item ++@code{AVX512_VPOPCNTDQ} -- The AVX512_VPOPCNTDQ instruction extensions. ++ ++@item ++@code{AVX512BW} -- The AVX512BW instruction extensions. ++ ++@item ++@code{AVX512CD} -- The AVX512CD instruction extensions. ++ ++@item ++@code{AVX512ER} -- The AVX512ER instruction extensions. ++ ++@item ++@code{AVX512DQ} -- The AVX512DQ instruction extensions. ++ ++@item ++@code{AVX512F} -- The AVX512F instruction extensions. ++ ++@item ++@code{AVX512PF} -- The AVX512PF instruction extensions. ++ ++@item ++@code{AVX512VL} -- The AVX512VL instruction extensions. ++ ++@item ++@code{BMI1} -- BMI1 instructions. ++ ++@item ++@code{BMI2} -- BMI2 instructions. ++ ++@item ++@code{CLDEMOTE} -- CLDEMOTE instruction. ++ ++@item ++@code{CLFLUSHOPT} -- CLFLUSHOPT instruction. ++ ++@item ++@code{CLFSH} -- CLFLUSH instruction. ++ ++@item ++@code{CLWB} -- CLWB instruction. ++ ++@item ++@code{CMOV} -- Conditional Move instructions. ++ ++@item ++@code{CMPXCHG16B} -- CMPXCHG16B instruction. ++ ++@item ++@code{CNXT_ID} -- L1 Context ID. ++ ++@item ++@code{CORE_CAPABILITIES} -- IA32_CORE_CAPABILITIES MSR. ++ ++@item ++@code{CX8} -- CMPXCHG8B instruction. ++ ++@item ++@code{DCA} -- Data prefetch from a memory mapped device. ++ ++@item ++@code{DE} -- Debugging Extensions. ++ ++@item ++@code{DEPR_FPU_CS_DS} -- Deprecates FPU CS and FPU DS values. ++ ++@item ++@code{DS} -- Debug Store. ++ ++@item ++@code{DS_CPL} -- CPL Qualified Debug Store. ++ ++@item ++@code{DTES64} -- 64-bit DS Area. ++ ++@item ++@code{EIST} -- Enhanced Intel SpeedStep technology. ++ ++@item ++@code{ENQCMD} -- Enqueue Stores instructions. ++ ++@item ++@code{ERMS} -- Enhanced REP MOVSB/STOSB. ++ ++@item ++@code{F16C} -- 16-bit floating-point conversion instructions. ++ ++@item ++@code{FMA} -- FMA extensions using YMM state. ++ ++@item ++@code{FMA4} -- FMA4 instruction extensions. ++ ++@item ++@code{FPU} -- X87 Floating Point Unit On-Chip. ++ ++@item ++@code{FSGSBASE} -- RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE instructions. ++ ++@item ++@code{FSRM} -- Fast Short REP MOV. ++ ++@item ++@code{FXSR} -- FXSAVE and FXRSTOR instructions. ++ ++@item ++@code{GFNI} -- GFNI instruction extensions. ++ ++@item ++@code{HLE} -- HLE instruction extensions. ++ ++@item ++@code{HTT} -- Max APIC IDs reserved field is Valid. ++ ++@item ++@code{HYBRID} -- Hybrid processor. ++ ++@item ++@code{IBRS_IBPB} -- Indirect branch restricted speculation (IBRS) and ++the indirect branch predictor barrier (IBPB). ++ ++@item ++@code{IBT} -- Intel Indirect Branch Tracking instruction extensions. ++ ++@item ++@code{INVARIANT_TSC} -- Invariant TSC. ++ ++@item ++@code{INVPCID} -- INVPCID instruction. ++ ++@item ++@code{L1D_FLUSH} -- IA32_FLUSH_CMD MSR. ++ ++@item ++@code{LAHF64_SAHF64} -- LAHF/SAHF available in 64-bit mode. ++ ++@item ++@code{LM} -- Long mode. ++ ++@item ++@code{LWP} -- Lightweight profiling. ++ ++@item ++@code{LZCNT} -- LZCNT instruction. ++ ++@item ++@code{MCA} -- Machine Check Architecture. ++ ++@item ++@code{MCE} -- Machine Check Exception. ++ ++@item ++@code{MD_CLEAR} -- MD_CLEAR. ++ ++@item ++@code{MMX} -- Intel MMX Technology. ++ ++@item ++@code{MONITOR} -- MONITOR/MWAIT instructions. ++ ++@item ++@code{MOVBE} -- MOVBE instruction. ++ ++@item ++@code{MOVDIRI} -- MOVDIRI instruction. ++ ++@item ++@code{MOVDIR64B} -- MOVDIR64B instruction. ++ ++@item ++@code{MPX} -- Intel Memory Protection Extensions. ++ ++@item ++@code{MSR} -- Model Specific Registers RDMSR and WRMSR instructions. ++ ++@item ++@code{MTRR} -- Memory Type Range Registers. ++ ++@item ++@code{NX} -- No-execute page protection. ++ ++@item ++@code{OSPKE} -- OS has set CR4.PKE to enable protection keys. ++ ++@item ++@code{OSXSAVE} -- The OS has set CR4.OSXSAVE[bit 18] to enable ++XSETBV/XGETBV instructions to access XCR0 and to support processor ++extended state management using XSAVE/XRSTOR. ++ ++@item ++@code{PAE} -- Physical Address Extension. ++ ++@item ++@code{PAGE1GB} -- 1-GByte page. ++ ++@item ++@code{PAT} -- Page Attribute Table. ++ ++@item ++@code{PBE} -- Pending Break Enable. ++ ++@item ++@code{PCID} -- Process-context identifiers. ++ ++@item ++@code{PCLMULQDQ} -- PCLMULQDQ instruction. ++ ++@item ++@code{PCONFIG} -- PCONFIG instruction. ++ ++@item ++@code{PDCM} -- Perfmon and Debug Capability. ++ ++@item ++@code{PGE} -- Page Global Bit. ++ ++@item ++@code{PKS} -- Protection keys for supervisor-mode pages. ++ ++@item ++@code{PKU} -- Protection keys for user-mode pages. ++ ++@item ++@code{POPCNT} -- POPCNT instruction. ++ ++@item ++@code{PREFETCHW} -- PREFETCHW instruction. ++ ++@item ++@code{PREFETCHWT1} -- PREFETCHWT1 instruction. ++ ++@item ++@code{PSE} -- Page Size Extension. ++ ++@item ++@code{PSE_36} -- 36-Bit Page Size Extension. ++ ++@item ++@code{PSN} -- Processor Serial Number. ++ ++@item ++@code{RDPID} -- RDPID instruction. ++ ++@item ++@code{RDRAND} -- RDRAND instruction. ++ ++@item ++@code{RDSEED} -- RDSEED instruction. ++ ++@item ++@code{RDT_A} -- Intel Resource Director Technology (Intel RDT) Allocation ++capability. ++ ++@item ++@code{RDT_M} -- Intel Resource Director Technology (Intel RDT) Monitoring ++capability. ++ ++@item ++@code{RDTSCP} -- RDTSCP instruction. ++ ++@item ++@code{RTM} -- RTM instruction extensions. ++ ++@item ++@code{SDBG} -- IA32_DEBUG_INTERFACE MSR for silicon debug. ++ ++@item ++@code{SEP} -- SYSENTER and SYSEXIT instructions. ++ ++@item ++@code{SERIALIZE} -- SERIALIZE instruction. ++ ++@item ++@code{SGX} -- Intel Software Guard Extensions. ++ ++@item ++@code{SGX_LC} -- SGX Launch Configuration. ++ ++@item ++@code{SHA} -- SHA instruction extensions. ++ ++@item ++@code{SHSTK} -- Intel Shadow Stack instruction extensions. ++ ++@item ++@code{SMAP} -- Supervisor-Mode Access Prevention. ++ ++@item ++@code{SMEP} -- Supervisor-Mode Execution Prevention. ++ ++@item ++@code{SMX} -- Safer Mode Extensions. ++ ++@item ++@code{SS} -- Self Snoop. ++ ++@item ++@code{SSBD} -- Speculative Store Bypass Disable (SSBD). ++ ++@item ++@code{SSE} -- Streaming SIMD Extensions. ++ ++@item ++@code{SSE2} -- Streaming SIMD Extensions 2. ++ ++@item ++@code{SSE3} -- Streaming SIMD Extensions 3. ++ ++@item ++@code{SSE4_1} -- Streaming SIMD Extensions 4.1. ++ ++@item ++@code{SSE4_2} -- Streaming SIMD Extensions 4.2. ++ ++@item ++@code{SSE4A} -- SSE4A instruction extensions. ++ ++@item ++@code{SSSE3} -- Supplemental Streaming SIMD Extensions 3. ++ ++@item ++@code{STIBP} -- Single thread indirect branch predictors (STIBP). ++ ++@item ++@code{SVM} -- Secure Virtual Machine. ++ ++@item ++@code{SYSCALL_SYSRET} -- SYSCALL/SYSRET instructions. ++ ++@item ++@code{TBM} -- Trailing bit manipulation instructions. ++ ++@item ++@code{TM} -- Thermal Monitor. ++ ++@item ++@code{TM2} -- Thermal Monitor 2. ++ ++@item ++@code{TRACE} -- Intel Processor Trace. ++ ++@item ++@code{TSC} -- Time Stamp Counter. RDTSC instruction. ++ ++@item ++@code{TSC_ADJUST} -- IA32_TSC_ADJUST MSR. ++ ++@item ++@code{TSC_DEADLINE} -- Local APIC timer supports one-shot operation ++using a TSC deadline value. ++ ++@item ++@code{TSXLDTRK} -- TSXLDTRK instructions. ++ ++@item ++@code{UMIP} -- User-mode instruction prevention. ++ ++@item ++@code{VAES} -- VAES instruction extensions. ++ ++@item ++@code{VME} -- Virtual 8086 Mode Enhancements. ++ ++@item ++@code{VMX} -- Virtual Machine Extensions. ++ ++@item ++@code{VPCLMULQDQ} -- VPCLMULQDQ instruction. ++ ++@item ++@code{WAITPKG} -- WAITPKG instruction extensions. ++ ++@item ++@code{WBNOINVD} -- WBINVD/WBNOINVD instructions. ++ ++@item ++@code{X2APIC} -- x2APIC. ++ ++@item ++@code{XFD} -- Extended Feature Disable (XFD). ++ ++@item ++@code{XGETBV_ECX_1} -- XGETBV with ECX = 1. ++ ++@item ++@code{XOP} -- XOP instruction extensions. ++ ++@item ++@code{XSAVE} -- The XSAVE/XRSTOR processor extended states feature, the ++XSETBV/XGETBV instructions, and XCR0. ++ ++@item ++@code{XSAVEC} -- XSAVEC instruction. ++ ++@item ++@code{XSAVEOPT} -- XSAVEOPT instruction. ++ ++@item ++@code{XSAVES} -- XSAVES/XRSTORS instructions. ++ ++@item ++@code{XTPRUPDCTRL} -- xTPR Update Control. ++ ++@end itemize ++ ++You could query if a processor supports @code{AVX} with: ++ ++@smallexample ++#include ++ ++int ++support_avx (void) ++@{ ++ return HAS_CPU_FEATURE (AVX); ++@} ++@end smallexample ++ ++and if @code{AVX} is usable with: ++ ++@smallexample ++#include ++ ++int ++usable_avx (void) ++@{ ++ return CPU_FEATURE_USABLE (AVX); ++@} ++@end smallexample +diff --git a/sysdeps/i386/i686/multiarch/Makefile b/sysdeps/i386/i686/multiarch/Makefile +index bf75a9947fe013a3..c4897922d710d37e 100644 +--- a/sysdeps/i386/i686/multiarch/Makefile ++++ b/sysdeps/i386/i686/multiarch/Makefile +@@ -1,7 +1,3 @@ +-ifeq ($(subdir),csu) +-tests += test-multiarch +-endif +- + ifeq ($(subdir),string) + gen-as-const-headers += locale-defines.sym + sysdep_routines += bzero-sse2 memset-sse2 memcpy-ssse3 mempcpy-ssse3 \ +diff --git a/sysdeps/i386/i686/multiarch/test-multiarch.c b/sysdeps/i386/i686/multiarch/test-multiarch.c +deleted file mode 100644 +index 593cfec2735fb5b0..0000000000000000 +--- a/sysdeps/i386/i686/multiarch/test-multiarch.c ++++ /dev/null +@@ -1 +0,0 @@ +-#include +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index 962bbcb07eba1259..59e928e9d08d3229 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -5,7 +5,8 @@ endif + ifeq ($(subdir),elf) + sysdep-dl-routines += dl-get-cpu-features + +-tests += tst-get-cpu-features tst-get-cpu-features-static ++tests += tst-get-cpu-features tst-get-cpu-features-static \ ++ tst-cpu-features-cpuinfo tst-cpu-features-supports + tests-static += tst-get-cpu-features-static + endif + +diff --git a/sysdeps/x86/Versions b/sysdeps/x86/Versions +index e02923708e160881..df70e602192053c0 100644 +--- a/sysdeps/x86/Versions ++++ b/sysdeps/x86/Versions +@@ -1,5 +1,5 @@ + ld { + GLIBC_PRIVATE { +- __get_cpu_features; ++ __x86_get_cpu_features; + } + } +diff --git a/sysdeps/x86/dl-get-cpu-features.c b/sysdeps/x86/dl-get-cpu-features.c +index 49593f19c64ad0bb..2aba0d167129b336 100644 +--- a/sysdeps/x86/dl-get-cpu-features.c ++++ b/sysdeps/x86/dl-get-cpu-features.c +@@ -18,10 +18,12 @@ + + #include + +-#undef __get_cpu_features ++#undef __x86_get_cpu_features + + const struct cpu_features * +-__get_cpu_features (void) ++__x86_get_cpu_features (unsigned int max) + { ++ if (max > COMMON_CPUID_INDEX_MAX) ++ return NULL; + return &GLRO(dl_x86_cpu_features); + } +diff --git a/sysdeps/x86/include/cpu-features.h b/sysdeps/x86/include/cpu-features.h +new file mode 100644 +index 0000000000000000..dcf29b6fe8578078 +--- /dev/null ++++ b/sysdeps/x86/include/cpu-features.h +@@ -0,0 +1,183 @@ ++/* Data structure for x86 CPU features. ++ 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 _PRIVATE_CPU_FEATURES_H ++#define _PRIVATE_CPU_FEATURES_H 1 ++ ++#ifdef _CPU_FEATURES_H ++# error this should be impossible ++#endif ++ ++#ifndef _ISOMAC ++/* Get most of the contents from the public header, but we define a ++ different `struct cpu_features' type for private use. */ ++# define cpu_features cpu_features_public ++# define __x86_get_cpu_features __x86_get_cpu_features_public ++#endif ++ ++#include ++ ++#ifndef _ISOMAC ++ ++# undef cpu_features ++# undef __x86_get_cpu_features ++# define __get_cpu_features() __x86_get_cpu_features (0) ++ ++enum ++{ ++ /* The integer bit array index for the first set of preferred feature ++ bits. */ ++ PREFERRED_FEATURE_INDEX_1 = 0, ++ /* The current maximum size of the feature integer bit array. */ ++ PREFERRED_FEATURE_INDEX_MAX ++}; ++ ++/* Only used directly in cpu-features.c. */ ++# define CPU_FEATURE_SET(ptr, name) \ ++ ptr->features[index_cpu_##name].usable.reg_##name |= bit_cpu_##name; ++# define CPU_FEATURE_UNSET(ptr, name) \ ++ ptr->features[index_cpu_##name].usable.reg_##name &= ~bit_cpu_##name; ++# define CPU_FEATURE_SET_USABLE(ptr, name) \ ++ ptr->features[index_cpu_##name].usable.reg_##name \ ++ |= ptr->features[index_cpu_##name].cpuid.reg_##name & bit_cpu_##name; ++# define CPU_FEATURE_PREFERRED_P(ptr, name) \ ++ ((ptr->preferred[index_arch_##name] & bit_arch_##name) != 0) ++# define CPU_FEATURE_CPU_P(ptr, name) \ ++ CPU_FEATURE_CHECK_P (ptr, name, cpuid) ++ ++/* HAS_CPU_FEATURE evaluates to true if CPU supports the feature. */ ++# undef HAS_CPU_FEATURE ++# define HAS_CPU_FEATURE(name) \ ++ CPU_FEATURE_CPU_P (__x86_get_cpu_features (0), name) ++/* CPU_FEATURE_USABLE evaluates to true if the feature is usable. */ ++# undef CPU_FEATURE_USABLE ++# define CPU_FEATURE_USABLE(name) \ ++ CPU_FEATURE_USABLE_P (__x86_get_cpu_features (0), name) ++/* CPU_FEATURE_PREFER evaluates to true if we prefer the feature at ++ runtime. */ ++# define CPU_FEATURE_PREFERRED(name) \ ++ CPU_FEATURE_PREFERRED_P(__get_cpu_features (), name) ++ ++# define CPU_FEATURES_CPU_P(ptr, name) \ ++ CPU_FEATURE_CPU_P (ptr, name) ++# define CPU_FEATURES_ARCH_P(ptr, name) \ ++ CPU_FEATURE_PREFERRED_P (ptr, name) ++# define HAS_ARCH_FEATURE(name) \ ++ CPU_FEATURE_PREFERRED (name) ++ ++/* PREFERRED_FEATURE_INDEX_1. */ ++# define bit_arch_I586 (1u << 0) ++# define bit_arch_I686 (1u << 1) ++# define bit_arch_Fast_Rep_String (1u << 2) ++# define bit_arch_Fast_Copy_Backward (1u << 3) ++# define bit_arch_Fast_Unaligned_Load (1u << 4) ++# define bit_arch_Fast_Unaligned_Copy (1u << 5) ++# define bit_arch_Slow_BSF (1u << 6) ++# define bit_arch_Slow_SSE4_2 (1u << 7) ++# define bit_arch_AVX_Fast_Unaligned_Load (1u << 8) ++# define bit_arch_Prefer_MAP_32BIT_EXEC (1u << 9) ++# define bit_arch_Prefer_PMINUB_for_stringop (1u << 10) ++# define bit_arch_Prefer_No_VZEROUPPER (1u << 11) ++# define bit_arch_Prefer_ERMS (1u << 12) ++# define bit_arch_Prefer_FSRM (1u << 13) ++# define bit_arch_Prefer_No_AVX512 (1u << 14) ++# define bit_arch_MathVec_Prefer_No_AVX512 (1u << 15) ++ ++# define index_arch_Fast_Rep_String PREFERRED_FEATURE_INDEX_1 ++# define index_arch_Fast_Copy_Backward PREFERRED_FEATURE_INDEX_1 ++# define index_arch_Slow_BSF PREFERRED_FEATURE_INDEX_1 ++# define index_arch_Fast_Unaligned_Load PREFERRED_FEATURE_INDEX_1 ++# define index_arch_Prefer_PMINUB_for_stringop PREFERRED_FEATURE_INDEX_1 ++# define index_arch_Fast_Unaligned_Copy PREFERRED_FEATURE_INDEX_1 ++# define index_arch_I586 PREFERRED_FEATURE_INDEX_1 ++# define index_arch_I686 PREFERRED_FEATURE_INDEX_1 ++# define index_arch_Slow_SSE4_2 PREFERRED_FEATURE_INDEX_1 ++# define index_arch_AVX_Fast_Unaligned_Load PREFERRED_FEATURE_INDEX_1 ++# define index_arch_Prefer_MAP_32BIT_EXEC PREFERRED_FEATURE_INDEX_1 ++# define index_arch_Prefer_No_VZEROUPPER PREFERRED_FEATURE_INDEX_1 ++# define index_arch_Prefer_ERMS PREFERRED_FEATURE_INDEX_1 ++# define index_arch_Prefer_No_AVX512 PREFERRED_FEATURE_INDEX_1 ++# define index_arch_MathVec_Prefer_No_AVX512 PREFERRED_FEATURE_INDEX_1 ++# define index_arch_Prefer_FSRM PREFERRED_FEATURE_INDEX_1 ++ ++/* XCR0 Feature flags. */ ++# define bit_XMM_state (1u << 1) ++# define bit_YMM_state (1u << 2) ++# define bit_Opmask_state (1u << 5) ++# define bit_ZMM0_15_state (1u << 6) ++# define bit_ZMM16_31_state (1u << 7) ++# define bit_XTILECFG_state (1u << 17) ++# define bit_XTILEDATA_state (1u << 18) ++ ++struct cpu_features ++{ ++ struct cpu_features_basic basic; ++ struct cpuid_features features[COMMON_CPUID_INDEX_MAX]; ++ unsigned int preferred[PREFERRED_FEATURE_INDEX_MAX]; ++ /* The state size for XSAVEC or XSAVE. The type must be unsigned long ++ int so that we use ++ ++ sub xsave_state_size_offset(%rip) %RSP_LP ++ ++ in _dl_runtime_resolve. */ ++ unsigned long int xsave_state_size; ++ /* The full state size for XSAVE when XSAVEC is disabled by ++ ++ GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC ++ */ ++ unsigned int xsave_state_full_size; ++ /* Data cache size for use in memory and string routines, typically ++ L1 size. */ ++ unsigned long int data_cache_size; ++ /* Shared cache size for use in memory and string routines, typically ++ L2 or L3 size. */ ++ unsigned long int shared_cache_size; ++ /* Threshold to use non temporal store. */ ++ unsigned long int non_temporal_threshold; ++ /* Threshold to use "rep movsb". */ ++ unsigned long int rep_movsb_threshold; ++ /* Threshold to use "rep stosb". */ ++ unsigned long int rep_stosb_threshold; ++}; ++ ++# if defined (_LIBC) && !IS_IN (nonlib) ++/* Unused for x86. */ ++# define INIT_ARCH() ++# define __x86_get_cpu_features(max) (&GLRO(dl_x86_cpu_features)) ++# endif ++ ++# ifdef __x86_64__ ++# define HAS_CPUID 1 ++# elif (defined __i586__ || defined __pentium__ \ ++ || defined __geode__ || defined __k6__) ++# define HAS_CPUID 1 ++# define HAS_I586 1 ++# define HAS_I686 HAS_ARCH_FEATURE (I686) ++# elif defined __i486__ ++# define HAS_CPUID 0 ++# define HAS_I586 HAS_ARCH_FEATURE (I586) ++# define HAS_I686 HAS_ARCH_FEATURE (I686) ++# else ++# define HAS_CPUID 1 ++# define HAS_I586 1 ++# define HAS_I686 1 ++# endif ++ ++#endif /* !_ISOMAC */ ++ ++#endif /* include/cpu-features.h */ +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/sys/platform/x86.h +similarity index 81% +rename from sysdeps/x86/cpu-features.h +rename to sysdeps/x86/sys/platform/x86.h +index 3b401d441b8d370a..ebc5f6fc16cb8104 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/sys/platform/x86.h +@@ -1,5 +1,6 @@ +-/* This file is part of the GNU C Library. +- Copyright (C) 2008-2018 Free Software Foundation, Inc. ++/* Data structure for x86 CPU features. ++ This file is part of the GNU C Library. ++ Copyright (C) 2008-2020 Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -15,17 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + +-#ifndef cpu_features_h +-#define cpu_features_h +- +-enum +-{ +- /* The integer bit array index for the first set of preferred feature +- bits. */ +- PREFERRED_FEATURE_INDEX_1 = 0, +- /* The current maximum size of the feature integer bit array. */ +- PREFERRED_FEATURE_INDEX_MAX +-}; ++#ifndef _SYS_PLATFORM_X86_H ++#define _SYS_PLATFORM_X86_H + + enum + { +@@ -76,73 +68,32 @@ struct cpu_features + { + struct cpu_features_basic basic; + struct cpuid_features features[COMMON_CPUID_INDEX_MAX]; +- unsigned int preferred[PREFERRED_FEATURE_INDEX_MAX]; +- /* The state size for XSAVEC or XSAVE. The type must be unsigned long +- int so that we use +- +- sub xsave_state_size_offset(%rip) %RSP_LP +- +- in _dl_runtime_resolve. */ +- unsigned long int xsave_state_size; +- /* The full state size for XSAVE when XSAVEC is disabled by +- +- GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC +- */ +- unsigned int xsave_state_full_size; +- /* Data cache size for use in memory and string routines, typically +- L1 size. */ +- unsigned long int data_cache_size; +- /* Shared cache size for use in memory and string routines, typically +- L2 or L3 size. */ +- unsigned long int shared_cache_size; +- /* Threshold to use non temporal store. */ +- unsigned long int non_temporal_threshold; +- /* Threshold to use "rep movsb". */ +- unsigned long int rep_movsb_threshold; +- /* Threshold to use "rep stosb". */ +- unsigned long int rep_stosb_threshold; + }; + +-/* Used from outside of glibc to get access to the CPU features +- structure. */ +-extern const struct cpu_features *__get_cpu_features (void) ++/* Get a pointer to the CPU features structure. */ ++extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + __attribute__ ((const)); + +-/* Only used directly in cpu-features.c. */ + #define CPU_FEATURE_CHECK_P(ptr, name, check) \ + ((ptr->features[index_cpu_##name].check.reg_##name \ + & bit_cpu_##name) != 0) +-#define CPU_FEATURE_SET(ptr, name) \ +- ptr->features[index_cpu_##name].usable.reg_##name |= bit_cpu_##name; +-#define CPU_FEATURE_UNSET(ptr, name) \ +- ptr->features[index_cpu_##name].usable.reg_##name &= ~bit_cpu_##name; +-#define CPU_FEATURE_SET_USABLE(ptr, name) \ +- ptr->features[index_cpu_##name].usable.reg_##name \ +- |= ptr->features[index_cpu_##name].cpuid.reg_##name & bit_cpu_##name; +-#define CPU_FEATURE_PREFERRED_P(ptr, name) \ +- ((ptr->preferred[index_arch_##name] & bit_arch_##name) != 0) + #define CPU_FEATURE_CPU_P(ptr, name) \ + CPU_FEATURE_CHECK_P (ptr, name, cpuid) + #define CPU_FEATURE_USABLE_P(ptr, name) \ + CPU_FEATURE_CHECK_P (ptr, name, usable) + + /* HAS_CPU_FEATURE evaluates to true if CPU supports the feature. */ +-#define HAS_CPU_FEATURE(name) \ +- CPU_FEATURE_CPU_P (__get_cpu_features (), name) ++#define HAS_CPU_FEATURE(name) \ ++ (__extension__ \ ++ ({ const struct cpu_features *__ptr = \ ++ __x86_get_cpu_features (COMMON_CPUID_INDEX_MAX); \ ++ __ptr && CPU_FEATURE_CPU_P (__ptr, name); })) + /* CPU_FEATURE_USABLE evaluates to true if the feature is usable. */ +-#define CPU_FEATURE_USABLE(name) \ +- CPU_FEATURE_USABLE_P (__get_cpu_features (), name) +-/* CPU_FEATURE_PREFER evaluates to true if we prefer the feature at +- runtime. */ +-#define CPU_FEATURE_PREFERRED(name) \ +- CPU_FEATURE_PREFERRED_P(__get_cpu_features (), name) +- +-#define CPU_FEATURES_CPU_P(ptr, name) \ +- CPU_FEATURE_CPU_P (ptr, name) +-#define CPU_FEATURES_ARCH_P(ptr, name) \ +- CPU_FEATURE_PREFERRED_P (ptr, name) +-#define HAS_ARCH_FEATURE(name) \ +- CPU_FEATURE_PREFERRED (name) ++#define CPU_FEATURE_USABLE(name) \ ++ (__extension__ \ ++ ({ const struct cpu_features *__ptr = \ ++ __x86_get_cpu_features (COMMON_CPUID_INDEX_MAX); \ ++ __ptr && CPU_FEATURE_USABLE_P (__ptr, name); })) + + /* CPU features. */ + +@@ -787,71 +738,4 @@ extern const struct cpu_features *__get_cpu_features (void) + /* EAX. */ + #define reg_AVX512_BF16 eax + +-/* FEATURE_INDEX_2. */ +-#define bit_arch_I586 (1u << 0) +-#define bit_arch_I686 (1u << 1) +-#define bit_arch_Fast_Rep_String (1u << 2) +-#define bit_arch_Fast_Copy_Backward (1u << 3) +-#define bit_arch_Fast_Unaligned_Load (1u << 4) +-#define bit_arch_Fast_Unaligned_Copy (1u << 5) +-#define bit_arch_Slow_BSF (1u << 6) +-#define bit_arch_Slow_SSE4_2 (1u << 7) +-#define bit_arch_AVX_Fast_Unaligned_Load (1u << 8) +-#define bit_arch_Prefer_MAP_32BIT_EXEC (1u << 9) +-#define bit_arch_Prefer_PMINUB_for_stringop (1u << 10) +-#define bit_arch_Prefer_No_VZEROUPPER (1u << 11) +-#define bit_arch_Prefer_ERMS (1u << 12) +-#define bit_arch_Prefer_FSRM (1u << 13) +-#define bit_arch_Prefer_No_AVX512 (1u << 14) +-#define bit_arch_MathVec_Prefer_No_AVX512 (1u << 15) +- +-#define index_arch_Fast_Rep_String PREFERRED_FEATURE_INDEX_1 +-#define index_arch_Fast_Copy_Backward PREFERRED_FEATURE_INDEX_1 +-#define index_arch_Slow_BSF PREFERRED_FEATURE_INDEX_1 +-#define index_arch_Fast_Unaligned_Load PREFERRED_FEATURE_INDEX_1 +-#define index_arch_Prefer_PMINUB_for_stringop PREFERRED_FEATURE_INDEX_1 +-#define index_arch_Fast_Unaligned_Copy PREFERRED_FEATURE_INDEX_1 +-#define index_arch_I586 PREFERRED_FEATURE_INDEX_1 +-#define index_arch_I686 PREFERRED_FEATURE_INDEX_1 +-#define index_arch_Slow_SSE4_2 PREFERRED_FEATURE_INDEX_1 +-#define index_arch_AVX_Fast_Unaligned_Load PREFERRED_FEATURE_INDEX_1 +-#define index_arch_Prefer_MAP_32BIT_EXEC PREFERRED_FEATURE_INDEX_1 +-#define index_arch_Prefer_No_VZEROUPPER PREFERRED_FEATURE_INDEX_1 +-#define index_arch_Prefer_ERMS PREFERRED_FEATURE_INDEX_1 +-#define index_arch_Prefer_No_AVX512 PREFERRED_FEATURE_INDEX_1 +-#define index_arch_MathVec_Prefer_No_AVX512 PREFERRED_FEATURE_INDEX_1 +-#define index_arch_Prefer_FSRM PREFERRED_FEATURE_INDEX_1 +- +-/* XCR0 Feature flags. */ +-#define bit_XMM_state (1u << 1) +-#define bit_YMM_state (1u << 2) +-#define bit_Opmask_state (1u << 5) +-#define bit_ZMM0_15_state (1u << 6) +-#define bit_ZMM16_31_state (1u << 7) +-#define bit_XTILECFG_state (1u << 17) +-#define bit_XTILEDATA_state (1u << 18) +- +-# if defined (_LIBC) && !IS_IN (nonlib) +-/* Unused for x86. */ +-# define INIT_ARCH() +-# define __get_cpu_features() (&GLRO(dl_x86_cpu_features)) +-# endif +- +-#ifdef __x86_64__ +-# define HAS_CPUID 1 +-#elif (defined __i586__ || defined __pentium__ \ +- || defined __geode__ || defined __k6__) +-# define HAS_CPUID 1 +-# define HAS_I586 1 +-# define HAS_I686 HAS_ARCH_FEATURE (I686) +-#elif defined __i486__ +-# define HAS_CPUID 0 +-# define HAS_I586 HAS_ARCH_FEATURE (I586) +-# define HAS_I686 HAS_ARCH_FEATURE (I686) +-#else +-# define HAS_CPUID 1 +-# define HAS_I586 1 +-# define HAS_I686 1 +-#endif +- +-#endif /* cpu_features_h */ ++#endif /* _SYS_PLATFORM_X86_H */ +diff --git a/sysdeps/x86/tst-cpu-features-cpuinfo.c b/sysdeps/x86/tst-cpu-features-cpuinfo.c +new file mode 100644 +index 0000000000000000..96277284d15a0690 +--- /dev/null ++++ b/sysdeps/x86/tst-cpu-features-cpuinfo.c +@@ -0,0 +1,250 @@ ++/* Test CPU feature data against /proc/cpuinfo. ++ This file is part of the GNU C Library. ++ Copyright (C) 2012-2020 Free Software Foundation, Inc. ++ ++ 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 char *cpu_flags; ++ ++/* Search for flags in /proc/cpuinfo and store line ++ in cpu_flags. */ ++void ++get_cpuinfo (void) ++{ ++ FILE *f; ++ char *line = NULL; ++ size_t len = 0; ++ ssize_t read; ++ ++ f = fopen ("/proc/cpuinfo", "r"); ++ if (f == NULL) ++ { ++ printf ("cannot open /proc/cpuinfo\n"); ++ exit (1); ++ } ++ ++ while ((read = getline (&line, &len, f)) != -1) ++ { ++ if (strncmp (line, "flags", 5) == 0) ++ { ++ cpu_flags = strdup (line); ++ break; ++ } ++ } ++ fclose (f); ++ free (line); ++} ++ ++int ++check_proc (const char *proc_name, int flag, int usable, const char *name) ++{ ++ int found = 0; ++ ++ printf ("Checking %s:\n", name); ++ if (!usable) ++ { ++ printf (" %s: insufficient usable info, skipped\n", name); ++ return 0; ++ } ++ printf (" %s: %d\n", name, flag); ++ if (strstr (cpu_flags, proc_name) != NULL) ++ found = 1; ++ printf (" cpuinfo (%s): %d\n", proc_name, found); ++ ++ if (found != flag) ++ printf (" *** failure ***\n"); ++ ++ return (found != flag); ++} ++ ++#define CHECK_PROC(str, name) \ ++ check_proc (#str, HAS_CPU_FEATURE (name), CPU_FEATURE_USABLE (name), \ ++ "HAS_CPU_FEATURE (" #name ")"); ++ ++static int ++do_test (int argc, char **argv) ++{ ++ int fails = 0; ++ ++ get_cpuinfo (); ++ fails += CHECK_PROC (acpi, ACPI); ++ fails += CHECK_PROC (adx, ADX); ++ fails += CHECK_PROC (apic, APIC); ++ fails += CHECK_PROC (aes, AES); ++ fails += CHECK_PROC (amx_bf16, AMX_BF16); ++ fails += CHECK_PROC (amx_int8, AMX_INT8); ++ fails += CHECK_PROC (amx_tile, AMX_TILE); ++ fails += CHECK_PROC (arch_capabilities, ARCH_CAPABILITIES); ++ fails += CHECK_PROC (avx, AVX); ++ fails += CHECK_PROC (avx2, AVX2); ++ fails += CHECK_PROC (avx512_4fmaps, AVX512_4FMAPS); ++ fails += CHECK_PROC (avx512_4vnniw, AVX512_4VNNIW); ++ fails += CHECK_PROC (avx512_bf16, AVX512_BF16); ++ fails += CHECK_PROC (avx512_bitalg, AVX512_BITALG); ++ fails += CHECK_PROC (avx512ifma, AVX512_IFMA); ++ fails += CHECK_PROC (avx512_vbmi, AVX512_VBMI); ++ fails += CHECK_PROC (avx512_vbmi2, AVX512_VBMI2); ++ fails += CHECK_PROC (avx512_vnni, AVX512_VNNI); ++ fails += CHECK_PROC (avx512_vp2intersect, AVX512_VP2INTERSECT); ++ fails += CHECK_PROC (avx512_vpopcntdq, AVX512_VPOPCNTDQ); ++ fails += CHECK_PROC (avx512bw, AVX512BW); ++ fails += CHECK_PROC (avx512cd, AVX512CD); ++ fails += CHECK_PROC (avx512er, AVX512ER); ++ fails += CHECK_PROC (avx512dq, AVX512DQ); ++ fails += CHECK_PROC (avx512f, AVX512F); ++ fails += CHECK_PROC (avx512pf, AVX512PF); ++ fails += CHECK_PROC (avx512vl, AVX512VL); ++ fails += CHECK_PROC (bmi1, BMI1); ++ fails += CHECK_PROC (bmi2, BMI2); ++ fails += CHECK_PROC (cldemote, CLDEMOTE); ++ fails += CHECK_PROC (clflushopt, CLFLUSHOPT); ++ fails += CHECK_PROC (clflush, CLFSH); ++ fails += CHECK_PROC (clwb, CLWB); ++ fails += CHECK_PROC (cmov, CMOV); ++ fails += CHECK_PROC (cx16, CMPXCHG16B); ++ fails += CHECK_PROC (cnxt_id, CNXT_ID); ++ fails += CHECK_PROC (core_capabilities, CORE_CAPABILITIES); ++ fails += CHECK_PROC (cx8, CX8); ++ fails += CHECK_PROC (dca, DCA); ++ fails += CHECK_PROC (de, DE); ++ fails += CHECK_PROC (zero_fcs_fds, DEPR_FPU_CS_DS); ++ fails += CHECK_PROC (ds, DS); ++ fails += CHECK_PROC (ds_cpl, DS_CPL); ++ fails += CHECK_PROC (dtes64, DTES64); ++ fails += CHECK_PROC (est, EIST); ++ fails += CHECK_PROC (enqcmd, ENQCMD); ++ fails += CHECK_PROC (erms, ERMS); ++ fails += CHECK_PROC (f16c, F16C); ++ fails += CHECK_PROC (fma, FMA); ++ fails += CHECK_PROC (fma4, FMA4); ++ fails += CHECK_PROC (fpu, FPU); ++ fails += CHECK_PROC (fsgsbase, FSGSBASE); ++ fails += CHECK_PROC (fsrm, FSRM); ++ fails += CHECK_PROC (fxsr, FXSR); ++ fails += CHECK_PROC (gfni, GFNI); ++ fails += CHECK_PROC (hle, HLE); ++ fails += CHECK_PROC (ht, HTT); ++ fails += CHECK_PROC (hybrid, HYBRID); ++ fails += CHECK_PROC (ibrs, IBRS_IBPB); ++ fails += CHECK_PROC (ibt, IBT); ++ fails += CHECK_PROC (invariant_tsc, INVARIANT_TSC); ++ fails += CHECK_PROC (invpcid, INVPCID); ++ fails += CHECK_PROC (flush_l1d, L1D_FLUSH); ++ fails += CHECK_PROC (lahf_lm, LAHF64_SAHF64); ++ fails += CHECK_PROC (lm, LM); ++ fails += CHECK_PROC (lwp, LWP); ++ fails += CHECK_PROC (abm, LZCNT); ++ fails += CHECK_PROC (mca, MCA); ++ fails += CHECK_PROC (mce, MCE); ++ fails += CHECK_PROC (md_clear, MD_CLEAR); ++ fails += CHECK_PROC (mmx, MMX); ++ fails += CHECK_PROC (monitor, MONITOR); ++ fails += CHECK_PROC (movbe, MOVBE); ++ fails += CHECK_PROC (movdiri, MOVDIRI); ++ fails += CHECK_PROC (movdir64b, MOVDIR64B); ++ fails += CHECK_PROC (mpx, MPX); ++ fails += CHECK_PROC (msr, MSR); ++ fails += CHECK_PROC (mtrr, MTRR); ++ fails += CHECK_PROC (nx, NX); ++ fails += CHECK_PROC (ospke, OSPKE); ++#if 0 ++ /* NB: /proc/cpuinfo doesn't report this feature. */ ++ fails += CHECK_PROC (osxsave, OSXSAVE); ++#endif ++ fails += CHECK_PROC (pae, PAE); ++ fails += CHECK_PROC (pdpe1gb, PAGE1GB); ++ fails += CHECK_PROC (pat, PAT); ++ fails += CHECK_PROC (pbe, PBE); ++ fails += CHECK_PROC (pcid, PCID); ++ fails += CHECK_PROC (pclmulqdq, PCLMULQDQ); ++ fails += CHECK_PROC (pconfig, PCONFIG); ++ fails += CHECK_PROC (pdcm, PDCM); ++ fails += CHECK_PROC (pge, PGE); ++ fails += CHECK_PROC (pks, PKS); ++ fails += CHECK_PROC (pku, PKU); ++ fails += CHECK_PROC (popcnt, POPCNT); ++ fails += CHECK_PROC (3dnowprefetch, PREFETCHW); ++ fails += CHECK_PROC (prefetchwt1, PREFETCHWT1); ++ fails += CHECK_PROC (pse, PSE); ++ fails += CHECK_PROC (pse36, PSE_36); ++ fails += CHECK_PROC (psn, PSN); ++ fails += CHECK_PROC (rdpid, RDPID); ++ fails += CHECK_PROC (rdrand, RDRAND); ++ fails += CHECK_PROC (rdseed, RDSEED); ++ fails += CHECK_PROC (rdt_a, RDT_A); ++ fails += CHECK_PROC (cqm, RDT_M); ++ fails += CHECK_PROC (rdtscp, RDTSCP); ++ fails += CHECK_PROC (rtm, RTM); ++ fails += CHECK_PROC (sdbg, SDBG); ++ fails += CHECK_PROC (sep, SEP); ++ fails += CHECK_PROC (serialize, SERIALIZE); ++ fails += CHECK_PROC (sgx, SGX); ++ fails += CHECK_PROC (sgx_lc, SGX_LC); ++ fails += CHECK_PROC (sha_ni, SHA); ++ fails += CHECK_PROC (shstk, SHSTK); ++ fails += CHECK_PROC (smap, SMAP); ++ fails += CHECK_PROC (smep, SMEP); ++ fails += CHECK_PROC (smx, SMX); ++ fails += CHECK_PROC (ss, SS); ++ fails += CHECK_PROC (ssbd, SSBD); ++ fails += CHECK_PROC (sse, SSE); ++ fails += CHECK_PROC (sse2, SSE2); ++ fails += CHECK_PROC (sse3, SSE3); ++ fails += CHECK_PROC (sse4_1, SSE4_1); ++ fails += CHECK_PROC (sse4_2, SSE4_2); ++ fails += CHECK_PROC (sse4a, SSE4A); ++ fails += CHECK_PROC (ssse3, SSSE3); ++ fails += CHECK_PROC (stibp, STIBP); ++ fails += CHECK_PROC (svm, SVM); ++#ifdef __x86_64__ ++ /* NB: SYSCALL_SYSRET is 64-bit only. */ ++ fails += CHECK_PROC (syscall, SYSCALL_SYSRET); ++#endif ++ fails += CHECK_PROC (tbm, TBM); ++ fails += CHECK_PROC (tm, TM); ++ fails += CHECK_PROC (tm2, TM2); ++ fails += CHECK_PROC (intel_pt, TRACE); ++ fails += CHECK_PROC (tsc, TSC); ++ fails += CHECK_PROC (tsc_adjust, TSC_ADJUST); ++ fails += CHECK_PROC (tsc_deadline, TSC_DEADLINE); ++ fails += CHECK_PROC (tsxldtrk, TSXLDTRK); ++ fails += CHECK_PROC (umip, UMIP); ++ fails += CHECK_PROC (vaes, VAES); ++ fails += CHECK_PROC (vme, VME); ++ fails += CHECK_PROC (vmx, VMX); ++ fails += CHECK_PROC (vpclmulqdq, VPCLMULQDQ); ++ fails += CHECK_PROC (waitpkg, WAITPKG); ++ fails += CHECK_PROC (wbnoinvd, WBNOINVD); ++ fails += CHECK_PROC (x2apic, X2APIC); ++ fails += CHECK_PROC (xfd, XFD); ++ fails += CHECK_PROC (xgetbv1, XGETBV_ECX_1); ++ fails += CHECK_PROC (xop, XOP); ++ fails += CHECK_PROC (xsave, XSAVE); ++ fails += CHECK_PROC (xsavec, XSAVEC); ++ fails += CHECK_PROC (xsaveopt, XSAVEOPT); ++ fails += CHECK_PROC (xsaves, XSAVES); ++ fails += CHECK_PROC (xtpr, XTPRUPDCTRL); ++ ++ printf ("%d differences between /proc/cpuinfo and glibc code.\n", fails); ++ ++ return (fails != 0); ++} ++ ++#include "../../../test-skeleton.c" +diff --git a/sysdeps/x86/tst-cpu-features-supports.c b/sysdeps/x86/tst-cpu-features-supports.c +new file mode 100644 +index 0000000000000000..bf881b531f4bc2ed +--- /dev/null ++++ b/sysdeps/x86/tst-cpu-features-supports.c +@@ -0,0 +1,192 @@ ++/* Test CPU feature data against __builtin_cpu_supports. ++ This file is part of the GNU C Library. ++ Copyright (C) 2020 Free Software Foundation, Inc. ++ ++ 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 ++ ++int ++check_supports (int supports, int usable, const char *supports_name, ++ const char *name) ++{ ++ printf ("Checking %s:\n", name); ++ printf (" %s: %d\n", name, usable); ++ printf (" __builtin_cpu_supports (%s): %d\n", ++ supports_name, supports); ++ ++ if ((supports != 0) != (usable != 0)) ++ { ++ printf (" *** failure ***\n"); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++#define CHECK_SUPPORTS(str, name) \ ++ check_supports (__builtin_cpu_supports (#str), \ ++ CPU_FEATURE_USABLE (name), \ ++ #str, "HAS_CPU_FEATURE (" #name ")"); ++ ++static int ++do_test (int argc, char **argv) ++{ ++ int fails = 0; ++ ++#if __GNUC_PREREQ (11, 0) ++ fails += CHECK_SUPPORTS (adx, ADX); ++#endif ++#if __GNUC_PREREQ (6, 0) ++ fails += CHECK_SUPPORTS (aes, AES); ++#endif ++#if __GNUC_PREREQ (11, 1) ++ fails += CHECK_SUPPORTS (amx_bf16, AMX_BF16); ++ fails += CHECK_SUPPORTS (amx_int8, AMX_INT8); ++ fails += CHECK_SUPPORTS (amx_tile, AMX_TILE); ++#endif ++ fails += CHECK_SUPPORTS (avx, AVX); ++ fails += CHECK_SUPPORTS (avx2, AVX2); ++#if __GNUC_PREREQ (7, 0) ++ fails += CHECK_SUPPORTS (avx5124fmaps, AVX512_4FMAPS); ++ fails += CHECK_SUPPORTS (avx5124vnniw, AVX512_4VNNIW); ++#endif ++#if __GNUC_PREREQ (10, 0) ++ fails += CHECK_SUPPORTS (avx512bf16, AVX512_BF16); ++#endif ++#if __GNUC_PREREQ (8, 0) ++ fails += CHECK_SUPPORTS (avx512bitalg, AVX512_BITALG); ++#endif ++#if __GNUC_PREREQ (6, 0) ++ fails += CHECK_SUPPORTS (avx512ifma, AVX512_IFMA); ++ fails += CHECK_SUPPORTS (avx512vbmi, AVX512_VBMI); ++#endif ++#if __GNUC_PREREQ (8, 0) ++ fails += CHECK_SUPPORTS (avx512vbmi2, AVX512_VBMI2); ++ fails += CHECK_SUPPORTS (avx512vnni, AVX512_VNNI); ++#endif ++#if __GNUC_PREREQ (10, 0) ++ fails += CHECK_SUPPORTS (avx512vp2intersect, AVX512_VP2INTERSECT); ++#endif ++#if __GNUC_PREREQ (7, 0) ++ fails += CHECK_SUPPORTS (avx512vpopcntdq, AVX512_VPOPCNTDQ); ++#endif ++#if __GNUC_PREREQ (6, 0) ++ fails += CHECK_SUPPORTS (avx512bw, AVX512BW); ++ fails += CHECK_SUPPORTS (avx512cd, AVX512CD); ++ fails += CHECK_SUPPORTS (avx512er, AVX512ER); ++ fails += CHECK_SUPPORTS (avx512dq, AVX512DQ); ++#endif ++#if __GNUC_PREREQ (5, 0) ++ fails += CHECK_SUPPORTS (avx512f, AVX512F); ++#endif ++#if __GNUC_PREREQ (6, 0) ++ fails += CHECK_SUPPORTS (avx512pf, AVX512PF); ++ fails += CHECK_SUPPORTS (avx512vl, AVX512VL); ++#endif ++#if __GNUC_PREREQ (5, 0) ++ fails += CHECK_SUPPORTS (bmi, BMI1); ++ fails += CHECK_SUPPORTS (bmi2, BMI2); ++#endif ++#if __GNUC_PREREQ (11, 0) ++ fails += CHECK_SUPPORTS (cldemote, CLDEMOTE); ++ fails += CHECK_SUPPORTS (clflushopt, CLFLUSHOPT); ++ fails += CHECK_SUPPORTS (clwb, CLWB); ++#endif ++ fails += CHECK_SUPPORTS (cmov, CMOV); ++#if __GNUC_PREREQ (11, 0) ++ fails += CHECK_SUPPORTS (cmpxchg16b, CMPXCHG16B); ++ fails += CHECK_SUPPORTS (cmpxchg8b, CX8); ++ fails += CHECK_SUPPORTS (enqcmd, ENQCMD); ++ fails += CHECK_SUPPORTS (f16c, F16C); ++#endif ++#if __GNUC_PREREQ (4, 9) ++ fails += CHECK_SUPPORTS (fma, FMA); ++ fails += CHECK_SUPPORTS (fma4, FMA4); ++#endif ++#if __GNUC_PREREQ (11, 0) ++ fails += CHECK_SUPPORTS (fsgsbase, FSGSBASE); ++ fails += CHECK_SUPPORTS (fxsave, FXSR); ++#endif ++#if __GNUC_PREREQ (8, 0) ++ fails += CHECK_SUPPORTS (gfni, GFNI); ++#endif ++#if __GNUC_PREREQ (11, 0) ++ fails += CHECK_SUPPORTS (hle, HLE); ++ fails += CHECK_SUPPORTS (ibt, IBT); ++ fails += CHECK_SUPPORTS (lahf_lm, LAHF64_SAHF64); ++ fails += CHECK_SUPPORTS (lm, LM); ++ fails += CHECK_SUPPORTS (lwp, LWP); ++ fails += CHECK_SUPPORTS (lzcnt, LZCNT); ++#endif ++ fails += CHECK_SUPPORTS (mmx, MMX); ++#if __GNUC_PREREQ (11, 0) ++ fails += CHECK_SUPPORTS (movbe, MOVBE); ++ fails += CHECK_SUPPORTS (movdiri, MOVDIRI); ++ fails += CHECK_SUPPORTS (movdir64b, MOVDIR64B); ++ fails += CHECK_SUPPORTS (osxsave, OSXSAVE); ++ fails += CHECK_SUPPORTS (pconfig, PCONFIG); ++ fails += CHECK_SUPPORTS (pku, PKU); ++#endif ++ fails += CHECK_SUPPORTS (popcnt, POPCNT); ++#if __GNUC_PREREQ (11, 0) ++ fails += CHECK_SUPPORTS (prefetchwt1, PREFETCHWT1); ++ fails += CHECK_SUPPORTS (rdpid, RDPID); ++ fails += CHECK_SUPPORTS (rdrnd, RDRAND); ++ fails += CHECK_SUPPORTS (rdseed, RDSEED); ++ fails += CHECK_SUPPORTS (rtm, RTM); ++ fails += CHECK_SUPPORTS (serialize, SERIALIZE); ++ fails += CHECK_SUPPORTS (sha, SHA); ++ fails += CHECK_SUPPORTS (shstk, SHSTK); ++#endif ++ fails += CHECK_SUPPORTS (sse, SSE); ++ fails += CHECK_SUPPORTS (sse2, SSE2); ++ fails += CHECK_SUPPORTS (sse3, SSE3); ++ fails += CHECK_SUPPORTS (sse4.1, SSE4_1); ++ fails += CHECK_SUPPORTS (sse4.2, SSE4_2); ++#if __GNUC_PREREQ (4, 9) ++ fails += CHECK_SUPPORTS (sse4a, SSE4A); ++#endif ++ fails += CHECK_SUPPORTS (ssse3, SSSE3); ++#if __GNUC_PREREQ (11, 0) ++ fails += CHECK_SUPPORTS (tbm, TBM); ++ fails += CHECK_SUPPORTS (tsxldtrk, TSXLDTRK); ++ fails += CHECK_SUPPORTS (vaes, VAES); ++#endif ++#if __GNUC_PREREQ (8, 0) ++ fails += CHECK_SUPPORTS (vpclmulqdq, VPCLMULQDQ); ++#endif ++#if __GNUC_PREREQ (11, 0) ++ fails += CHECK_SUPPORTS (waitpkg, WAITPKG); ++ fails += CHECK_SUPPORTS (wbnoinvd, WBNOINVD); ++#endif ++#if __GNUC_PREREQ (4, 9) ++ fails += CHECK_SUPPORTS (xop, XOP); ++#endif ++#if __GNUC_PREREQ (11, 0) ++ fails += CHECK_SUPPORTS (xsave, XSAVE); ++ fails += CHECK_SUPPORTS (xsavec, XSAVEC); ++ fails += CHECK_SUPPORTS (xsaveopt, XSAVEOPT); ++ fails += CHECK_SUPPORTS (xsaves, XSAVES); ++#endif ++ ++ printf ("%d differences between __builtin_cpu_supports and glibc code.\n", ++ fails); ++ ++ return (fails != 0); ++} ++ ++#include "../../../test-skeleton.c" +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index 582b125a2dad3f21..95e0d33f6c7eeace 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -1,5 +1,5 @@ +-/* Test case for x86 __get_cpu_features interface +- Copyright (C) 2015-2018 Free Software Foundation, Inc. ++/* Test case for __x86_get_cpu_features interface ++ Copyright (C) 2015-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 +@@ -18,7 +18,7 @@ + + #include + #include +-#include ++#include + #include + + #define CHECK_CPU_FEATURE(name) \ +@@ -44,7 +44,7 @@ static const char * const cpu_kinds[] = + static int + do_test (void) + { +- const struct cpu_features *cpu_features = __get_cpu_features (); ++ const struct cpu_features *cpu_features = __x86_get_cpu_features (0); + + switch (cpu_features->basic.kind) + { +diff --git a/sysdeps/x86_64/fpu/math-tests-arch.h b/sysdeps/x86_64/fpu/math-tests-arch.h +index 61955d70863321fd..c908eac6b4fff16d 100644 +--- a/sysdeps/x86_64/fpu/math-tests-arch.h ++++ b/sysdeps/x86_64/fpu/math-tests-arch.h +@@ -16,7 +16,7 @@ + License along with the GNU C Library; if not, see + . */ + +-#include ++#include + + #if defined REQUIRE_AVX + +diff --git a/sysdeps/x86_64/multiarch/Makefile b/sysdeps/x86_64/multiarch/Makefile +index 395e432c092ca17c..9477538af46787a5 100644 +--- a/sysdeps/x86_64/multiarch/Makefile ++++ b/sysdeps/x86_64/multiarch/Makefile +@@ -1,7 +1,3 @@ +-ifeq ($(subdir),csu) +-tests += test-multiarch +-endif +- + ifeq ($(subdir),string) + + sysdep_routines += strncat-c stpncpy-c strncpy-c \ +diff --git a/sysdeps/x86_64/multiarch/test-multiarch.c b/sysdeps/x86_64/multiarch/test-multiarch.c +deleted file mode 100644 +index cc2ea56a6753402d..0000000000000000 +--- a/sysdeps/x86_64/multiarch/test-multiarch.c ++++ /dev/null +@@ -1,96 +0,0 @@ +-/* Test CPU feature data. +- This file is part of the GNU C Library. +- Copyright (C) 2012-2018 Free Software Foundation, Inc. +- +- 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 char *cpu_flags; +- +-/* Search for flags in /proc/cpuinfo and store line +- in cpu_flags. */ +-void +-get_cpuinfo (void) +-{ +- FILE *f; +- char *line = NULL; +- size_t len = 0; +- ssize_t read; +- +- f = fopen ("/proc/cpuinfo", "r"); +- if (f == NULL) +- { +- printf ("cannot open /proc/cpuinfo\n"); +- exit (1); +- } +- +- while ((read = getline (&line, &len, f)) != -1) +- { +- if (strncmp (line, "flags", 5) == 0) +- { +- cpu_flags = strdup (line); +- break; +- } +- } +- fclose (f); +- free (line); +-} +- +-int +-check_proc (const char *proc_name, int flag, const char *name) +-{ +- int found = 0; +- +- printf ("Checking %s:\n", name); +- printf (" init-arch %d\n", flag); +- if (strstr (cpu_flags, proc_name) != NULL) +- found = 1; +- printf (" cpuinfo (%s) %d\n", proc_name, found); +- +- if (found != flag) +- printf (" *** failure ***\n"); +- +- return (found != flag); +-} +- +-static int +-do_test (int argc, char **argv) +-{ +- int fails; +- +- get_cpuinfo (); +- fails = check_proc ("avx", CPU_FEATURE_USABLE (AVX), +- "CPU_FEATURE_USABLE (AVX)"); +- fails += check_proc ("fma4", CPU_FEATURE_USABLE (FMA4), +- "CPU_FEATURE_USABLE (FMA4)"); +- fails += check_proc ("sse4_2", CPU_FEATURE_USABLE (SSE4_2), +- "CPU_FEATURE_USABLE (SSE4_2)"); +- fails += check_proc ("sse4_1", CPU_FEATURE_USABLE (SSE4_1) +- , "CPU_FEATURE_USABLE (SSE4_1)"); +- fails += check_proc ("ssse3", CPU_FEATURE_USABLE (SSSE3), +- "CPU_FEATURE_USABLE (SSSE3)"); +- fails += check_proc ("popcnt", CPU_FEATURE_USABLE (POPCNT), +- "CPU_FEATURE_USABLE (POPCNT)"); +- +- printf ("%d differences between /proc/cpuinfo and glibc code.\n", fails); +- +- return (fails != 0); +-} +- +-#include "../../../test-skeleton.c" diff --git a/SOURCES/glibc-rh1817513-84.patch b/SOURCES/glibc-rh1817513-84.patch new file mode 100644 index 0000000..e7124ef --- /dev/null +++ b/SOURCES/glibc-rh1817513-84.patch @@ -0,0 +1,207 @@ +commit f2c679d4b2c73a95f437c705f960a4af1fa23498 +Author: H.J. Lu +Date: Tue Sep 15 05:49:27 2020 -0700 + + : Add Intel Key Locker support + + Add Intel Key Locker: + + https://software.intel.com/content/www/us/en/develop/download/intel-key-locker-specification.html + + support to . Intel Key Locker has + + 1. KL: AES Key Locker instructions. + 2. WIDE_KL: AES wide Key Locker instructions. + 3. AESKLE: AES Key Locker instructions are enabled by OS. + + Applications should use + + if (CPU_FEATURE_USABLE (KL)) + + and + + if (CPU_FEATURE_USABLE (WIDE_KL)) + + to check if AES Key Locker instructions and AES wide Key Locker + instructions are usable. + +diff --git a/manual/platform.texi b/manual/platform.texi +index 2c145acdc3564cbb..95b0ed0642c9f8a9 100644 +--- a/manual/platform.texi ++++ b/manual/platform.texi +@@ -177,6 +177,9 @@ The supported processor features are: + @item + @code{AES} -- The AES instruction extensions. + ++@item ++@code{AESKLE} -- AES Key Locker instructions are enabled by OS. ++ + @item + @code{AMX_BF16} -- Tile computational operations on bfloat16 numbers. + +@@ -353,6 +356,9 @@ the indirect branch predictor barrier (IBPB). + @item + @code{INVPCID} -- INVPCID instruction. + ++@item ++@code{KL} -- AES Key Locker instructions. ++ + @item + @code{L1D_FLUSH} -- IA32_FLUSH_CMD MSR. + +@@ -598,6 +604,9 @@ using a TSC deadline value. + @item + @code{WBNOINVD} -- WBINVD/WBNOINVD instructions. + ++@item ++@code{WIDE_KL} -- AES wide Key Locker instructions. ++ + @item + @code{X2APIC} -- x2APIC. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 6954728c47d0126b..77a596a15404b575 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -269,6 +269,14 @@ update_usable (struct cpu_features *cpu_features) + /* Determine if PKU is usable. */ + if (CPU_FEATURES_CPU_P (cpu_features, OSPKE)) + CPU_FEATURE_SET (cpu_features, PKU); ++ ++ /* Determine if Key Locker instructions are usable. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AESKLE)) ++ { ++ CPU_FEATURE_SET (cpu_features, AESKLE); ++ CPU_FEATURE_SET_USABLE (cpu_features, KL); ++ CPU_FEATURE_SET_USABLE (cpu_features, WIDE_KL); ++ } + } + + static void +@@ -341,6 +349,12 @@ get_common_indices (struct cpu_features *cpu_features, + cpu_features->features[COMMON_CPUID_INDEX_D_ECX_1].cpuid.ecx, + cpu_features->features[COMMON_CPUID_INDEX_D_ECX_1].cpuid.edx); + ++ if (cpu_features->basic.max_cpuid >= 0x19) ++ __cpuid_count (0x19, 0, ++ cpu_features->features[COMMON_CPUID_INDEX_19].cpuid.eax, ++ cpu_features->features[COMMON_CPUID_INDEX_19].cpuid.ebx, ++ cpu_features->features[COMMON_CPUID_INDEX_19].cpuid.ecx, ++ cpu_features->features[COMMON_CPUID_INDEX_19].cpuid.edx); + } + + _Static_assert (((index_arch_Fast_Unaligned_Load +diff --git a/sysdeps/x86/sys/platform/x86.h b/sysdeps/x86/sys/platform/x86.h +index ebc5f6fc16cb8104..bcc81ab5f8ac8265 100644 +--- a/sysdeps/x86/sys/platform/x86.h ++++ b/sysdeps/x86/sys/platform/x86.h +@@ -28,6 +28,7 @@ enum + COMMON_CPUID_INDEX_80000007, + COMMON_CPUID_INDEX_80000008, + COMMON_CPUID_INDEX_7_ECX_1, ++ COMMON_CPUID_INDEX_19, + /* Keep the following line at the end. */ + COMMON_CPUID_INDEX_MAX + }; +@@ -224,7 +225,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* Note: Bits 17-21: The value of MAWAU used by the BNDLDX and BNDSTX + instructions in 64-bit mode. */ + #define bit_cpu_RDPID (1u << 22) +-#define bit_cpu_INDEX_7_ECX_23 (1u << 23) ++#define bit_cpu_KL (1u << 23) + #define bit_cpu_INDEX_7_ECX_24 (1u << 24) + #define bit_cpu_CLDEMOTE (1u << 25) + #define bit_cpu_INDEX_7_ECX_26 (1u << 26) +@@ -312,6 +313,12 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* EAX. */ + #define bit_cpu_AVX512_BF16 (1u << 5) + ++/* COMMON_CPUID_INDEX_19. */ ++ ++/* EBX. */ ++#define bit_cpu_AESKLE (1u << 0) ++#define bit_cpu_WIDE_KL (1u << 2) ++ + /* COMMON_CPUID_INDEX_1. */ + + /* ECX. */ +@@ -437,7 +444,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + #define index_cpu_INDEX_7_ECX_15 COMMON_CPUID_INDEX_7 + #define index_cpu_INDEX_7_ECX_16 COMMON_CPUID_INDEX_7 + #define index_cpu_RDPID COMMON_CPUID_INDEX_7 +-#define index_cpu_INDEX_7_ECX_23 COMMON_CPUID_INDEX_7 ++#define index_cpu_KL COMMON_CPUID_INDEX_7 + #define index_cpu_INDEX_7_ECX_24 COMMON_CPUID_INDEX_7 + #define index_cpu_CLDEMOTE COMMON_CPUID_INDEX_7 + #define index_cpu_INDEX_7_ECX_26 COMMON_CPUID_INDEX_7 +@@ -525,6 +532,12 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* EAX. */ + #define index_cpu_AVX512_BF16 COMMON_CPUID_INDEX_7_ECX_1 + ++/* COMMON_CPUID_INDEX_19. */ ++ ++/* EBX. */ ++#define index_cpu_AESKLE COMMON_CPUID_INDEX_19 ++#define index_cpu_WIDE_KL COMMON_CPUID_INDEX_19 ++ + /* COMMON_CPUID_INDEX_1. */ + + /* ECX. */ +@@ -650,7 +663,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + #define reg_INDEX_7_ECX_15 ecx + #define reg_INDEX_7_ECX_16 ecx + #define reg_RDPID ecx +-#define reg_INDEX_7_ECX_23 ecx ++#define reg_KL ecx + #define reg_INDEX_7_ECX_24 ecx + #define reg_CLDEMOTE ecx + #define reg_INDEX_7_ECX_26 ecx +@@ -738,4 +751,10 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int) + /* EAX. */ + #define reg_AVX512_BF16 eax + ++/* COMMON_CPUID_INDEX_19. */ ++ ++/* EBX. */ ++#define reg_AESKLE ebx ++#define reg_WIDE_KL ebx ++ + #endif /* _SYS_PLATFORM_X86_H */ +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index 95e0d33f6c7eeace..c01d701b52090983 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -170,6 +170,7 @@ do_test (void) + CHECK_CPU_FEATURE (AVX512_BITALG); + CHECK_CPU_FEATURE (AVX512_VPOPCNTDQ); + CHECK_CPU_FEATURE (RDPID); ++ CHECK_CPU_FEATURE (KL); + CHECK_CPU_FEATURE (CLDEMOTE); + CHECK_CPU_FEATURE (MOVDIRI); + CHECK_CPU_FEATURE (MOVDIR64B); +@@ -217,6 +218,8 @@ do_test (void) + CHECK_CPU_FEATURE (INVARIANT_TSC); + CHECK_CPU_FEATURE (WBNOINVD); + CHECK_CPU_FEATURE (AVX512_BF16); ++ CHECK_CPU_FEATURE (AESKLE); ++ CHECK_CPU_FEATURE (WIDE_KL); + + printf ("Usable CPU features:\n"); + CHECK_CPU_FEATURE_USABLE (SSE3); +@@ -323,6 +326,7 @@ do_test (void) + CHECK_CPU_FEATURE_USABLE (AVX512_BITALG); + CHECK_CPU_FEATURE_USABLE (AVX512_VPOPCNTDQ); + CHECK_CPU_FEATURE_USABLE (RDPID); ++ CHECK_CPU_FEATURE_USABLE (KL); + CHECK_CPU_FEATURE_USABLE (CLDEMOTE); + CHECK_CPU_FEATURE_USABLE (MOVDIRI); + CHECK_CPU_FEATURE_USABLE (MOVDIR64B); +@@ -370,6 +374,8 @@ do_test (void) + CHECK_CPU_FEATURE_USABLE (INVARIANT_TSC); + CHECK_CPU_FEATURE_USABLE (WBNOINVD); + CHECK_CPU_FEATURE_USABLE (AVX512_BF16); ++ CHECK_CPU_FEATURE_USABLE (AESKLE); ++ CHECK_CPU_FEATURE_USABLE (WIDE_KL); + + return 0; + } diff --git a/SOURCES/glibc-rh1817513-85.patch b/SOURCES/glibc-rh1817513-85.patch new file mode 100644 index 0000000..10a18fa --- /dev/null +++ b/SOURCES/glibc-rh1817513-85.patch @@ -0,0 +1,73 @@ +commit 94cd37ebb293321115a36a422b091fdb72d2fb08 +Author: H.J. Lu +Date: Wed Sep 16 05:27:32 2020 -0700 + + x86: Use HAS_CPU_FEATURE with IBT and SHSTK [BZ #26625] + + commit 04bba1e5d84b6fd8d3a3b006bc240cd5d241ee30 + Author: H.J. Lu + Date: Wed Aug 5 13:51:56 2020 -0700 + + x86: Set CPU usable feature bits conservatively [BZ #26552] + + Set CPU usable feature bits only for CPU features which are usable in + user space and whose usability can be detected from user space, excluding + features like FSGSBASE whose enable bit can only be checked in the kernel. + + no longer turns on the usable bits of IBT and SHSTK since we don't know + if IBT and SHSTK are usable until much later. Use HAS_CPU_FEATURE to + check if the processor supports IBT and SHSTK. + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 77a596a15404b575..7f2ff00f2b4b45f2 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -722,9 +722,9 @@ no_cpuid: + GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK + */ + unsigned int cet_feature = 0; +- if (!CPU_FEATURE_USABLE (IBT)) ++ if (!HAS_CPU_FEATURE (IBT)) + cet_feature |= GNU_PROPERTY_X86_FEATURE_1_IBT; +- if (!CPU_FEATURE_USABLE (SHSTK)) ++ if (!HAS_CPU_FEATURE (SHSTK)) + cet_feature |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; + + if (cet_feature) +diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c +index 11ff0618fae7230f..d481bddc27e5d7cc 100644 +--- a/sysdeps/x86/dl-cet.c ++++ b/sysdeps/x86/dl-cet.c +@@ -74,10 +74,10 @@ dl_cet_check (struct link_map *m, const char *program) + + GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK + */ +- enable_ibt &= (CPU_FEATURE_USABLE (IBT) ++ enable_ibt &= (HAS_CPU_FEATURE (IBT) + && (enable_ibt_type == cet_always_on + || (m->l_cet & lc_ibt) != 0)); +- enable_shstk &= (CPU_FEATURE_USABLE (SHSTK) ++ enable_shstk &= (HAS_CPU_FEATURE (SHSTK) + && (enable_shstk_type == cet_always_on + || (m->l_cet & lc_shstk) != 0)); + } +diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c +index c01d701b52090983..3ec94e0c9a191f36 100644 +--- a/sysdeps/x86/tst-get-cpu-features.c ++++ b/sysdeps/x86/tst-get-cpu-features.c +@@ -318,7 +318,6 @@ do_test (void) + CHECK_CPU_FEATURE_USABLE (OSPKE); + CHECK_CPU_FEATURE_USABLE (WAITPKG); + CHECK_CPU_FEATURE_USABLE (AVX512_VBMI2); +- CHECK_CPU_FEATURE_USABLE (SHSTK); + CHECK_CPU_FEATURE_USABLE (GFNI); + CHECK_CPU_FEATURE_USABLE (VAES); + CHECK_CPU_FEATURE_USABLE (VPCLMULQDQ); +@@ -342,7 +341,6 @@ do_test (void) + CHECK_CPU_FEATURE_USABLE (HYBRID); + CHECK_CPU_FEATURE_USABLE (TSXLDTRK); + CHECK_CPU_FEATURE_USABLE (PCONFIG); +- CHECK_CPU_FEATURE_USABLE (IBT); + CHECK_CPU_FEATURE_USABLE (AMX_BF16); + CHECK_CPU_FEATURE_USABLE (AMX_TILE); + CHECK_CPU_FEATURE_USABLE (AMX_INT8); diff --git a/SOURCES/glibc-rh1817513-86.patch b/SOURCES/glibc-rh1817513-86.patch new file mode 100644 index 0000000..05a09e7 --- /dev/null +++ b/SOURCES/glibc-rh1817513-86.patch @@ -0,0 +1,173 @@ +commit c6702789344043fa998923c8f32ed0bdb2edfa9c +Author: Vincent Mihalkovic +Date: Tue Sep 29 12:34:39 2020 +0200 + + ld.so: add an --argv0 option [BZ #16124] + +Conflicts: + elf/Makefile + (Missing test backports.) + +diff --git a/elf/Makefile b/elf/Makefile +index 82b5b4a07495c805..837a070c267527e1 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -198,7 +198,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-dlopenfail tst-dlopenfail-2 \ + tst-filterobj tst-filterobj-dlopen tst-auxobj tst-auxobj-dlopen \ + tst-audit14 tst-audit15 tst-audit16 \ +- tst-tls-ie tst-tls-ie-dlmopen ++ tst-tls-ie tst-tls-ie-dlmopen \ ++ argv0test + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -395,7 +396,7 @@ endif + ifeq (yes,$(build-shared)) + ifeq ($(run-built-tests),yes) + tests-special += $(objpfx)tst-pathopt.out $(objpfx)tst-rtld-load-self.out \ +- $(objpfx)tst-rtld-preload.out ++ $(objpfx)tst-rtld-preload.out $(objpfx)argv0test.out + endif + tests-special += $(objpfx)check-textrel.out $(objpfx)check-execstack.out \ + $(objpfx)check-wx-segment.out \ +@@ -1716,3 +1717,10 @@ $(objpfx)tst-tls-ie-dlmopen.out: \ + $(objpfx)tst-tls-ie-mod6.so + + $(objpfx)tst-tls-surplus: $(libdl) ++ ++$(objpfx)argv0test.out: tst-rtld-argv0.sh $(objpfx)ld.so \ ++ $(objpfx)argv0test ++ $(SHELL) $< $(objpfx)ld.so $(objpfx)argv0test \ ++ '$(test-wrapper-env)' '$(run_program_env)' \ ++ '$(rpath-link)' 'test-argv0' > $@; \ ++ $(evaluate-test) +diff --git a/elf/argv0test.c b/elf/argv0test.c +new file mode 100644 +index 0000000000000000..c22ba5ea70ed7dbf +--- /dev/null ++++ b/elf/argv0test.c +@@ -0,0 +1,31 @@ ++/* Test for --argv0 option ld.so. ++ ++ 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 ++ ++static int ++do_test (int argc, char **argv) ++{ ++ TEST_COMPARE_STRING (argv[0], "test-argv0"); ++ return 0; ++} ++ ++#define TEST_FUNCTION_ARGV do_test ++#include +diff --git a/elf/rtld.c b/elf/rtld.c +index 67441ac6f252350e..4107a215abd554f4 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -1196,6 +1196,8 @@ dl_main (const ElfW(Phdr) *phdr, + installing it. */ + rtld_is_main = true; + ++ char *argv0 = NULL; ++ + /* Note the place where the dynamic linker actually came from. */ + GL(dl_rtld_map).l_name = rtld_progname; + +@@ -1253,6 +1255,14 @@ dl_main (const ElfW(Phdr) *phdr, + else if (! strcmp (_dl_argv[1], "--preload") && _dl_argc > 2) + { + preloadarg = _dl_argv[2]; ++ _dl_skip_args += 2; ++ _dl_argc -= 2; ++ _dl_argv += 2; ++ } ++ else if (! strcmp (_dl_argv[1], "--argv0") && _dl_argc > 2) ++ { ++ argv0 = _dl_argv[2]; ++ + _dl_skip_args += 2; + _dl_argc -= 2; + _dl_argv += 2; +@@ -1286,7 +1296,8 @@ of this helper program; chances are you did not intend to run this program.\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\ +- --preload LIST preload objects named in LIST\n"); ++ --preload LIST preload objects named in LIST\n\ ++ --argv0 STRING set argv[0] to STRING before running\n"); + + ++_dl_skip_args; + --_dl_argc; +@@ -1378,6 +1389,10 @@ of this helper program; chances are you did not intend to run this program.\n\ + break; + } + #endif ++ ++ /* Set the argv[0] string now that we've processed the executable. */ ++ if (argv0 != NULL) ++ _dl_argv[0] = argv0; + } + else + { +diff --git a/elf/tst-rtld-argv0.sh b/elf/tst-rtld-argv0.sh +new file mode 100755 +index 0000000000000000..14d97fb375fc652b +--- /dev/null ++++ b/elf/tst-rtld-argv0.sh +@@ -0,0 +1,37 @@ ++#!/bin/sh ++# Test for --argv0 option ld.so. ++# 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 ++# . ++ ++set -e ++ ++rtld=$1 ++test_program=$2 ++test_wrapper_env=$3 ++run_program_env=$4 ++library_path=$5 ++argv0=$6 ++ ++echo "# [${test_wrapper_env}] [${run_program_env}] [$rtld] [--library-path]" \ ++ "[$library_path] [--argv0] [$argv0] [$test_program]" ++${test_wrapper_env} \ ++${run_program_env} \ ++$rtld --library-path "$library_path" \ ++ --argv0 "$argv0" $test_program 2>&1 && rc=0 || rc=$? ++echo "# exit status $rc" ++ ++exit $rc diff --git a/SOURCES/glibc-rh1817513-87.patch b/SOURCES/glibc-rh1817513-87.patch new file mode 100644 index 0000000..b3c202c --- /dev/null +++ b/SOURCES/glibc-rh1817513-87.patch @@ -0,0 +1,97 @@ +commit 56f8d442942ee51824b4683be83f776a811a3f2a +Author: Florian Weimer +Date: Wed Oct 7 16:40:23 2020 +0200 + + elf: Do not search HWCAP subdirectories in statically linked binaries + + This functionality does not seem to be useful since static dlopen + is mostly used for iconv/character set conversion and NSS support. + gconv modules are loaded with full paths anyway, so that the + HWCAP subdirectory logic does not apply. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/Makefile b/elf/Makefile +index 837a070c267527e1..ef655630d50b07aa 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -29,7 +29,7 @@ routines = $(all-dl-routines) dl-support dl-iteratephdr \ + + # The core dynamic linking functions are in libc for the static and + # profiled libraries. +-dl-routines = $(addprefix dl-,load lookup object reloc deps hwcaps \ ++dl-routines = $(addprefix dl-,load lookup object reloc deps \ + runtime init fini debug misc \ + version profile tls origin scope \ + execstack open close trampoline \ +@@ -59,7 +59,7 @@ 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-error-minimal dl-conflict dl-hwcaps + all-rtld-routines = $(rtld-routines) $(sysdep-rtld-routines) + + CFLAGS-dl-runtime.c += -fexceptions -fasynchronous-unwind-tables +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 64da5323d0e368c1..2b4dd9a0f3e27b70 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -101,9 +101,13 @@ int __stack_prot attribute_hidden attribute_relro + static struct r_search_path_struct env_path_list attribute_relro; + + /* List of the hardware capabilities we might end up using. */ ++#ifdef SHARED + static const struct r_strlenpair *capstr attribute_relro; + static size_t ncapstr attribute_relro; + static size_t max_capstrlen attribute_relro; ++#else ++enum { ncapstr = 1, max_capstrlen = 0 }; ++#endif + + + /* Get the generated information about the trusted directories. Use +@@ -691,9 +695,11 @@ _dl_init_paths (const char *llp) + /* Fill in the information about the application's RPATH and the + directories addressed by the LD_LIBRARY_PATH environment variable. */ + ++#ifdef SHARED + /* Get the capabilities. */ + capstr = _dl_important_hwcaps (GLRO(dl_platform), GLRO(dl_platformlen), + &ncapstr, &max_capstrlen); ++#endif + + /* First set up the rest of the default search directory entries. */ + aelem = rtld_search_dirs.dirs = (struct r_search_path_elem **) +@@ -1459,11 +1465,15 @@ print_search_path (struct r_search_path_elem **list, + for (cnt = 0; cnt < ncapstr; ++cnt) + if ((*list)->status[cnt] != nonexisting) + { ++#ifdef SHARED + char *cp = __mempcpy (endp, capstr[cnt].str, capstr[cnt].len); + if (cp == buf || (cp == buf + 1 && buf[0] == '/')) + cp[0] = '\0'; + else + cp[-1] = '\0'; ++#else ++ *endp = '\0'; ++#endif + + _dl_debug_printf_c (first ? "%s" : ":%s", buf); + first = 0; +@@ -1836,11 +1846,15 @@ open_path (const char *name, size_t namelen, int mode, + if (this_dir->status[cnt] == nonexisting) + continue; + ++#ifdef SHARED + buflen = + ((char *) __mempcpy (__mempcpy (edp, capstr[cnt].str, + capstr[cnt].len), + name, namelen) + - buf); ++#else ++ buflen = (char *) __mempcpy (edp, name, namelen) - buf; ++#endif + + /* Print name we try if this is wanted. */ + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)) diff --git a/SOURCES/glibc-rh1817513-88.patch b/SOURCES/glibc-rh1817513-88.patch new file mode 100644 index 0000000..6100353 --- /dev/null +++ b/SOURCES/glibc-rh1817513-88.patch @@ -0,0 +1,144 @@ +commit b31d4355ae817aa3caf9414f842cc07465bca028 +Author: Florian Weimer +Date: Wed Oct 7 16:39:50 2020 +0200 + + elf: Implement _dl_write + + The generic version is parallel to _dl_writev. It cannot use + _dl_writev directly because the errno value needs to be obtained + under a lock. + + Reviewed-by: Adhemerval Zanella + +Backport adjusted for different INTERNAL_SYSCALL_CALL definition +downstream. + +diff --git a/elf/Makefile b/elf/Makefile +index ef655630d50b07aa..e2078f6bc325b7e0 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -34,7 +34,7 @@ dl-routines = $(addprefix dl-,load lookup object reloc deps \ + version profile tls origin scope \ + execstack open close trampoline \ + exception sort-maps lookup-direct \ +- call-libc-early-init) ++ call-libc-early-init write) + ifeq (yes,$(use-ldconfig)) + dl-routines += dl-cache + endif +diff --git a/elf/dl-write.c b/elf/dl-write.c +new file mode 100644 +index 0000000000000000..7350aff0035d4fbc +--- /dev/null ++++ b/elf/dl-write.c +@@ -0,0 +1,56 @@ ++/* Implementation of the _dl_write function. 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 ++#include ++#include ++#include ++ ++ssize_t ++_dl_write (int fd, const void *buffer, size_t length) ++{ ++ struct iovec iov = { .iov_base = (void *) buffer, .iov_len = length }; ++ ssize_t ret; ++ ++#if RTLD_PRIVATE_ERRNO ++ /* We have to take this lock just to be sure we don't clobber the private ++ errno when it's being used by another thread that cares about it. ++ Yet we must be sure not to try calling the lock functions before ++ the thread library is fully initialized. */ ++ if (__glibc_unlikely (_dl_starting_up)) ++ { ++ ret = __writev (fd, &iov, 1); ++ if (ret < 0) ++ ret = -errno; ++ } ++ else ++ { ++ __rtld_lock_lock_recursive (GL(dl_load_lock)); ++ __writev (fd, &iov, 1); ++ if (ret < 0) ++ ret = -errno; ++ __rtld_lock_unlock_recursive (GL(dl_load_lock)); ++ } ++#else ++ ret = __writev (fd, &iov, 1); ++ if (ret < 0) ++ ret = -errno; ++#endif ++ ++ return ret; ++} +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 37f1915b0c75a020..4aa28b0229e0b339 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -754,6 +754,12 @@ _dl_dprintf (int fd, const char *fmt, ...) + } + #endif + ++/* Write LENGTH bytes at BUFFER to FD, like write. Returns the number ++ of bytes written on success, or a negative error constant on ++ failure. */ ++ssize_t _dl_write (int fd, const void *buffer, size_t length) ++ attribute_hidden; ++ + /* Write a message on the specified descriptor standard output. The + parameters are interpreted as for a `printf' call. */ + #define _dl_printf(fmt, args...) \ +diff --git a/sysdeps/unix/sysv/linux/dl-write.c b/sysdeps/unix/sysv/linux/dl-write.c +new file mode 100644 +index 0000000000000000..2c670a8059077076 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/dl-write.c +@@ -0,0 +1,31 @@ ++/* Implementation of the _dl_write function. Linux 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 ++#include ++#include ++ ++ssize_t ++_dl_write (int fd, const void *buffer, size_t length) ++{ ++ INTERNAL_SYSCALL_DECL (err); ++ long int r = INTERNAL_SYSCALL_CALL (write, err, fd, buffer, length); ++ if (INTERNAL_SYSCALL_ERROR_P (r, err)) ++ r = - INTERNAL_SYSCALL_ERRNO (r, err); ++ return r; ++} diff --git a/SOURCES/glibc-rh1817513-89.patch b/SOURCES/glibc-rh1817513-89.patch new file mode 100644 index 0000000..64a511e --- /dev/null +++ b/SOURCES/glibc-rh1817513-89.patch @@ -0,0 +1,46 @@ +commit 72d36ffd7db55ae599f4c77feb0eae25a0f3714e +Author: Florian Weimer +Date: Thu Oct 8 10:57:09 2020 +0200 + + elf: Implement __rtld_malloc_is_complete + + In some cases, it is difficult to determine the kind of malloc + based on the execution context, so a function to determine that + is helpful. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-minimal.c b/elf/dl-minimal.c +index 4335f1bd24289b01..cf7df8a8d5eabe9d 100644 +--- a/elf/dl-minimal.c ++++ b/elf/dl-minimal.c +@@ -59,6 +59,14 @@ __rtld_malloc_init_stubs (void) + __rtld_realloc = &rtld_realloc; + } + ++bool ++__rtld_malloc_is_complete (void) ++{ ++ /* The caller assumes that there is an active malloc. */ ++ assert (__rtld_malloc != NULL); ++ return __rtld_malloc != &rtld_malloc; ++} ++ + /* Lookup NAME at VERSION in the scope of MATCH. */ + static void * + lookup_malloc_symbol (struct link_map *main_map, const char *name, +diff --git a/include/rtld-malloc.h b/include/rtld-malloc.h +index b026a3270cd24819..9266ec532f3f3376 100644 +--- a/include/rtld-malloc.h ++++ b/include/rtld-malloc.h +@@ -66,6 +66,10 @@ realloc (void *ptr, size_t size) + implementation. */ + void __rtld_malloc_init_stubs (void) attribute_hidden; + ++/* Return false if the active malloc is the ld.so minimal malloc, true ++ if it is the full implementation from libc.so. */ ++_Bool __rtld_malloc_is_complete (void) attribute_hidden; ++ + /* Called shortly before the final self-relocation (when RELRO + variables are still writable) to activate the real malloc + implementation. MAIN_MAP is the link map of the executable. */ diff --git a/SOURCES/glibc-rh1817513-9.patch b/SOURCES/glibc-rh1817513-9.patch new file mode 100644 index 0000000..06b352b --- /dev/null +++ b/SOURCES/glibc-rh1817513-9.patch @@ -0,0 +1,247 @@ +commit 72771e53753647111d31c5c4bf43d8901e6baf7e +Author: H.J. Lu +Date: Wed Oct 17 15:16:38 2018 -0700 + + x86: Use _rdtsc intrinsic for HP_TIMING_NOW + + Since _rdtsc intrinsic is supported in GCC 4.9, we can use it for + HP_TIMING_NOW. This patch + + 1. Create x86 hp-timing.h to replace i686 and x86_64 hp-timing.h. + 2. Move MINIMUM_ISA from init-arch.h to isa.h so that x86 hp-timing.h + can check minimum x86 ISA to decide if _rdtsc can be used. + + NB: Checking if __i686__ isn't sufficient since __i686__ may not be + defined when building for i686 class processors. + + * sysdeps/i386/init-arch.h: Removed. + * sysdeps/i386/i586/init-arch.h: Likewise. + * sysdeps/i386/i686/init-arch.h: Likewise. + * sysdeps/i386/i686/hp-timing.h: Likewise. + * sysdeps/x86_64/hp-timing.h: Likewise. + * sysdeps/i386/isa.h: New file. + * sysdeps/i386/i586/isa.h: Likewise. + * sysdeps/i386/i686/isa.h: Likewise. + * sysdeps/x86_64/isa.h: Likewise. + * sysdeps/x86/hp-timing.h: New file. + * sysdeps/x86/init-arch.h: Include . + +diff --git a/sysdeps/i386/i586/init-arch.h b/sysdeps/i386/i586/isa.h +similarity index 85% +rename from sysdeps/i386/i586/init-arch.h +rename to sysdeps/i386/i586/isa.h +index 72fb46c61e4c5f34..79481ce68033e58c 100644 +--- a/sysdeps/i386/i586/init-arch.h ++++ b/sysdeps/i386/i586/isa.h +@@ -1,4 +1,5 @@ +-/* Copyright (C) 2015-2018 Free Software Foundation, Inc. ++/* x86 ISA info. i586 version. ++ Copyright (C) 2018 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 +@@ -15,5 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + ++#ifndef _ISA_H ++#define _ISA_H ++ + #define MINIMUM_ISA 586 +-#include ++ ++#endif +diff --git a/sysdeps/i386/i686/init-arch.h b/sysdeps/i386/i686/isa.h +similarity index 85% +rename from sysdeps/i386/i686/init-arch.h +rename to sysdeps/i386/i686/isa.h +index ab99392b586b1e2d..584e26bd4f928021 100644 +--- a/sysdeps/i386/i686/init-arch.h ++++ b/sysdeps/i386/i686/isa.h +@@ -1,4 +1,5 @@ +-/* Copyright (C) 2015-2018 Free Software Foundation, Inc. ++/* x86 ISA info. i686 version. ++ Copyright (C) 2018 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 +@@ -15,5 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + ++#ifndef _ISA_H ++#define _ISA_H ++ + #define MINIMUM_ISA 686 +-#include ++ ++#endif +diff --git a/sysdeps/i386/init-arch.h b/sysdeps/i386/isa.h +similarity index 85% +rename from sysdeps/i386/init-arch.h +rename to sysdeps/i386/isa.h +index 043089ceb99db33f..e0a1e9c84fd37efb 100644 +--- a/sysdeps/i386/init-arch.h ++++ b/sysdeps/i386/isa.h +@@ -1,4 +1,5 @@ +-/* Copyright (C) 2015-2018 Free Software Foundation, Inc. ++/* x86 ISA info. i486 version. ++ Copyright (C) 2018 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 +@@ -15,5 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + ++#ifndef _ISA_H ++#define _ISA_H ++ + #define MINIMUM_ISA 486 +-#include ++ ++#endif +diff --git a/sysdeps/i386/i686/hp-timing.h b/sysdeps/x86/hp-timing.h +similarity index 69% +rename from sysdeps/i386/i686/hp-timing.h +rename to sysdeps/x86/hp-timing.h +index 59af526fdba0b6f5..1c20e9d8289cc15b 100644 +--- a/sysdeps/i386/i686/hp-timing.h ++++ b/sysdeps/x86/hp-timing.h +@@ -1,7 +1,6 @@ +-/* High precision, low overhead timing functions. i686 version. +- Copyright (C) 1998-2018 Free Software Foundation, Inc. ++/* High precision, low overhead timing functions. x86 version. ++ Copyright (C) 2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by Ulrich Drepper , 1998. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -20,12 +19,17 @@ + #ifndef _HP_TIMING_H + #define _HP_TIMING_H 1 + ++#include ++ ++#if MINIMUM_ISA == 686 || MINIMUM_ISA == 8664 ++# include ++ + /* We always assume having the timestamp register. */ +-#define HP_TIMING_AVAIL (1) +-#define HP_SMALL_TIMING_AVAIL (1) ++# define HP_TIMING_AVAIL (1) ++# define HP_SMALL_TIMING_AVAIL (1) + + /* We indeed have inlined functions. */ +-#define HP_TIMING_INLINE (1) ++# define HP_TIMING_INLINE (1) + + /* We use 64bit values for the times. */ + typedef unsigned long long int hp_timing_t; +@@ -35,8 +39,14 @@ typedef unsigned long long int hp_timing_t; + running in this moment. This could be changed by using a barrier like + 'cpuid' right before the `rdtsc' instruciton. But we are not interested + in accurate clock cycles here so we don't do this. */ +-#define HP_TIMING_NOW(Var) __asm__ __volatile__ ("rdtsc" : "=A" (Var)) ++# define HP_TIMING_NOW(Var) ((Var) = _rdtsc ()) + +-#include ++# include ++#else ++/* NB: Undefine _HP_TIMING_H so that will ++ be included. */ ++# undef _HP_TIMING_H ++# include ++#endif + +-#endif /* hp-timing.h */ ++#endif /* hp-timing.h */ +diff --git a/sysdeps/x86/init-arch.h b/sysdeps/x86/init-arch.h +index a81ca8a4eb292e72..bc860fcd69a605b3 100644 +--- a/sysdeps/x86/init-arch.h ++++ b/sysdeps/x86/init-arch.h +@@ -21,6 +21,7 @@ + # include + #endif + #include ++#include + + #ifndef __x86_64__ + /* Due to the reordering and the other nifty extensions in i686, it is +diff --git a/sysdeps/x86_64/hp-timing.h b/sysdeps/x86_64/hp-timing.h +deleted file mode 100644 +index ec543bef03b6c2d1..0000000000000000 +--- a/sysdeps/x86_64/hp-timing.h ++++ /dev/null +@@ -1,40 +0,0 @@ +-/* High precision, low overhead timing functions. x86-64 version. +- Copyright (C) 2002-2018 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 _HP_TIMING_H +-#define _HP_TIMING_H 1 +- +-/* We always assume having the timestamp register. */ +-#define HP_TIMING_AVAIL (1) +-#define HP_SMALL_TIMING_AVAIL (1) +- +-/* We indeed have inlined functions. */ +-#define HP_TIMING_INLINE (1) +- +-/* We use 64bit values for the times. */ +-typedef unsigned long long int hp_timing_t; +- +-/* The "=A" constraint used in 32-bit mode does not work in 64-bit mode. */ +-#define HP_TIMING_NOW(Var) \ +- ({ unsigned int _hi, _lo; \ +- asm volatile ("rdtsc" : "=a" (_lo), "=d" (_hi)); \ +- (Var) = ((unsigned long long int) _hi << 32) | _lo; }) +- +-#include +- +-#endif /* hp-timing.h */ +diff --git a/sysdeps/x86_64/isa.h b/sysdeps/x86_64/isa.h +new file mode 100644 +index 0000000000000000..452bce75eb03a474 +--- /dev/null ++++ b/sysdeps/x86_64/isa.h +@@ -0,0 +1,24 @@ ++/* x86 ISA info. x86-64 version. ++ Copyright (C) 2018 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 _ISA_H ++#define _ISA_H ++ ++#define MINIMUM_ISA 8664 ++ ++#endif diff --git a/SOURCES/glibc-rh1817513-90.patch b/SOURCES/glibc-rh1817513-90.patch new file mode 100644 index 0000000..344808e --- /dev/null +++ b/SOURCES/glibc-rh1817513-90.patch @@ -0,0 +1,568 @@ +commit 2bf9e641fd50ec34b04b70829679abf64fc0ed78 +Author: Florian Weimer +Date: Thu Oct 8 10:57:09 2020 +0200 + + elf: Extract command-line/environment variables state from rtld.c + + Introduce struct dl_main_state and move it to . Rename + enum mode to enum rtld_mode and add the rtld_mode_ prefix to the enum + constants. + + This avoids the need for putting state that is only needed during + startup into the ld.so data segment. + +Conflicts: + elf/rtld.c + (Caused by glibc-fedora-__libc_multiple_libcs.patch.) + +diff --git a/elf/dl-main.h b/elf/dl-main.h +new file mode 100644 +index 0000000000000000..bcc9bcf2e8fee6e7 +--- /dev/null ++++ b/elf/dl-main.h +@@ -0,0 +1,98 @@ ++/* Information collection during ld.so startup. ++ Copyright (C) 1995-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 _DL_MAIN ++#define _DL_MAIN ++ ++#include ++ ++/* Length limits for names and paths, to protect the dynamic linker, ++ particularly when __libc_enable_secure is active. */ ++#ifdef NAME_MAX ++# define SECURE_NAME_LIMIT NAME_MAX ++#else ++# define SECURE_NAME_LIMIT 255 ++#endif ++#ifdef PATH_MAX ++# define SECURE_PATH_LIMIT PATH_MAX ++#else ++# define SECURE_PATH_LIMIT 1024 ++#endif ++ ++/* Strings containing colon-separated lists of audit modules. */ ++struct audit_list ++{ ++ /* Array of strings containing colon-separated path lists. Each ++ audit module needs its own namespace, so pre-allocate the largest ++ possible list. */ ++ const char *audit_strings[DL_NNS]; ++ ++ /* Number of entries added to audit_strings. */ ++ size_t length; ++ ++ /* Index into the audit_strings array (for the iteration phase). */ ++ size_t current_index; ++ ++ /* Tail of audit_strings[current_index] which still needs ++ processing. */ ++ const char *current_tail; ++ ++ /* Scratch buffer for returning a name which is part of the strings ++ in audit_strings. */ ++ char fname[SECURE_NAME_LIMIT]; ++}; ++ ++/* This is a list of all the modes the dynamic loader can be in. */ ++enum rtld_mode ++ { ++ rtld_mode_normal, rtld_mode_list, rtld_mode_verify, rtld_mode_trace, ++ }; ++ ++/* Aggregated state information extracted from environment variables ++ and the ld.so command line. */ ++struct dl_main_state ++{ ++ struct audit_list audit_list; ++ ++ /* The library search path. */ ++ const char *library_path; ++ ++ /* The list preloaded objects from LD_PRELOAD. */ ++ const char *preloadlist; ++ ++ /* The preload list passed as a command argument. */ ++ const char *preloadarg; ++ ++ enum rtld_mode mode; ++ ++ /* True if any of the debugging options is enabled. */ ++ bool any_debug; ++ ++ /* True if information about versions has to be printed. */ ++ bool version_info; ++}; ++ ++/* Helper function to invoke _dl_init_paths with the right arguments ++ from *STATE. */ ++static inline void ++call_init_paths (const struct dl_main_state *state) ++{ ++ _dl_init_paths (state->library_path); ++} ++ ++#endif /* _DL_MAIN */ +diff --git a/elf/rtld.c b/elf/rtld.c +index 4107a215abd554f4..fbfa441bf3b050ff 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -45,6 +45,7 @@ + #include + #include + #include ++#include + + #include + +@@ -109,42 +110,6 @@ static void print_missing_version (int errcode, const char *objname, + /* Print the various times we collected. */ + static void print_statistics (const hp_timing_t *total_timep); + +-/* Length limits for names and paths, to protect the dynamic linker, +- particularly when __libc_enable_secure is active. */ +-#ifdef NAME_MAX +-# define SECURE_NAME_LIMIT NAME_MAX +-#else +-# define SECURE_NAME_LIMIT 255 +-#endif +-#ifdef PATH_MAX +-# define SECURE_PATH_LIMIT PATH_MAX +-#else +-# define SECURE_PATH_LIMIT 1024 +-#endif +- +-/* Strings containing colon-separated lists of audit modules. */ +-struct audit_list +-{ +- /* Array of strings containing colon-separated path lists. Each +- audit module needs its own namespace, so pre-allocate the largest +- possible list. */ +- const char *audit_strings[DL_NNS]; +- +- /* Number of entries added to audit_strings. */ +- size_t length; +- +- /* Index into the audit_strings array (for the iteration phase). */ +- size_t current_index; +- +- /* Tail of audit_strings[current_index] which still needs +- processing. */ +- const char *current_tail; +- +- /* Scratch buffer for returning a name which is part of the strings +- in audit_strings. */ +- char fname[SECURE_NAME_LIMIT]; +-}; +- + /* Creates an empty audit list. */ + static void audit_list_init (struct audit_list *); + +@@ -165,13 +130,13 @@ static void audit_list_add_dynamic_tag (struct audit_list *, + audit_list_add_dynamic_tags calls. */ + static const char *audit_list_next (struct audit_list *); + +-/* This is a list of all the modes the dynamic loader can be in. */ +-enum mode { normal, list, verify, trace }; ++/* Initialize *STATE with the defaults. */ ++static void dl_main_state_init (struct dl_main_state *state); + + /* Process all environments variables the dynamic linker must recognize. + Since all of them start with `LD_' we are a bit smarter while finding + all the entries. */ +-static void process_envvars (enum mode *modep, struct audit_list *); ++static void process_envvars (struct dl_main_state *state); + + #ifdef DL_ARGV_NOT_RELRO + int _dl_argc attribute_hidden; +@@ -314,6 +279,18 @@ audit_list_count (struct audit_list *list) + return naudit; + } + ++static void ++dl_main_state_init (struct dl_main_state *state) ++{ ++ audit_list_init (&state->audit_list); ++ state->library_path = NULL; ++ state->preloadlist = NULL; ++ state->preloadarg = NULL; ++ state->mode = rtld_mode_normal; ++ state->any_debug = false; ++ state->version_info = false; ++} ++ + /* Set nonzero during loading and initialization of executable and + libraries, cleared before the executable's entry point runs. This + must not be initialized to nonzero, because the unused dynamic +@@ -896,15 +873,6 @@ security_init (void) + + #include "setup-vdso.h" + +-/* The library search path. */ +-static const char *library_path attribute_relro; +-/* The list preloaded objects. */ +-static const char *preloadlist attribute_relro; +-/* Nonzero if information about versions has to be printed. */ +-static int version_info attribute_relro; +-/* The preload list passed as a command argument. */ +-static const char *preloadarg attribute_relro; +- + /* The LD_PRELOAD environment variable gives list of libraries + separated by white space or colons that are loaded before the + executable's dependencies and prepended to the global scope list. +@@ -1146,7 +1114,6 @@ dl_main (const ElfW(Phdr) *phdr, + ElfW(auxv_t) *auxv) + { + const ElfW(Phdr) *ph; +- enum mode mode; + struct link_map *main_map; + size_t file_size; + char *file; +@@ -1156,8 +1123,8 @@ dl_main (const ElfW(Phdr) *phdr, + bool rtld_is_main = false; + void *tcbp = NULL; + +- struct audit_list audit_list; +- audit_list_init (&audit_list); ++ struct dl_main_state state; ++ dl_main_state_init (&state); + + GL(dl_init_static_tls) = &_dl_nothread_init_static_tls; + +@@ -1172,7 +1139,7 @@ dl_main (const ElfW(Phdr) *phdr, + GL(dl_make_stack_executable_hook) = &_dl_make_stack_executable; + + /* Process the environment variable which control the behaviour. */ +- process_envvars (&mode, &audit_list); ++ process_envvars (&state); + + /* Set up a flag which tells we are just starting. */ + _dl_starting_up = 1; +@@ -1204,7 +1171,7 @@ dl_main (const ElfW(Phdr) *phdr, + while (_dl_argc > 1) + if (! strcmp (_dl_argv[1], "--list")) + { +- mode = list; ++ state.mode = rtld_mode_list; + GLRO(dl_lazy) = -1; /* This means do no dependency analysis. */ + + ++_dl_skip_args; +@@ -1213,7 +1180,7 @@ dl_main (const ElfW(Phdr) *phdr, + } + else if (! strcmp (_dl_argv[1], "--verify")) + { +- mode = verify; ++ state.mode = rtld_mode_verify; + + ++_dl_skip_args; + --_dl_argc; +@@ -1229,7 +1196,7 @@ dl_main (const ElfW(Phdr) *phdr, + else if (! strcmp (_dl_argv[1], "--library-path") + && _dl_argc > 2) + { +- library_path = _dl_argv[2]; ++ state.library_path = _dl_argv[2]; + + _dl_skip_args += 2; + _dl_argc -= 2; +@@ -1246,7 +1213,7 @@ dl_main (const ElfW(Phdr) *phdr, + } + else if (! strcmp (_dl_argv[1], "--audit") && _dl_argc > 2) + { +- audit_list_add_string (&audit_list, _dl_argv[2]); ++ audit_list_add_string (&state.audit_list, _dl_argv[2]); + + _dl_skip_args += 2; + _dl_argc -= 2; +@@ -1254,7 +1221,7 @@ dl_main (const ElfW(Phdr) *phdr, + } + else if (! strcmp (_dl_argv[1], "--preload") && _dl_argc > 2) + { +- preloadarg = _dl_argv[2]; ++ state.preloadarg = _dl_argv[2]; + _dl_skip_args += 2; + _dl_argc -= 2; + _dl_argv += 2; +@@ -1322,7 +1289,7 @@ of this helper program; chances are you did not intend to run this program.\n\ + break; + } + +- if (__builtin_expect (mode, normal) == verify) ++ if (__glibc_unlikely (state.mode == rtld_mode_verify)) + { + const char *objname; + const char *err_str = NULL; +@@ -1351,7 +1318,7 @@ of this helper program; chances are you did not intend to run this program.\n\ + /* Now the map for the main executable is available. */ + main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded; + +- if (__builtin_expect (mode, normal) == normal ++ if (__glibc_likely (state.mode == rtld_mode_normal) + && GL(dl_rtld_map).l_info[DT_SONAME] != NULL + && main_map->l_info[DT_SONAME] != NULL + && strcmp ((const char *) D_PTR (&GL(dl_rtld_map), l_info[DT_STRTAB]) +@@ -1592,7 +1559,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + _dl_setup_hash (main_map); + } + +- if (__builtin_expect (mode, normal) == verify) ++ if (__glibc_unlikely (state.mode == rtld_mode_verify)) + { + /* We were called just to verify that this is a dynamic + executable using us as the program interpreter. Exit with an +@@ -1619,7 +1586,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + + /* Initialize the data structures for the search paths for shared + objects. */ +- _dl_init_paths (library_path); ++ call_init_paths (&state); + + /* Initialize _r_debug. */ + struct r_debug *r = _dl_debug_initialize (GL(dl_rtld_map).l_addr, +@@ -1684,14 +1651,14 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + /* Assign a module ID. Do this before loading any audit modules. */ + GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid (); + +- audit_list_add_dynamic_tag (&audit_list, main_map, DT_AUDIT); +- audit_list_add_dynamic_tag (&audit_list, main_map, DT_DEPAUDIT); ++ audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_AUDIT); ++ audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_DEPAUDIT); + + /* If we have auditing DSOs to load, do it now. */ + bool need_security_init = true; +- if (audit_list.length > 0) ++ if (state.audit_list.length > 0) + { +- size_t naudit = audit_list_count (&audit_list); ++ size_t naudit = audit_list_count (&state.audit_list); + + /* Since we start using the auditing DSOs right away we need to + initialize the data structures now. */ +@@ -1704,7 +1671,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + security_init (); + need_security_init = false; + +- load_audit_modules (main_map, &audit_list); ++ load_audit_modules (main_map, &state.audit_list); + + /* The count based on audit strings may overestimate the number + of audit modules that got loaded, but not underestimate. */ +@@ -1759,19 +1726,21 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + struct link_map **preloads = NULL; + unsigned int npreloads = 0; + +- if (__glibc_unlikely (preloadlist != NULL)) ++ if (__glibc_unlikely (state.preloadlist != NULL)) + { + RTLD_TIMING_VAR (start); + rtld_timer_start (&start); +- npreloads += handle_preload_list (preloadlist, main_map, "LD_PRELOAD"); ++ npreloads += handle_preload_list (state.preloadlist, main_map, ++ "LD_PRELOAD"); + rtld_timer_accum (&load_time, start); + } + +- if (__glibc_unlikely (preloadarg != NULL)) ++ if (__glibc_unlikely (state.preloadarg != NULL)) + { + RTLD_TIMING_VAR (start); + rtld_timer_start (&start); +- npreloads += handle_preload_list (preloadarg, main_map, "--preload"); ++ npreloads += handle_preload_list (state.preloadarg, main_map, ++ "--preload"); + rtld_timer_accum (&load_time, start); + } + +@@ -1878,7 +1847,8 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + { + RTLD_TIMING_VAR (start); + rtld_timer_start (&start); +- _dl_map_object_deps (main_map, preloads, npreloads, mode == trace, 0); ++ _dl_map_object_deps (main_map, preloads, npreloads, ++ state.mode == rtld_mode_trace, 0); + rtld_timer_accum (&load_time, start); + } + +@@ -1905,7 +1875,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + rtld_multiple_ref = true; + + GL(dl_rtld_map).l_prev = main_map->l_searchlist.r_list[i - 1]; +- if (__builtin_expect (mode, normal) == normal) ++ if (__glibc_likely (state.mode == rtld_mode_normal)) + { + GL(dl_rtld_map).l_next = (i + 1 < main_map->l_searchlist.r_nlist + ? main_map->l_searchlist.r_list[i + 1] +@@ -1938,8 +1908,8 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + versions we need. */ + { + struct version_check_args args; +- args.doexit = mode == normal; +- args.dotrace = mode == trace; ++ args.doexit = state.mode == rtld_mode_normal; ++ args.dotrace = state.mode == rtld_mode_trace; + _dl_receive_error (print_missing_version, version_check_doit, &args); + } + +@@ -1959,7 +1929,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + earlier. */ + security_init (); + +- if (__builtin_expect (mode, normal) != normal) ++ if (__glibc_unlikely (state.mode != rtld_mode_normal)) + { + /* We were run just to list the shared libraries. It is + important that we do this before real relocation, because the +@@ -2061,7 +2031,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + (size_t) l->l_map_start); + } + +- if (__builtin_expect (mode, trace) != trace) ++ if (__glibc_unlikely (state.mode != rtld_mode_trace)) + for (i = 1; i < (unsigned int) _dl_argc; ++i) + { + const ElfW(Sym) *ref = NULL; +@@ -2115,7 +2085,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + } + } + #define VERNEEDTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (DT_VERNEED)) +- if (version_info) ++ if (state.version_info) + { + /* Print more information. This means here, print information + about the versions needed. */ +@@ -2477,13 +2447,10 @@ print_missing_version (int errcode __attribute__ ((unused)), + objname, errstring); + } + +-/* Nonzero if any of the debugging options is enabled. */ +-static int any_debug attribute_relro; +- + /* Process the string given as the parameter which explains which debugging + options are enabled. */ + static void +-process_dl_debug (const char *dl_debug) ++process_dl_debug (struct dl_main_state *state, const char *dl_debug) + { + /* When adding new entries make sure that the maximal length of a name + is correctly handled in the LD_DEBUG_HELP code below. */ +@@ -2540,7 +2507,7 @@ process_dl_debug (const char *dl_debug) + && memcmp (dl_debug, debopts[cnt].name, len) == 0) + { + GLRO(dl_debug_mask) |= debopts[cnt].mask; +- any_debug = 1; ++ state->any_debug = true; + break; + } + +@@ -2594,11 +2561,10 @@ extern char **_environ attribute_hidden; + + + static void +-process_envvars (enum mode *modep, struct audit_list *audit_list) ++process_envvars (struct dl_main_state *state) + { + char **runp = _environ; + char *envline; +- enum mode mode = normal; + char *debug_output = NULL; + + /* This is the default place for profiling data file. */ +@@ -2630,25 +2596,25 @@ process_envvars (enum mode *modep, struct audit_list *audit_list) + /* Debugging of the dynamic linker? */ + if (memcmp (envline, "DEBUG", 5) == 0) + { +- process_dl_debug (&envline[6]); ++ process_dl_debug (state, &envline[6]); + break; + } + if (memcmp (envline, "AUDIT", 5) == 0) +- audit_list_add_string (audit_list, &envline[6]); ++ audit_list_add_string (&state->audit_list, &envline[6]); + break; + + case 7: + /* Print information about versions. */ + if (memcmp (envline, "VERBOSE", 7) == 0) + { +- version_info = envline[8] != '\0'; ++ state->version_info = envline[8] != '\0'; + break; + } + + /* List of objects to be preloaded. */ + if (memcmp (envline, "PRELOAD", 7) == 0) + { +- preloadlist = &envline[8]; ++ state->preloadlist = &envline[8]; + break; + } + +@@ -2697,7 +2663,7 @@ process_envvars (enum mode *modep, struct audit_list *audit_list) + if (!__libc_enable_secure + && memcmp (envline, "LIBRARY_PATH", 12) == 0) + { +- library_path = &envline[13]; ++ state->library_path = &envline[13]; + break; + } + +@@ -2739,7 +2705,7 @@ process_envvars (enum mode *modep, struct audit_list *audit_list) + /* The mode of the dynamic linker can be set. */ + if (memcmp (envline, "TRACE_PRELINKING", 16) == 0) + { +- mode = trace; ++ state->mode = rtld_mode_trace; + GLRO(dl_verbose) = 1; + GLRO(dl_debug_mask) |= DL_DEBUG_PRELINK; + GLRO(dl_trace_prelink) = &envline[17]; +@@ -2749,7 +2715,7 @@ process_envvars (enum mode *modep, struct audit_list *audit_list) + case 20: + /* The mode of the dynamic linker can be set. */ + if (memcmp (envline, "TRACE_LOADED_OBJECTS", 20) == 0) +- mode = trace; ++ state->mode = rtld_mode_trace; + break; + + /* We might have some extra environment variable to handle. This +@@ -2762,9 +2728,6 @@ process_envvars (enum mode *modep, struct audit_list *audit_list) + } + } + +- /* The caller wants this information. */ +- *modep = mode; +- + /* Extra security for SUID binaries. Remove all dangerous environment + variables. */ + if (__builtin_expect (__libc_enable_secure, 0)) +@@ -2793,13 +2756,13 @@ process_envvars (enum mode *modep, struct audit_list *audit_list) + GLRO(dl_debug_mask) = 0; + } + +- if (mode != normal) ++ if (state->mode != rtld_mode_normal) + _exit (5); + } + /* If we have to run the dynamic linker in debugging mode and the + LD_DEBUG_OUTPUT environment variable is given, we write the debug + messages to this file. */ +- else if (any_debug && debug_output != NULL) ++ else if (state->any_debug && debug_output != NULL) + { + const int flags = O_WRONLY | O_APPEND | O_CREAT | O_NOFOLLOW; + size_t name_len = strlen (debug_output); diff --git a/SOURCES/glibc-rh1817513-91.patch b/SOURCES/glibc-rh1817513-91.patch new file mode 100644 index 0000000..00dbfed --- /dev/null +++ b/SOURCES/glibc-rh1817513-91.patch @@ -0,0 +1,161 @@ +commit 9590a71adcf134c77f2d0f5711b0d6ab1b4193e6 +Author: Florian Weimer +Date: Thu Oct 8 10:57:10 2020 +0200 + + elf: Move ld.so error/help output to _dl_usage + + Also add a comment to elf/Makefile, explaining why we cannot use + config.status for autoconf template processing. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/Makefile b/elf/Makefile +index e2078f6bc325b7e0..e5666e5bf7817c3c 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -59,7 +59,7 @@ 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-error-minimal dl-conflict dl-hwcaps dl-usage + all-rtld-routines = $(rtld-routines) $(sysdep-rtld-routines) + + CFLAGS-dl-runtime.c += -fexceptions -fasynchronous-unwind-tables +@@ -598,6 +598,12 @@ ldso_install: $(inst_rtlddir)/$(rtld-installed-name) + endif + + ++# Workarounds for ${exec_prefix} expansion in configure variables. ++# config.status cannot be used directly for processing ldd.bash.in or ++# expanding variables such as sysconfdir because the expansion ++# contains the literal string ${exec_prefix}, which is not valid in C ++# headers or installed shell scripts. ++ + ldd-rewrite = -e 's%@RTLD@%$(rtlddir)/$(rtld-installed-name)%g' \ + -e 's%@VERSION@%$(version)%g' \ + -e 's|@PKGVERSION@|$(PKGVERSION)|g' \ +@@ -635,6 +641,7 @@ libof-ldconfig = ldconfig + CFLAGS-dl-cache.c += $(SYSCONF-FLAGS) + CFLAGS-cache.c += $(SYSCONF-FLAGS) + CFLAGS-rtld.c += $(SYSCONF-FLAGS) ++CFLAGS-dl-usage.c += $(SYSCONF-FLAGS) + + cpp-srcs-left := $(all-rtld-routines:=.os) + lib := rtld +diff --git a/elf/dl-main.h b/elf/dl-main.h +index bcc9bcf2e8fee6e7..b01f433f9c8d9e1a 100644 +--- a/elf/dl-main.h ++++ b/elf/dl-main.h +@@ -19,7 +19,9 @@ + #ifndef _DL_MAIN + #define _DL_MAIN + ++#include + #include ++#include + + /* Length limits for names and paths, to protect the dynamic linker, + particularly when __libc_enable_secure is active. */ +@@ -95,4 +97,7 @@ call_init_paths (const struct dl_main_state *state) + _dl_init_paths (state->library_path); + } + ++/* Print ld.so usage information and exit. */ ++_Noreturn void _dl_usage (void) attribute_hidden; ++ + #endif /* _DL_MAIN */ +diff --git a/elf/dl-usage.c b/elf/dl-usage.c +new file mode 100644 +index 0000000000000000..f3d89d22b71d7d12 +--- /dev/null ++++ b/elf/dl-usage.c +@@ -0,0 +1,51 @@ ++/* Print usage information and help for ld.so. ++ Copyright (C) 1995-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 ++ ++void ++_dl_usage (void) ++{ ++ _dl_fatal_printf ("\ ++Usage: ld.so [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\ ++You have invoked `ld.so', the helper program for shared library executables.\n\ ++This program usually lives in the file `/lib/ld.so', and special directives\n\ ++in executable files using ELF shared libraries tell the system's program\n\ ++loader to load the helper program from this file. This helper program loads\n\ ++the shared libraries needed by the program executable, prepares the program\n\ ++to run, and runs it. You may invoke this helper program directly from the\n\ ++command line to load and run an ELF executable file; this is like executing\n\ ++that file itself, but always uses this helper program from the file you\n\ ++specified, instead of the helper program file specified in the executable\n\ ++file you run. This is mostly of use for maintainers to test new versions\n\ ++of this helper program; chances are you did not intend to run this program.\n\ ++\n\ ++ --list list all dependencies and how they are resolved\n\ ++ --verify verify that given object really is a dynamically linked\n\ ++ object we can handle\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\ ++ --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\ ++ --preload LIST preload objects named in LIST\n\ ++ --argv0 STRING set argv[0] to STRING before running\n"); ++} +diff --git a/elf/rtld.c b/elf/rtld.c +index fbfa441bf3b050ff..a12a56b550bbc837 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -1240,31 +1240,7 @@ dl_main (const ElfW(Phdr) *phdr, + /* If we have no further argument the program was called incorrectly. + Grant the user some education. */ + if (_dl_argc < 2) +- _dl_fatal_printf ("\ +-Usage: ld.so [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\ +-You have invoked `ld.so', the helper program for shared library executables.\n\ +-This program usually lives in the file `/lib/ld.so', and special directives\n\ +-in executable files using ELF shared libraries tell the system's program\n\ +-loader to load the helper program from this file. This helper program loads\n\ +-the shared libraries needed by the program executable, prepares the program\n\ +-to run, and runs it. You may invoke this helper program directly from the\n\ +-command line to load and run an ELF executable file; this is like executing\n\ +-that file itself, but always uses this helper program from the file you\n\ +-specified, instead of the helper program file specified in the executable\n\ +-file you run. This is mostly of use for maintainers to test new versions\n\ +-of this helper program; chances are you did not intend to run this program.\n\ +-\n\ +- --list list all dependencies and how they are resolved\n\ +- --verify verify that given object really is a dynamically linked\n\ +- object we can handle\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\ +- --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\ +- --preload LIST preload objects named in LIST\n\ +- --argv0 STRING set argv[0] to STRING before running\n"); ++ _dl_usage (); + + ++_dl_skip_args; + --_dl_argc; diff --git a/SOURCES/glibc-rh1817513-92.patch b/SOURCES/glibc-rh1817513-92.patch new file mode 100644 index 0000000..45c4c95 --- /dev/null +++ b/SOURCES/glibc-rh1817513-92.patch @@ -0,0 +1,113 @@ +commit 27316f4a23efdc90bdfe4569a6c4b7e27941606e +Author: Florian Weimer +Date: Thu Oct 8 10:57:10 2020 +0200 + + elf: Record whether paths come from LD_LIBRARY_PATH or --library-path + + This allows more precise LD_DEBUG diagnostics. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 2b4dd9a0f3e27b70..1403a2e9c04e9a16 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -682,7 +682,7 @@ cache_rpath (struct link_map *l, + + + void +-_dl_init_paths (const char *llp) ++_dl_init_paths (const char *llp, const char *source) + { + size_t idx; + const char *strp; +@@ -820,7 +820,7 @@ _dl_init_paths (const char *llp) + } + + (void) fillin_rpath (llp_tmp, env_path_list.dirs, ":;", +- "LD_LIBRARY_PATH", NULL, l); ++ source, NULL, l); + + if (env_path_list.dirs[0] == NULL) + { +diff --git a/elf/dl-main.h b/elf/dl-main.h +index b01f433f9c8d9e1a..79c9c40056504f80 100644 +--- a/elf/dl-main.h ++++ b/elf/dl-main.h +@@ -74,6 +74,9 @@ struct dl_main_state + /* The library search path. */ + const char *library_path; + ++ /* Where library_path comes from. LD_LIBRARY_PATH or --library-path. */ ++ const char *library_path_source; ++ + /* The list preloaded objects from LD_PRELOAD. */ + const char *preloadlist; + +@@ -94,7 +97,7 @@ struct dl_main_state + static inline void + call_init_paths (const struct dl_main_state *state) + { +- _dl_init_paths (state->library_path); ++ _dl_init_paths (state->library_path, state->library_path_source); + } + + /* Print ld.so usage information and exit. */ +diff --git a/elf/dl-support.c b/elf/dl-support.c +index ef5455b91c17ca30..fb9672367f8d6abd 100644 +--- a/elf/dl-support.c ++++ b/elf/dl-support.c +@@ -315,7 +315,7 @@ _dl_non_dynamic_init (void) + + /* Initialize the data structures for the search paths for shared + objects. */ +- _dl_init_paths (getenv ("LD_LIBRARY_PATH")); ++ _dl_init_paths (getenv ("LD_LIBRARY_PATH"), "LD_LIBRARY_PATH"); + + /* Remember the last search directory added at startup. */ + _dl_init_all_dirs = GL(dl_all_dirs); +diff --git a/elf/rtld.c b/elf/rtld.c +index a12a56b550bbc837..8e91cee41b62b894 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -284,6 +284,7 @@ dl_main_state_init (struct dl_main_state *state) + { + audit_list_init (&state->audit_list); + state->library_path = NULL; ++ state->library_path_source = NULL; + state->preloadlist = NULL; + state->preloadarg = NULL; + state->mode = rtld_mode_normal; +@@ -1197,6 +1198,7 @@ dl_main (const ElfW(Phdr) *phdr, + && _dl_argc > 2) + { + state.library_path = _dl_argv[2]; ++ state.library_path_source = "--library-path"; + + _dl_skip_args += 2; + _dl_argc -= 2; +@@ -2640,6 +2642,7 @@ process_envvars (struct dl_main_state *state) + && memcmp (envline, "LIBRARY_PATH", 12) == 0) + { + state->library_path = &envline[13]; ++ state->library_path_source = "LD_LIBRARY_PATH"; + break; + } + +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 4aa28b0229e0b339..aa006afafaf46dee 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1044,8 +1044,10 @@ rtld_hidden_proto (_dl_debug_state) + extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns) + attribute_hidden; + +-/* Initialize the basic data structure for the search paths. */ +-extern void _dl_init_paths (const char *library_path) 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) ++ attribute_hidden; + + /* Gather the information needed to install the profiling tables and start + the timers. */ diff --git a/SOURCES/glibc-rh1817513-93.patch b/SOURCES/glibc-rh1817513-93.patch new file mode 100644 index 0000000..e755b67 --- /dev/null +++ b/SOURCES/glibc-rh1817513-93.patch @@ -0,0 +1,202 @@ +commit e0f1a58f3d1f4f55591b524e9dcff23cc98a509e +Author: Florian Weimer +Date: Thu Oct 8 10:57:10 2020 +0200 + + elf: Implement ld.so --help + + --help processing is deferred to the point where the executable has + been loaded, so that it is possible to eventually include information + from the main executable in the help output. + + As suggested in the GNU command-line interface guidelines, the help + message is printed to standard output, and the exit status is + successful. + + Handle usage errors closer to the GNU command-line interface + guidelines. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-main.h b/elf/dl-main.h +index 79c9c40056504f80..ac7249a580214860 100644 +--- a/elf/dl-main.h ++++ b/elf/dl-main.h +@@ -63,6 +63,7 @@ struct audit_list + enum rtld_mode + { + rtld_mode_normal, rtld_mode_list, rtld_mode_verify, rtld_mode_trace, ++ rtld_mode_help, + }; + + /* Aggregated state information extracted from environment variables +@@ -101,6 +102,11 @@ call_init_paths (const struct dl_main_state *state) + } + + /* Print ld.so usage information and exit. */ +-_Noreturn void _dl_usage (void) attribute_hidden; ++_Noreturn void _dl_usage (const char *argv0, const char *wrong_option) ++ attribute_hidden; ++ ++/* Print ld.so --help output and exit. */ ++_Noreturn void _dl_help (const char *argv0, struct dl_main_state *state) ++ attribute_hidden; + + #endif /* _DL_MAIN */ +diff --git a/elf/dl-usage.c b/elf/dl-usage.c +index f3d89d22b71d7d12..c1820dca2fa117ee 100644 +--- a/elf/dl-usage.c ++++ b/elf/dl-usage.c +@@ -19,12 +19,24 @@ + #include + #include + #include ++#include + + void +-_dl_usage (void) ++_dl_usage (const char *argv0, const char *wrong_option) + { +- _dl_fatal_printf ("\ +-Usage: ld.so [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\ ++ if (wrong_option != NULL) ++ _dl_error_printf ("%s: unrecognized option '%s'\n", argv0, wrong_option); ++ else ++ _dl_error_printf ("%s: missing program name\n", argv0); ++ _dl_error_printf ("Try '%s --help' for more information.\n", argv0); ++ _exit (EXIT_FAILURE); ++} ++ ++void ++_dl_help (const char *argv0, struct dl_main_state *state) ++{ ++ _dl_printf ("\ ++Usage: %s [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\ + You have invoked `ld.so', the helper program for shared library executables.\n\ + This program usually lives in the file `/lib/ld.so', and special directives\n\ + in executable files using ELF shared libraries tell the system's program\n\ +@@ -47,5 +59,9 @@ of this helper program; chances are you did not intend to run this program.\n\ + in LIST\n\ + --audit LIST use objects named in LIST as auditors\n\ + --preload LIST preload objects named in LIST\n\ +- --argv0 STRING set argv[0] to STRING before running\n"); ++ --argv0 STRING set argv[0] to STRING before running\n\ ++ --help display this help and exit\n\ ++", ++ argv0); ++ _exit (EXIT_SUCCESS); + } +diff --git a/elf/rtld.c b/elf/rtld.c +index 8e91cee41b62b894..b92641cb1c2d99a6 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -1145,6 +1145,7 @@ dl_main (const ElfW(Phdr) *phdr, + /* Set up a flag which tells we are just starting. */ + _dl_starting_up = 1; + ++ const char *ld_so_name = _dl_argv[0]; + if (*user_entry == (ElfW(Addr)) ENTRY_POINT) + { + /* Ho ho. We are not the program interpreter! We are the program +@@ -1172,8 +1173,12 @@ dl_main (const ElfW(Phdr) *phdr, + while (_dl_argc > 1) + if (! strcmp (_dl_argv[1], "--list")) + { +- state.mode = rtld_mode_list; +- GLRO(dl_lazy) = -1; /* This means do no dependency analysis. */ ++ if (state.mode != rtld_mode_help) ++ { ++ state.mode = rtld_mode_list; ++ /* This means do no dependency analysis. */ ++ GLRO(dl_lazy) = -1; ++ } + + ++_dl_skip_args; + --_dl_argc; +@@ -1181,7 +1186,8 @@ dl_main (const ElfW(Phdr) *phdr, + } + else if (! strcmp (_dl_argv[1], "--verify")) + { +- state.mode = rtld_mode_verify; ++ if (state.mode != rtld_mode_help) ++ state.mode = rtld_mode_verify; + + ++_dl_skip_args; + --_dl_argc; +@@ -1236,13 +1242,34 @@ dl_main (const ElfW(Phdr) *phdr, + _dl_argc -= 2; + _dl_argv += 2; + } ++ else if (strcmp (_dl_argv[1], "--help") == 0) ++ { ++ state.mode = rtld_mode_help; ++ --_dl_argc; ++ ++_dl_argv; ++ } ++ else if (_dl_argv[1][0] == '-' && _dl_argv[1][1] == '-') ++ { ++ if (_dl_argv[1][1] == '\0') ++ /* End of option list. */ ++ break; ++ else ++ /* Unrecognized option. */ ++ _dl_usage (ld_so_name, _dl_argv[1]); ++ } + else + break; + + /* If we have no further argument the program was called incorrectly. + Grant the user some education. */ + if (_dl_argc < 2) +- _dl_usage (); ++ { ++ if (state.mode == rtld_mode_help) ++ /* --help without an executable is not an error. */ ++ _dl_help (ld_so_name, &state); ++ else ++ _dl_usage (ld_so_name, NULL); ++ } + + ++_dl_skip_args; + --_dl_argc; +@@ -1267,7 +1294,8 @@ dl_main (const ElfW(Phdr) *phdr, + break; + } + +- if (__glibc_unlikely (state.mode == rtld_mode_verify)) ++ if (__glibc_unlikely (state.mode == rtld_mode_verify ++ || state.mode == rtld_mode_help)) + { + const char *objname; + const char *err_str = NULL; +@@ -1280,9 +1308,16 @@ dl_main (const ElfW(Phdr) *phdr, + (void) _dl_catch_error (&objname, &err_str, &malloced, map_doit, + &args); + if (__glibc_unlikely (err_str != NULL)) +- /* We don't free the returned string, the programs stops +- anyway. */ +- _exit (EXIT_FAILURE); ++ { ++ /* We don't free the returned string, the programs stops ++ anyway. */ ++ if (state.mode == rtld_mode_help) ++ /* Mask the failure to load the main object. The help ++ message contains less information in this case. */ ++ _dl_help (ld_so_name, &state); ++ else ++ _exit (EXIT_FAILURE); ++ } + } + else + { +@@ -1632,6 +1667,11 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_AUDIT); + audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_DEPAUDIT); + ++ /* At this point, all data has been obtained that is included in the ++ --help output. */ ++ if (__glibc_unlikely (state.mode == rtld_mode_help)) ++ _dl_help (ld_so_name, &state); ++ + /* If we have auditing DSOs to load, do it now. */ + bool need_security_init = true; + if (state.audit_list.length > 0) diff --git a/SOURCES/glibc-rh1817513-94.patch b/SOURCES/glibc-rh1817513-94.patch new file mode 100644 index 0000000..8d1b874 --- /dev/null +++ b/SOURCES/glibc-rh1817513-94.patch @@ -0,0 +1,79 @@ +commit 542923d949e8b2480e48bd85fea13cf5d00d30b7 +Author: Florian Weimer +Date: Thu Oct 8 15:33:00 2020 +0200 + + elf: Implement ld.so --version + + This prints out version information for the dynamic loader and + exits immediately, without further command line processing + (which seems to match what some GNU tools do). + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-main.h b/elf/dl-main.h +index ac7249a580214860..b51256d3b48230b0 100644 +--- a/elf/dl-main.h ++++ b/elf/dl-main.h +@@ -105,6 +105,9 @@ call_init_paths (const struct dl_main_state *state) + _Noreturn void _dl_usage (const char *argv0, const char *wrong_option) + attribute_hidden; + ++/* Print ld.so version information and exit. */ ++_Noreturn void _dl_version (void) attribute_hidden; ++ + /* Print ld.so --help output and exit. */ + _Noreturn void _dl_help (const char *argv0, struct dl_main_state *state) + attribute_hidden; +diff --git a/elf/dl-usage.c b/elf/dl-usage.c +index c1820dca2fa117ee..f3c5ac76d37f9c03 100644 +--- a/elf/dl-usage.c ++++ b/elf/dl-usage.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include "version.h" + + void + _dl_usage (const char *argv0, const char *wrong_option) +@@ -32,6 +33,19 @@ _dl_usage (const char *argv0, const char *wrong_option) + _exit (EXIT_FAILURE); + } + ++void ++_dl_version (void) ++{ ++ _dl_printf ("\ ++ld.so " PKGVERSION RELEASE " release version " VERSION ".\n\ ++Copyright (C) 2020 Free Software Foundation, Inc.\n\ ++This is free software; see the source for copying conditions.\n\ ++There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n\ ++PARTICULAR PURPOSE.\n\ ++"); ++ _exit (EXIT_SUCCESS); ++} ++ + void + _dl_help (const char *argv0, struct dl_main_state *state) + { +@@ -61,6 +75,7 @@ of this helper program; chances are you did not intend to run this program.\n\ + --preload LIST preload objects named in LIST\n\ + --argv0 STRING set argv[0] to STRING before running\n\ + --help display this help and exit\n\ ++ --version output version information and exit\n\ + ", + argv0); + _exit (EXIT_SUCCESS); +diff --git a/elf/rtld.c b/elf/rtld.c +index b92641cb1c2d99a6..da1eef108508b95f 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -1248,6 +1248,8 @@ dl_main (const ElfW(Phdr) *phdr, + --_dl_argc; + ++_dl_argv; + } ++ else if (strcmp (_dl_argv[1], "--version") == 0) ++ _dl_version (); + else if (_dl_argv[1][0] == '-' && _dl_argv[1][1] == '-') + { + if (_dl_argv[1][1] == '\0') diff --git a/SOURCES/glibc-rh1817513-95.patch b/SOURCES/glibc-rh1817513-95.patch new file mode 100644 index 0000000..12e1075 --- /dev/null +++ b/SOURCES/glibc-rh1817513-95.patch @@ -0,0 +1,43 @@ +commit ca52c56abf50b89a95dc2a4a5504c0d7d3862961 +Author: Florian Weimer +Date: Thu Oct 8 15:33:00 2020 +0200 + + elf: Use the term "program interpreter" in the ld.so help message + + This is the term that the ELF standard itself uses. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-usage.c b/elf/dl-usage.c +index f3c5ac76d37f9c03..8c24c13770500df9 100644 +--- a/elf/dl-usage.c ++++ b/elf/dl-usage.c +@@ -51,17 +51,17 @@ _dl_help (const char *argv0, struct dl_main_state *state) + { + _dl_printf ("\ + Usage: %s [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\ +-You have invoked `ld.so', the helper program for shared library executables.\n\ +-This program usually lives in the file `/lib/ld.so', and special directives\n\ +-in executable files using ELF shared libraries tell the system's program\n\ +-loader to load the helper program from this file. This helper program loads\n\ +-the shared libraries needed by the program executable, prepares the program\n\ +-to run, and runs it. You may invoke this helper program directly from the\n\ +-command line to load and run an ELF executable file; this is like executing\n\ +-that file itself, but always uses this helper program from the file you\n\ +-specified, instead of the helper program file specified in the executable\n\ +-file you run. This is mostly of use for maintainers to test new versions\n\ +-of this helper program; chances are you did not intend to run this program.\n\ ++You have invoked 'ld.so', the program interpreter for dynamically-linked\n\ ++ELF programs. Usually, the program interpreter is invoked automatically\n\ ++when a dynamically-linked executable is started.\n\ ++\n\ ++You may invoke the program interpreter program directly from the command\n\ ++line to load and run an ELF executable file; this is like executing that\n\ ++file itself, but always uses the program interpreter you invoked,\n\ ++instead of the program interpreter specified in the executable file you\n\ ++run. Invoking the program interpreter directly provides access to\n\ ++additional diagnostics, and changing the dynamic linker behavior without\n\ ++setting environment variables (which would be inherited by subprocesses).\n\ + \n\ + --list list all dependencies and how they are resolved\n\ + --verify verify that given object really is a dynamically linked\n\ diff --git a/SOURCES/glibc-rh1817513-96.patch b/SOURCES/glibc-rh1817513-96.patch new file mode 100644 index 0000000..94a0c03 --- /dev/null +++ b/SOURCES/glibc-rh1817513-96.patch @@ -0,0 +1,39 @@ +commit db03874df9843ab98c4faeb658f04d17e6db83a6 +Author: Florian Weimer +Date: Thu Oct 8 15:33:00 2020 +0200 + + elf: Print the full name of the dynamic loader in the ld.so help message + + This requires defining a macro for the full path, matching the + -Wl,--dynamic-link= arguments used for linking glibc programs, + and ldd script. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/Makefile b/elf/Makefile +index e5666e5bf7817c3c..bc96b8fd65e376cc 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -641,7 +641,8 @@ libof-ldconfig = ldconfig + CFLAGS-dl-cache.c += $(SYSCONF-FLAGS) + CFLAGS-cache.c += $(SYSCONF-FLAGS) + CFLAGS-rtld.c += $(SYSCONF-FLAGS) +-CFLAGS-dl-usage.c += $(SYSCONF-FLAGS) ++CFLAGS-dl-usage.c += $(SYSCONF-FLAGS) \ ++ -D'RTLD="$(rtlddir)/$(rtld-installed-name)"' + + cpp-srcs-left := $(all-rtld-routines:=.os) + lib := rtld +diff --git a/elf/dl-usage.c b/elf/dl-usage.c +index 8c24c13770500df9..1003a435bfc2b39e 100644 +--- a/elf/dl-usage.c ++++ b/elf/dl-usage.c +@@ -76,6 +76,8 @@ setting environment variables (which would be inherited by subprocesses).\n\ + --argv0 STRING set argv[0] to STRING before running\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ ++\n\ ++This program interpreter self-identifies as: " RTLD "\n\ + ", + argv0); + _exit (EXIT_SUCCESS); diff --git a/SOURCES/glibc-rh1817513-97.patch b/SOURCES/glibc-rh1817513-97.patch new file mode 100644 index 0000000..754d50a --- /dev/null +++ b/SOURCES/glibc-rh1817513-97.patch @@ -0,0 +1,174 @@ +commit 50b1b7a3905cbcdfbcc7eab335aa81478d711d1a +Author: Florian Weimer +Date: Thu Oct 8 15:33:00 2020 +0200 + + elf: Make __rtld_env_path_list and __rtld_search_dirs global variables + + They have been renamed from env_path_list and rtld_search_dirs to + avoid linknamespace issues. + + This change will allow future use these variables in diagnostics. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 1403a2e9c04e9a16..2eb4f35b2467f7d8 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -98,7 +98,7 @@ int __stack_prot attribute_hidden attribute_relro + + + /* This is the decomposed LD_LIBRARY_PATH search path. */ +-static struct r_search_path_struct env_path_list attribute_relro; ++struct r_search_path_struct __rtld_env_path_list attribute_relro; + + /* List of the hardware capabilities we might end up using. */ + #ifdef SHARED +@@ -442,7 +442,7 @@ add_name_to_object (struct link_map *l, const char *name) + } + + /* Standard search directories. */ +-static struct r_search_path_struct rtld_search_dirs attribute_relro; ++struct r_search_path_struct __rtld_search_dirs attribute_relro; + + static size_t max_dirnamelen; + +@@ -702,9 +702,9 @@ _dl_init_paths (const char *llp, const char *source) + #endif + + /* First set up the rest of the default search directory entries. */ +- aelem = rtld_search_dirs.dirs = (struct r_search_path_elem **) ++ aelem = __rtld_search_dirs.dirs = (struct r_search_path_elem **) + malloc ((nsystem_dirs_len + 1) * sizeof (struct r_search_path_elem *)); +- if (rtld_search_dirs.dirs == NULL) ++ if (__rtld_search_dirs.dirs == NULL) + { + errstring = N_("cannot create search path array"); + signal_error: +@@ -715,16 +715,17 @@ _dl_init_paths (const char *llp, const char *source) + + ncapstr * sizeof (enum r_dir_status)) + / sizeof (struct r_search_path_elem)); + +- rtld_search_dirs.dirs[0] = malloc (nsystem_dirs_len * round_size +- * sizeof (*rtld_search_dirs.dirs[0])); +- if (rtld_search_dirs.dirs[0] == NULL) ++ __rtld_search_dirs.dirs[0] ++ = malloc (nsystem_dirs_len * round_size ++ * sizeof (*__rtld_search_dirs.dirs[0])); ++ if (__rtld_search_dirs.dirs[0] == NULL) + { + errstring = N_("cannot create cache for search path"); + goto signal_error; + } + +- rtld_search_dirs.malloced = 0; +- pelem = GL(dl_all_dirs) = rtld_search_dirs.dirs[0]; ++ __rtld_search_dirs.malloced = 0; ++ pelem = GL(dl_all_dirs) = __rtld_search_dirs.dirs[0]; + strp = system_dirs; + idx = 0; + +@@ -811,27 +812,27 @@ _dl_init_paths (const char *llp, const char *source) + if (*cp == ':' || *cp == ';') + ++nllp; + +- env_path_list.dirs = (struct r_search_path_elem **) ++ __rtld_env_path_list.dirs = (struct r_search_path_elem **) + malloc ((nllp + 1) * sizeof (struct r_search_path_elem *)); +- if (env_path_list.dirs == NULL) ++ if (__rtld_env_path_list.dirs == NULL) + { + errstring = N_("cannot create cache for search path"); + goto signal_error; + } + +- (void) fillin_rpath (llp_tmp, env_path_list.dirs, ":;", ++ (void) fillin_rpath (llp_tmp, __rtld_env_path_list.dirs, ":;", + source, NULL, l); + +- if (env_path_list.dirs[0] == NULL) ++ if (__rtld_env_path_list.dirs[0] == NULL) + { +- free (env_path_list.dirs); +- env_path_list.dirs = (void *) -1; ++ free (__rtld_env_path_list.dirs); ++ __rtld_env_path_list.dirs = (void *) -1; + } + +- env_path_list.malloced = 0; ++ __rtld_env_path_list.malloced = 0; + } + else +- env_path_list.dirs = (void *) -1; ++ __rtld_env_path_list.dirs = (void *) -1; + } + + +@@ -1946,9 +1947,9 @@ open_path (const char *name, size_t namelen, int mode, + if (sps->malloced) + free (sps->dirs); + +- /* rtld_search_dirs and env_path_list are attribute_relro, therefore +- avoid writing into it. */ +- if (sps != &rtld_search_dirs && sps != &env_path_list) ++ /* __rtld_search_dirs and __rtld_env_path_list are ++ attribute_relro, therefore avoid writing to them. */ ++ if (sps != &__rtld_search_dirs && sps != &__rtld_env_path_list) + sps->dirs = (void *) -1; + } + +@@ -2096,8 +2097,8 @@ _dl_map_object (struct link_map *loader, const char *name, + } + + /* Try the LD_LIBRARY_PATH environment variable. */ +- if (fd == -1 && env_path_list.dirs != (void *) -1) +- fd = open_path (name, namelen, mode, &env_path_list, ++ if (fd == -1 && __rtld_env_path_list.dirs != (void *) -1) ++ fd = open_path (name, namelen, mode, &__rtld_env_path_list, + &realname, &fb, + loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded, + LA_SER_LIBPATH, &found_other_class); +@@ -2186,8 +2187,8 @@ _dl_map_object (struct link_map *loader, const char *name, + if (fd == -1 + && ((l = loader ?: GL(dl_ns)[nsid]._ns_loaded) == NULL + || __glibc_likely (!(l->l_flags_1 & DF_1_NODEFLIB))) +- && rtld_search_dirs.dirs != (void *) -1) +- fd = open_path (name, namelen, mode, &rtld_search_dirs, ++ && __rtld_search_dirs.dirs != (void *) -1) ++ fd = open_path (name, namelen, mode, &__rtld_search_dirs, + &realname, &fb, l, LA_SER_DEFAULT, &found_other_class); + + /* Add another newline when we are tracing the library loading. */ +@@ -2355,7 +2356,7 @@ _dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting) + } + + /* Try the LD_LIBRARY_PATH environment variable. */ +- add_path (&p, &env_path_list, XXX_ENV); ++ add_path (&p, &__rtld_env_path_list, XXX_ENV); + + /* Look at the RUNPATH information for this binary. */ + if (cache_rpath (loader, &loader->l_runpath_dirs, DT_RUNPATH, "RUNPATH")) +@@ -2367,7 +2368,7 @@ _dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting) + + /* Finally, try the default path. */ + if (!(loader->l_flags_1 & DF_1_NODEFLIB)) +- add_path (&p, &rtld_search_dirs, XXX_default); ++ add_path (&p, &__rtld_search_dirs, XXX_default); + + if (counting) + /* Count the struct size before the string area, which we didn't +diff --git a/include/link.h b/include/link.h +index e90fa79a0b332087..cdd011f59445e490 100644 +--- a/include/link.h ++++ b/include/link.h +@@ -79,6 +79,10 @@ struct r_search_path_struct + int malloced; + }; + ++/* Search path information computed by _dl_init_paths. */ ++extern struct r_search_path_struct __rtld_search_dirs attribute_hidden; ++extern struct r_search_path_struct __rtld_env_path_list attribute_hidden; ++ + /* Structure describing a loaded shared object. The `l_next' and `l_prev' + members form a chain of all the shared objects loaded at startup. + diff --git a/SOURCES/glibc-rh1817513-98.patch b/SOURCES/glibc-rh1817513-98.patch new file mode 100644 index 0000000..d861cbc --- /dev/null +++ b/SOURCES/glibc-rh1817513-98.patch @@ -0,0 +1,81 @@ +commit 10b39a5124aea509dfeef2f39a0835adb0fb2296 +Author: Florian Weimer +Date: Fri Oct 9 10:13:14 2020 +0200 + + elf: Add library search path information to ld.so --help + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-usage.c b/elf/dl-usage.c +index 1003a435bfc2b39e..8d39bc9d5442bc59 100644 +--- a/elf/dl-usage.c ++++ b/elf/dl-usage.c +@@ -46,6 +46,61 @@ PARTICULAR PURPOSE.\n\ + _exit (EXIT_SUCCESS); + } + ++/* Print part of the library search path (from a single source). */ ++static void ++print_search_path_for_help_1 (struct r_search_path_elem **list) ++{ ++ if (list == NULL || list == (void *) -1) ++ /* Path is missing or marked as inactive. */ ++ return; ++ ++ for (; *list != NULL; ++list) ++ { ++ _dl_write (STDOUT_FILENO, " ", 2); ++ const char *name = (*list)->dirname; ++ size_t namelen = (*list)->dirnamelen; ++ if (namelen == 0) ++ { ++ /* The empty string denotes the current directory. */ ++ name = "."; ++ namelen = 1; ++ } ++ else if (namelen > 1) ++ /* Remove the trailing slash. */ ++ --namelen; ++ _dl_write (STDOUT_FILENO, name, namelen); ++ _dl_printf (" (%s)\n", (*list)->what); ++ } ++} ++ ++/* Prints the library search path. See _dl_init_paths in dl-load.c ++ how this information is populated. */ ++static void ++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); ++ ++ _dl_printf ("\nShared library search path:\n"); ++ ++ /* The print order should reflect the processing in ++ _dl_map_object. */ ++ ++ struct link_map *map = GL(dl_ns)[LM_ID_BASE]._ns_loaded; ++ if (map != NULL) ++ print_search_path_for_help_1 (map->l_rpath_dirs.dirs); ++ ++ print_search_path_for_help_1 (__rtld_env_path_list.dirs); ++ ++ if (map != NULL) ++ print_search_path_for_help_1 (map->l_runpath_dirs.dirs); ++ ++ _dl_printf (" (libraries located via %s)\n", LD_SO_CACHE); ++ ++ print_search_path_for_help_1 (__rtld_search_dirs.dirs); ++} ++ + void + _dl_help (const char *argv0, struct dl_main_state *state) + { +@@ -80,5 +135,6 @@ setting environment variables (which would be inherited by subprocesses).\n\ + This program interpreter self-identifies as: " RTLD "\n\ + ", + argv0); ++ print_search_path_for_help (state); + _exit (EXIT_SUCCESS); + } diff --git a/SOURCES/glibc-rh1817513-99.patch b/SOURCES/glibc-rh1817513-99.patch new file mode 100644 index 0000000..b55d80e --- /dev/null +++ b/SOURCES/glibc-rh1817513-99.patch @@ -0,0 +1,94 @@ +commit 647103ea3a2aae2e6791b3bebe9e33eedc168102 +Author: Florian Weimer +Date: Fri Oct 9 10:13:14 2020 +0200 + + elf: Enhance ld.so --help to print HWCAP subdirectories + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-usage.c b/elf/dl-usage.c +index 8d39bc9d5442bc59..c07f43835bd771cf 100644 +--- a/elf/dl-usage.c ++++ b/elf/dl-usage.c +@@ -22,6 +22,8 @@ + #include + #include "version.h" + ++#include ++ + void + _dl_usage (const char *argv0, const char *wrong_option) + { +@@ -101,6 +103,65 @@ print_search_path_for_help (struct dl_main_state *state) + print_search_path_for_help_1 (__rtld_search_dirs.dirs); + } + ++/* Helper function for printing flags associated with a HWCAP name. */ ++static void ++print_hwcap_1 (bool *first, bool active, const char *label) ++{ ++ if (active) ++ { ++ if (*first) ++ { ++ _dl_printf (" ("); ++ *first = false; ++ } ++ else ++ _dl_printf (", "); ++ _dl_printf ("%s", label); ++ } ++} ++ ++/* Called after a series of print_hwcap_1 calls to emit the line ++ terminator. */ ++static void ++print_hwcap_1_finish (bool *first) ++{ ++ if (*first) ++ _dl_printf ("\n"); ++ else ++ _dl_printf (")\n"); ++} ++ ++/* Write a list of hwcap subdirectories to standard output. See ++ _dl_important_hwcaps in dl-hwcaps.c. */ ++static void ++print_legacy_hwcap_directories (void) ++{ ++ _dl_printf ("\n\ ++Legacy HWCAP subdirectories under library search path directories:\n"); ++ ++ const char *platform = GLRO (dl_platform); ++ if (platform != NULL) ++ _dl_printf (" %s (AT_PLATFORM; supported, searched)\n", platform); ++ ++ _dl_printf (" tls (supported, searched)\n"); ++ ++ uint64_t hwcap_mask = GET_HWCAP_MASK(); ++ uint64_t searched = GLRO (dl_hwcap) & hwcap_mask; ++ for (int n = 63; n >= 0; --n) ++ { ++ uint64_t bit = 1ULL << n; ++ if (HWCAP_IMPORTANT & bit) ++ { ++ _dl_printf (" %s", _dl_hwcap_string (n)); ++ bool first = true; ++ print_hwcap_1 (&first, GLRO (dl_hwcap) & bit, "supported"); ++ print_hwcap_1 (&first, !(hwcap_mask & bit), "masked"); ++ print_hwcap_1 (&first, searched & bit, "searched"); ++ print_hwcap_1_finish (&first); ++ } ++ } ++} ++ + void + _dl_help (const char *argv0, struct dl_main_state *state) + { +@@ -136,5 +197,6 @@ This program interpreter self-identifies as: " RTLD "\n\ + ", + argv0); + print_search_path_for_help (state); ++ print_legacy_hwcap_directories (); + _exit (EXIT_SUCCESS); + } diff --git a/SOURCES/glibc-rh1882466-1.patch b/SOURCES/glibc-rh1882466-1.patch new file mode 100644 index 0000000..7a22ce0 --- /dev/null +++ b/SOURCES/glibc-rh1882466-1.patch @@ -0,0 +1,51 @@ +commit cb81264fd9973cd95bbc71495185b98979d28918 +Author: Florian Weimer +Date: Fri Dec 11 17:24:08 2020 +0100 + + support: Add support_slibdir_prefix variable + + Reviewed-by: Carlos O'Donell + +diff --git a/support/Makefile b/support/Makefile +index 35b21b19a248ba7f..dcf3c4baa2a31070 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -184,6 +184,7 @@ CFLAGS-support_paths.c = \ + -DLIBDIR_PATH=\"$(libdir)\" \ + -DBINDIR_PATH=\"$(bindir)\" \ + -DSBINDIR_PATH=\"$(sbindir)\" \ ++ -DSLIBDIR_PATH=\"$(slibdir)\" \ + -DROOTSBINDIR_PATH=\"$(rootsbindir)\" \ + -DCOMPLOCALEDIR_PATH=\"$(complocaledir)\" + +diff --git a/support/support.h b/support/support.h +index 6f7f804847f67600..f50f8cc1496d657d 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -110,6 +110,8 @@ extern const char support_libdir_prefix[]; + extern const char support_bindir_prefix[]; + /* Corresponds to the install's sbin/ directory. */ + extern const char support_sbindir_prefix[]; ++/* Corresponds to the install's system /lib or /lib64 directory. */ ++extern const char support_slibdir_prefix[]; + /* Corresponds to the install's sbin/ directory (without prefix). */ + extern const char support_install_rootsbindir[]; + /* Corresponds to the install's compiled locale directory. */ +diff --git a/support/support_paths.c b/support/support_paths.c +index 6b15fae0f0173b1e..be61c8acee3ec1a5 100644 +--- a/support/support_paths.c ++++ b/support/support_paths.c +@@ -72,6 +72,13 @@ const char support_sbindir_prefix[] = SBINDIR_PATH; + # error please -DSBINDIR_PATH=something in the Makefile + #endif + ++#ifdef SLIBDIR_PATH ++/* Corresponds to the system /lib or /lib64 directory. */ ++const char support_slibdir_prefix[] = SLIBDIR_PATH; ++#else ++# error please -DSLIBDIR_PATH=something in the Makefile ++#endif ++ + #ifdef ROOTSBINDIR_PATH + /* Corresponds to the install's sbin/ directory. */ + const char support_install_rootsbindir[] = ROOTSBINDIR_PATH; diff --git a/SOURCES/glibc-rh1882466-2.patch b/SOURCES/glibc-rh1882466-2.patch new file mode 100644 index 0000000..1ee6651 --- /dev/null +++ b/SOURCES/glibc-rh1882466-2.patch @@ -0,0 +1,98 @@ +commit 9ffa50b26b0cb5d3043adf6d3d0b1ea735acc147 +Author: Florian Weimer +Date: Fri Dec 11 17:30:03 2020 +0100 + + elf: Include libc.so.6 as main program in dependency sort (bug 20972) + + _dl_map_object_deps always sorts the initially loaded object first + during dependency sorting. This means it is relocated last in + dl_open_worker. This results in crashes in IFUNC resolvers without + lazy bindings if libraries are preloaded that refer to IFUNCs in + libc.so.6: the resolvers are called when libc.so.6 has not been + relocated yet, so references to _rtld_global_ro etc. crash. + + The fix is to check against the libc.so.6 link map recorded by the + __libc_early_init framework, and let it participate in the dependency + sort. + + This fixes bug 20972. + + Reviewed-by: Carlos O'Donell + +Conflicts: + elf/Makefile + (Usual test backport differences.) + +diff --git a/elf/Makefile b/elf/Makefile +index 67029930dd2cb461..fc9c685b9d23bb6c 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -215,7 +215,7 @@ tests-internal += loadtest unload unload2 circleload1 \ + tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \ + tst-ptrguard1 tst-stackguard1 tst-libc_dlvsym \ + tst-create_format1 tst-tls-surplus tst-dl-hwcaps_split +-tests-container += tst-pldd ++tests-container += tst-pldd tst-preload-pthread-libc + ifeq ($(build-hardcoded-path-in-tests),yes) + tests += tst-dlopen-aout + tst-dlopen-aout-no-pie = yes +diff --git a/elf/dl-deps.c b/elf/dl-deps.c +index 50f053a1586efdc3..007069f670eced95 100644 +--- a/elf/dl-deps.c ++++ b/elf/dl-deps.c +@@ -610,7 +610,12 @@ Filters not supported with LD_TRACE_PRELINKING")); + memcpy (l_initfini, map->l_searchlist.r_list, + nlist * sizeof (struct link_map *)); + +- _dl_sort_maps (&l_initfini[1], nlist - 1, NULL, false); ++ /* If libc.so.6 is the main map, it participates in the sort, so ++ that the relocation order is correct regarding libc.so.6. */ ++ if (l_initfini[0] == GL (dl_ns)[l_initfini[0]->l_ns].libc_map) ++ _dl_sort_maps (l_initfini, nlist, NULL, false); ++ else ++ _dl_sort_maps (&l_initfini[1], nlist - 1, NULL, false); + + /* Terminate the list of dependencies. */ + l_initfini[nlist] = NULL; +diff --git a/elf/tst-preload-pthread-libc.c b/elf/tst-preload-pthread-libc.c +new file mode 100644 +index 0000000000000000..48cb512a93f3da19 +--- /dev/null ++++ b/elf/tst-preload-pthread-libc.c +@@ -0,0 +1,36 @@ ++/* Test relocation ordering if the main executable is libc.so.6 (bug 20972). ++ 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 ++ ++int ++main (void) ++{ ++ char *libc = xasprintf ("%s/%s", support_slibdir_prefix, LIBC_SO); ++ char *argv[] = { libc, NULL }; ++ char *envp[] = { (char *) "LD_PRELOAD=" LIBPTHREAD_SO, ++ /* Relocation ordering matters most without lazy binding. */ ++ (char *) "LD_BIND_NOW=1", ++ NULL }; ++ execve (libc, argv, envp); ++ printf ("execve of %s failed: %m\n", libc); ++ return 1; ++} diff --git a/SOURCES/glibc-rh1882466-3.patch b/SOURCES/glibc-rh1882466-3.patch new file mode 100644 index 0000000..d254df7 --- /dev/null +++ b/SOURCES/glibc-rh1882466-3.patch @@ -0,0 +1,45 @@ +commit 4d0985543f479a6f421d4d8a9e0d1dc71c9c2c53 +Author: Florian Weimer +Date: Tue Dec 15 20:56:04 2020 +0100 + + elf: Record libc.so link map when it is the main program (bug 20972) + + Otherwise, it will not participate in the dependency sorting. + + Fixes commit 9ffa50b26b0cb5d3043adf6d3d0b1ea735acc147 + ("elf: Include libc.so.6 as main program in dependency sort + (bug 20972)"). + +Conflicts: + elf/rtld.c + (Missing backported header include.) + +diff --git a/elf/rtld.c b/elf/rtld.c +index fde5a6a4a485207e..992f825ba00762a7 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -46,6 +46,7 @@ + #include + #include + #include ++#include + + #include + +@@ -1588,6 +1589,16 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + { + /* Extract the contents of the dynamic section for easy access. */ + elf_get_dynamic_info (main_map, NULL); ++ ++ /* If the main map is libc.so, update the base namespace to ++ refer to this map. If libc.so is loaded later, this happens ++ in _dl_map_object_from_fd. */ ++ if (main_map->l_info[DT_SONAME] != NULL ++ && (strcmp (((const char *) D_PTR (main_map, l_info[DT_STRTAB]) ++ + main_map->l_info[DT_SONAME]->d_un.d_val), LIBC_SO) ++ == 0)) ++ GL(dl_ns)[LM_ID_BASE].libc_map = main_map; ++ + /* Set up our cache of pointers into the hash table. */ + _dl_setup_hash (main_map); + } diff --git a/SPECS/glibc.spec b/SPECS/glibc.spec index 6f09cec..48786c5 100644 --- a/SPECS/glibc.spec +++ b/SPECS/glibc.spec @@ -1,6 +1,6 @@ %define glibcsrcdir glibc-2.28 %define glibcversion 2.28 -%define glibcrelease 141%{?dist} +%define glibcrelease 145%{?dist} # Pre-release tarballs are pulled in from git using a command that is # effectively: # @@ -541,6 +541,142 @@ Patch404: glibc-rh1855790-8.patch Patch405: glibc-rh1855790-9.patch Patch406: glibc-rh1855790-10.patch Patch407: glibc-rh1855790-11.patch +Patch408: glibc-rh1817513-1.patch +Patch409: glibc-rh1817513-2.patch +Patch410: glibc-rh1817513-3.patch +Patch411: glibc-rh1817513-4.patch +Patch412: glibc-rh1817513-5.patch +Patch413: glibc-rh1817513-6.patch +Patch414: glibc-rh1817513-7.patch +Patch415: glibc-rh1817513-8.patch +Patch416: glibc-rh1817513-9.patch +Patch417: glibc-rh1817513-10.patch +Patch418: glibc-rh1817513-11.patch +Patch419: glibc-rh1817513-12.patch +Patch420: glibc-rh1817513-13.patch +Patch421: glibc-rh1817513-14.patch +Patch422: glibc-rh1817513-15.patch +Patch423: glibc-rh1817513-16.patch +Patch424: glibc-rh1817513-17.patch +Patch425: glibc-rh1817513-18.patch +Patch426: glibc-rh1817513-19.patch +Patch427: glibc-rh1817513-20.patch +Patch428: glibc-rh1817513-21.patch +Patch429: glibc-rh1817513-22.patch +Patch430: glibc-rh1817513-23.patch +Patch431: glibc-rh1817513-24.patch +Patch432: glibc-rh1817513-25.patch +Patch433: glibc-rh1817513-26.patch +Patch434: glibc-rh1817513-27.patch +Patch435: glibc-rh1817513-28.patch +Patch436: glibc-rh1817513-29.patch +Patch437: glibc-rh1817513-30.patch +Patch438: glibc-rh1817513-31.patch +Patch439: glibc-rh1817513-32.patch +Patch440: glibc-rh1817513-33.patch +Patch441: glibc-rh1817513-34.patch +Patch442: glibc-rh1817513-35.patch +Patch443: glibc-rh1817513-36.patch +Patch444: glibc-rh1817513-37.patch +Patch445: glibc-rh1817513-38.patch +Patch446: glibc-rh1817513-39.patch +Patch447: glibc-rh1817513-40.patch +Patch448: glibc-rh1817513-41.patch +Patch449: glibc-rh1817513-42.patch +Patch450: glibc-rh1817513-43.patch +Patch451: glibc-rh1817513-44.patch +Patch452: glibc-rh1817513-45.patch +Patch453: glibc-rh1817513-46.patch +Patch454: glibc-rh1817513-47.patch +Patch455: glibc-rh1817513-48.patch +Patch456: glibc-rh1817513-49.patch +Patch457: glibc-rh1817513-50.patch +Patch458: glibc-rh1817513-51.patch +Patch459: glibc-rh1817513-52.patch +Patch460: glibc-rh1817513-53.patch +Patch461: glibc-rh1817513-54.patch +Patch462: glibc-rh1817513-55.patch +Patch463: glibc-rh1817513-56.patch +Patch464: glibc-rh1817513-57.patch +Patch465: glibc-rh1817513-58.patch +Patch466: glibc-rh1817513-59.patch +Patch467: glibc-rh1817513-60.patch +Patch468: glibc-rh1817513-61.patch +Patch469: glibc-rh1817513-62.patch +Patch470: glibc-rh1817513-63.patch +Patch471: glibc-rh1817513-64.patch +Patch472: glibc-rh1817513-65.patch +Patch473: glibc-rh1817513-66.patch +Patch474: glibc-rh1817513-67.patch +Patch475: glibc-rh1817513-68.patch +Patch476: glibc-rh1817513-69.patch +Patch477: glibc-rh1817513-70.patch +Patch478: glibc-rh1817513-71.patch +Patch479: glibc-rh1817513-72.patch +Patch480: glibc-rh1817513-73.patch +Patch481: glibc-rh1817513-74.patch +Patch482: glibc-rh1817513-75.patch +Patch483: glibc-rh1817513-76.patch +Patch484: glibc-rh1817513-77.patch +Patch485: glibc-rh1817513-78.patch +Patch486: glibc-rh1817513-79.patch +Patch487: glibc-rh1817513-80.patch +Patch488: glibc-rh1817513-81.patch +Patch489: glibc-rh1817513-82.patch +Patch490: glibc-rh1817513-83.patch +Patch491: glibc-rh1817513-84.patch +Patch492: glibc-rh1817513-85.patch +Patch493: glibc-rh1817513-86.patch +Patch494: glibc-rh1817513-87.patch +Patch495: glibc-rh1817513-88.patch +Patch496: glibc-rh1817513-89.patch +Patch497: glibc-rh1817513-90.patch +Patch498: glibc-rh1817513-91.patch +Patch499: glibc-rh1817513-92.patch +Patch500: glibc-rh1817513-93.patch +Patch501: glibc-rh1817513-94.patch +Patch502: glibc-rh1817513-95.patch +Patch503: glibc-rh1817513-96.patch +Patch504: glibc-rh1817513-97.patch +Patch505: glibc-rh1817513-98.patch +Patch506: glibc-rh1817513-99.patch +Patch507: glibc-rh1817513-100.patch +Patch508: glibc-rh1817513-101.patch +Patch509: glibc-rh1817513-102.patch +Patch510: glibc-rh1817513-103.patch +Patch511: glibc-rh1817513-104.patch +Patch512: glibc-rh1817513-105.patch +Patch513: glibc-rh1817513-106.patch +Patch514: glibc-rh1817513-107.patch +Patch515: glibc-rh1817513-108.patch +Patch516: glibc-rh1817513-109.patch +Patch517: glibc-rh1817513-110.patch +Patch518: glibc-rh1817513-111.patch +Patch519: glibc-rh1817513-112.patch +Patch520: glibc-rh1817513-113.patch +Patch521: glibc-rh1817513-114.patch +Patch522: glibc-rh1817513-115.patch +Patch523: glibc-rh1817513-116.patch +Patch524: glibc-rh1817513-117.patch +Patch525: glibc-rh1817513-118.patch +Patch526: glibc-rh1817513-119.patch +Patch527: glibc-rh1817513-120.patch +Patch528: glibc-rh1817513-121.patch +Patch529: glibc-rh1817513-122.patch +Patch530: glibc-rh1817513-123.patch +Patch531: glibc-rh1817513-124.patch +Patch532: glibc-rh1817513-125.patch +Patch533: glibc-rh1817513-126.patch +Patch534: glibc-rh1817513-127.patch +Patch535: glibc-rh1817513-128.patch +Patch536: glibc-rh1817513-129.patch +Patch537: glibc-rh1817513-130.patch +Patch538: glibc-rh1817513-131.patch +Patch539: glibc-rh1817513-132.patch +Patch540: glibc-rh1882466-1.patch +Patch541: glibc-rh1882466-2.patch +Patch542: glibc-rh1882466-3.patch +Patch543: glibc-rh1817513-133.patch ############################################################################## # Continued list of core "glibc" package information: @@ -2452,6 +2588,16 @@ fi %files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared %changelog +* Mon Jan 4 2021 Florian Weimer - 2.28-145 +- Update glibc-hwcaps fix from upstream (#1817513) + +* Tue Dec 15 2020 Florian Weimer - 2.28-144 +- Support running libc.so.6 as a main program in more cases (#1882466) + +* Thu Dec 10 2020 Florian Weimer - 2.28-142 +- Add glibc-hwcaps support (#1817513) +- Implement DT_AUDIT support (#1871385) + * Mon Nov 30 2020 Carlos O'Donell - 2.28-141 - Update Intel CET support (#1855790)