aboutsummaryrefslogtreecommitdiff
path: root/sysdeps
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2023-01-26 08:26:18 -0800
committerH.J. Lu <hjl.tools@gmail.com>2023-02-22 18:28:37 -0800
commit317f1c0a8a71a862b1e600ff5386b08e02cf4b95 (patch)
treec380e1c78d06fbb479bb39c82e8dd28119eef13f /sysdeps
parentbde121872001d8f3224eeafa5b7effb871c3fbca (diff)
downloadglibc-317f1c0a8a71a862b1e600ff5386b08e02cf4b95.tar
glibc-317f1c0a8a71a862b1e600ff5386b08e02cf4b95.tar.gz
glibc-317f1c0a8a71a862b1e600ff5386b08e02cf4b95.tar.bz2
glibc-317f1c0a8a71a862b1e600ff5386b08e02cf4b95.zip
x86-64: Add glibc.cpu.prefer_map_32bit_exec [BZ #28656]
Crossing 2GB boundaries with indirect calls and jumps can use more branch prediction resources on Intel Golden Cove CPU (see the "Misprediction for Branches >2GB" section in Intel 64 and IA-32 Architectures Optimization Reference Manual.) There is visible performance improvement on workloads with many PLT calls when executable and shared libraries are mmapped below 2GB. Add the Prefer_MAP_32BIT_EXEC bit so that mmap will try to map executable or denywrite pages in shared libraries with MAP_32BIT first. NB: Prefer_MAP_32BIT_EXEC reduces bits available for address space layout randomization (ASLR), which is always disabled for SUID programs and can only be enabled by the tunable, glibc.cpu.prefer_map_32bit_exec, or the environment variable, LD_PREFER_MAP_32BIT_EXEC. This works only between shared libraries or between shared libraries and executables with addresses below 2GB. PIEs are usually loaded at a random address above 4GB by the kernel.
Diffstat (limited to 'sysdeps')
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/64/Makefile25
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list29
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/64/mmap_internal.h43
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1a.c34
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1b.c1
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-mod.c33
-rw-r--r--sysdeps/x86/cpu-features.c15
-rw-r--r--sysdeps/x86/include/cpu-features-preferred_feature_index_1.def1
8 files changed, 181 insertions, 0 deletions
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/Makefile b/sysdeps/unix/sysv/linux/x86_64/64/Makefile
index a7b6dc5a53..8ff4f27786 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/Makefile
+++ b/sysdeps/unix/sysv/linux/x86_64/64/Makefile
@@ -1,2 +1,27 @@
# The default ABI is 64.
default-abi := 64
+
+ifeq ($(subdir),elf)
+ifneq ($(have-tunables),no)
+
+tests-map-32bit = \
+ tst-map-32bit-1a \
+ tst-map-32bit-1b \
+# tests-map-32bit
+tst-map-32bit-1a-no-pie = yes
+tst-map-32bit-1b-no-pie = yes
+tests += $(tests-map-32bit)
+
+modules-map-32bit = \
+ tst-map-32bit-mod \
+# modules-map-32bit
+modules-names += $(modules-map-32bit)
+
+$(objpfx)tst-map-32bit-mod.so: $(libsupport)
+tst-map-32bit-1a-ENV = LD_PREFER_MAP_32BIT_EXEC=1
+$(objpfx)tst-map-32bit-1a: $(objpfx)tst-map-32bit-mod.so
+tst-map-32bit-1b-ENV = GLIBC_TUNABLES=glibc.cpu.prefer_map_32bit_exec=1
+$(objpfx)tst-map-32bit-1b: $(objpfx)tst-map-32bit-mod.so
+
+endif
+endif
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list b/sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list
new file mode 100644
index 0000000000..0aab52e662
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list
@@ -0,0 +1,29 @@
+# x86-64 specific tunables.
+# Copyright (C) 2023 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
+# <https://www.gnu.org/licenses/>.
+
+glibc {
+ cpu {
+ prefer_map_32bit_exec {
+ type: INT_32
+ minval: 0
+ maxval: 1
+ env_alias: LD_PREFER_MAP_32BIT_EXEC
+ security_level: SXID_IGNORE
+ }
+ }
+}
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/mmap_internal.h b/sysdeps/unix/sysv/linux/x86_64/64/mmap_internal.h
new file mode 100644
index 0000000000..33dec3f805
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86_64/64/mmap_internal.h
@@ -0,0 +1,43 @@
+/* Linux mmap system call. x86-64 version.
+ Copyright (C) 2015-2023 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
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef MMAP_X86_64_INTERNAL_H
+#define MMAP_X86_64_INTERNAL_H
+
+#include <ldsodefs.h>
+
+/* If the Prefer_MAP_32BIT_EXEC bit is set, try to map executable or
+ denywrite pages with MAP_32BIT first. */
+#define MMAP_PREPARE(addr, len, prot, flags, fd, offset) \
+ if ((addr) == NULL \
+ && (((prot) & PROT_EXEC) != 0 \
+ || ((flags) & MAP_DENYWRITE) != 0) \
+ && HAS_ARCH_FEATURE (Prefer_MAP_32BIT_EXEC)) \
+ { \
+ void *ret = (void*) INLINE_SYSCALL_CALL (mmap, (addr), (len), \
+ (prot), \
+ (flags) | MAP_32BIT, \
+ (fd), (offset)); \
+ if (ret != MAP_FAILED) \
+ return ret; \
+ }
+
+#include_next <mmap_internal.h>
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1a.c b/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1a.c
new file mode 100644
index 0000000000..abc396589e
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1a.c
@@ -0,0 +1,34 @@
+/* Check that LD_PREFER_MAP_32BIT_EXEC works in PDE and shared library.
+ Copyright (C) 2023 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <support/check.h>
+
+extern void dso_check_map_32bit (void);
+
+static int
+do_test (void)
+{
+ printf ("do_test: %p\n", do_test);
+ TEST_VERIFY ((uintptr_t) do_test < 0xffffffffUL);
+ dso_check_map_32bit ();
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1b.c b/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1b.c
new file mode 100644
index 0000000000..34ab01c773
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-1b.c
@@ -0,0 +1 @@
+#include "tst-map-32bit-1a.c"
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-mod.c b/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-mod.c
new file mode 100644
index 0000000000..78d4b6133c
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86_64/64/tst-map-32bit-mod.c
@@ -0,0 +1,33 @@
+/* Check that LD_PREFER_MAP_32BIT_EXEC works in shared library.
+ Copyright (C) 2023 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <support/check.h>
+
+static void
+dso_do_test (void)
+{
+}
+
+void
+dso_check_map_32bit (void)
+{
+ printf ("dso_do_test: %p\n", dso_do_test);
+ TEST_VERIFY ((uintptr_t) dso_do_test < 0xffffffffUL);
+}
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
index a2197ed211..822688e21f 100644
--- a/sysdeps/x86/cpu-features.c
+++ b/sysdeps/x86/cpu-features.c
@@ -27,6 +27,16 @@
extern void TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *)
attribute_hidden;
+# ifdef __LP64__
+static void
+TUNABLE_CALLBACK (set_prefer_map_32bit_exec) (tunable_val_t *valp)
+{
+ if (valp->numval)
+ GLRO(dl_x86_cpu_features).preferred[index_arch_Prefer_MAP_32BIT_EXEC]
+ |= bit_arch_Prefer_MAP_32BIT_EXEC;
+}
+# endif
+
# if CET_ENABLED
extern void TUNABLE_CALLBACK (set_x86_ibt) (tunable_val_t *)
attribute_hidden;
@@ -705,6 +715,11 @@ no_cpuid:
#if HAVE_TUNABLES
TUNABLE_GET (hwcaps, tunable_val_t *, TUNABLE_CALLBACK (set_hwcaps));
+# ifdef __LP64__
+ TUNABLE_GET (prefer_map_32bit_exec, tunable_val_t *,
+ TUNABLE_CALLBACK (set_prefer_map_32bit_exec));
+# endif
+
bool disable_xsave_features = false;
if (!CPU_FEATURE_USABLE_P (cpu_features, OSXSAVE))
diff --git a/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def b/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def
index e45f9cb159..d20c5b3196 100644
--- a/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def
+++ b/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def
@@ -26,6 +26,7 @@ BIT (I586)
BIT (I686)
BIT (Slow_SSE4_2)
BIT (AVX_Fast_Unaligned_Load)
+BIT (Prefer_MAP_32BIT_EXEC)
BIT (Prefer_No_VZEROUPPER)
BIT (Prefer_ERMS)
BIT (Prefer_No_AVX512)