[lld] 2c1bdd4 - [LLD][ELF] Allow merging XO and RX sections, and add `--[no-]xosegment` flag (#132412)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 7 23:47:54 PDT 2025
Author: Csanád Hajdú
Date: 2025-04-08T08:47:51+02:00
New Revision: 2c1bdd4a0811af89eb9631935fbd90f13a04eacb
URL: https://github.com/llvm/llvm-project/commit/2c1bdd4a0811af89eb9631935fbd90f13a04eacb
DIFF: https://github.com/llvm/llvm-project/commit/2c1bdd4a0811af89eb9631935fbd90f13a04eacb.diff
LOG: [LLD][ELF] Allow merging XO and RX sections, and add `--[no-]xosegment` flag (#132412)
Following from the discussion in #132224, this seems like the best
approach to deal with a mix of XO and RX output sections in the same
binary. This change will also simplify the implementation of the
PURECODE section flag for AArch64.
To control this behaviour, the `--[no-]xosegment` flag is added to LLD
(similarly to `--[no-]rosegment`), which determines whether to allow
merging XO and RX sections in the same segment. The default value is
`--no-xosegment`, which is a breaking change compared to the previous
behaviour.
Release notes are also added, since this will be a breaking change.
Added:
lld/test/ELF/aarch64-execute-only-mixed.s
lld/test/ELF/arm-execute-only-mixed.s
Modified:
lld/ELF/Config.h
lld/ELF/Driver.cpp
lld/ELF/Options.td
lld/ELF/Writer.cpp
lld/docs/ReleaseNotes.rst
lld/test/ELF/aarch64-execute-only.s
lld/test/ELF/arm-execute-only.s
Removed:
################################################################################
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 03b3cd4771f49..f0e9592d85dd6 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -341,6 +341,7 @@ struct Config {
llvm::DenseSet<llvm::StringRef> saveTempsArgs;
llvm::SmallVector<std::pair<llvm::GlobPattern, uint32_t>, 0> shuffleSections;
bool singleRoRx;
+ bool singleXoRx;
bool shared;
bool symbolic;
bool isStatic = false;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 0a220432333cc..b3c5518b42877 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -1485,6 +1485,7 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
ctx.arg.randomizeSectionPadding =
args::getInteger(args, OPT_randomize_section_padding, 0);
ctx.arg.singleRoRx = !args.hasFlag(OPT_rosegment, OPT_no_rosegment, true);
+ ctx.arg.singleXoRx = !args.hasFlag(OPT_xosegment, OPT_no_xosegment, false);
ctx.arg.soName = args.getLastArgValue(OPT_soname);
ctx.arg.sortSection = getSortSection(ctx, args);
ctx.arg.splitStackAdjustSize =
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index 62d8f49acde39..76d28096f82c8 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -432,6 +432,10 @@ defm rosegment: BB<"rosegment",
"Put read-only non-executable sections in their own segment (default)",
"Do not put read-only non-executable sections in their own segment">;
+defm xosegment: BB<"xosegment",
+ "Put execute-only sections in their own segment",
+ "Do not put execute-only sections in their own segment (default)">;
+
defm rpath: Eq<"rpath", "Add a DT_RUNPATH to the output">;
def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">;
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 2cea6a44b391a..28b24f90716b8 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -2379,10 +2379,16 @@ Writer<ELFT>::createPhdrs(Partition &part) {
// so when hasSectionsCommand, since we cannot introduce the extra alignment
// needed to create a new LOAD)
uint64_t newFlags = computeFlags(ctx, sec->getPhdrFlags());
- // When --no-rosegment is specified, RO and RX sections are compatible.
- uint32_t incompatible = flags ^ newFlags;
- if (ctx.arg.singleRoRx && !(newFlags & PF_W))
- incompatible &= ~PF_X;
+ uint64_t incompatible = flags ^ newFlags;
+ if (!(newFlags & PF_W)) {
+ // When --no-rosegment is specified, RO and RX sections are compatible.
+ if (ctx.arg.singleRoRx)
+ incompatible &= ~PF_X;
+ // When --no-xosegment is specified (the default), XO and RX sections are
+ // compatible.
+ if (ctx.arg.singleXoRx)
+ incompatible &= ~PF_R;
+ }
if (incompatible)
load = nullptr;
diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst
index 2b7b7fe52ea12..36028514cba27 100644
--- a/lld/docs/ReleaseNotes.rst
+++ b/lld/docs/ReleaseNotes.rst
@@ -42,8 +42,16 @@ ELF Improvements
* Linker script ``OVERLAY`` descriptions now support virtual memory regions
(e.g. ``>region``) and ``NOCROSSREFS``.
+* Added ``--xosegment`` and ``--no-xosegment`` flags to control whether to place
+ executable-only and readable-executable sections in the same segment. The
+ default value is ``--no-xosegment``.
+ (`#132412 <https://github.com/llvm/llvm-project/pull/132412>`_)
+
Breaking changes
----------------
+* Executable-only and readable-executable sections are now allowed to be placed
+ in the same segment by default. Pass ``--xosegment`` to lld in order to get
+ the old behavior back.
COFF Improvements
-----------------
diff --git a/lld/test/ELF/aarch64-execute-only-mixed.s b/lld/test/ELF/aarch64-execute-only-mixed.s
new file mode 100644
index 0000000000000..f95a1547bfba2
--- /dev/null
+++ b/lld/test/ELF/aarch64-execute-only-mixed.s
@@ -0,0 +1,55 @@
+// REQUIRES: aarch64
+// RUN: rm -rf %t && split-file %s %t && cd %t
+
+// RUN: llvm-mc -filetype=obj -triple=aarch64 start.s -o start.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64 xo.s -o xo.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64 rx.s -o rx.o
+// RUN: ld.lld start.o xo.o -o xo
+// RUN: ld.lld start.o rx.o -o rx-default
+// RUN: ld.lld --xosegment start.o rx.o -o rx-xosegment
+// RUN: ld.lld --no-xosegment start.o rx.o -o rx-no-xosegment
+// RUN: llvm-readelf -l xo | FileCheck --check-prefix=CHECK-XO %s
+// RUN: llvm-readelf -l rx-default | FileCheck --check-prefix=CHECK-MERGED %s
+// RUN: llvm-readelf -l rx-xosegment | FileCheck --check-prefix=CHECK-SEPARATE %s
+// RUN: llvm-readelf -l rx-no-xosegment | FileCheck --check-prefix=CHECK-MERGED %s
+
+// CHECK-XO: PHDR
+// CHECK-XO-NEXT: LOAD
+// CHECK-XO-NEXT: LOAD 0x000120 0x0000000000210120 0x0000000000210120 0x00000c 0x00000c E 0x10000
+/// Index should match the index of the LOAD segment above.
+// CHECK-XO: 02 .text .foo
+
+// CHECK-MERGED: PHDR
+// CHECK-MERGED-NEXT: LOAD
+// CHECK-MERGED-NEXT: LOAD 0x000120 0x0000000000210120 0x0000000000210120 0x00000c 0x00000c R E 0x10000
+/// Index should match the index of the LOAD segment above.
+// CHECK-MERGED: 02 .text .foo
+
+// CHECK-SEPARATE: PHDR
+// CHECK-SEPARATE-NEXT: LOAD
+// CHECK-SEPARATE-NEXT: LOAD 0x000158 0x0000000000210158 0x0000000000210158 0x000008 0x000008 E 0x10000
+// CHECK-SEPARATE-NEXT: LOAD 0x000160 0x0000000000220160 0x0000000000220160 0x000004 0x000004 R E 0x10000
+/// Index should match the index of the LOAD segment above.
+// CHECK-SEPARATE: 02 .text
+// CHECK-SEPARATE: 03 .foo
+
+//--- start.s
+.section .text,"axy", at progbits,unique,0
+.global _start
+_start:
+ bl foo
+ ret
+
+//--- xo.s
+.section .foo,"axy", at progbits,unique,0
+.global foo
+foo:
+ ret
+
+//--- rx.s
+/// Ensure that the implicitly-created .text section has the SHF_AARCH64_PURECODE flag.
+.section .text,"axy", at progbits,unique,0
+.section .foo,"ax", at progbits,unique,0
+.global foo
+foo:
+ ret
diff --git a/lld/test/ELF/aarch64-execute-only.s b/lld/test/ELF/aarch64-execute-only.s
index 20908ba9f754f..d4ee783e2c578 100644
--- a/lld/test/ELF/aarch64-execute-only.s
+++ b/lld/test/ELF/aarch64-execute-only.s
@@ -1,12 +1,12 @@
// REQUIRES: aarch64
// RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o
-// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: ld.lld --xosegment %t.o -o %t.so -shared
// RUN: llvm-readelf -l %t.so | FileCheck --implicit-check-not=LOAD %s
// RUN: echo ".section .foo,\"ax\"; ret" > %t.s
// RUN: llvm-mc -filetype=obj -triple=aarch64 %t.s -o %t2.o
-// RUN: ld.lld %t.o %t2.o -o %t.so -shared
+// RUN: ld.lld --xosegment %t.o %t2.o -o %t.so -shared
// RUN: llvm-readelf -l %t.so | FileCheck --check-prefix=DIFF --implicit-check-not=LOAD %s
// CHECK: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000245 0x000245 R 0x10000
diff --git a/lld/test/ELF/arm-execute-only-mixed.s b/lld/test/ELF/arm-execute-only-mixed.s
new file mode 100644
index 0000000000000..17c227cf69983
--- /dev/null
+++ b/lld/test/ELF/arm-execute-only-mixed.s
@@ -0,0 +1,55 @@
+// REQUIRES: arm
+// RUN: rm -rf %t && split-file %s %t && cd %t
+
+// RUN: llvm-mc -filetype=obj -triple=armv7 start.s -o start.o
+// RUN: llvm-mc -filetype=obj -triple=armv7 xo.s -o xo.o
+// RUN: llvm-mc -filetype=obj -triple=armv7 rx.s -o rx.o
+// RUN: ld.lld start.o xo.o -o xo
+// RUN: ld.lld start.o rx.o -o rx-default
+// RUN: ld.lld --xosegment start.o rx.o -o rx-xosegment
+// RUN: ld.lld --no-xosegment start.o rx.o -o rx-no-xosegment
+// RUN: llvm-readelf -l xo | FileCheck --check-prefix=CHECK-XO %s
+// RUN: llvm-readelf -l rx-default | FileCheck --check-prefix=CHECK-MERGED %s
+// RUN: llvm-readelf -l rx-xosegment | FileCheck --check-prefix=CHECK-SEPARATE %s
+// RUN: llvm-readelf -l rx-no-xosegment | FileCheck --check-prefix=CHECK-MERGED %s
+
+// CHECK-XO: PHDR
+// CHECK-XO-NEXT: LOAD
+// CHECK-XO-NEXT: LOAD 0x0000b4 0x000200b4 0x000200b4 0x0000c 0x0000c E 0x10000
+/// Index should match the index of the LOAD segment above.
+// CHECK-XO: 02 .text .foo
+
+// CHECK-MERGED: PHDR
+// CHECK-MERGED-NEXT: LOAD
+// CHECK-MERGED-NEXT: LOAD 0x0000b4 0x000200b4 0x000200b4 0x0000c 0x0000c R E 0x10000
+/// Index should match the index of the LOAD segment above.
+// CHECK-MERGED: 02 .text .foo
+
+// CHECK-SEPARATE: PHDR
+// CHECK-SEPARATE-NEXT: LOAD
+// CHECK-SEPARATE-NEXT: LOAD 0x0000d4 0x000200d4 0x000200d4 0x00008 0x00008 E 0x10000
+// CHECK-SEPARATE-NEXT: LOAD 0x0000dc 0x000300dc 0x000300dc 0x00004 0x00004 R E 0x10000
+/// Index should match the index of the LOAD segment above.
+// CHECK-SEPARATE: 02 .text
+// CHECK-SEPARATE: 03 .foo
+
+//--- start.s
+.section .text,"axy",%progbits,unique,0
+.global _start
+_start:
+ bl foo
+ bx lr
+
+//--- xo.s
+.section .foo,"axy",%progbits,unique,0
+.global foo
+foo:
+ bx lr
+
+//--- rx.s
+/// Ensure that the implicitly-created .text section has the SHF_ARM_PURECODE flag.
+.section .text,"axy",%progbits,unique,0
+.section .foo,"ax",%progbits,unique,0
+.global foo
+foo:
+ bx lr
diff --git a/lld/test/ELF/arm-execute-only.s b/lld/test/ELF/arm-execute-only.s
index e938be5e64a4b..3bb89ad0620f8 100644
--- a/lld/test/ELF/arm-execute-only.s
+++ b/lld/test/ELF/arm-execute-only.s
@@ -1,13 +1,13 @@
// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7-pc-linux %s -o %t.o
-// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: ld.lld --xosegment %t.o -o %t.so -shared
// RUN: llvm-readelf -l %t.so | FileCheck --implicit-check-not=LOAD %s
// RUN: echo ".section .foo,\"ax\"; \
// RUN: bx lr" > %t.s
// RUN: llvm-mc -filetype=obj -triple=armv7-pc-linux %t.s -o %t2.o
-// RUN: ld.lld %t.o %t2.o -o %t.so -shared
+// RUN: ld.lld --xosegment %t.o %t2.o -o %t.so -shared
// RUN: llvm-readelf -l %t.so | FileCheck --check-prefix=DIFF --implicit-check-not=LOAD %s
// CHECK: LOAD 0x000000 0x00000000 0x00000000 0x0016d 0x0016d R 0x10000
More information about the llvm-commits
mailing list