Skip to content

Commit 2c1bdd4

Browse files
authored
[LLD][ELF] Allow merging XO and RX sections, and add --[no-]xosegment flag (llvm#132412)
Following from the discussion in llvm#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.
1 parent 0d19efa commit 2c1bdd4

9 files changed

+138
-8
lines changed

lld/ELF/Config.h

+1
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ struct Config {
341341
llvm::DenseSet<llvm::StringRef> saveTempsArgs;
342342
llvm::SmallVector<std::pair<llvm::GlobPattern, uint32_t>, 0> shuffleSections;
343343
bool singleRoRx;
344+
bool singleXoRx;
344345
bool shared;
345346
bool symbolic;
346347
bool isStatic = false;

lld/ELF/Driver.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -1485,6 +1485,7 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
14851485
ctx.arg.randomizeSectionPadding =
14861486
args::getInteger(args, OPT_randomize_section_padding, 0);
14871487
ctx.arg.singleRoRx = !args.hasFlag(OPT_rosegment, OPT_no_rosegment, true);
1488+
ctx.arg.singleXoRx = !args.hasFlag(OPT_xosegment, OPT_no_xosegment, false);
14881489
ctx.arg.soName = args.getLastArgValue(OPT_soname);
14891490
ctx.arg.sortSection = getSortSection(ctx, args);
14901491
ctx.arg.splitStackAdjustSize =

lld/ELF/Options.td

+4
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,10 @@ defm rosegment: BB<"rosegment",
432432
"Put read-only non-executable sections in their own segment (default)",
433433
"Do not put read-only non-executable sections in their own segment">;
434434

435+
defm xosegment: BB<"xosegment",
436+
"Put execute-only sections in their own segment",
437+
"Do not put execute-only sections in their own segment (default)">;
438+
435439
defm rpath: Eq<"rpath", "Add a DT_RUNPATH to the output">;
436440

437441
def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">;

lld/ELF/Writer.cpp

+10-4
Original file line numberDiff line numberDiff line change
@@ -2379,10 +2379,16 @@ Writer<ELFT>::createPhdrs(Partition &part) {
23792379
// so when hasSectionsCommand, since we cannot introduce the extra alignment
23802380
// needed to create a new LOAD)
23812381
uint64_t newFlags = computeFlags(ctx, sec->getPhdrFlags());
2382-
// When --no-rosegment is specified, RO and RX sections are compatible.
2383-
uint32_t incompatible = flags ^ newFlags;
2384-
if (ctx.arg.singleRoRx && !(newFlags & PF_W))
2385-
incompatible &= ~PF_X;
2382+
uint64_t incompatible = flags ^ newFlags;
2383+
if (!(newFlags & PF_W)) {
2384+
// When --no-rosegment is specified, RO and RX sections are compatible.
2385+
if (ctx.arg.singleRoRx)
2386+
incompatible &= ~PF_X;
2387+
// When --no-xosegment is specified (the default), XO and RX sections are
2388+
// compatible.
2389+
if (ctx.arg.singleXoRx)
2390+
incompatible &= ~PF_R;
2391+
}
23862392
if (incompatible)
23872393
load = nullptr;
23882394

lld/docs/ReleaseNotes.rst

+8
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,16 @@ ELF Improvements
4242
* Linker script ``OVERLAY`` descriptions now support virtual memory regions
4343
(e.g. ``>region``) and ``NOCROSSREFS``.
4444

45+
* Added ``--xosegment`` and ``--no-xosegment`` flags to control whether to place
46+
executable-only and readable-executable sections in the same segment. The
47+
default value is ``--no-xosegment``.
48+
(`#132412 <https://github.com/llvm/llvm-project/pull/132412>`_)
49+
4550
Breaking changes
4651
----------------
52+
* Executable-only and readable-executable sections are now allowed to be placed
53+
in the same segment by default. Pass ``--xosegment`` to lld in order to get
54+
the old behavior back.
4755

4856
COFF Improvements
4957
-----------------
+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// REQUIRES: aarch64
2+
// RUN: rm -rf %t && split-file %s %t && cd %t
3+
4+
// RUN: llvm-mc -filetype=obj -triple=aarch64 start.s -o start.o
5+
// RUN: llvm-mc -filetype=obj -triple=aarch64 xo.s -o xo.o
6+
// RUN: llvm-mc -filetype=obj -triple=aarch64 rx.s -o rx.o
7+
// RUN: ld.lld start.o xo.o -o xo
8+
// RUN: ld.lld start.o rx.o -o rx-default
9+
// RUN: ld.lld --xosegment start.o rx.o -o rx-xosegment
10+
// RUN: ld.lld --no-xosegment start.o rx.o -o rx-no-xosegment
11+
// RUN: llvm-readelf -l xo | FileCheck --check-prefix=CHECK-XO %s
12+
// RUN: llvm-readelf -l rx-default | FileCheck --check-prefix=CHECK-MERGED %s
13+
// RUN: llvm-readelf -l rx-xosegment | FileCheck --check-prefix=CHECK-SEPARATE %s
14+
// RUN: llvm-readelf -l rx-no-xosegment | FileCheck --check-prefix=CHECK-MERGED %s
15+
16+
// CHECK-XO: PHDR
17+
// CHECK-XO-NEXT: LOAD
18+
// CHECK-XO-NEXT: LOAD 0x000120 0x0000000000210120 0x0000000000210120 0x00000c 0x00000c E 0x10000
19+
/// Index should match the index of the LOAD segment above.
20+
// CHECK-XO: 02 .text .foo
21+
22+
// CHECK-MERGED: PHDR
23+
// CHECK-MERGED-NEXT: LOAD
24+
// CHECK-MERGED-NEXT: LOAD 0x000120 0x0000000000210120 0x0000000000210120 0x00000c 0x00000c R E 0x10000
25+
/// Index should match the index of the LOAD segment above.
26+
// CHECK-MERGED: 02 .text .foo
27+
28+
// CHECK-SEPARATE: PHDR
29+
// CHECK-SEPARATE-NEXT: LOAD
30+
// CHECK-SEPARATE-NEXT: LOAD 0x000158 0x0000000000210158 0x0000000000210158 0x000008 0x000008 E 0x10000
31+
// CHECK-SEPARATE-NEXT: LOAD 0x000160 0x0000000000220160 0x0000000000220160 0x000004 0x000004 R E 0x10000
32+
/// Index should match the index of the LOAD segment above.
33+
// CHECK-SEPARATE: 02 .text
34+
// CHECK-SEPARATE: 03 .foo
35+
36+
//--- start.s
37+
.section .text,"axy",@progbits,unique,0
38+
.global _start
39+
_start:
40+
bl foo
41+
ret
42+
43+
//--- xo.s
44+
.section .foo,"axy",@progbits,unique,0
45+
.global foo
46+
foo:
47+
ret
48+
49+
//--- rx.s
50+
/// Ensure that the implicitly-created .text section has the SHF_AARCH64_PURECODE flag.
51+
.section .text,"axy",@progbits,unique,0
52+
.section .foo,"ax",@progbits,unique,0
53+
.global foo
54+
foo:
55+
ret

lld/test/ELF/aarch64-execute-only.s

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// REQUIRES: aarch64
22

33
// RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o
4-
// RUN: ld.lld %t.o -o %t.so -shared
4+
// RUN: ld.lld --xosegment %t.o -o %t.so -shared
55
// RUN: llvm-readelf -l %t.so | FileCheck --implicit-check-not=LOAD %s
66

77
// RUN: echo ".section .foo,\"ax\"; ret" > %t.s
88
// RUN: llvm-mc -filetype=obj -triple=aarch64 %t.s -o %t2.o
9-
// RUN: ld.lld %t.o %t2.o -o %t.so -shared
9+
// RUN: ld.lld --xosegment %t.o %t2.o -o %t.so -shared
1010
// RUN: llvm-readelf -l %t.so | FileCheck --check-prefix=DIFF --implicit-check-not=LOAD %s
1111

1212
// CHECK: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000245 0x000245 R 0x10000

lld/test/ELF/arm-execute-only-mixed.s

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// REQUIRES: arm
2+
// RUN: rm -rf %t && split-file %s %t && cd %t
3+
4+
// RUN: llvm-mc -filetype=obj -triple=armv7 start.s -o start.o
5+
// RUN: llvm-mc -filetype=obj -triple=armv7 xo.s -o xo.o
6+
// RUN: llvm-mc -filetype=obj -triple=armv7 rx.s -o rx.o
7+
// RUN: ld.lld start.o xo.o -o xo
8+
// RUN: ld.lld start.o rx.o -o rx-default
9+
// RUN: ld.lld --xosegment start.o rx.o -o rx-xosegment
10+
// RUN: ld.lld --no-xosegment start.o rx.o -o rx-no-xosegment
11+
// RUN: llvm-readelf -l xo | FileCheck --check-prefix=CHECK-XO %s
12+
// RUN: llvm-readelf -l rx-default | FileCheck --check-prefix=CHECK-MERGED %s
13+
// RUN: llvm-readelf -l rx-xosegment | FileCheck --check-prefix=CHECK-SEPARATE %s
14+
// RUN: llvm-readelf -l rx-no-xosegment | FileCheck --check-prefix=CHECK-MERGED %s
15+
16+
// CHECK-XO: PHDR
17+
// CHECK-XO-NEXT: LOAD
18+
// CHECK-XO-NEXT: LOAD 0x0000b4 0x000200b4 0x000200b4 0x0000c 0x0000c E 0x10000
19+
/// Index should match the index of the LOAD segment above.
20+
// CHECK-XO: 02 .text .foo
21+
22+
// CHECK-MERGED: PHDR
23+
// CHECK-MERGED-NEXT: LOAD
24+
// CHECK-MERGED-NEXT: LOAD 0x0000b4 0x000200b4 0x000200b4 0x0000c 0x0000c R E 0x10000
25+
/// Index should match the index of the LOAD segment above.
26+
// CHECK-MERGED: 02 .text .foo
27+
28+
// CHECK-SEPARATE: PHDR
29+
// CHECK-SEPARATE-NEXT: LOAD
30+
// CHECK-SEPARATE-NEXT: LOAD 0x0000d4 0x000200d4 0x000200d4 0x00008 0x00008 E 0x10000
31+
// CHECK-SEPARATE-NEXT: LOAD 0x0000dc 0x000300dc 0x000300dc 0x00004 0x00004 R E 0x10000
32+
/// Index should match the index of the LOAD segment above.
33+
// CHECK-SEPARATE: 02 .text
34+
// CHECK-SEPARATE: 03 .foo
35+
36+
//--- start.s
37+
.section .text,"axy",%progbits,unique,0
38+
.global _start
39+
_start:
40+
bl foo
41+
bx lr
42+
43+
//--- xo.s
44+
.section .foo,"axy",%progbits,unique,0
45+
.global foo
46+
foo:
47+
bx lr
48+
49+
//--- rx.s
50+
/// Ensure that the implicitly-created .text section has the SHF_ARM_PURECODE flag.
51+
.section .text,"axy",%progbits,unique,0
52+
.section .foo,"ax",%progbits,unique,0
53+
.global foo
54+
foo:
55+
bx lr

lld/test/ELF/arm-execute-only.s

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
// REQUIRES: arm
22

33
// RUN: llvm-mc -filetype=obj -triple=armv7-pc-linux %s -o %t.o
4-
// RUN: ld.lld %t.o -o %t.so -shared
4+
// RUN: ld.lld --xosegment %t.o -o %t.so -shared
55
// RUN: llvm-readelf -l %t.so | FileCheck --implicit-check-not=LOAD %s
66

77
// RUN: echo ".section .foo,\"ax\"; \
88
// RUN: bx lr" > %t.s
99
// RUN: llvm-mc -filetype=obj -triple=armv7-pc-linux %t.s -o %t2.o
10-
// RUN: ld.lld %t.o %t2.o -o %t.so -shared
10+
// RUN: ld.lld --xosegment %t.o %t2.o -o %t.so -shared
1111
// RUN: llvm-readelf -l %t.so | FileCheck --check-prefix=DIFF --implicit-check-not=LOAD %s
1212

1313
// CHECK: LOAD 0x000000 0x00000000 0x00000000 0x0016d 0x0016d R 0x10000

0 commit comments

Comments
 (0)