Skip to content

[ELF] Allow KEEP within OVERLAY #130661

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 11, 2025

Conversation

nathanchance
Copy link
Member

@nathanchance nathanchance commented Mar 10, 2025

When attempting to add KEEP within an OVERLAY description, which the Linux kernel would like to do for ARCH=arm to avoid dropping the .vectors sections with --gc-sections (patch), ld.lld errors with:

ld.lld: error: ./arch/arm/kernel/vmlinux.lds:37: section pattern is expected
>>>  __vectors_lma = .; OVERLAY 0xffff0000 : AT(__vectors_lma) { .vectors { KEEP(*(.vectors)) } ...
>>>                                                                               ^

readOverlaySectionDescription() does not handle all input section description keywords, despite GNU ld's documentation stating that

The section definitions within the OVERLAY construct are identical to those within the general SECTIONS construct, except that no addresses and no memory regions may be defined for sections within an OVERLAY.

Reuse the existing parsing in readInputSectionDescription(), which handles KEEP, allowing the Linux kernel's use case to work properly.

When attempting to add KEEP within an OVERLAY description, which the
Linux kernel would like to do for ARCH=arm to avoid dropping the
.vectors sections with '--gc-sections' [1], ld.lld errors with:

  ld.lld: error: ./arch/arm/kernel/vmlinux.lds:37: section pattern is expected
  >>>  __vectors_lma = .; OVERLAY 0xffff0000 : AT(__vectors_lma) { .vectors { KEEP(*(.vectors)) } ...
  >>>                                                                               ^

readOverlaySectionDescription() does not handle all input section
description keywords, despite GNU ld's documentation stating that "The
section definitions within the OVERLAY construct are identical to those
within the general SECTIONS construct, except that no addresses and no
memory regions may be defined for sections within an OVERLAY."

Reuse the existing parsing in readInputSectionDescription(), which
handles KEEP, allowing the Linux kernel's use case to work properly.

[1]: https://lore.kernel.org/[email protected]/
@llvmbot
Copy link
Member

llvmbot commented Mar 10, 2025

@llvm/pr-subscribers-lld-elf

Author: Nathan Chancellor (nathanchance)

Changes

When attempting to add KEEP within an OVERLAY description, which the
Linux kernel would like to do for ARCH=arm to avoid dropping the
.vectors sections with '--gc-sections' [1], ld.lld errors with:

ld.lld: error: ./arch/arm/kernel/vmlinux.lds:37: section pattern is expected
>>> __vectors_lma = .; OVERLAY 0xffff0000 : AT(__vectors_lma) { .vectors { KEEP(*(.vectors)) } ...
>>> ^

readOverlaySectionDescription() does not handle all input section
description keywords, despite GNU ld's documentation stating that "The
section definitions within the OVERLAY construct are identical to those
within the general SECTIONS construct, except that no addresses and no
memory regions may be defined for sections within an OVERLAY."

Reuse the existing parsing in readInputSectionDescription(), which
handles KEEP, allowing the Linux kernel's use case to work properly.

[1]: https://lore.kernel.org/20250221125520.14035-1-ceggers@arri.de/


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

2 Files Affected:

  • (modified) lld/ELF/ScriptParser.cpp (+2-14)
  • (added) lld/test/ELF/linkerscript/overlay-keep.test (+51)
diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp
index 671a5ec4deccb..4c52bfda7a70e 100644
--- a/lld/ELF/ScriptParser.cpp
+++ b/lld/ELF/ScriptParser.cpp
@@ -988,20 +988,8 @@ OutputDesc *ScriptParser::readOverlaySectionDescription() {
       ctx.script->createOutputSection(readName(), getCurrentLocation());
   osd->osec.inOverlay = true;
   expect("{");
-  while (auto tok = till("}")) {
-    uint64_t withFlags = 0;
-    uint64_t withoutFlags = 0;
-    if (tok == "INPUT_SECTION_FLAGS") {
-      std::tie(withFlags, withoutFlags) = readInputSectionFlags();
-      tok = till("");
-    }
-    if (tok == "CLASS")
-      osd->osec.commands.push_back(make<InputSectionDescription>(
-          StringRef{}, withFlags, withoutFlags, readSectionClassName()));
-    else
-      osd->osec.commands.push_back(
-          readInputSectionRules(tok, withFlags, withoutFlags));
-  }
+  while (auto tok = till("}"))
+    osd->osec.commands.push_back(readInputSectionDescription(tok));
   osd->osec.phdrs = readOutputSectionPhdrs();
   return osd;
 }
diff --git a/lld/test/ELF/linkerscript/overlay-keep.test b/lld/test/ELF/linkerscript/overlay-keep.test
new file mode 100644
index 0000000000000..1b163523eead5
--- /dev/null
+++ b/lld/test/ELF/linkerscript/overlay-keep.test
@@ -0,0 +1,51 @@
+# REQUIRES: x86
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o
+# RUN: ld.lld a.o --gc-sections --script nokeep.t -o a
+# RUN: llvm-objdump --section-headers a | FileCheck --check-prefix=NOKEEP %s
+# RUN: ld.lld a.o --gc-sections --script keep.t -o a
+# RUN: llvm-objdump --section-headers a | FileCheck --check-prefix=KEEP %s
+
+# NOKEEP:      Sections:
+# NOKEEP-NEXT: Idx Name          Size
+# NOKEEP-NEXT:   0               00000000
+# NOKEEP-NEXT:   1 .text         00000004
+# NOKEEP-NEXT:   2 .keep1        00000000
+
+# KEEP:      Sections:
+# KEEP-NEXT: Idx Name          Size
+# KEEP-NEXT:   0               00000000
+# KEEP-NEXT:   1 .text         00000004
+# KEEP-NEXT:   2 .keep1        00000004
+# KEEP-NEXT:   3 .keep2        00000004
+
+#--- a.s
+.global _start
+_start:
+ .long 1
+
+.section .keep1, "a"
+keep1:
+ .long 2
+
+.section .keep2, "a"
+keep2:
+ .long 3
+
+#--- nokeep.t
+SECTIONS {
+  .text : { *(.text) }
+  OVERLAY 0x1000 : AT ( 0x4000 ) {
+    .keep1 { *(.keep1) }
+    .keep2 { *(.keep2) }
+  }
+}
+
+#--- keep.t
+SECTIONS {
+  .text : { *(.text) }
+  OVERLAY 0x1000 : AT ( 0x4000 ) {
+    .keep1 { KEEP(*(.keep1)) }
+    .keep2 { KEEP(*(.keep2)) }
+  }
+}

@llvmbot
Copy link
Member

llvmbot commented Mar 10, 2025

@llvm/pr-subscribers-lld

Author: Nathan Chancellor (nathanchance)

Changes

When attempting to add KEEP within an OVERLAY description, which the
Linux kernel would like to do for ARCH=arm to avoid dropping the
.vectors sections with '--gc-sections' [1], ld.lld errors with:

ld.lld: error: ./arch/arm/kernel/vmlinux.lds:37: section pattern is expected
>>> __vectors_lma = .; OVERLAY 0xffff0000 : AT(__vectors_lma) { .vectors { KEEP(*(.vectors)) } ...
>>> ^

readOverlaySectionDescription() does not handle all input section
description keywords, despite GNU ld's documentation stating that "The
section definitions within the OVERLAY construct are identical to those
within the general SECTIONS construct, except that no addresses and no
memory regions may be defined for sections within an OVERLAY."

Reuse the existing parsing in readInputSectionDescription(), which
handles KEEP, allowing the Linux kernel's use case to work properly.

[1]: https://lore.kernel.org/20250221125520.14035-1-ceggers@arri.de/


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

2 Files Affected:

  • (modified) lld/ELF/ScriptParser.cpp (+2-14)
  • (added) lld/test/ELF/linkerscript/overlay-keep.test (+51)
diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp
index 671a5ec4deccb..4c52bfda7a70e 100644
--- a/lld/ELF/ScriptParser.cpp
+++ b/lld/ELF/ScriptParser.cpp
@@ -988,20 +988,8 @@ OutputDesc *ScriptParser::readOverlaySectionDescription() {
       ctx.script->createOutputSection(readName(), getCurrentLocation());
   osd->osec.inOverlay = true;
   expect("{");
-  while (auto tok = till("}")) {
-    uint64_t withFlags = 0;
-    uint64_t withoutFlags = 0;
-    if (tok == "INPUT_SECTION_FLAGS") {
-      std::tie(withFlags, withoutFlags) = readInputSectionFlags();
-      tok = till("");
-    }
-    if (tok == "CLASS")
-      osd->osec.commands.push_back(make<InputSectionDescription>(
-          StringRef{}, withFlags, withoutFlags, readSectionClassName()));
-    else
-      osd->osec.commands.push_back(
-          readInputSectionRules(tok, withFlags, withoutFlags));
-  }
+  while (auto tok = till("}"))
+    osd->osec.commands.push_back(readInputSectionDescription(tok));
   osd->osec.phdrs = readOutputSectionPhdrs();
   return osd;
 }
diff --git a/lld/test/ELF/linkerscript/overlay-keep.test b/lld/test/ELF/linkerscript/overlay-keep.test
new file mode 100644
index 0000000000000..1b163523eead5
--- /dev/null
+++ b/lld/test/ELF/linkerscript/overlay-keep.test
@@ -0,0 +1,51 @@
+# REQUIRES: x86
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o
+# RUN: ld.lld a.o --gc-sections --script nokeep.t -o a
+# RUN: llvm-objdump --section-headers a | FileCheck --check-prefix=NOKEEP %s
+# RUN: ld.lld a.o --gc-sections --script keep.t -o a
+# RUN: llvm-objdump --section-headers a | FileCheck --check-prefix=KEEP %s
+
+# NOKEEP:      Sections:
+# NOKEEP-NEXT: Idx Name          Size
+# NOKEEP-NEXT:   0               00000000
+# NOKEEP-NEXT:   1 .text         00000004
+# NOKEEP-NEXT:   2 .keep1        00000000
+
+# KEEP:      Sections:
+# KEEP-NEXT: Idx Name          Size
+# KEEP-NEXT:   0               00000000
+# KEEP-NEXT:   1 .text         00000004
+# KEEP-NEXT:   2 .keep1        00000004
+# KEEP-NEXT:   3 .keep2        00000004
+
+#--- a.s
+.global _start
+_start:
+ .long 1
+
+.section .keep1, "a"
+keep1:
+ .long 2
+
+.section .keep2, "a"
+keep2:
+ .long 3
+
+#--- nokeep.t
+SECTIONS {
+  .text : { *(.text) }
+  OVERLAY 0x1000 : AT ( 0x4000 ) {
+    .keep1 { *(.keep1) }
+    .keep2 { *(.keep2) }
+  }
+}
+
+#--- keep.t
+SECTIONS {
+  .text : { *(.text) }
+  OVERLAY 0x1000 : AT ( 0x4000 ) {
+    .keep1 { KEEP(*(.keep1)) }
+    .keep2 { KEEP(*(.keep2)) }
+  }
+}

@lenary
Copy link
Member

lenary commented Mar 11, 2025

Should there be tests that we don't support the things that GNU says are disallowed in overlays?

@nathanchance
Copy link
Member Author

Should there be tests that we don't support the things that GNU says are disallowed in overlays?

I think that err1.t in lld/test/ELF/linkerscript/overlay.test already does that. As far as I can tell, the only thing this PR is allowing is KEEP() based on my reading and understanding of the differences between the current readOverlaySectionDescription() and readInputSectionDescription().

@nathanchance nathanchance merged commit 381599f into llvm:main Mar 11, 2025
14 checks passed
@nathanchance nathanchance deleted the lld-keep-within-overlay branch March 11, 2025 19:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants