[lld] r276243 - [ELF] - Initial support of tree-style linker script implemented.

George Rimar via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 20 23:43:02 PDT 2016


Author: grimar
Date: Thu Jul 21 01:43:01 2016
New Revision: 276243

URL: http://llvm.org/viewvc/llvm-project?rev=276243&view=rev
Log:
[ELF] - Initial support of tree-style linker script implemented.

Approach uses LLVM-style RTTI for representing the linker script
commands in a form of tree for future simplification of parsing.

Core idea and code sample belongs to Rui Ueyama.

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

Modified:
    lld/trunk/ELF/LinkerScript.cpp
    lld/trunk/ELF/LinkerScript.h

Modified: lld/trunk/ELF/LinkerScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.cpp?rev=276243&r1=276242&r2=276243&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.cpp (original)
+++ lld/trunk/ELF/LinkerScript.cpp Thu Jul 21 01:43:01 2016
@@ -39,6 +39,14 @@ using namespace lld::elf;
 
 ScriptConfiguration *elf::ScriptConfig;
 
+bool SymbolAssignment::classof(const BaseCommand *C) {
+  return C->Kind == AssignmentKind;
+}
+
+bool OutputSectionCommand::classof(const BaseCommand *C) {
+  return C->Kind == OutputSectionKind;
+}
+
 // This is an operator-precedence parser to parse and evaluate
 // a linker script expression. For each linker script arithmetic
 // expression (e.g. ". = . + 0x1000"), a new instance of ExprParser
@@ -259,7 +267,7 @@ void LinkerScript<ELFT>::assignAddresses
   for (OutputSectionBase<ELFT> *Sec : Sections) {
     StringRef Name = Sec->getName();
     if (getSectionIndex(Name) == INT_MAX)
-      Opt.Commands.push_back({SectionKind, {}, Name, {}});
+      Opt.Commands.push_back(llvm::make_unique<OutputSectionCommand>(Name));
   }
 
   // Assign addresses as instructed by linker script SECTIONS sub-commands.
@@ -267,14 +275,14 @@ void LinkerScript<ELFT>::assignAddresses
   uintX_t MinVA = std::numeric_limits<uintX_t>::max();
   uintX_t ThreadBssOffset = 0;
 
-  for (SectionsCommand &Cmd : Opt.Commands) {
-    if (Cmd.Kind == AssignmentKind) {
-      uint64_t Val = evalExpr(Cmd.Expr, Dot);
+  for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
+    if (auto *Cmd = dyn_cast<SymbolAssignment>(Base.get())) {
+      uint64_t Val = evalExpr(Cmd->Expr, Dot);
+      if (Cmd->Name == ".") {
 
-      if (Cmd.Name == ".") {
         Dot = Val;
       } else {
-        auto *D = cast<DefinedRegular<ELFT>>(Symtab<ELFT>::X->find(Cmd.Name));
+        auto *D = cast<DefinedRegular<ELFT>>(Symtab<ELFT>::X->find(Cmd->Name));
         D->Value = Val;
       }
       continue;
@@ -283,9 +291,9 @@ void LinkerScript<ELFT>::assignAddresses
     // Find all the sections with required name. There can be more than
     // one section with such name, if the alignment, flags or type
     // attribute differs.
-    assert(Cmd.Kind == SectionKind);
+    auto *Cmd = cast<OutputSectionCommand>(Base.get());
     for (OutputSectionBase<ELFT> *Sec : Sections) {
-      if (Sec->getName() != Cmd.Name)
+      if (Sec->getName() != Cmd->Name)
         continue;
 
       if ((Sec->getFlags() & SHF_TLS) && Sec->getType() == SHT_NOBITS) {
@@ -412,13 +420,16 @@ ArrayRef<uint8_t> LinkerScript<ELFT>::ge
 // SECTIONS commands. Sections are laid out as the same order as they
 // were in the script. If a given name did not appear in the script,
 // it returns INT_MAX, so that it will be laid out at end of file.
-template <class ELFT>
-int LinkerScript<ELFT>::getSectionIndex(StringRef Name) {
+template <class ELFT> int LinkerScript<ELFT>::getSectionIndex(StringRef Name) {
   auto Begin = Opt.Commands.begin();
   auto End = Opt.Commands.end();
-  auto I = std::find_if(Begin, End, [&](SectionsCommand &N) {
-    return N.Kind == SectionKind && N.Name == Name;
-  });
+  auto I =
+      std::find_if(Begin, End, [&](const std::unique_ptr<BaseCommand> &Base) {
+        if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get()))
+          if (Cmd->Name == Name)
+            return true;
+        return false;
+      });
   return I == End ? INT_MAX : (I - Begin);
 }
 
@@ -433,12 +444,11 @@ int LinkerScript<ELFT>::compareSections(
   return I < J ? -1 : 1;
 }
 
-template <class ELFT>
-void LinkerScript<ELFT>::addScriptedSymbols() {
-  for (SectionsCommand &Cmd : Opt.Commands)
-    if (Cmd.Kind == AssignmentKind)
-      if (Cmd.Name != "." && Symtab<ELFT>::X->find(Cmd.Name) == nullptr)
-        Symtab<ELFT>::X->addAbsolute(Cmd.Name, STV_DEFAULT);
+template <class ELFT> void LinkerScript<ELFT>::addScriptedSymbols() {
+  for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands)
+    if (auto *Cmd = dyn_cast<SymbolAssignment>(Base.get()))
+      if (Cmd->Name != "." && Symtab<ELFT>::X->find(Cmd->Name) == nullptr)
+        Symtab<ELFT>::X->addAbsolute(Cmd->Name, STV_DEFAULT);
 }
 
 template <class ELFT> bool LinkerScript<ELFT>::hasPhdrsCommands() {
@@ -451,15 +461,16 @@ template <class ELFT> bool LinkerScript<
 template <class ELFT>
 std::vector<size_t>
 LinkerScript<ELFT>::getPhdrIndicesForSection(StringRef Name) {
-  for (SectionsCommand &Cmd : Opt.Commands) {
-    if (Cmd.Kind != SectionKind || Cmd.Name != Name)
+  for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
+    auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get());
+    if (!Cmd || Cmd->Name != Name)
       continue;
 
     std::vector<size_t> Indices;
-    for (StringRef PhdrName : Cmd.Phdrs) {
+    for (StringRef PhdrName : Cmd->Phdrs) {
       auto ItPhdr =
           std::find_if(Opt.PhdrsCommands.rbegin(), Opt.PhdrsCommands.rend(),
-                       [&](PhdrsCommand &Cmd) { return Cmd.Name == PhdrName; });
+                       [&](PhdrsCommand &P) { return P.Name == PhdrName; });
       if (ItPhdr == Opt.PhdrsCommands.rend())
         error("section header '" + PhdrName + "' is not listed in PHDRS");
       else
@@ -705,12 +716,12 @@ void ScriptParser::readLocationCounterVa
   if (Expr.empty())
     error("error in location counter expression");
   else
-    Opt.Commands.push_back({AssignmentKind, std::move(Expr), ".", {}});
+    Opt.Commands.push_back(llvm::make_unique<SymbolAssignment>(".", Expr));
 }
 
 void ScriptParser::readOutputSectionDescription(StringRef OutSec) {
-  Opt.Commands.push_back({SectionKind, {}, OutSec, {}});
-  SectionsCommand &Cmd = Opt.Commands.back();
+  OutputSectionCommand *Cmd = new OutputSectionCommand(OutSec);
+  Opt.Commands.emplace_back(Cmd);
   expect(":");
   expect("{");
 
@@ -734,7 +745,7 @@ void ScriptParser::readOutputSectionDesc
       setError("unknown command " + Tok);
     }
   }
-  Cmd.Phdrs = readOutputSectionPhdrs();
+  Cmd->Phdrs = readOutputSectionPhdrs();
 
   StringRef Tok = peek();
   if (Tok.startswith("=")) {
@@ -754,7 +765,7 @@ void ScriptParser::readSymbolAssignment(
   if (Expr.empty())
     error("error in symbol assignment expression");
   else
-    Opt.Commands.push_back({AssignmentKind, std::move(Expr), Name, {}});
+    Opt.Commands.push_back(llvm::make_unique<SymbolAssignment>(Name, Expr));
 }
 
 std::vector<StringRef> ScriptParser::readSectionsCommandExpr() {

Modified: lld/trunk/ELF/LinkerScript.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.h?rev=276243&r1=276242&r2=276243&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.h (original)
+++ lld/trunk/ELF/LinkerScript.h Thu Jul 21 01:43:01 2016
@@ -41,16 +41,37 @@ struct SectionRule {
   StringRef SectionPattern;
 };
 
-// This enum represents what we can observe in SECTIONS tag of script:
-// ExprKind is a location counter change, like ". = . + 0x1000"
-// SectionKind is a description of output section, like ".data :..."
-enum SectionsCommandKind { SectionKind, AssignmentKind };
+// This enum represents what we can observe in SECTIONS tag of script.
+// Each sections-command may of be one of the following:
+// (https://sourceware.org/binutils/docs/ld/SECTIONS.html#SECTIONS)
+// * An ENTRY command.
+// * A symbol assignment.
+// * An output section description.
+// * An overlay description.
+// We support only AssignmentKind and OutputSectionKind for now.
+enum SectionsCommandKind { AssignmentKind, OutputSectionKind };
+
+struct BaseCommand {
+  BaseCommand(int K) : Kind(K) {}
+  virtual ~BaseCommand() {}
+  int Kind;
+};
 
-struct SectionsCommand {
-  SectionsCommandKind Kind;
+struct SymbolAssignment : BaseCommand {
+  SymbolAssignment(StringRef Name, std::vector<StringRef> &Expr)
+      : BaseCommand(AssignmentKind), Name(Name), Expr(std::move(Expr)) {}
+  static bool classof(const BaseCommand *C);
+  StringRef Name;
   std::vector<StringRef> Expr;
+};
+
+struct OutputSectionCommand : BaseCommand {
+  OutputSectionCommand(StringRef Name)
+      : BaseCommand(OutputSectionKind), Name(Name) {}
+  static bool classof(const BaseCommand *C);
   StringRef Name;
   std::vector<StringRef> Phdrs;
+  std::vector<uint8_t> Filler;
 };
 
 struct PhdrsCommand {
@@ -69,7 +90,7 @@ struct ScriptConfiguration {
   llvm::StringMap<std::vector<uint8_t>> Filler;
 
   // Used to assign addresses to sections.
-  std::vector<SectionsCommand> Commands;
+  std::vector<std::unique_ptr<BaseCommand>> Commands;
 
   // Used to assign sections to headers.
   std::vector<PhdrsCommand> PhdrsCommands;




More information about the llvm-commits mailing list