[ELF] - Linkerscript: reimplemented output sections constrains matching functionality.
authorGeorge Rimar <grimar@accesssoftek.com>
Fri, 12 Aug 2016 09:07:57 +0000 (09:07 +0000)
committerGeorge Rimar <grimar@accesssoftek.com>
Fri, 12 Aug 2016 09:07:57 +0000 (09:07 +0000)
Previously filtering that was used worked incorrectly.
For example for next script it would just remove both sections completely:

SECTIONS {
. = 0x1000;
.aaa : ONLY_IF_RW { *(.aaa.*) }
. = 0x2000;
.aaa : ONLY_IF_RO { *(.aaa.*) }
}

Patch fixes above issues and adds testcase showing the issue. Testcase is a subset of
FreeBSD script which has:

.eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
...
.eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }

Differential revision: https://reviews.llvm.org/D23326

llvm-svn: 278486

lld/ELF/LinkerScript.cpp
lld/ELF/LinkerScript.h
lld/test/ELF/linkerscript/linkerscript-multi-sections-constraint.s [new file with mode: 0644]
lld/test/ELF/linkerscript/linkerscript-sections-constraint.s

index 64918d7..1c24614 100644 (file)
@@ -216,20 +216,33 @@ void LinkerScript<ELFT>::discard(OutputSectionCommand &Cmd) {
 }
 
 template <class ELFT>
+static bool matchConstraints(ArrayRef<InputSectionBase<ELFT> *> Sections,
+                             ConstraintKind Kind) {
+  bool RO = (Kind == ConstraintKind::ReadOnly);
+  bool RW = (Kind == ConstraintKind::ReadWrite);
+  return !llvm::any_of(Sections, [=](InputSectionBase<ELFT> *Sec) {
+    bool Writable = Sec->getSectionHdr()->sh_flags & SHF_WRITE;
+    return (RO && Writable) || (RW && !Writable);
+  });
+}
+
+template <class ELFT>
 std::vector<InputSectionBase<ELFT> *>
-LinkerScript<ELFT>::createInputSectionList(OutputSectionCommand &Cmd) {
+LinkerScript<ELFT>::createInputSectionList(OutputSectionCommand &OutCmd) {
   std::vector<InputSectionBase<ELFT> *> Ret;
 
-  for (const std::unique_ptr<BaseCommand> &Base : Cmd.Commands) {
-    if (auto *Cmd = dyn_cast<SymbolAssignment>(Base.get())) {
-      if (shouldDefine<ELFT>(Cmd))
-        addSynthetic<ELFT>(Cmd);
-      Ret.push_back(new (LAlloc.Allocate()) LayoutInputSection<ELFT>(Cmd));
+  for (const std::unique_ptr<BaseCommand> &Base : OutCmd.Commands) {
+    if (auto *OutCmd = dyn_cast<SymbolAssignment>(Base.get())) {
+      if (shouldDefine<ELFT>(OutCmd))
+        addSynthetic<ELFT>(OutCmd);
+      Ret.push_back(new (LAlloc.Allocate()) LayoutInputSection<ELFT>(OutCmd));
       continue;
     }
 
     auto *Cmd = cast<InputSectionDescription>(Base.get());
     std::vector<InputSectionBase<ELFT> *> V = getInputSections(Cmd);
+    if (!matchConstraints<ELFT>(V, OutCmd.Constraint))
+      continue;
     if (Cmd->SortInner)
       std::stable_sort(V.begin(), V.end(), getComparator<ELFT>(Cmd->SortInner));
     if (Cmd->SortOuter)
@@ -283,38 +296,6 @@ void LinkerScript<ELFT>::createSections(OutputSectionFactory<ELFT> &Factory) {
       OutSec->addSection(S);
     }
   }
-
-  // Remove from the output all the sections which did not meet
-  // the optional constraints.
-  filter();
-}
-
-template <class R, class T>
-static inline void removeElementsIf(R &Range, const T &Pred) {
-  Range.erase(std::remove_if(Range.begin(), Range.end(), Pred), Range.end());
-}
-
-// Process ONLY_IF_RO and ONLY_IF_RW.
-template <class ELFT> void LinkerScript<ELFT>::filter() {
-  // In this loop, we remove output sections if they don't satisfy
-  // requested properties.
-  for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
-    auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get());
-    if (!Cmd || Cmd->Name == "/DISCARD/")
-      continue;
-
-    if (Cmd->Constraint == ConstraintKind::NoConstraint)
-      continue;
-
-    bool RO = (Cmd->Constraint == ConstraintKind::ReadOnly);
-    bool RW = (Cmd->Constraint == ConstraintKind::ReadWrite);
-
-    removeElementsIf(*OutputSections, [&](OutputSectionBase<ELFT> *S) {
-      bool Writable = (S->getFlags() & SHF_WRITE);
-      return S->getName() == Cmd->Name &&
-             ((RO && Writable) || (RW && !Writable));
-    });
-  }
 }
 
 template <class ELFT> void assignOffsets(OutputSectionBase<ELFT> *Sec) {
index ecf9f5c..53a6db5 100644 (file)
@@ -167,8 +167,6 @@ private:
   // "ScriptConfig" is a bit too long, so define a short name for it.
   ScriptConfiguration &Opt = *ScriptConfig;
 
-  void filter();
-
   int getSectionIndex(StringRef Name);
   std::vector<size_t> getPhdrIndices(StringRef SectionName);
   size_t getPhdrIndex(StringRef PhdrName);
diff --git a/lld/test/ELF/linkerscript/linkerscript-multi-sections-constraint.s b/lld/test/ELF/linkerscript/linkerscript-multi-sections-constraint.s
new file mode 100644 (file)
index 0000000..c9d0943
--- /dev/null
@@ -0,0 +1,26 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN:  . = 0x1000; .aaa : ONLY_IF_RO { *(.aaa.*) } \
+# RUN:  . = 0x2000; .aaa : ONLY_IF_RW { *(.aaa.*) } } " > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+
+# CHECK:      Sections:
+# CHECK-NEXT: Idx Name          Size      Address          Type
+# CHECK-NEXT:   0               00000000 0000000000000000
+# CHECK-NEXT:   1 .aaa          00000010 0000000000002000 DATA
+# CHECK-NEXT:   2 .text         00000001 0000000000002010 TEXT DATA
+# CHECK-NEXT:   3 .symtab       00000030 0000000000000000
+# CHECK-NEXT:   4 .shstrtab     00000026 0000000000000000
+# CHECK-NEXT:   5 .strtab       00000008 0000000000000000
+
+.global _start
+_start:
+ nop
+
+.section .aaa.1, "aw"
+.quad 1
+
+.section .aaa.2, "aw"
+.quad 1
index cceba92..75c192c 100644 (file)
 # BASE-NEXT:   2 .readable     00000004 0000000000000204 DATA
 
 # RUN: echo "SECTIONS { \
-# RUN:  .writable : ONLY_IF_RO { *(.writable) } \
-# RUN:  .readable : ONLY_IF_RW { *(.readable) }}" > %t.script
-# RUN: ld.lld -o %t1 --script %t.script %t
-# RUN: llvm-objdump -section-headers %t1 | \
-# RUN:   FileCheck -check-prefix=NOSECTIONS %s
-# NOSECTIONS: Sections:
-# NOSECTIONS-NOT: .writable
-# NOSECTIONS-NOT: .readable
-
-# RUN: echo "SECTIONS { \
-# RUN:  .foo : ONLY_IF_RO { *(.foo.*) }}" > %t.script
-# RUN: ld.lld -o %t1 --script %t.script %t
-# RUN: llvm-objdump -section-headers %t1 | \
-# RUN:   FileCheck -check-prefix=NOSECTIONS2 %s
-# NOSECTIONS2: Sections:
-# NOSECTIONS2-NOT: .foo
+# RUN:  .foo : ONLY_IF_RO { *(.foo.*) } \
+# RUN:  .writable : ONLY_IF_RW { *(.writable) } \
+# RUN:  .readable : ONLY_IF_RO { *(.readable) }}" > %t2.script
+# RUN: ld.lld -o %t2 --script %t2.script %t
+# RUN: llvm-objdump -section-headers %t2 | \
+# RUN:   FileCheck -check-prefix=NO1 %s
+# NO1: Sections:
+# NO1-NEXT: Idx Name          Size      Address          Type
+# NO1-NEXT: 0               00000000 0000000000000000
+# NO1-NEXT: 1 .writable     00000004 0000000000000200 DATA
+# NO1-NEXT: 2 .readable     00000004 0000000000000204 DATA
+# NO1-NEXT: 3 .text         00000001 0000000000000208 TEXT DATA
+# NO1-NEXT: 4 .foo.2        00000004 0000000000000209 DATA
+# NO1-NEXT: 5 .foo.1        00000004 000000000000020d TEXT DATA
 
 .global _start
 _start: