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

Sean Silva via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 12 17:29:21 PST 2016


Nice!

-- Sean Silva

On Fri, Feb 12, 2016 at 1:47 PM, Rui Ueyama via llvm-commits <
llvm-commits at lists.llvm.org> wrote:

> 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
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160212/57d0b426/attachment.html>


More information about the llvm-commits mailing list