[lld] [ELF] adjustOutputSections: don't copy SHF_EXECINSTR when an output does not contain input sections (PR #70911)

via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 1 01:10:54 PDT 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lld

Author: Fangrui Song (MaskRay)

<details>
<summary>Changes</summary>

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.


---
Full diff: https://github.com/llvm/llvm-project/pull/70911.diff


6 Files Affected:

- (modified) lld/ELF/LinkerScript.cpp (+2-2) 
- (modified) lld/docs/ELF/linker_script.rst (+10) 
- (modified) lld/test/ELF/linkerscript/empty-synthetic-removed-flags.s (-1) 
- (modified) lld/test/ELF/linkerscript/extend-pt-load2.test (+6-5) 
- (modified) lld/test/ELF/linkerscript/insert-before.test (+6-5) 
- (modified) lld/test/ELF/linkerscript/lma-align2.test (+7-7) 


``````````diff
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index df091613dc0a144..198c63bf0a8a24b 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -1193,8 +1193,8 @@ void LinkerScript::adjustOutputSections() {
     // We do not want to keep any special flags for output section
     // in case it is empty.
     if (isEmpty)
-      sec->flags = flags & ((sec->nonAlloc ? 0 : (uint64_t)SHF_ALLOC) |
-                            SHF_WRITE | SHF_EXECINSTR);
+      sec->flags =
+          flags & ((sec->nonAlloc ? 0 : (uint64_t)SHF_ALLOC) | SHF_WRITE);
 
     // The code below may remove empty output sections. We should save the
     // specified program headers (if exist) and propagate them to subsequent
diff --git a/lld/docs/ELF/linker_script.rst b/lld/docs/ELF/linker_script.rst
index fbd96abcb44c5b1..3606ef4fe4b8ee1 100644
--- a/lld/docs/ELF/linker_script.rst
+++ b/lld/docs/ELF/linker_script.rst
@@ -97,6 +97,16 @@ The presence of ``address`` can cause the condition unsatisfied. LLD will warn.
 GNU ld from Binutils 2.35 onwards will reduce sh_addralign so that
 sh_addr=0 (modulo sh_addralign).
 
+When an output section has no input section, GNU ld will eliminate it if it
+only contains symbol assignments (e.g. ``.foo { symbol = 42; }``). LLD will
+retain such sections unless all the symbol assignments are unreferenced
+``PROVIDED``.
+
+When an output section has no input section but advances the location counter,
+GNU ld sets the ``SHF_WRITE`` flag. LLD sets the SHF_WRITE flag only if the
+preceding output section with non-empty input sections also has the SHF_WRITE
+flag.
+
 Output section type
 -------------------
 
diff --git a/lld/test/ELF/linkerscript/empty-synthetic-removed-flags.s b/lld/test/ELF/linkerscript/empty-synthetic-removed-flags.s
index b8d72702425f19f..dfc502e8da9e1d4 100644
--- a/lld/test/ELF/linkerscript/empty-synthetic-removed-flags.s
+++ b/lld/test/ELF/linkerscript/empty-synthetic-removed-flags.s
@@ -29,7 +29,6 @@
 # EMPTY-NEXT:  Type: SHT_PROGBITS
 # EMPTY-NEXT:  Flags [
 # EMPTY-NEXT:    SHF_ALLOC
-# EMPTY-NEXT:    SHF_EXECINSTR
 # EMPTY-NEXT:  ]
 
 .section .foo,"ax"
diff --git a/lld/test/ELF/linkerscript/extend-pt-load2.test b/lld/test/ELF/linkerscript/extend-pt-load2.test
index 3e91f3b4f162d07..81f5379681e5775 100644
--- a/lld/test/ELF/linkerscript/extend-pt-load2.test
+++ b/lld/test/ELF/linkerscript/extend-pt-load2.test
@@ -16,10 +16,11 @@ SECTIONS {
   .data.rel.ro : { *(.data.rel.ro) }
 }
 
-# CHECK:      .text        PROGBITS 00000000000001f4 0001f4 000001 00 AX
-# CHECK-NEXT: bar          PROGBITS 00000000000001f5 0001f5 000e0b 00 AX
-# CHECK-NEXT: .data.rel.ro PROGBITS 0000000000001000 001000 000001 00 WA
+# CHECK:      .text        PROGBITS 000000000000022c 00022c 000001 00 AX 0
+# CHECK-NEXT: bar          PROGBITS 000000000000022d 00022d 000dd3 00 A  0
+# CHECK-NEXT: .data.rel.ro PROGBITS 0000000000001000 001000 000001 00 WA 0
 
-# CHECK:      LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0001f1 0x0001f1 R   0x1000
-# CHECK:      LOAD 0x0001f4 0x00000000000001f4 0x00000000000001f4 0x000e0c 0x000e0c R E 0x1000
+# CHECK:      LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000229 0x000229 R   0x1000
+# CHECK-NEXT: LOAD 0x00022c 0x000000000000022c 0x000000000000022c 0x000001 0x000001 R E 0x1000
+# CHECK-NEXT: LOAD 0x00022d 0x000000000000022d 0x000000000000022d 0x000dd3 0x000dd3 R   0x1000
 # CHECK-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000068 0x000068 RW  0x1000
diff --git a/lld/test/ELF/linkerscript/insert-before.test b/lld/test/ELF/linkerscript/insert-before.test
index f9611538c013b2b..e6ed413639827a9 100644
--- a/lld/test/ELF/linkerscript/insert-before.test
+++ b/lld/test/ELF/linkerscript/insert-before.test
@@ -9,13 +9,14 @@
 # RUN: llvm-readelf -S -l %t1 | FileCheck %s
 # CHECK:      Name      Type     Address          Off    Size   ES Flg
 # CHECK-NEXT:           NULL
-# CHECK-NEXT: .foo.text PROGBITS 0000000000000000 001000 000008 00  AX
-# CHECK-NEXT: .text     PROGBITS 0000000000000008 001008 000008 00  AX
-# CHECK-NEXT: .byte     PROGBITS 0000000000000010 001010 000001 00  AX
-# CHECK-NEXT: .foo.data PROGBITS 0000000000000011 001011 000008 00  WA
-# CHECK-NEXT: .data     PROGBITS 0000000000000019 001019 000008 00  WA
+# CHECK-NEXT: .foo.text PROGBITS 0000000000000000 001000 000008 00  AX 0
+# CHECK-NEXT: .text     PROGBITS 0000000000000008 001008 000008 00  AX 0
+# CHECK-NEXT: .byte     PROGBITS 0000000000000010 001010 000001 00  A  0
+# CHECK-NEXT: .foo.data PROGBITS 0000000000000011 001011 000008 00  WA 0
+# CHECK-NEXT: .data     PROGBITS 0000000000000019 001019 000008 00  WA 0
 # CHECK:      Type
 # CHECK-NEXT: LOAD {{.*}} R E
+# CHECK-NEXT: LOAD {{.*}} R
 # CHECK-NEXT: LOAD {{.*}} RW
 # CHECK-NEXT: GNU_STACK {{.*}} RW
 
diff --git a/lld/test/ELF/linkerscript/lma-align2.test b/lld/test/ELF/linkerscript/lma-align2.test
index 2177101ff37475d..23b06b179b6e85d 100644
--- a/lld/test/ELF/linkerscript/lma-align2.test
+++ b/lld/test/ELF/linkerscript/lma-align2.test
@@ -7,17 +7,17 @@
 # CHECK:      Name         Type     Address          Off    Size   ES Flg Lk Inf Al
 # CHECK-NEXT:              NULL     0000000000000000 000000 000000 00      0   0  0
 # CHECK-NEXT: .text        PROGBITS 0000000008000000 001000 000001 00  AX  0   0  4
-# CHECK-NEXT: .data        PROGBITS 0000000020000000 002000 000006 00  AX  0   0  8
-# CHECK-NEXT: .data2       PROGBITS 000000000800000e 00200e 000008 00  AX  0   0  1
-# CHECK-NEXT: .data3       PROGBITS 0000000020000008 002018 000000 00  AX  0   0  8
-# CHECK-NEXT: .data4       PROGBITS 0000000008000018 002018 000008 00  AX  0   0  1
+# CHECK-NEXT: .data        PROGBITS 0000000020000000 002000 000006 00  A   0   0  8
+# CHECK-NEXT: .data2       PROGBITS 000000000800000e 00200e 000008 00  A   0   0  1
+# CHECK-NEXT: .data3       PROGBITS 0000000020000008 002018 000000 00  A   0   0  8
+# CHECK-NEXT: .data4       PROGBITS 0000000008000018 002018 000008 00  A   0   0  1
 
 
 # CHECK:      Type  Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
 # CHECK-NEXT: LOAD  0x001000 0x0000000008000000 0x0000000008000000 0x000001 0x000001 R E 0x1000
-# CHECK-NEXT: LOAD  0x002000 0x0000000020000000 0x0000000008000008 0x000006 0x000006 R E 0x1000
-# CHECK-NEXT: LOAD  0x00200e 0x000000000800000e 0x000000000800000e 0x000008 0x000008 R E 0x1000
-# CHECK-NEXT: LOAD  0x002018 0x0000000008000018 0x0000000008000018 0x000008 0x000008 R E 0x1000
+# CHECK-NEXT: LOAD  0x002000 0x0000000020000000 0x0000000008000008 0x000006 0x000006 R   0x1000
+# CHECK-NEXT: LOAD  0x00200e 0x000000000800000e 0x000000000800000e 0x000008 0x000008 R   0x1000
+# CHECK-NEXT: LOAD  0x002018 0x0000000008000018 0x0000000008000018 0x000008 0x000008 R   0x1000
 
 MEMORY {
   CODE (rx) : ORIGIN = 0x08000000, LENGTH = 100K

``````````

</details>


https://github.com/llvm/llvm-project/pull/70911


More information about the llvm-commits mailing list