[PATCH] ld: Disable separate code by default for Linux/x86
WANG Rui
r@hev.cc
Mon Mar 16 14:20:41 GMT 2026
Years ago, commit f6aec96dce1d ("ld: Add --enable-separate-code") introduced
-z separate-code, mainly to avoid mixing code and data in the same segment
for better cache performance, and enabled it by default for Linux/x86.
Today, Linux already has working support for mapping executable code with THP,
which can noticeably reduce iTLB pressure and bring measurable performance
benefits.
In practice, I observed that on AArch64 and LoongArch64 distros, ELF executables
typically place the code PT_LOAD segment first, so both the virtual address and
file offset are 0. That turns out to be an important prerequisite for THP-aware
PT_LOAD alignment optimizations [1][2][3], and the data shows clear performance
wins on both AArch64 and LoongArch64. [4][1]
Linux/x86 is a bit of an outlier here: the default -z separate-code setting
happens to break this layout. So this patch changes the Linux/x86 default to
-z noseparate-code.
Benchmark
Machine: AMD Ryzen 9 7950X (x86_64)
Binutils: 2.46
GCC: 15.2.1 (built with -z,noseparate-code + --enable-host-pie)
Linux kernel: 6.19.6 with patch [1]
Workload: building Linux v7.0-rc1 vmlinux with x86_64_defconfig.
Without patch With patch
instructions 8,246,133,611,932 8,246,025,137,750
cpu-cycles 8,001,028,142,928 7,565,925,107,502
itlb-misses 3,672,158,331 26,821,242
time elapsed 64.66 s 61.97 s
Instructions are basically unchanged. iTLB misses drop from ~3.67B to
~26M (~99.27% reduction), which results in about a ~5.44% reduction in
cycles and ~4.18% shorter wall time for this workload.
[1] https://lore.kernel.org/linux-fsdevel/20260313005211.882831-1-r@hev.cc
[2] https://sourceware.org/pipermail/libc-alpha/2026-March/175776.html
[3] https://lore.kernel.org/linux-fsdevel/20260310145406.3073394-1-usama.arif@linux.dev
[4] https://lore.kernel.org/linux-fsdevel/20260314095022.217231-1-r@hev.cc
bfd/
* configure.ac: Remove Linux/x86 default enabling of
-z separate-code.
* configure: Regenerated.
ld/
* configure.tgt: Do not enable -z separate-code by default
for Linux/x86 targets.
Signed-off-by: WANG Rui <r@hev.cc>
---
bfd/configure | 8 --------
bfd/configure.ac | 10 ----------
ld/configure.tgt | 5 +----
3 files changed, 1 insertion(+), 22 deletions(-)
diff --git a/bfd/configure b/bfd/configure
index f474c6af9cd..830c06a6c34 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -12356,14 +12356,6 @@ if test "${enable_separate_code+set}" = set; then :
esac
fi
-# Enable -z separate-code by default for Linux/x86.
-case "${target}" in
-i[3-7]86-*-linux-* | x86_64-*-linux-*)
- if test ${ac_default_ld_z_separate_code} = unset; then
- ac_default_ld_z_separate_code=1
- fi
- ;;
-esac
if test "${ac_default_ld_z_separate_code}" = unset; then
ac_default_ld_z_separate_code=0
fi
diff --git a/bfd/configure.ac b/bfd/configure.ac
index c30a75ba8b7..e152cf0cf94 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -131,16 +131,6 @@ AC_ARG_ENABLE(separate-code,
yes) ac_default_ld_z_separate_code=1 ;;
no) ac_default_ld_z_separate_code=0 ;;
esac])
-# Enable -z separate-code by default for Linux/x86.
-changequote(,)dnl
-case "${target}" in
-i[3-7]86-*-linux-* | x86_64-*-linux-*)
-changequote([,])dnl
- if test ${ac_default_ld_z_separate_code} = unset; then
- ac_default_ld_z_separate_code=1
- fi
- ;;
-esac
if test "${ac_default_ld_z_separate_code}" = unset; then
ac_default_ld_z_separate_code=0
fi
diff --git a/ld/configure.tgt b/ld/configure.tgt
index 3e158913b89..c96f55ab7ce 100644
--- a/ld/configure.tgt
+++ b/ld/configure.tgt
@@ -1119,12 +1119,9 @@ frv-*-* | hppa*-*-* | ia64-*-* | mips*-*-*)
;;
esac
-# Enable -z separate-code and --warn-textrel by default for Linux/x86.
+# Enable --warn-textrel by default for Linux/x86.
case "${target}" in
i[3-7]86-*-linux-* | x86_64-*-linux-*)
- if test ${ac_default_ld_z_separate_code} = unset; then
- ac_default_ld_z_separate_code=1
- fi
if test ${ac_default_ld_textrel_check} = unset; then
ac_default_ld_textrel_check=yes
fi
--
2.53.0
More information about the Binutils
mailing list