[lld] r260745 - ELF: Add wildcard pattern matching to SECTIONS linker script command.

Rui Ueyama via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 12 13:47:28 PST 2016


Author: ruiu
Date: Fri Feb 12 15:47:28 2016
New Revision: 260745

URL: http://llvm.org/viewvc/llvm-project?rev=260745&view=rev
Log:
ELF: Add wildcard pattern matching to SECTIONS linker script command.

Each rule in SECTIONS commands is something like ".foo *(.baz.*)",
which instructs the linker to collect all sections whose name matches
".baz.*" from all files and put them into .foo section.

Previously, we didn't recognize the wildcard character. This patch
adds that feature.

Performance impact is a bit concerning because a linker script can
contain hundreds of SECTIONS rules, and doing pattern matching against
each rule would be too expensive. We could merge all patterns into
single DFA so that it takes O(n) to the input size. However, it is
probably too much at this moment -- we don't know whether the
performance of pattern matching matters or not. So I chose to
implement the simplest algorithm in this patch. I hope this simple
pattern matcher is sufficient.

Modified:
    lld/trunk/ELF/LinkerScript.cpp
    lld/trunk/ELF/LinkerScript.h
    lld/trunk/ELF/Writer.cpp
    lld/trunk/test/ELF/linkerscript-sections.s

Modified: lld/trunk/ELF/LinkerScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.cpp?rev=260745&r1=260744&r2=260745&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.cpp (original)
+++ lld/trunk/ELF/LinkerScript.cpp Fri Feb 12 15:47:28 2016
@@ -16,6 +16,7 @@
 #include "LinkerScript.h"
 #include "Config.h"
 #include "Driver.h"
+#include "InputSection.h"
 #include "SymbolTable.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/MemoryBuffer.h"
@@ -23,17 +24,23 @@
 #include "llvm/Support/StringSaver.h"
 
 using namespace llvm;
+using namespace llvm::object;
 using namespace lld;
 using namespace lld::elf2;
 
 LinkerScript *elf2::Script;
 
-StringRef LinkerScript::getOutputSection(StringRef S) {
-  return Sections.lookup(S);
+template <class ELFT>
+StringRef LinkerScript::getOutputSection(InputSectionBase<ELFT> *S) {
+  for (SectionRule &R : Sections)
+    if (R.match(S))
+      return R.Dest;
+  return "";
 }
 
-bool LinkerScript::isDiscarded(StringRef S) {
-  return Sections.lookup(S) == "/DISCARD/";
+template <class ELFT>
+bool LinkerScript::isDiscarded(InputSectionBase<ELFT> *S) {
+  return getOutputSection(S) == "/DISCARD/";
 }
 
 // A compartor to sort output sections. Returns -1 or 1 if both
@@ -48,6 +55,33 @@ int LinkerScript::compareSections(String
   return I < J ? -1 : 1;
 }
 
+// Returns true if S matches T. S may contain a meta character '*'
+// which matches zero or more occurrences of any character.
+static bool matchStr(StringRef S, StringRef T) {
+  for (;;) {
+    if (S.empty())
+      return T.empty();
+    if (S[0] == '*') {
+      S = S.substr(1);
+      if (S.empty())
+        // Fast path. If a pattern is '*', it matches anything.
+        return true;
+      for (size_t I = 0, E = T.size(); I < E; ++I)
+        if (matchStr(S, T.substr(I)))
+          return true;
+      return false;
+    }
+    if (T.empty() || S[0] != T[0])
+      return false;
+    S = S.substr(1);
+    T = T.substr(1);
+  }
+}
+
+template <class ELFT> bool SectionRule::match(InputSectionBase<ELFT> *S) {
+  return matchStr(SectionPattern, S->getSectionName());
+}
+
 class elf2::ScriptParser {
 public:
   ScriptParser(BumpPtrAllocator *A, StringRef S, bool B)
@@ -352,7 +386,7 @@ void ScriptParser::readOutputSectionDesc
     next(); // Skip input file name.
     expect("(");
     while (!Error && !skip(")"))
-      Script->Sections[next()] = OutSec;
+      Script->Sections.push_back({OutSec, next()});
   }
 }
 
@@ -370,3 +404,18 @@ void LinkerScript::read(MemoryBufferRef
   StringRef Path = MB.getBufferIdentifier();
   ScriptParser(&Alloc, MB.getBuffer(), isUnderSysroot(Path)).run();
 }
+
+template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF32LE> *);
+template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF32BE> *);
+template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF64LE> *);
+template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF64BE> *);
+
+template bool LinkerScript::isDiscarded(InputSectionBase<ELF32LE> *);
+template bool LinkerScript::isDiscarded(InputSectionBase<ELF32BE> *);
+template bool LinkerScript::isDiscarded(InputSectionBase<ELF64LE> *);
+template bool LinkerScript::isDiscarded(InputSectionBase<ELF64BE> *);
+
+template bool SectionRule::match(InputSectionBase<ELF32LE> *);
+template bool SectionRule::match(InputSectionBase<ELF32BE> *);
+template bool SectionRule::match(InputSectionBase<ELF64LE> *);
+template bool SectionRule::match(InputSectionBase<ELF64BE> *);

Modified: lld/trunk/ELF/LinkerScript.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.h?rev=260745&r1=260744&r2=260745&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.h (original)
+++ lld/trunk/ELF/LinkerScript.h Fri Feb 12 15:47:28 2016
@@ -20,7 +20,23 @@ namespace lld {
 namespace elf2 {
 
 class ScriptParser;
+template <class ELFT> class InputSectionBase;
 
+// This class represents each rule in SECTIONS command.
+class SectionRule {
+public:
+  SectionRule(StringRef D, StringRef S) : Dest(D), SectionPattern(S) {}
+
+  // Returns true if S should be in Dest section.
+  template <class ELFT> bool match(InputSectionBase<ELFT> *S);
+
+  StringRef Dest;
+
+private:
+  StringRef SectionPattern;
+};
+
+// This is a runner of the linker script.
 class LinkerScript {
   friend class ScriptParser;
 
@@ -29,14 +45,13 @@ public:
   // this object and Config.
   void read(MemoryBufferRef MB);
 
-  StringRef getOutputSection(StringRef InputSection);
-  bool isDiscarded(StringRef InputSection);
+  template <class ELFT> StringRef getOutputSection(InputSectionBase<ELFT> *S);
+  template <class ELFT> bool isDiscarded(InputSectionBase<ELFT> *S);
   int compareSections(StringRef A, StringRef B);
 
 private:
-  // A map for SECTIONS command. The key is input section name
-  // and the value is the corresponding output section name.
-  llvm::DenseMap<StringRef, StringRef> Sections;
+  // SECTIONS commands.
+  std::vector<SectionRule> Sections;
 
   // Output sections are sorted by this order.
   std::vector<StringRef> SectionOrder;

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=260745&r1=260744&r2=260745&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Fri Feb 12 15:47:28 2016
@@ -74,7 +74,7 @@ private:
   void writeHeader();
   void writeSections();
   bool isDiscarded(InputSectionBase<ELFT> *IS) const;
-  StringRef getOutputSectionName(StringRef S) const;
+  StringRef getOutputSectionName(InputSectionBase<ELFT> *S) const;
   bool needsInterpSection() const {
     return !Symtab.getSharedFiles().empty() && !Config->DynamicLinker.empty();
   }
@@ -726,16 +726,17 @@ void Writer<ELFT>::addCopyRelSymbols(std
 }
 
 template <class ELFT>
-StringRef Writer<ELFT>::getOutputSectionName(StringRef S) const {
-  StringRef Out = Script->getOutputSection(S);
-  if (!Out.empty())
-    return Out;
+StringRef Writer<ELFT>::getOutputSectionName(InputSectionBase<ELFT> *S) const {
+  StringRef Dest = Script->getOutputSection<ELFT>(S);
+  if (!Dest.empty())
+    return Dest;
 
+  StringRef Name = S->getSectionName();
   for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.",
                       ".init_array.", ".fini_array.", ".ctors.", ".dtors."})
-    if (S.startswith(V))
+    if (Name.startswith(V))
       return V.drop_back();
-  return S;
+  return Name;
 }
 
 template <class ELFT>
@@ -750,7 +751,7 @@ void reportDiscarded(InputSectionBase<EL
 template <class ELFT>
 bool Writer<ELFT>::isDiscarded(InputSectionBase<ELFT> *S) const {
   return !S || !S->isLive() || S == &InputSection<ELFT>::Discarded ||
-         Script->isDiscarded(S->getSectionName());
+         Script->isDiscarded(S);
 }
 
 // The beginning and the ending of .rel[a].plt section are marked
@@ -934,8 +935,7 @@ template <class ELFT> bool Writer<ELFT>:
       }
       OutputSectionBase<ELFT> *Sec;
       bool IsNew;
-      std::tie(Sec, IsNew) =
-          Factory.create(C, getOutputSectionName(C->getSectionName()));
+      std::tie(Sec, IsNew) = Factory.create(C, getOutputSectionName(C));
       if (IsNew) {
         OwningSections.emplace_back(Sec);
         OutputSections.push_back(Sec);

Modified: lld/trunk/test/ELF/linkerscript-sections.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript-sections.s?rev=260745&r1=260744&r2=260745&view=diff
==============================================================================
--- lld/trunk/test/ELF/linkerscript-sections.s (original)
+++ lld/trunk/test/ELF/linkerscript-sections.s Fri Feb 12 15:47:28 2016
@@ -38,6 +38,20 @@
 # RUN: llvm-objdump -section-headers %t3 | \
 # RUN:   FileCheck -check-prefix=SEC-ORDER %s
 
+# The same test as above but with wildcard patterns.
+# RUN: echo "SECTIONS { \
+# RUN:          .bss : { *(.bss) } \
+# RUN:          other : { *(o*er) } \
+# RUN:          .shstrtab : { *(.shstrt*) } \
+# RUN:          .symtab : { *(.symtab) } \
+# RUN:          .strtab : { *(.strtab) } \
+# RUN:          .data : { *(*data) } \
+# RUN:          .text : { *(.text) } }" > %t.script
+# RUN: cp %t %t.abc
+# RUN: ld.lld -o %t3 --script %t.script %t.abc
+# RUN: llvm-objdump -section-headers %t3 | \
+# RUN:   FileCheck -check-prefix=SEC-ORDER %s
+
 #           Idx Name          Size
 # SEC-ORDER: 1 .bss          00000002 {{[0-9a-f]*}} BSS
 # SEC-ORDER: 2 other         00000003 {{[0-9a-f]*}} DATA




More information about the llvm-commits mailing list