diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 03b3cd4771f4..f0e9592d85dd 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -341,6 +341,7 @@ struct Config { llvm::DenseSet saveTempsArgs; llvm::SmallVector, 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 0a220432333c..b3c5518b4287 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 62d8f49acde3..76d28096f82c 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 2cea6a44b391..28b24f90716b 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -2379,10 +2379,16 @@ Writer::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 2b7b7fe52ea1..36028514cba2 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 `_) + 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 000000000000..f95a1547bfba --- /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",@progbits,unique,0 +.global _start +_start: + bl foo + ret + +//--- xo.s +.section .foo,"axy",@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",@progbits,unique,0 +.section .foo,"ax",@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 20908ba9f754..d4ee783e2c57 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 000000000000..17c227cf6998 --- /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 e938be5e64a4..3bb89ad0620f 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