[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