<div dir="ltr">Nice!<div><br></div><div>-- Sean Silva</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Feb 12, 2016 at 1:47 PM, Rui Ueyama via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: ruiu<br>
Date: Fri Feb 12 15:47:28 2016<br>
New Revision: 260745<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=260745&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=260745&view=rev</a><br>
Log:<br>
ELF: Add wildcard pattern matching to SECTIONS linker script command.<br>
<br>
Each rule in SECTIONS commands is something like ".foo *(.baz.*)",<br>
which instructs the linker to collect all sections whose name matches<br>
".baz.*" from all files and put them into .foo section.<br>
<br>
Previously, we didn't recognize the wildcard character. This patch<br>
adds that feature.<br>
<br>
Performance impact is a bit concerning because a linker script can<br>
contain hundreds of SECTIONS rules, and doing pattern matching against<br>
each rule would be too expensive. We could merge all patterns into<br>
single DFA so that it takes O(n) to the input size. However, it is<br>
probably too much at this moment -- we don't know whether the<br>
performance of pattern matching matters or not. So I chose to<br>
implement the simplest algorithm in this patch. I hope this simple<br>
pattern matcher is sufficient.<br>
<br>
Modified:<br>
    lld/trunk/ELF/LinkerScript.cpp<br>
    lld/trunk/ELF/LinkerScript.h<br>
    lld/trunk/ELF/Writer.cpp<br>
    lld/trunk/test/ELF/linkerscript-sections.s<br>
<br>
Modified: lld/trunk/ELF/LinkerScript.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.cpp?rev=260745&r1=260744&r2=260745&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.cpp?rev=260745&r1=260744&r2=260745&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/ELF/LinkerScript.cpp (original)<br>
+++ lld/trunk/ELF/LinkerScript.cpp Fri Feb 12 15:47:28 2016<br>
@@ -16,6 +16,7 @@<br>
 #include "LinkerScript.h"<br>
 #include "Config.h"<br>
 #include "Driver.h"<br>
+#include "InputSection.h"<br>
 #include "SymbolTable.h"<br>
 #include "llvm/Support/FileSystem.h"<br>
 #include "llvm/Support/MemoryBuffer.h"<br>
@@ -23,17 +24,23 @@<br>
 #include "llvm/Support/StringSaver.h"<br>
<br>
 using namespace llvm;<br>
+using namespace llvm::object;<br>
 using namespace lld;<br>
 using namespace lld::elf2;<br>
<br>
 LinkerScript *elf2::Script;<br>
<br>
-StringRef LinkerScript::getOutputSection(StringRef S) {<br>
-  return Sections.lookup(S);<br>
+template <class ELFT><br>
+StringRef LinkerScript::getOutputSection(InputSectionBase<ELFT> *S) {<br>
+  for (SectionRule &R : Sections)<br>
+    if (R.match(S))<br>
+      return R.Dest;<br>
+  return "";<br>
 }<br>
<br>
-bool LinkerScript::isDiscarded(StringRef S) {<br>
-  return Sections.lookup(S) == "/DISCARD/";<br>
+template <class ELFT><br>
+bool LinkerScript::isDiscarded(InputSectionBase<ELFT> *S) {<br>
+  return getOutputSection(S) == "/DISCARD/";<br>
 }<br>
<br>
 // A compartor to sort output sections. Returns -1 or 1 if both<br>
@@ -48,6 +55,33 @@ int LinkerScript::compareSections(String<br>
   return I < J ? -1 : 1;<br>
 }<br>
<br>
+// Returns true if S matches T. S may contain a meta character '*'<br>
+// which matches zero or more occurrences of any character.<br>
+static bool matchStr(StringRef S, StringRef T) {<br>
+  for (;;) {<br>
+    if (S.empty())<br>
+      return T.empty();<br>
+    if (S[0] == '*') {<br>
+      S = S.substr(1);<br>
+      if (S.empty())<br>
+        // Fast path. If a pattern is '*', it matches anything.<br>
+        return true;<br>
+      for (size_t I = 0, E = T.size(); I < E; ++I)<br>
+        if (matchStr(S, T.substr(I)))<br>
+          return true;<br>
+      return false;<br>
+    }<br>
+    if (T.empty() || S[0] != T[0])<br>
+      return false;<br>
+    S = S.substr(1);<br>
+    T = T.substr(1);<br>
+  }<br>
+}<br>
+<br>
+template <class ELFT> bool SectionRule::match(InputSectionBase<ELFT> *S) {<br>
+  return matchStr(SectionPattern, S->getSectionName());<br>
+}<br>
+<br>
 class elf2::ScriptParser {<br>
 public:<br>
   ScriptParser(BumpPtrAllocator *A, StringRef S, bool B)<br>
@@ -352,7 +386,7 @@ void ScriptParser::readOutputSectionDesc<br>
     next(); // Skip input file name.<br>
     expect("(");<br>
     while (!Error && !skip(")"))<br>
-      Script->Sections[next()] = OutSec;<br>
+      Script->Sections.push_back({OutSec, next()});<br>
   }<br>
 }<br>
<br>
@@ -370,3 +404,18 @@ void LinkerScript::read(MemoryBufferRef<br>
   StringRef Path = MB.getBufferIdentifier();<br>
   ScriptParser(&Alloc, MB.getBuffer(), isUnderSysroot(Path)).run();<br>
 }<br>
+<br>
+template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF32LE> *);<br>
+template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF32BE> *);<br>
+template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF64LE> *);<br>
+template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF64BE> *);<br>
+<br>
+template bool LinkerScript::isDiscarded(InputSectionBase<ELF32LE> *);<br>
+template bool LinkerScript::isDiscarded(InputSectionBase<ELF32BE> *);<br>
+template bool LinkerScript::isDiscarded(InputSectionBase<ELF64LE> *);<br>
+template bool LinkerScript::isDiscarded(InputSectionBase<ELF64BE> *);<br>
+<br>
+template bool SectionRule::match(InputSectionBase<ELF32LE> *);<br>
+template bool SectionRule::match(InputSectionBase<ELF32BE> *);<br>
+template bool SectionRule::match(InputSectionBase<ELF64LE> *);<br>
+template bool SectionRule::match(InputSectionBase<ELF64BE> *);<br>
<br>
Modified: lld/trunk/ELF/LinkerScript.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.h?rev=260745&r1=260744&r2=260745&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.h?rev=260745&r1=260744&r2=260745&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/ELF/LinkerScript.h (original)<br>
+++ lld/trunk/ELF/LinkerScript.h Fri Feb 12 15:47:28 2016<br>
@@ -20,7 +20,23 @@ namespace lld {<br>
 namespace elf2 {<br>
<br>
 class ScriptParser;<br>
+template <class ELFT> class InputSectionBase;<br>
<br>
+// This class represents each rule in SECTIONS command.<br>
+class SectionRule {<br>
+public:<br>
+  SectionRule(StringRef D, StringRef S) : Dest(D), SectionPattern(S) {}<br>
+<br>
+  // Returns true if S should be in Dest section.<br>
+  template <class ELFT> bool match(InputSectionBase<ELFT> *S);<br>
+<br>
+  StringRef Dest;<br>
+<br>
+private:<br>
+  StringRef SectionPattern;<br>
+};<br>
+<br>
+// This is a runner of the linker script.<br>
 class LinkerScript {<br>
   friend class ScriptParser;<br>
<br>
@@ -29,14 +45,13 @@ public:<br>
   // this object and Config.<br>
   void read(MemoryBufferRef MB);<br>
<br>
-  StringRef getOutputSection(StringRef InputSection);<br>
-  bool isDiscarded(StringRef InputSection);<br>
+  template <class ELFT> StringRef getOutputSection(InputSectionBase<ELFT> *S);<br>
+  template <class ELFT> bool isDiscarded(InputSectionBase<ELFT> *S);<br>
   int compareSections(StringRef A, StringRef B);<br>
<br>
 private:<br>
-  // A map for SECTIONS command. The key is input section name<br>
-  // and the value is the corresponding output section name.<br>
-  llvm::DenseMap<StringRef, StringRef> Sections;<br>
+  // SECTIONS commands.<br>
+  std::vector<SectionRule> Sections;<br>
<br>
   // Output sections are sorted by this order.<br>
   std::vector<StringRef> SectionOrder;<br>
<br>
Modified: lld/trunk/ELF/Writer.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=260745&r1=260744&r2=260745&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=260745&r1=260744&r2=260745&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/ELF/Writer.cpp (original)<br>
+++ lld/trunk/ELF/Writer.cpp Fri Feb 12 15:47:28 2016<br>
@@ -74,7 +74,7 @@ private:<br>
   void writeHeader();<br>
   void writeSections();<br>
   bool isDiscarded(InputSectionBase<ELFT> *IS) const;<br>
-  StringRef getOutputSectionName(StringRef S) const;<br>
+  StringRef getOutputSectionName(InputSectionBase<ELFT> *S) const;<br>
   bool needsInterpSection() const {<br>
     return !Symtab.getSharedFiles().empty() && !Config->DynamicLinker.empty();<br>
   }<br>
@@ -726,16 +726,17 @@ void Writer<ELFT>::addCopyRelSymbols(std<br>
 }<br>
<br>
 template <class ELFT><br>
-StringRef Writer<ELFT>::getOutputSectionName(StringRef S) const {<br>
-  StringRef Out = Script->getOutputSection(S);<br>
-  if (!Out.empty())<br>
-    return Out;<br>
+StringRef Writer<ELFT>::getOutputSectionName(InputSectionBase<ELFT> *S) const {<br>
+  StringRef Dest = Script->getOutputSection<ELFT>(S);<br>
+  if (!Dest.empty())<br>
+    return Dest;<br>
<br>
+  StringRef Name = S->getSectionName();<br>
   for (StringRef V : {".text.", ".rodata.", ".<a href="http://data.rel.ro" rel="noreferrer" target="_blank">data.rel.ro</a>.", ".data.", ".bss.",<br>
                       ".init_array.", ".fini_array.", ".ctors.", ".dtors."})<br>
-    if (S.startswith(V))<br>
+    if (Name.startswith(V))<br>
       return V.drop_back();<br>
-  return S;<br>
+  return Name;<br>
 }<br>
<br>
 template <class ELFT><br>
@@ -750,7 +751,7 @@ void reportDiscarded(InputSectionBase<EL<br>
 template <class ELFT><br>
 bool Writer<ELFT>::isDiscarded(InputSectionBase<ELFT> *S) const {<br>
   return !S || !S->isLive() || S == &InputSection<ELFT>::Discarded ||<br>
-         Script->isDiscarded(S->getSectionName());<br>
+         Script->isDiscarded(S);<br>
 }<br>
<br>
 // The beginning and the ending of .rel[a].plt section are marked<br>
@@ -934,8 +935,7 @@ template <class ELFT> bool Writer<ELFT>:<br>
       }<br>
       OutputSectionBase<ELFT> *Sec;<br>
       bool IsNew;<br>
-      std::tie(Sec, IsNew) =<br>
-          Factory.create(C, getOutputSectionName(C->getSectionName()));<br>
+      std::tie(Sec, IsNew) = Factory.create(C, getOutputSectionName(C));<br>
       if (IsNew) {<br>
         OwningSections.emplace_back(Sec);<br>
         OutputSections.push_back(Sec);<br>
<br>
Modified: lld/trunk/test/ELF/linkerscript-sections.s<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript-sections.s?rev=260745&r1=260744&r2=260745&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript-sections.s?rev=260745&r1=260744&r2=260745&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/test/ELF/linkerscript-sections.s (original)<br>
+++ lld/trunk/test/ELF/linkerscript-sections.s Fri Feb 12 15:47:28 2016<br>
@@ -38,6 +38,20 @@<br>
 # RUN: llvm-objdump -section-headers %t3 | \<br>
 # RUN:   FileCheck -check-prefix=SEC-ORDER %s<br>
<br>
+# The same test as above but with wildcard patterns.<br>
+# RUN: echo "SECTIONS { \<br>
+# RUN:          .bss : { *(.bss) } \<br>
+# RUN:          other : { *(o*er) } \<br>
+# RUN:          .shstrtab : { *(.shstrt*) } \<br>
+# RUN:          .symtab : { *(.symtab) } \<br>
+# RUN:          .strtab : { *(.strtab) } \<br>
+# RUN:          .data : { *(*data) } \<br>
+# RUN:          .text : { *(.text) } }" > %t.script<br>
+# RUN: cp %t %t.abc<br>
+# RUN: ld.lld -o %t3 --script %t.script %t.abc<br>
+# RUN: llvm-objdump -section-headers %t3 | \<br>
+# RUN:   FileCheck -check-prefix=SEC-ORDER %s<br>
+<br>
 #           Idx Name          Size<br>
 # SEC-ORDER: 1 .bss          00000002 {{[0-9a-f]*}} BSS<br>
 # SEC-ORDER: 2 other         00000003 {{[0-9a-f]*}} DATA<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>