@@ -24,6 +24,7 @@
#include <dl-procinfo.h>
#include <stdint.h>
#include <_itoa.h>
+#include <dl-hwcaps.h>
#ifndef _DL_PLATFORMS_COUNT
# define _DL_PLATFORMS_COUNT 0
@@ -258,8 +259,10 @@ _dl_load_cache_lookup (const char *name)
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) & GLRO(dl_hwcap_mask))
+ 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. */
@@ -24,6 +24,7 @@
#include <ldsodefs.h>
#include <dl-procinfo.h>
+#include <dl-hwcaps.h>
#ifdef _DL_FIRST_PLATFORM
# define _DL_FIRST_EXTRA (_DL_FIRST_PLATFORM + _DL_PLATFORMS_COUNT)
@@ -37,8 +38,9 @@ internal_function
_dl_important_hwcaps (const char *platform, size_t platform_len, 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) & GLRO(dl_hwcap_mask);
+ uint64_t masked = GLRO(dl_hwcap) & hwcap_mask;
size_t cnt = platform != NULL;
size_t n, m;
size_t total;
@@ -125,7 +127,12 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
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. */
- GLRO(dl_hwcap_mask) |= (uint64_t) mask << _DL_FIRST_EXTRA;
+ hwcap_mask |= (uint64_t) mask << _DL_FIRST_EXTRA;
+#if HAVE_TUNABLES
+ TUNABLE_SET (glibc, tune, 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)
{
new file mode 100644
@@ -0,0 +1,31 @@
+/* Hardware capability support for run-time dynamic loader.
+ Copyright (C) 2017 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <elf/dl-tunables.h>
+
+#ifdef SHARED
+# if HAVE_TUNABLES
+# define GET_HWCAP_MASK() \
+ TUNABLE_GET (glibc, tune, hwcap_mask, uint64_t, NULL)
+# else
+# define GET_HWCAP_MASK() GLRO(dl_hwcap_mask)
+# endif
+#else
+/* HWCAP_MASK is ignored in static binaries. */
+# define GET_HWCAP_MASK() (0)
+#endif
@@ -164,6 +164,7 @@ uint64_t _dl_hwcap2 __attribute__ ((nocommon));
/* The value of the FPU control word the kernel will preset in hardware. */
fpu_control_t _dl_fpu_control = _FPU_DEFAULT;
+#if !HAVE_TUNABLES
/* This is not initialized to HWCAP_IMPORTANT, matching the definition
of _dl_important_hwcaps, below, where no hwcap strings are ever
used. This mask is still used to mediate the lookups in the cache
@@ -171,6 +172,7 @@ fpu_control_t _dl_fpu_control = _FPU_DEFAULT;
LD_HWCAP_MASK environment variable here), there is no real point in
setting _dl_hwcap nonzero below, but we do anyway. */
uint64_t _dl_hwcap_mask __attribute__ ((nocommon));
+#endif
/* Prevailing state of the stack. Generally this includes PF_X, indicating it's
* executable but this isn't true for all platforms. */
@@ -159,7 +159,9 @@ struct rtld_global_ro _rtld_global_ro attribute_relro =
._dl_debug_fd = STDERR_FILENO,
._dl_use_load_bias = -2,
._dl_correct_cache_id = _DL_CACHE_DEFAULT_ID,
+#if !HAVE_TUNABLES
._dl_hwcap_mask = HWCAP_IMPORTANT,
+#endif
._dl_lazy = 1,
._dl_fpu_control = _FPU_DEFAULT,
._dl_pagesize = EXEC_PAGESIZE,
@@ -2402,6 +2404,7 @@ process_envvars (enum mode *modep)
_dl_show_auxv ();
break;
+#if !HAVE_TUNABLES
case 10:
/* Mask for the important hardware capabilities. */
if (!__libc_enable_secure
@@ -2409,6 +2412,7 @@ process_envvars (enum mode *modep)
GLRO(dl_hwcap_mask) = __strtoul_internal (&envline[11], NULL,
0, 0);
break;
+#endif
case 11:
/* Path where the binary is found. */
@@ -515,8 +515,10 @@ struct rtld_global_ro
/* Mask for hardware capabilities that are available. */
EXTERN uint64_t _dl_hwcap;
+#if !HAVE_TUNABLES
/* Mask for important hardware capabilities we honour. */
EXTERN uint64_t _dl_hwcap_mask;
+#endif
#ifdef HAVE_AUX_VECTOR
/* Pointer to the auxv list supplied to the program at startup. */
@@ -27,6 +27,7 @@
#include <sysdep.h>
#include <tls.h>
#include <dl-plt.h>
+#include <elf/dl-hwcaps.h>
/* Return nonzero iff ELF header is compatible with the running host. */
static inline int
@@ -37,7 +38,8 @@ elf_machine_matches_host (const Elf32_Ehdr *ehdr)
else if (ehdr->e_machine == EM_SPARC32PLUS)
{
#ifdef SHARED
- return GLRO(dl_hwcap) & GLRO(dl_hwcap_mask) & HWCAP_SPARC_V9;
+ uint64_t hwcap_mask = GET_HWCAP_MASK();
+ return GLRO(dl_hwcap) & hwcap_mask & HWCAP_SPARC_V9;
#else
return GLRO(dl_hwcap) & HWCAP_SPARC_V9;
#endif
@@ -316,7 +316,11 @@ no_cpuid:
/* Reuse dl_platform, dl_hwcap and dl_hwcap_mask for x86. */
GLRO(dl_platform) = NULL;
GLRO(dl_hwcap) = 0;
+#if !HAVE_TUNABLES
+ /* The glibc.tune.hwcap_mask tunable is initialized already, so no need to do
+ this. */
GLRO(dl_hwcap_mask) = HWCAP_IMPORTANT;
+#endif
# ifdef __x86_64__
if (cpu_features->kind == arch_kind_intel)