Skip to content

Commit a40f651

Browse files
authored
[ELF] adjustOutputSections: don't copy SHF_EXECINSTR when an output does not contain input sections (#70911)
For an output section with no input section, GNU ld eliminates the output section when there are only symbol assignments (e.g. `.foo : { symbol = 42; }`) but not for `.foo : { . += 42; }` (`SHF_ALLOC|SHF_WRITE`). We choose to retain such an output section with a symbol assignment (unless unreferenced `PROVIDE`). We copy the previous section flag (see https://reviews.llvm.org/D37736) to hopefully make the current PT_LOAD segment extend to the current output section: * decrease the number of PT_LOAD segments * If a new PT_LOAD segment is introduced without a page-size alignment as a separator, there may be a run-time crash. However, this `flags` copying behavior is not suitable for `.foo : { . += 42; }` when `flags` contains `SHF_EXECINSTR`. The executable bit is surprising (https://discourse.llvm.org/t/lld-output-section-flag-assignment-behavior/74359). I think we should drop SHF_EXECINSTR when copying `flags`. The risk is a code section followed by `.foo : { symbol = 42; }` will be broken, which I believe is unrelated as such uses are almost always related to data sections. For data-command-only output sections (e.g. `.foo : { QUAD(42) }`), we keep allowing copyable SHF_WRITE. Some tests are updated to drop the SHF_EXECINSTR flag. GNU ld doesn't set SHF_EXECINSTR as well, though it sets SHF_WRITE for some tests while we don't.
1 parent bd29197 commit a40f651

File tree

6 files changed

+35
-22
lines changed

6 files changed

+35
-22
lines changed

lld/ELF/LinkerScript.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,7 +1167,9 @@ void LinkerScript::adjustOutputSections() {
11671167
// * The address assignment.
11681168
// The other option is to pick flags that minimize the impact the section
11691169
// will have on the rest of the linker. That is why we copy the flags from
1170-
// the previous sections. Only a few flags are needed to keep the impact low.
1170+
// the previous sections. We copy just SHF_ALLOC and SHF_WRITE to keep the
1171+
// impact low. We do not propagate SHF_EXECINSTR as in some cases this can
1172+
// lead to executable writeable section.
11711173
uint64_t flags = SHF_ALLOC;
11721174

11731175
SmallVector<StringRef, 0> defPhdrs;
@@ -1193,8 +1195,8 @@ void LinkerScript::adjustOutputSections() {
11931195
// We do not want to keep any special flags for output section
11941196
// in case it is empty.
11951197
if (isEmpty)
1196-
sec->flags = flags & ((sec->nonAlloc ? 0 : (uint64_t)SHF_ALLOC) |
1197-
SHF_WRITE | SHF_EXECINSTR);
1198+
sec->flags =
1199+
flags & ((sec->nonAlloc ? 0 : (uint64_t)SHF_ALLOC) | SHF_WRITE);
11981200

11991201
// The code below may remove empty output sections. We should save the
12001202
// specified program headers (if exist) and propagate them to subsequent

lld/docs/ELF/linker_script.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,16 @@ The presence of ``address`` can cause the condition unsatisfied. LLD will warn.
9797
GNU ld from Binutils 2.35 onwards will reduce sh_addralign so that
9898
sh_addr=0 (modulo sh_addralign).
9999

100+
When an output section has no input section, GNU ld will eliminate it if it
101+
only contains symbol assignments (e.g. ``.foo { symbol = 42; }``). LLD will
102+
retain such sections unless all the symbol assignments are unreferenced
103+
``PROVIDED``.
104+
105+
When an output section has no input section but advances the location counter,
106+
GNU ld sets the ``SHF_WRITE`` flag. LLD sets the SHF_WRITE flag only if the
107+
preceding output section with non-empty input sections also has the SHF_WRITE
108+
flag.
109+
100110
Output section type
101111
-------------------
102112

lld/test/ELF/linkerscript/empty-synthetic-removed-flags.s

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
# EMPTY-NEXT: Type: SHT_PROGBITS
3030
# EMPTY-NEXT: Flags [
3131
# EMPTY-NEXT: SHF_ALLOC
32-
# EMPTY-NEXT: SHF_EXECINSTR
3332
# EMPTY-NEXT: ]
3433

3534
.section .foo,"ax"

lld/test/ELF/linkerscript/extend-pt-load2.test

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@ SECTIONS {
1919
.data.rel.ro : { *(.data.rel.ro) }
2020
}
2121

22-
# CHECK: .rodata PROGBITS 0000000000000215 000215 000001 00 A 0
23-
# CHECK-NEXT: foo PROGBITS 0000000000000216 000216 000000 00 A 0
24-
# CHECK-NEXT: .text PROGBITS 0000000000000218 000218 000001 00 AX 0
25-
# CHECK-NEXT: bar PROGBITS 0000000000000219 000219 000de7 00 AX 0
22+
# CHECK: .rodata PROGBITS 000000000000024d 00024d 000001 00 A 0
23+
# CHECK-NEXT: foo PROGBITS 000000000000024e 00024e 000000 00 A 0
24+
# CHECK-NEXT: .text PROGBITS 0000000000000250 000250 000001 00 AX 0
25+
# CHECK-NEXT: bar PROGBITS 0000000000000251 000251 000daf 00 A 0
2626
# CHECK-NEXT: .data.rel.ro PROGBITS 0000000000001000 001000 000001 00 WA 0
2727

28-
# CHECK: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000216 0x000216 R 0x1000
29-
# CHECK: LOAD 0x000218 0x0000000000000218 0x0000000000000218 0x000de8 0x000de8 R E 0x1000
28+
# CHECK: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x00024e 0x00024e R 0x1000
29+
# CHECK-NEXT: LOAD 0x000250 0x0000000000000250 0x0000000000000250 0x000001 0x000001 R E 0x1000
30+
# CHECK-NEXT: LOAD 0x000251 0x0000000000000251 0x0000000000000251 0x000daf 0x000daf R 0x1000
3031
# CHECK-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000068 0x000068 RW 0x1000

lld/test/ELF/linkerscript/insert-before.test

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@
99
# RUN: llvm-readelf -S -l %t1 | FileCheck %s
1010
# CHECK: Name Type Address Off Size ES Flg
1111
# CHECK-NEXT: NULL
12-
# CHECK-NEXT: .foo.text PROGBITS 0000000000000000 001000 000008 00 AX
13-
# CHECK-NEXT: .text PROGBITS 0000000000000008 001008 000008 00 AX
14-
# CHECK-NEXT: .byte PROGBITS 0000000000000010 001010 000001 00 AX
15-
# CHECK-NEXT: .foo.data PROGBITS 0000000000000011 001011 000008 00 WA
16-
# CHECK-NEXT: .data PROGBITS 0000000000000019 001019 000008 00 WA
12+
# CHECK-NEXT: .foo.text PROGBITS 0000000000000000 001000 000008 00 AX 0
13+
# CHECK-NEXT: .text PROGBITS 0000000000000008 001008 000008 00 AX 0
14+
# CHECK-NEXT: .byte PROGBITS 0000000000000010 001010 000001 00 A 0
15+
# CHECK-NEXT: .foo.data PROGBITS 0000000000000011 001011 000008 00 WA 0
16+
# CHECK-NEXT: .data PROGBITS 0000000000000019 001019 000008 00 WA 0
1717
# CHECK: Type
1818
# CHECK-NEXT: LOAD {{.*}} R E
19+
# CHECK-NEXT: LOAD {{.*}} R
1920
# CHECK-NEXT: LOAD {{.*}} RW
2021
# CHECK-NEXT: GNU_STACK {{.*}} RW
2122

lld/test/ELF/linkerscript/lma-align2.test

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@
77
# CHECK: Name Type Address Off Size ES Flg Lk Inf Al
88
# CHECK-NEXT: NULL 0000000000000000 000000 000000 00 0 0 0
99
# CHECK-NEXT: .text PROGBITS 0000000008000000 001000 000001 00 AX 0 0 4
10-
# CHECK-NEXT: .data PROGBITS 0000000020000000 002000 000006 00 AX 0 0 8
11-
# CHECK-NEXT: .data2 PROGBITS 000000000800000e 00200e 000008 00 AX 0 0 1
12-
# CHECK-NEXT: .data3 PROGBITS 0000000020000008 002018 000000 00 AX 0 0 8
13-
# CHECK-NEXT: .data4 PROGBITS 0000000008000018 002018 000008 00 AX 0 0 1
10+
# CHECK-NEXT: .data PROGBITS 0000000020000000 002000 000006 00 A 0 0 8
11+
# CHECK-NEXT: .data2 PROGBITS 000000000800000e 00200e 000008 00 A 0 0 1
12+
# CHECK-NEXT: .data3 PROGBITS 0000000020000008 002018 000000 00 A 0 0 8
13+
# CHECK-NEXT: .data4 PROGBITS 0000000008000018 002018 000008 00 A 0 0 1
1414

1515

1616
# CHECK: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
1717
# CHECK-NEXT: LOAD 0x001000 0x0000000008000000 0x0000000008000000 0x000001 0x000001 R E 0x1000
18-
# CHECK-NEXT: LOAD 0x002000 0x0000000020000000 0x0000000008000008 0x000006 0x000006 R E 0x1000
19-
# CHECK-NEXT: LOAD 0x00200e 0x000000000800000e 0x000000000800000e 0x000008 0x000008 R E 0x1000
20-
# CHECK-NEXT: LOAD 0x002018 0x0000000008000018 0x0000000008000018 0x000008 0x000008 R E 0x1000
18+
# CHECK-NEXT: LOAD 0x002000 0x0000000020000000 0x0000000008000008 0x000006 0x000006 R 0x1000
19+
# CHECK-NEXT: LOAD 0x00200e 0x000000000800000e 0x000000000800000e 0x000008 0x000008 R 0x1000
20+
# CHECK-NEXT: LOAD 0x002018 0x0000000008000018 0x0000000008000018 0x000008 0x000008 R 0x1000
2121

2222
MEMORY {
2323
CODE (rx) : ORIGIN = 0x08000000, LENGTH = 100K

0 commit comments

Comments
 (0)