<div dir="ltr">Yes, I missed them. Sorry. I committed the missed tests shortly after I realized this in <span style="color:rgb(80,0,80);font-size:12.8000001907349px">232404.</span></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Mar 16, 2015 at 5:10 PM, Shankar Easwaran <span dir="ltr"><<a href="mailto:shankare@codeaurora.org" target="_blank">shankare@codeaurora.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On 3/16/2015 2:55 PM, Rafael Auler wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Author: rafauler<br>
Date: Mon Mar 16 14:55:15 2015<br>
New Revision: 232402<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=232402&view=rev" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project?rev=232402&view=rev</a><br>
Log:<br>
[LinkerScript] Implement semantics for simple sections mappings<br>
<br>
This commit implements the behaviour of the SECTIONS linker script directive,<br>
used to not only define a custom mapping between input and output sections, but<br>
also order input sections in the output file. To do this, we modify<br>
DefaultLayout with hooks at important places that allow us to re-order input<br>
sections according to a custom order. We also add a hook in SegmentChunk to<br>
allow us to calculate linker script expressions while assigning virtual<br>
addresses to the input sections that live in a segment.<br>
<br>
Not all SECTIONS constructs are currently supported, but only the ones that do<br>
not use special sort orders. It adds two LIT test as practical examples of<br>
which sections directives are currently supported.<br>
</blockquote></span>
missed lit tests ?<div class="HOEnZb"><div class="h5"><br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
In terms of high-level changes, it creates a new class "script::Sema" that owns<br>
all linker script ASTs and the logic for linker script semantics as well.<br>
ELFLinkingContext owns a single copy of Sema, which will be used throughout<br>
the object file writing process (to layout sections as proposed by the linker<br>
script).<br>
<br>
Other high-level change is that the writer no longer uses a "const" copy of<br>
the linking context. This happens because linker script expressions must be<br>
calculated *while* calculating final virtual addresses, which is a very late<br>
step in object file writing. While calculating these expressions, we need to<br>
update the linker script symbol table (inside the semantics object), and, thus,<br>
we are "modifying our context" as we prepare to write the file.<br>
<br>
<a href="http://reviews.llvm.org/D8157" target="_blank">http://reviews.llvm.org/D8157</a><br>
<br>
Modified:<br>
     lld/trunk/include/lld/<u></u>ReaderWriter/<u></u>ELFLinkingContext.h<br>
     lld/trunk/include/lld/<u></u>ReaderWriter/LinkerScript.h<br>
     lld/trunk/lib/Driver/<u></u>GnuLdDriver.cpp<br>
     lld/trunk/lib/ReaderWriter/<u></u>ELF/Chunk.h<br>
     lld/trunk/lib/ReaderWriter/<u></u>ELF/DefaultLayout.h<br>
     lld/trunk/lib/ReaderWriter/<u></u>ELF/ELFLinkingContext.cpp<br>
     lld/trunk/lib/ReaderWriter/<u></u>ELF/Hexagon/<u></u>HexagonTargetHandler.h<br>
     lld/trunk/lib/ReaderWriter/<u></u>ELF/Mips/MipsTargetHandler.h<br>
     lld/trunk/lib/ReaderWriter/<u></u>ELF/SectionChunks.h<br>
     lld/trunk/lib/ReaderWriter/<u></u>ELF/SegmentChunks.h<br>
     lld/trunk/lib/ReaderWriter/<u></u>ELF/TargetLayout.h<br>
     lld/trunk/lib/ReaderWriter/<u></u>LinkerScript.cpp<br>
     lld/trunk/unittests/<u></u>DriverTests/GnuLdDriverTest.<u></u>cpp<br>
<br>
Modified: lld/trunk/include/lld/<u></u>ReaderWriter/<u></u>ELFLinkingContext.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h?rev=232402&r1=232401&r2=232402&view=diff" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/lld/trunk/include/lld/<u></u>ReaderWriter/<u></u>ELFLinkingContext.h?rev=<u></u>232402&r1=232401&r2=232402&<u></u>view=diff</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- lld/trunk/include/lld/<u></u>ReaderWriter/<u></u>ELFLinkingContext.h (original)<br>
+++ lld/trunk/include/lld/<u></u>ReaderWriter/<u></u>ELFLinkingContext.h Mon Mar 16 14:55:15 2015<br>
@@ -298,16 +298,6 @@ public:<br>
    bool collectStats() const { return _collectStats; }<br>
    void setCollectStats(bool s) { _collectStats = s; }<br>
  -  // We can parse several linker scripts via command line whose ASTs are stored<br>
-  // in the current linking context via addLinkerScript().<br>
-  void addLinkerScript(std::unique_<u></u>ptr<script::Parser> script) {<br>
-    _scripts.push_back(std::move(<u></u>script));<br>
-  }<br>
-<br>
-  const std::vector<std::unique_ptr<<u></u>script::Parser>> &scripts() const {<br>
-    return _scripts;<br>
-  }<br>
-<br>
    // --wrap option.<br>
    void addWrapForSymbol(StringRef sym) { _wrapCalls.insert(sym); }<br>
  @@ -315,6 +305,8 @@ public:<br>
      void setUndefinesResolver(std::<u></u>unique_ptr<File> resolver);<br>
  +  script::Sema &linkerScriptSema() { return _linkerScriptSema; }<br>
+<br>
  private:<br>
    ELFLinkingContext() = delete;<br>
  @@ -358,8 +350,11 @@ protected:<br>
    llvm::StringSet<> _wrapCalls;<br>
    std::map<std::string, uint64_t> _absoluteSymbols;<br>
    llvm::StringSet<> _dynamicallyExportedSymbols;<br>
-  std::vector<std::unique_ptr<<u></u>script::Parser>> _scripts;<br>
    std::unique_ptr<File> _resolver;<br>
+<br>
+  // The linker script semantic object, which owns all script ASTs, is stored<br>
+  // in the current linking context via _linkerScriptSema.<br>
+  script::Sema _linkerScriptSema;<br>
  };<br>
  } // end namespace lld<br>
  <br>
Modified: lld/trunk/include/lld/<u></u>ReaderWriter/LinkerScript.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/LinkerScript.h?rev=232402&r1=232401&r2=232402&view=diff" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/lld/trunk/include/lld/<u></u>ReaderWriter/LinkerScript.h?<u></u>rev=232402&r1=232401&r2=<u></u>232402&view=diff</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- lld/trunk/include/lld/<u></u>ReaderWriter/LinkerScript.h (original)<br>
+++ lld/trunk/include/lld/<u></u>ReaderWriter/LinkerScript.h Mon Mar 16 14:55:15 2015<br>
@@ -18,6 +18,8 @@<br>
  #include "lld/Core/Error.h"<br>
  #include "lld/Core/LLVM.h"<br>
  #include "lld/Core/range.h"<br>
+#include "llvm/ADT/DenseSet.h"<br>
+#include "llvm/ADT/DenseMap.h"<br>
  #include "llvm/ADT/StringMap.h"<br>
  #include "llvm/ADT/StringSwitch.h"<br>
  #include "llvm/Support/Allocator.h"<br>
@@ -26,6 +28,7 @@<br>
  #include "llvm/Support/raw_ostream.h"<br>
  #include <memory><br>
  #include <system_error><br>
+#include <unordered_map><br>
  #include <vector><br>
    namespace lld {<br>
@@ -159,6 +162,7 @@ public:<br>
      Group,<br>
      Input,<br>
      InputSectionsCmd,<br>
+    InputSectionName,<br>
      Memory,<br>
      Output,<br>
      OutputArch,<br>
@@ -167,6 +171,7 @@ public:<br>
      Overlay,<br>
      SearchDir,<br>
      Sections,<br>
+    SortedGroup,<br>
      SymbolAssignment,<br>
    };<br>
  @@ -604,23 +609,15 @@ enum class WildcardSortMode {<br>
  ///   .y: { *(SORT(.text*)) }<br>
  ///   /*      ^~~~~~~~~~~^  InputSectionSortedGroup : InputSection  */<br>
  /// }<br>
-class InputSection {<br>
+class InputSection : public Command {<br>
  public:<br>
-  enum class Kind { InputSectionName, SortedGroup };<br>
-<br>
-  Kind getKind() const { return _kind; }<br>
-  inline llvm::BumpPtrAllocator &getAllocator() const;<br>
-<br>
-  virtual void dump(raw_ostream &os) const = 0;<br>
-<br>
-  virtual ~InputSection() {}<br>
+  static bool classof(const Command *c) {<br>
+    return c->getKind() == Kind::InputSectionName ||<br>
+           c->getKind() == Kind::SortedGroup;<br>
+  }<br>
    protected:<br>
-  InputSection(Parser &ctx, Kind k) : _ctx(ctx), _kind(k) {}<br>
-<br>
-private:<br>
-  Parser &_ctx;<br>
-  Kind _kind;<br>
+  InputSection(Parser &ctx, Kind k) : Command(ctx, k) {}<br>
  };<br>
    class InputSectionName : public InputSection {<br>
@@ -631,10 +628,11 @@ public:<br>
      void dump(raw_ostream &os) const override;<br>
  -  static bool classof(const InputSection *c) {<br>
+  static bool classof(const Command *c) {<br>
      return c->getKind() == Kind::InputSectionName;<br>
    }<br>
    bool hasExcludeFile() const { return _excludeFile; }<br>
+  StringRef name() const { return _name; }<br>
    private:<br>
    StringRef _name;<br>
@@ -643,6 +641,8 @@ private:<br>
    class InputSectionSortedGroup : public InputSection {<br>
  public:<br>
+  typedef llvm::ArrayRef<const InputSection *>::const_iterator const_iterator;<br>
+<br>
    InputSectionSortedGroup(Parser &ctx, WildcardSortMode sort,<br>
                            const SmallVectorImpl<const InputSection *> &sections)<br>
        : InputSection(ctx, Kind::SortedGroup), _sortMode(sort) {<br>
@@ -654,12 +654,15 @@ public:<br>
    }<br>
      void dump(raw_ostream &os) const override;<br>
-  WildcardSortMode getSortMode() const { return _sortMode; }<br>
+  WildcardSortMode sortMode() const { return _sortMode; }<br>
  -  static bool classof(const InputSection *c) {<br>
+  static bool classof(const Command *c) {<br>
      return c->getKind() == Kind::SortedGroup;<br>
    }<br>
  +  const_iterator begin() const { return _sections.begin(); }<br>
+  const_iterator end() const { return _sections.end(); }<br>
+<br>
  private:<br>
    WildcardSortMode _sortMode;<br>
    llvm::ArrayRef<const InputSection *> _sections;<br>
@@ -677,13 +680,14 @@ private:<br>
  /// }<br>
  class InputSectionsCmd : public Command {<br>
  public:<br>
+  typedef llvm::ArrayRef<const InputSection *>::const_iterator const_iterator;<br>
    typedef std::vector<const InputSection *> VectorTy;<br>
  -  InputSectionsCmd(Parser &ctx, StringRef fileName, StringRef archiveName,<br>
+  InputSectionsCmd(Parser &ctx, StringRef memberName, StringRef archiveName,<br>
                     bool keep, WildcardSortMode fileSortMode,<br>
                     WildcardSortMode archiveSortMode,<br>
                     const SmallVectorImpl<const InputSection *> &sections)<br>
-      : Command(ctx, Kind::InputSectionsCmd), _fileName(fileName),<br>
+      : Command(ctx, Kind::InputSectionsCmd), _memberName(memberName),<br>
          _archiveName(archiveName), _keep(keep), _fileSortMode(fileSortMode),<br>
          _archiveSortMode(<u></u>archiveSortMode) {<br>
      size_t numSections = sections.size();<br>
@@ -699,8 +703,15 @@ public:<br>
      return c->getKind() == Kind::InputSectionsCmd;<br>
    }<br>
  +  StringRef memberName() const { return _memberName; }<br>
+  StringRef archiveName() const { return _archiveName; }<br>
+  const_iterator begin() const { return _sections.begin(); }<br>
+  const_iterator end() const { return _sections.end(); }<br>
+  WildcardSortMode archiveSortMode() const { return _archiveSortMode; }<br>
+  WildcardSortMode fileSortMode() const { return _fileSortMode; }<br>
+<br>
  private:<br>
-  StringRef _fileName;<br>
+  StringRef _memberName;<br>
    StringRef _archiveName;<br>
    bool _keep;<br>
    WildcardSortMode _fileSortMode;<br>
@@ -724,6 +735,8 @@ class OutputSectionDescription : public<br>
  public:<br>
    enum Constraint { C_None, C_OnlyIfRO, C_OnlyIfRW };<br>
  +  typedef llvm::ArrayRef<const Command *>::const_iterator const_iterator;<br>
+<br>
    OutputSectionDescription(<br>
        Parser &ctx, StringRef sectionName, const Expression *address,<br>
        const Expression *align, const Expression *subAlign, const Expression *at,<br>
@@ -749,6 +762,10 @@ public:<br>
      void dump(raw_ostream &os) const override;<br>
  +  const_iterator begin() const { return _outputSectionCommands.begin()<u></u>; }<br>
+  const_iterator end() const { return _outputSectionCommands.end(); }<br>
+  StringRef name() const { return _sectionName; }<br>
+<br>
  private:<br>
    StringRef _sectionName;<br>
    const Expression *_address;<br>
@@ -1174,15 +1191,195 @@ private:<br>
    Token _bufferedToken;<br>
  };<br>
  +/// script::Sema traverses all parsed linker script structures and populate<br>
+/// internal data structures to be able to answer the following questions:<br>
+///<br>
+///   * According to the linker script, which input section goes first in the<br>
+///     output file layout, input section A or input section B?<br>
+///<br>
+///   * What is the name of the output section that input section A should be<br>
+///     mapped to?<br>
+///<br>
+///   * Which linker script expressions should be calculated before emitting<br>
+///     a given section?<br>
+///<br>
+///   * How to evaluate a given linker script expression?<br>
+///<br>
+class Sema {<br>
+public:<br>
+  /// From the linker script point of view, this class represents the minimum<br>
+  /// set of information to uniquely identify an input section.<br>
+  struct SectionKey {<br>
+    StringRef archivePath;<br>
+    StringRef memberPath;<br>
+    StringRef sectionName;<br>
+  };<br>
+<br>
+  Sema();<br>
+<br>
+  /// We can parse several linker scripts via command line whose ASTs are stored<br>
+  /// here via addLinkerScript().<br>
+  void addLinkerScript(std::unique_<u></u>ptr<Parser> script) {<br>
+    _scripts.push_back(std::move(<u></u>script));<br>
+  }<br>
+<br>
+  const std::vector<std::unique_ptr<<u></u>Parser>> &getLinkerScripts() {<br>
+    return _scripts;<br>
+  }<br>
+<br>
+  /// Prepare our data structures according to the linker scripts currently in<br>
+  /// our control (control given via addLinkerScript()). Called once all linker<br>
+  /// scripts have been parsed.<br>
+  void perform();<br>
+<br>
+  /// Answer if we have layout commands (section mapping rules). If we don't,<br>
+  /// the output file writer can assume there is no linker script special rule<br>
+  /// to handle.<br>
+  bool hasLayoutCommands() const { return _layoutCommands.size() > 0; }<br>
+<br>
+  /// Return true if this section has a mapping rule in the linker script<br>
+  bool hasMapping(const SectionKey &key) const {<br>
+    return getLayoutOrder(key, true) >= 0;<br>
+  }<br>
+<br>
+  /// Order function - used to sort input sections in the output file according<br>
+  /// to linker script custom mappings. Return true if lhs should appear before<br>
+  /// rhs.<br>
+  bool less(const SectionKey &lhs, const SectionKey &rhs) const;<br>
+<br>
+  /// Retrieve the name of the output section that this input section is mapped<br>
+  /// to, according to custom linker script mappings.<br>
+  StringRef getOutputSection(const SectionKey &key) const;<br>
+<br>
+  /// Retrieve all the linker script expressions that need to be evaluated<br>
+  /// before the given section is emitted. This is *not* const because the<br>
+  /// first section to retrieve a given set of expression is the only one to<br>
+  /// receive it. This set is marked as "delivered" and no other sections can<br>
+  /// retrieve this set again. If we don't do this, multiple sections may map<br>
+  /// to the same set of expressions because of wildcards rules.<br>
+  std::vector<const SymbolAssignment *> getExprs(const SectionKey &key);<br>
+<br>
+  /// Evaluate a single linker script expression according to our current<br>
+  /// context (symbol table). This function is *not* constant because it can<br>
+  /// update our symbol table with new symbols calculated in this expression.<br>
+  std::error_code evalExpr(const SymbolAssignment *assgn, uint64_t &curPos);<br>
+<br>
+  void dump() const;<br>
+<br>
+private:<br>
+  /// A custom hash operator to teach the STL how to handle our custom keys.<br>
+  /// This will be used in our hash table mapping Sections to a Layout Order<br>
+  /// number (caching results).<br>
+  struct SectionKeyHash {<br>
+    int64_t operator()(const SectionKey &k) const {<br>
+      return llvm::hash_combine(k.<u></u>archivePath, k.memberPath, k.sectionName);<br>
+    }<br>
+  };<br>
+<br>
+  /// Teach the STL when two section keys are the same. This will be used in<br>
+  /// our hash table mapping Sections to a Layout Order number (caching results)<br>
+  struct SectionKeyEq {<br>
+    bool operator()(const SectionKey &lhs, const SectionKey &rhs) const {<br>
+      return ((lhs.archivePath == rhs.archivePath) &&<br>
+              (lhs.memberPath == rhs.memberPath) &&<br>
+              (lhs.sectionName == rhs.sectionName));<br>
+    }<br>
+  };<br>
+<br>
+  /// Given an order id, check if it matches the tuple<br>
+  /// <archivePath, memberPath, sectionName> and returns the<br>
+  /// internal id that matched, or -1 if no matches.<br>
+  int matchSectionName(int id, const SectionKey &key) const;<br>
+<br>
+  /// Returns a number that will determine the order of this input section<br>
+  /// in the final layout. If coarse is true, we simply return the layour order<br>
+  /// of the higher-level node InputSectionsCmd, used to order input sections.<br>
+  /// If coarse is false, we return the layout index down to the internal<br>
+  /// InputSectionsCmd arrangement, used to get the set of preceding linker<br>
+  ///expressions.<br>
+  int getLayoutOrder(const SectionKey &key, bool coarse) const;<br>
+<br>
+  /// Compare two sections that have the same mapping rule (i.e., are matched<br>
+  /// by the same InputSectionsCmd).<br>
+  /// Determine if lhs < rhs by analyzing the InputSectionsCmd structure.<br>
+  bool localCompare(int order, const SectionKey &lhs,<br>
+                    const SectionKey &rhs) const;<br>
+<br>
+<br>
+  /// Our goal with all linearizeAST overloaded functions is to<br>
+  /// traverse the linker script AST while putting nodes in a vector and<br>
+  /// thus enforcing order among nodes (which comes first).<br>
+  ///<br>
+  /// The order among nodes is determined by their indexes in this vector<br>
+  /// (_layoutCommands). This index allows us to solve the problem of<br>
+  /// establishing the order among two different input sections: we match each<br>
+  /// input sections with their respective layout command and use the indexes<br>
+  /// of these commands to order these sections.<br>
+  ///<br>
+  /// Example:<br>
+  ///<br>
+  ///     Given the linker script:<br>
+  ///       SECTIONS {<br>
+  ///         .text : { *(.text) }<br>
+  ///         .data : { *(.data) }<br>
+  ///       }<br>
+  ///<br>
+  ///     The _layoutCommands vector should contain:<br>
+  ///         id 0 : <OutputSectionDescription> (_sectionName = ".text")<br>
+  ///         id 1 : <InputSectionsCmd> (_memberName = "*")<br>
+  ///         id 2 : <InputSectionName> (_name = ".text)<br>
+  ///         id 3 : <OutputSectionDescription> (_sectionName = ".data")<br>
+  ///         id 4 : <InputSectionsCmd> (_memberName = "*")<br>
+  ///         id 5 : <InputSectionName> (_name = ".data")<br>
+  ///<br>
+  ///     If we need to sort the following input sections:<br>
+  ///<br>
+  ///     input section A:  .text from libc.a (member errno.o)<br>
+  ///     input section B:  .data from libc.a (member write.o)<br>
+  ///<br>
+  ///     Then we match input section A with the InputSectionsCmd of id 1, and<br>
+  ///     input section B with the InputSectionsCmd of id 4. Since 1 < 4, we<br>
+  ///     put A before B.<br>
+  ///<br>
+  /// The second problem handled by the linearization of the AST is the task<br>
+  /// of finding all preceding expressions that need to be calculated before<br>
+  /// emitting a given section. This task is easier to deal with when all nodes<br>
+  /// are in a vector because otherwise we would need to traverse multiple<br>
+  /// levels of the AST to find the set of expressions that preceed a layout<br>
+  /// command.<br>
+  ///<br>
+  /// The linker script commands that are linearized ("layout commands") are:<br>
+  ///<br>
+  ///   * OutputSectionDescription, containing an output section name<br>
+  ///   * InputSectionsCmd, containing an input file name<br>
+  ///   * InputSectionName, containing a single input section name<br>
+  ///   * InputSectionSortedName, a group of input section names<br>
+  ///   * SymbolAssignment, containing an expression that may<br>
+  ///     change the address where the linker is outputting data<br>
+  ///<br>
+  void linearizeAST(const Sections *sections);<br>
+  void linearizeAST(const InputSectionsCmd *inputSections);<br>
+  void linearizeAST(const InputSection *inputSection);<br>
+<br>
+  void perform(const LinkerScript *ls);<br>
+<br>
+  std::vector<std::unique_ptr<<u></u>Parser>> _scripts;<br>
+  std::vector<const Command *> _layoutCommands;<br>
+  std::unordered_multimap<std::<u></u>string, int> _memberToLayoutOrder;<br>
+  std::vector<std::pair<<u></u>StringRef, int>> _memberNameWildcards;<br>
+  mutable std::unordered_map<SectionKey, int, SectionKeyHash, SectionKeyEq><br>
+      _cacheSectionOrder, _cacheExpressionOrder;<br>
+  llvm::DenseSet<int> _deliveredExprs;<br>
+<br>
+  Expression::SymbolTableTy _symbolTable;<br>
+};<br>
+<br>
  llvm::BumpPtrAllocator &Command::getAllocator() const {<br>
    return _ctx.getAllocator();<br>
  }<br>
  llvm::BumpPtrAllocator &Expression::getAllocator() const {<br>
    return _ctx.getAllocator();<br>
  }<br>
-llvm::BumpPtrAllocator &InputSection::getAllocator() const {<br>
-  return _ctx.getAllocator();<br>
-}<br>
  } // end namespace script<br>
  } // end namespace lld<br>
  <br>
Modified: lld/trunk/lib/Driver/<u></u>GnuLdDriver.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/GnuLdDriver.cpp?rev=232402&r1=232401&r2=232402&view=diff" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/lld/trunk/lib/Driver/<u></u>GnuLdDriver.cpp?rev=232402&r1=<u></u>232401&r2=232402&view=diff</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- lld/trunk/lib/Driver/<u></u>GnuLdDriver.cpp (original)<br>
+++ lld/trunk/lib/Driver/<u></u>GnuLdDriver.cpp Mon Mar 16 14:55:15 2015<br>
@@ -315,7 +315,7 @@ std::error_code GnuLdDriver::evalLinkerS<br>
      }<br>
    }<br>
    // Transfer ownership of the script to the linking context<br>
-  ctx.addLinkerScript(std::move(<u></u>parser));<br>
+  ctx.linkerScriptSema().<u></u>addLinkerScript(std::move(<u></u>parser));<br>
    return std::error_code();<br>
  }<br>
  @@ -734,6 +734,9 @@ bool GnuLdDriver::parse(int argc, const<br>
    if (!ctx->validate(diag))<br>
      return false;<br>
  +  // Perform linker script semantic actions<br>
+  ctx->linkerScriptSema().<u></u>perform();<br>
+<br>
    context.swap(ctx);<br>
    return true;<br>
  }<br>
<br>
Modified: lld/trunk/lib/ReaderWriter/<u></u>ELF/Chunk.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Chunk.h?rev=232402&r1=232401&r2=232402&view=diff" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/lld/trunk/lib/<u></u>ReaderWriter/ELF/Chunk.h?rev=<u></u>232402&r1=232401&r2=232402&<u></u>view=diff</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- lld/trunk/lib/ReaderWriter/<u></u>ELF/Chunk.h (original)<br>
+++ lld/trunk/lib/ReaderWriter/<u></u>ELF/Chunk.h Mon Mar 16 14:55:15 2015<br>
@@ -39,7 +39,8 @@ public:<br>
                         SectionHeader, ///< Section header<br>
                         ELFSegment,    ///< Segment<br>
                         ELFSection,    ///< Section<br>
-                       AtomSection    ///< A section containing atoms.<br>
+                       AtomSection,   ///< A section containing atoms.<br>
+                       Expression     ///< A linker script expression<br>
    };<br>
    /// \brief the ContentType of the chunk<br>
    enum ContentType : uint8_t{ Unknown, Header, Code, Data, Note, TLS };<br>
<br>
Modified: lld/trunk/lib/ReaderWriter/<u></u>ELF/DefaultLayout.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/DefaultLayout.h?rev=232402&r1=232401&r2=232402&view=diff" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/lld/trunk/lib/<u></u>ReaderWriter/ELF/<u></u>DefaultLayout.h?rev=232402&r1=<u></u>232401&r2=232402&view=diff</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- lld/trunk/lib/ReaderWriter/<u></u>ELF/DefaultLayout.h (original)<br>
+++ lld/trunk/lib/ReaderWriter/<u></u>ELF/DefaultLayout.h Mon Mar 16 14:55:15 2015<br>
@@ -169,7 +169,8 @@ public:<br>
      typedef llvm::DenseSet<const Atom *> AtomSetT;<br>
  -  DefaultLayout(const ELFLinkingContext &context) : _context(context) {}<br>
+  DefaultLayout(<u></u>ELFLinkingContext &context)<br>
+      : _context(context), _linkerScriptSema(context.<u></u>linkerScriptSema()) {}<br>
      /// \brief Return the section order for a input section<br>
    SectionOrder getSectionOrder(StringRef name, int32_t contentType,<br>
@@ -180,13 +181,15 @@ public:<br>
    virtual StringRef getInputSectionName(const DefinedAtom *da) const;<br>
      /// \brief Return the name of the output section from the input section.<br>
-  virtual StringRef getOutputSectionName(StringRef inputSectionName) const;<br>
+  virtual StringRef getOutputSectionName(StringRef archivePath,<br>
+                                         StringRef memberPath,<br>
+                                         StringRef inputSectionName) const;<br>
      /// \brief Gets or creates a section.<br>
    AtomSection<ELFT> *<br>
    getSection(StringRef name, int32_t contentType,<br>
               DefinedAtom::<u></u>ContentPermissions contentPermissions,<br>
-             StringRef path);<br>
+             const DefinedAtom *da);<br>
      /// \brief Gets the segment for a output section<br>
    virtual Layout::SegmentType getSegmentType(Section<ELFT> *section) const;<br>
@@ -215,6 +218,18 @@ public:<br>
    // Output sections with the same name into a OutputSection<br>
    void createOutputSections();<br>
  +  /// \brief Sort the sections by their order as defined by the layout,<br>
+  /// preparing all sections to be assigned to a segment.<br>
+  virtual void sortInputSections();<br>
+<br>
+  /// \brief Add extra chunks to a segment just before including the input<br>
+  /// section given by <archivePath, memberPath, sectionName>. This<br>
+  /// is used to add linker script expressions before each section.<br>
+  virtual void addExtraChunksToSegment(<u></u>Segment<ELFT> *segment,<br>
+                                       StringRef archivePath,<br>
+                                       StringRef memberPath,<br>
+                                       StringRef sectionName);<br>
+<br>
    void assignSectionsToSegments() override;<br>
      void assignVirtualAddress() override;<br>
@@ -323,7 +338,8 @@ protected:<br>
    std::vector<lld::AtomLayout *> _absoluteAtoms;<br>
    AtomSetT _referencedDynAtoms;<br>
    llvm::StringSet<> _copiedDynSymNames;<br>
-  const ELFLinkingContext &_context;<br>
+  ELFLinkingContext &_context;<br>
+  script::Sema &_linkerScriptSema;<br>
  };<br>
    template <class ELFT><br>
@@ -415,7 +431,15 @@ DefaultLayout<ELFT>::<u></u>getInputSectionName<br>
  /// \brief This maps the input sections to the output section names.<br>
  template <class ELFT><br>
  StringRef<br>
-DefaultLayout<ELFT>::<u></u>getOutputSectionName(StringRef inputSectionName) const {<br>
+DefaultLayout<ELFT>::<u></u>getOutputSectionName(StringRef archivePath,<br>
+                                          StringRef memberPath,<br>
+                                          StringRef inputSectionName) const {<br>
+  StringRef outputSectionName;<br>
+  if (_linkerScriptSema.<u></u>hasLayoutCommands() &&<br>
+      !(outputSectionName = _linkerScriptSema.<u></u>getOutputSection(<br>
+           {archivePath, memberPath, inputSectionName})).empty())<br>
+    return outputSectionName;<br>
+<br>
    return llvm::StringSwitch<StringRef>(<u></u>inputSectionName)<br>
        .StartsWith(".text", ".text")<br>
        .StartsWith(".ctors", ".ctors")<br>
@@ -533,17 +557,20 @@ template <class ELFT><br>
  AtomSection<ELFT> *<br>
  DefaultLayout<ELFT>::<u></u>getSection(StringRef sectionName, int32_t contentType,<br>
                                  DefinedAtom::<u></u>ContentPermissions permissions,<br>
-                                StringRef path) {<br>
-  const SectionKey sectionKey(sectionName, permissions, path);<br>
-  SectionOrder sectionOrder =<br>
-      getSectionOrder(sectionName, contentType, permissions);<br>
+                                const DefinedAtom *da) {<br>
+  const SectionKey sectionKey(sectionName, permissions, da->file().path());<br>
+  SectionOrder sectionOrder = getSectionOrder(sectionName, contentType, permissions);<br>
    auto sec = _sectionMap.find(sectionKey);<br>
    if (sec != _sectionMap.end())<br>
      return sec->second;<br>
    AtomSection<ELFT> *newSec =<br>
        createSection(sectionName, contentType, permissions, sectionOrder);<br>
-  newSec->setOutputSectionName(<u></u>getOutputSectionName(<u></u>sectionName));<br>
+<br>
+  newSec->setOutputSectionName(<u></u>getOutputSectionName(<br>
+      da->file().archivePath(), da->file().memberPath(), sectionName));<br>
    newSec->setOrder(sectionOrder)<u></u>;<br>
+  newSec->setArchiveNameOrPath(<u></u>da->file().archivePath());<br>
+  newSec->setMemberNameOrPath(<u></u>da->file().memberPath());<br>
    _sections.push_back(newSec);<br>
    _sectionMap.insert(std::make_<u></u>pair(sectionKey, newSec));<br>
    return newSec;<br>
@@ -563,8 +590,8 @@ DefaultLayout<ELFT>::addAtom(<u></u>const Atom<br>
      const DefinedAtom::ContentType contentType = definedAtom->contentType();<br>
        StringRef sectionName = getInputSectionName(<u></u>definedAtom);<br>
-    AtomSection<ELFT> *section = getSection(<br>
-        sectionName, contentType, permissions, definedAtom->file().path());<br>
+    AtomSection<ELFT> *section =<br>
+        getSection(sectionName, contentType, permissions, definedAtom);<br>
        // Add runtime relocations to the .rela section.<br>
      for (const auto &reloc : *definedAtom) {<br>
@@ -632,10 +659,7 @@ template <class ELFT> void DefaultLayout<br>
    ScopedTask task(getDefaultDomain(), "assignSectionsToSegments");<br>
    ELFLinkingContext::OutputMagic outputMagic = _context.getOutputMagic();<br>
    // sort the sections by their order as defined by the layout<br>
-  std::stable_sort(_sections.<u></u>begin(), _sections.end(),<br>
-                   [](Chunk<ELFT> *A, Chunk<ELFT> *B) {<br>
-    return A->order() < B->order();<br>
-  });<br>
+  sortInputSections();<br>
    // Create output sections.<br>
    createOutputSections();<br>
    // Set the ordinal after sorting the sections<br>
@@ -686,8 +710,8 @@ template <class ELFT> void DefaultLayout<br>
            if (!additionalSegmentInsert.<u></u>second) {<br>
              segment = additionalSegmentInsert.first-<u></u>>second;<br>
            } else {<br>
-            segment = new (_allocator) Segment<ELFT>(_context, segmentName,<br>
-                                                     segmentType);<br>
+            segment = new (_allocator)<br>
+                Segment<ELFT>(_context, segmentName, segmentType);<br>
              additionalSegmentInsert.first-<u></u>>second = segment;<br>
              _segments.push_back(segment);<br>
            }<br>
@@ -713,11 +737,16 @@ template <class ELFT> void DefaultLayout<br>
          if (!segmentInsert.second) {<br>
            segment = segmentInsert.first->second;<br>
          } else {<br>
-          segment = new (_allocator) Segment<ELFT>(_context, "PT_LOAD",<br>
-                                                   llvm::ELF::PT_LOAD);<br>
+          segment = new (_allocator)<br>
+              Segment<ELFT>(_context, "PT_LOAD", llvm::ELF::PT_LOAD);<br>
            segmentInsert.first->second = segment;<br>
            _segments.push_back(segment);<br>
          }<br>
+        // Insert chunks with linker script expressions that occur at this<br>
+        // point, just before appending a new input section<br>
+        addExtraChunksToSegment(<u></u>segment, section->archivePath(),<br>
+                                section->memberPath(),<br>
+                                section->inputSectionName());<br>
          segment->append(section);<br>
        }<br>
      }<br>
@@ -754,6 +783,7 @@ DefaultLayout<ELFT>::<u></u>assignVirtualAddres<br>
        break;<br>
      }<br>
    }<br>
+  assert(firstLoadSegment != nullptr && "No loadable segment!");<br>
    firstLoadSegment->prepend(_<u></u>programHeader);<br>
    firstLoadSegment->prepend(_<u></u>elfHeader);<br>
    bool newSegmentHeaderAdded = true;<br>
@@ -870,6 +900,86 @@ void DefaultLayout<ELFT>::<u></u>assignFileOffs<br>
      fileoffset += si->fileSize();<br>
    }<br>
  }<br>
+<br>
+template <class ELFT> void DefaultLayout<ELFT>::<u></u>sortInputSections() {<br>
+  // First, sort according to default layout's order<br>
+  std::stable_sort(<br>
+      _sections.begin(), _sections.end(),<br>
+      [](Chunk<ELFT> *A, Chunk<ELFT> *B) { return A->order() < B->order(); });<br>
+<br>
+  if (!_linkerScriptSema.<u></u>hasLayoutCommands())<br>
+    return;<br>
+<br>
+  // Sort the sections by their order as defined by the linker script<br>
+  std::stable_sort(this->_<u></u>sections.begin(), this->_sections.end(),<br>
+                   [this](Chunk<ELFT> *A, Chunk<ELFT> *B) {<br>
+                     auto *a = dyn_cast<Section<ELFT>>(A);<br>
+                     auto *b = dyn_cast<Section<ELFT>>(B);<br>
+<br>
+                     if (a == nullptr)<br>
+                       return false;<br>
+                     if (b == nullptr)<br>
+                       return true;<br>
+<br>
+                     return _linkerScriptSema.less(<br>
+                         {a->archivePath(), a->memberPath(),<br>
+                          a->inputSectionName()},<br>
+                         {b->archivePath(), b->memberPath(),<br>
+                          b->inputSectionName()});<br>
+                   });<br>
+  // Now try to arrange sections with no mapping rules to sections with<br>
+  // similar content<br>
+  auto p = this->_sections.begin();<br>
+  // Find first section that has no assigned rule id<br>
+  while (p != this->_sections.end()) {<br>
+    auto *sect = dyn_cast<AtomSection<ELFT>>(*<u></u>p);<br>
+    if (!sect)<br>
+      break;<br>
+<br>
+    if (!_linkerScriptSema.<u></u>hasMapping({sect->archivePath(<u></u>),<br>
+                                       sect->memberPath(),<br>
+                                       sect->inputSectionName()}))<br>
+      break;<br>
+<br>
+    ++p;<br>
+  }<br>
+  // For all sections that have no assigned rule id, try to move them near a<br>
+  // section with similar contents<br>
+  if (p != this->_sections.begin()) {<br>
+    for (; p != this->_sections.end(); ++p) {<br>
+      auto q = p;<br>
+      --q;<br>
+      while (q != this->_sections.begin() &&<br>
+             (*q)->getContentType() != (*p)->getContentType())<br>
+        --q;<br>
+      if ((*q)->getContentType() != (*p)->getContentType())<br>
+        continue;<br>
+      ++q;<br>
+      for (auto i = p; i != q;) {<br>
+        auto next = i--;<br>
+        std::iter_swap(i, next);<br>
+      }<br>
+    }<br>
+  }<br>
+}<br>
+<br>
+template <class ELFT><br>
+void DefaultLayout<ELFT>::<u></u>addExtraChunksToSegment(<u></u>Segment<ELFT> *segment,<br>
+                                                  StringRef archivePath,<br>
+                                                  StringRef memberPath,<br>
+                                                  StringRef sectionName) {<br>
+  if (!_linkerScriptSema.<u></u>hasLayoutCommands())<br>
+    return;<br>
+<br>
+  std::vector<const script::SymbolAssignment *> exprs =<br>
+      _linkerScriptSema.getExprs({<u></u>archivePath, memberPath, sectionName});<br>
+  for (auto expr : exprs) {<br>
+    auto expChunk =<br>
+        new (this->_allocator) ExpressionChunk<ELFT>(this->_<u></u>context, expr);<br>
+    segment->append(expChunk);<br>
+  }<br>
+}<br>
+<br>
  } // end namespace elf<br>
  } // end namespace lld<br>
  <br>
Modified: lld/trunk/lib/ReaderWriter/<u></u>ELF/ELFLinkingContext.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp?rev=232402&r1=232401&r2=232402&view=diff" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/lld/trunk/lib/<u></u>ReaderWriter/ELF/<u></u>ELFLinkingContext.cpp?rev=<u></u>232402&r1=232401&r2=232402&<u></u>view=diff</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- lld/trunk/lib/ReaderWriter/<u></u>ELF/ELFLinkingContext.cpp (original)<br>
+++ lld/trunk/lib/ReaderWriter/<u></u>ELF/ELFLinkingContext.cpp Mon Mar 16 14:55:15 2015<br>
@@ -47,7 +47,7 @@ ELFLinkingContext::<u></u>ELFLinkingContext(<br>
        _mergeRODataToTextSegment(<u></u>true), _demangle(true),<br>
        _stripSymbols(false), _alignSegments(true), _collectStats(false),<br>
        _outputMagic(OutputMagic::<u></u>DEFAULT), _initFunction("_init"),<br>
-      _finiFunction("_fini"), _sysrootPath("") {}<br>
+      _finiFunction("_fini"), _sysrootPath(""), _linkerScriptSema() {}<br>
    void ELFLinkingContext::addPasses(<u></u>PassManager &pm) {<br>
    pm.add(llvm::make_unique<elf::<u></u>OrderPass>());<br>
<br>
Modified: lld/trunk/lib/ReaderWriter/<u></u>ELF/Hexagon/<u></u>HexagonTargetHandler.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h?rev=232402&r1=232401&r2=232402&view=diff" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/lld/trunk/lib/<u></u>ReaderWriter/ELF/Hexagon/<u></u>HexagonTargetHandler.h?rev=<u></u>232402&r1=232401&r2=232402&<u></u>view=diff</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- lld/trunk/lib/ReaderWriter/<u></u>ELF/Hexagon/<u></u>HexagonTargetHandler.h (original)<br>
+++ lld/trunk/lib/ReaderWriter/<u></u>ELF/Hexagon/<u></u>HexagonTargetHandler.h Mon Mar 16 14:55:15 2015<br>
@@ -29,7 +29,7 @@ public:<br>
      ORDER_SDATA = 205<br>
    };<br>
  -  HexagonTargetLayout(const HexagonLinkingContext &hti)<br>
+  HexagonTargetLayout(<u></u>HexagonLinkingContext &hti)<br>
        : TargetLayout<HexagonELFType>(<u></u>hti), _sdataSection(nullptr),<br>
          _gotSymAtom(nullptr), _cachedGotSymAtom(false) {<br>
      _sdataSection = new (_alloc) SDataSection<HexagonELFType>(<u></u>hti);<br>
<br>
Modified: lld/trunk/lib/ReaderWriter/<u></u>ELF/Mips/MipsTargetHandler.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h?rev=232402&r1=232401&r2=232402&view=diff" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/lld/trunk/lib/<u></u>ReaderWriter/ELF/Mips/<u></u>MipsTargetHandler.h?rev=<u></u>232402&r1=232401&r2=232402&<u></u>view=diff</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- lld/trunk/lib/ReaderWriter/<u></u>ELF/Mips/MipsTargetHandler.h (original)<br>
+++ lld/trunk/lib/ReaderWriter/<u></u>ELF/Mips/MipsTargetHandler.h Mon Mar 16 14:55:15 2015<br>
@@ -26,7 +26,7 @@ namespace elf {<br>
  template <class ELFType><br>
  class MipsTargetLayout final : public TargetLayout<ELFType> {<br>
  public:<br>
-  MipsTargetLayout(const MipsLinkingContext &ctx)<br>
+  MipsTargetLayout(<u></u>MipsLinkingContext &ctx)<br>
        : TargetLayout<ELFType>(ctx),<br>
          _gotSection(new (_alloc) MipsGOTSection<ELFType>(ctx)),<br>
          _pltSection(new (_alloc) MipsPLTSection<ELFType>(ctx)) {}<br>
<br>
Modified: lld/trunk/lib/ReaderWriter/<u></u>ELF/SectionChunks.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h?rev=232402&r1=232401&r2=232402&view=diff" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/lld/trunk/lib/<u></u>ReaderWriter/ELF/<u></u>SectionChunks.h?rev=232402&r1=<u></u>232401&r2=232402&view=diff</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- lld/trunk/lib/ReaderWriter/<u></u>ELF/SectionChunks.h (original)<br>
+++ lld/trunk/lib/ReaderWriter/<u></u>ELF/SectionChunks.h Mon Mar 16 14:55:15 2015<br>
@@ -123,6 +123,14 @@ public:<br>
      _outputSectionName = outputSectionName;<br>
    }<br>
  +  void setArchiveNameOrPath(StringRef name) { _archivePath = name; }<br>
+<br>
+  void setMemberNameOrPath(StringRef name) { _memberPath = name; }<br>
+<br>
+  StringRef archivePath() { return _archivePath; }<br>
+<br>
+  StringRef memberPath() { return _memberPath; }<br>
+<br>
  protected:<br>
    /// \brief OutputSection this Section is a member of, or nullptr.<br>
    OutputSection<ELFT> *_outputSection;<br>
@@ -144,6 +152,8 @@ protected:<br>
    StringRef _inputSectionName;<br>
    /// \brief Output section name.<br>
    StringRef _outputSectionName;<br>
+  StringRef _archivePath;<br>
+  StringRef _memberPath;<br>
  };<br>
    /// \brief A section containing atoms.<br>
<br>
Modified: lld/trunk/lib/ReaderWriter/<u></u>ELF/SegmentChunks.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h?rev=232402&r1=232401&r2=232402&view=diff" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/lld/trunk/lib/<u></u>ReaderWriter/ELF/<u></u>SegmentChunks.h?rev=232402&r1=<u></u>232401&r2=232402&view=diff</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- lld/trunk/lib/ReaderWriter/<u></u>ELF/SegmentChunks.h (original)<br>
+++ lld/trunk/lib/ReaderWriter/<u></u>ELF/SegmentChunks.h Mon Mar 16 14:55:15 2015<br>
@@ -269,6 +269,37 @@ protected:<br>
    llvm::BumpPtrAllocator _segmentAllocate;<br>
  };<br>
  +/// This chunk represents a linker script expression that needs to be calculated<br>
+/// at the time the virtual addresses for the parent segment are being assigned.<br>
+template <class ELFT> class ExpressionChunk : public Chunk<ELFT> {<br>
+public:<br>
+  ExpressionChunk(<u></u>ELFLinkingContext &ctx, const script::SymbolAssignment *expr)<br>
+      : Chunk<ELFT>(StringRef(), Chunk<ELFT>::Kind::Expression, ctx),<br>
+        _expr(expr), _linkerScriptSema(ctx.<u></u>linkerScriptSema()) {<br>
+    this->_alignment = 1;<br>
+  }<br>
+<br>
+  static bool classof(const Chunk<ELFT> *c) {<br>
+    return c->kind() == Chunk<ELFT>::Kind::Expression;<br>
+  }<br>
+<br>
+  int getContentType() const override {<br>
+    return Chunk<ELFT>::ContentType::<u></u>Unknown;<br>
+  }<br>
+  void write(ELFWriter *, TargetLayout<ELFT> &,<br>
+             llvm::FileOutputBuffer &) override {}<br>
+  void doPreFlight() override {}<br>
+  void finalize() override {}<br>
+<br>
+  std::error_code evalExpr(uint64_t &curPos) {<br>
+    return _linkerScriptSema.evalExpr(_<u></u>expr, curPos);<br>
+  }<br>
+<br>
+private:<br>
+  const script::SymbolAssignment *_expr;<br>
+  script::Sema &_linkerScriptSema;<br>
+};<br>
+<br>
  /// \brief A Program Header segment contains a set of chunks instead of sections<br>
  /// The segment doesn't contain any slice<br>
  template <class ELFT> class ProgramHeaderSegment : public Segment<ELFT> {<br>
@@ -390,11 +421,16 @@ void Segment<ELFT>::<u></u>assignFileOffsets(ui<br>
    bool isDataPageAlignedForNMagic = false;<br>
    bool alignSegments = this->_context.alignSegments()<u></u>;<br>
    uint64_t p_align = this->_context.getPageSize();<br>
+  uint64_t lastVirtualAddress = 0;<br>
      this->setFileOffset(<u></u>startOffset);<br>
    for (auto &slice : slices()) {<br>
      bool isFirstSection = true;<br>
      for (auto section : slice->sections()) {<br>
+      // Handle linker script expressions, which may change the offset<br>
+      if (!isFirstSection)<br>
+        if (auto expr = dyn_cast<ExpressionChunk<ELFT><u></u>>(section))<br>
+          fileOffset += expr->virtualAddr() - lastVirtualAddress;<br>
        // Align fileoffset to the alignment of the section.<br>
        fileOffset = llvm::RoundUpToAlignment(<u></u>fileOffset, section->alignment());<br>
        // If the linker outputmagic is set to OutputMagic::NMAGIC, align the Data<br>
@@ -429,6 +465,7 @@ void Segment<ELFT>::<u></u>assignFileOffsets(ui<br>
        }<br>
        section->setFileOffset(<u></u>fileOffset);<br>
        fileOffset += section->fileSize();<br>
+      lastVirtualAddress = section->virtualAddr() + section->memSize();<br>
      }<br>
      slice->setFileSize(fileOffset - curSliceFileOffset);<br>
    }<br>
@@ -457,7 +494,7 @@ template <class ELFT> void Segment<ELFT><br>
    SegmentSlice<ELFT> *slice = nullptr;<br>
    uint64_t tlsStartAddr = 0;<br>
    bool alignSegments = this->_context.alignSegments()<u></u>;<br>
-  StringRef prevOutputSectionName;<br>
+  StringRef prevOutputSectionName = StringRef();<br>
      for (auto si = _sections.begin(); si != _sections.end(); ++si) {<br>
      // If this is first section in the segment, page align the section start<br>
@@ -481,6 +518,10 @@ template <class ELFT> void Segment<ELFT><br>
        }<br>
        // align the startOffset to the section alignment<br>
        uint64_t newAddr = llvm::RoundUpToAlignment(<u></u>startAddr, (*si)->alignment());<br>
+      // Handle linker script expressions, which *may update newAddr* if the<br>
+      // expression assigns to "."<br>
+      if (auto expr = dyn_cast<ExpressionChunk<ELFT><u></u>>(*si))<br>
+        expr->evalExpr(newAddr);<br>
        curSliceAddress = newAddr;<br>
        sliceAlign = (*si)->alignment();<br>
        (*si)->setVirtualAddr(<u></u>curSliceAddress);<br>
@@ -513,9 +554,22 @@ template <class ELFT> void Segment<ELFT><br>
          isDataPageAlignedForNMagic = true;<br>
        }<br>
        uint64_t newAddr = llvm::RoundUpToAlignment(<u></u>curAddr, (*si)->alignment());<br>
+      // Handle linker script expressions, which *may update newAddr* if the<br>
+      // expression assigns to "."<br>
+      if (auto expr = dyn_cast<ExpressionChunk<ELFT><u></u>>(*si))<br>
+        expr->evalExpr(newAddr);<br>
        Section<ELFT> *sec = dyn_cast<Section<ELFT>>(*si);<br>
-      StringRef curOutputSectionName =<br>
-          sec ? sec->outputSectionName() : (*si)->name();<br>
+      StringRef curOutputSectionName;<br>
+      if (sec)<br>
+        curOutputSectionName = sec->outputSectionName();<br>
+      else {<br>
+        // If this is a linker script expression, propagate the name of the<br>
+        // previous section instead<br>
+        if (isa<ExpressionChunk<ELFT>>(*<u></u>si))<br>
+          curOutputSectionName = prevOutputSectionName;<br>
+        else<br>
+          curOutputSectionName = (*si)->name();<br>
+      }<br>
        bool autoCreateSlice = true;<br>
        if (curOutputSectionName == prevOutputSectionName)<br>
          autoCreateSlice = false;<br>
<br>
Modified: lld/trunk/lib/ReaderWriter/<u></u>ELF/TargetLayout.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/TargetLayout.h?rev=232402&r1=232401&r2=232402&view=diff" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/lld/trunk/lib/<u></u>ReaderWriter/ELF/TargetLayout.<u></u>h?rev=232402&r1=232401&r2=<u></u>232402&view=diff</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- lld/trunk/lib/ReaderWriter/<u></u>ELF/TargetLayout.h (original)<br>
+++ lld/trunk/lib/ReaderWriter/<u></u>ELF/TargetLayout.h Mon Mar 16 14:55:15 2015<br>
@@ -20,8 +20,7 @@ namespace elf {<br>
  /// be changed in the final layout<br>
  template <class ELFT> class TargetLayout : public DefaultLayout<ELFT> {<br>
  public:<br>
-  TargetLayout(const ELFLinkingContext &context)<br>
-      : DefaultLayout<ELFT>(context) {}<br>
+  TargetLayout(ELFLinkingContext &context) : DefaultLayout<ELFT>(context) {}<br>
  };<br>
  } // end namespace elf<br>
  } // end namespace lld<br>
<br>
Modified: lld/trunk/lib/ReaderWriter/<u></u>LinkerScript.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/LinkerScript.cpp?rev=232402&r1=232401&r2=232402&view=diff" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/lld/trunk/lib/<u></u>ReaderWriter/LinkerScript.cpp?<u></u>rev=232402&r1=232401&r2=<u></u>232402&view=diff</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- lld/trunk/lib/ReaderWriter/<u></u>LinkerScript.cpp (original)<br>
+++ lld/trunk/lib/ReaderWriter/<u></u>LinkerScript.cpp Mon Mar 16 14:55:15 2015<br>
@@ -835,7 +835,7 @@ void InputSectionsCmd::dump(raw_<u></u>ostream<br>
      os << "KEEP(";<br>
      int numParen = dumpSortDirectives(os, _fileSortMode);<br>
-  os << _fileName;<br>
+  os << _memberName;<br>
    for (int i = 0; i < numParen; ++i)<br>
      os << ")";<br>
  @@ -1699,7 +1699,7 @@ const InputSectionsCmd *Parser::parseInp<br>
    bool keep = false;<br>
    WildcardSortMode fileSortMode = WildcardSortMode::NA;<br>
    WildcardSortMode archiveSortMode = WildcardSortMode::NA;<br>
-  StringRef fileName;<br>
+  StringRef memberName;<br>
    StringRef archiveName;<br>
      if (_tok._kind == Token::kw_keep) {<br>
@@ -1715,7 +1715,7 @@ const InputSectionsCmd *Parser::parseInp<br>
      int numParen = parseSortDirectives(<u></u>fileSortMode);<br>
      if (numParen == -1)<br>
        return nullptr;<br>
-    fileName = _tok._range;<br>
+    memberName = _tok._range;<br>
      consumeToken();<br>
      if (numParen) {<br>
        while (numParen--)<br>
@@ -1745,7 +1745,7 @@ const InputSectionsCmd *Parser::parseInp<br>
      if (_tok._kind != Token::l_paren)<br>
      return new (_alloc)<br>
-        InputSectionsCmd(*this, fileName, archiveName, keep, fileSortMode,<br>
+        InputSectionsCmd(*this, memberName, archiveName, keep, fileSortMode,<br>
                           archiveSortMode, inputSections);<br>
    consumeToken();<br>
  @@ -1789,7 +1789,7 @@ const InputSectionsCmd *Parser::parseInp<br>
      if (!expectAndConsume(Token::r_<u></u>paren, "expected )"))<br>
        return nullptr;<br>
    return new (_alloc)<br>
-      InputSectionsCmd(*this, fileName, archiveName, keep, fileSortMode,<br>
+      InputSectionsCmd(*this, memberName, archiveName, keep, fileSortMode,<br>
                         archiveSortMode, inputSections);<br>
  }<br>
  @@ -2141,5 +2141,402 @@ Extern *Parser::parseExtern() {<br>
    return new (_alloc) Extern(*this, symbols);<br>
  }<br>
  -} // end namespace script<br>
+// Sema member functions<br>
+Sema::Sema()<br>
+    : _scripts(), _layoutCommands(), _memberToLayoutOrder(),<br>
+      _memberNameWildcards(), _cacheSectionOrder(), _cacheExpressionOrder(),<br>
+      _deliveredExprs(), _symbolTable() {}<br>
+<br>
+void Sema::perform() {<br>
+  for (auto &parser : _scripts)<br>
+    perform(parser->get());<br>
+}<br>
+<br>
+bool Sema::less(const SectionKey &lhs, const SectionKey &rhs) const {<br>
+  int a = getLayoutOrder(lhs, true);<br>
+  int b = getLayoutOrder(rhs, true);<br>
+<br>
+  if (a != b) {<br>
+    if (a < 0)<br>
+      return false;<br>
+    if (b < 0)<br>
+      return true;<br>
+    return a < b;<br>
+  }<br>
+<br>
+  // If both sections are not mapped anywhere, they have the same order<br>
+  if (a < 0)<br>
+    return false;<br>
+<br>
+  // If both sections fall into the same layout order, we need to find their<br>
+  // relative position as written in the (InputSectionsCmd).<br>
+  return localCompare(a, lhs, rhs);<br>
+}<br>
+<br>
+StringRef Sema::getOutputSection(const SectionKey &key) const {<br>
+  int layoutOrder = getLayoutOrder(key, true);<br>
+  if (layoutOrder < 0)<br>
+    return StringRef();<br>
+<br>
+  for (int i = layoutOrder - 1; i >= 0; --i) {<br>
+    if (!isa<<u></u>OutputSectionDescription>(_<u></u>layoutCommands[i]))<br>
+      continue;<br>
+<br>
+    const OutputSectionDescription *out =<br>
+        dyn_cast<<u></u>OutputSectionDescription>(_<u></u>layoutCommands[i]);<br>
+    return out->name();<br>
+  }<br>
+<br>
+  return StringRef();<br>
+}<br>
+<br>
+std::vector<const SymbolAssignment *><br>
+Sema::getExprs(const SectionKey &key) {<br>
+  int layoutOrder = getLayoutOrder(key, false);<br>
+  auto ans = std::vector<const SymbolAssignment *>();<br>
+<br>
+  if (layoutOrder < 0 || _deliveredExprs.count(<u></u>layoutOrder) > 0)<br>
+    return ans;<br>
+<br>
+  for (int i = layoutOrder - 1; i >= 0; --i) {<br>
+    if (isa<InputSection>(_<u></u>layoutCommands[i]))<br>
+      break;<br>
+    if (auto assgn = dyn_cast<SymbolAssignment>(_<u></u>layoutCommands[i]))<br>
+      ans.push_back(assgn);<br>
+  }<br>
+<br>
+  // Reverse this order so we evaluate the expressions in the original order<br>
+  // of the linker script<br>
+  std::reverse(ans.begin(), ans.end());<br>
+<br>
+  // Mark this layout number as delivered<br>
+  _deliveredExprs.insert(<u></u>layoutOrder);<br>
+  return ans;<br>
+}<br>
+<br>
+std::error_code Sema::evalExpr(const SymbolAssignment *assgn,<br>
+                               uint64_t &curPos) {<br>
+  _symbolTable[StringRef(".")] = curPos;<br>
+<br>
+  auto ans = assgn->expr()->evalExpr(_<u></u>symbolTable);<br>
+  if (ans.getError())<br>
+    return ans.getError();<br>
+  uint64_t result = *ans;<br>
+<br>
+  if (assgn->symbol() == ".") {<br>
+    curPos = result;<br>
+    return std::error_code();<br>
+  }<br>
+<br>
+  _symbolTable[assgn->symbol()] = result;<br>
+  return std::error_code();<br>
+}<br>
+<br>
+void Sema::dump() const {<br>
+  raw_ostream &os = llvm::outs();<br>
+  os << "Linker script semantics dump\n";<br>
+  int num = 0;<br>
+  for (auto &parser : _scripts) {<br>
+    os << "Dumping script #" << ++num << ":\n";<br>
+    parser->get()->dump(os);<br>
+    os << "\n";<br>
+  }<br>
+  os << "Dumping rule ids:\n";<br>
+  for (unsigned i = 0; i < _layoutCommands.size(); ++i) {<br>
+    os << "LayoutOrder " << i << ":\n";<br>
+    _layoutCommands[i]->dump(os);<br>
+    os << "\n\n";<br>
+  }<br>
+}<br>
+<br>
+/// Given a string "pattern" with wildcard characters, return true if it<br>
+/// matches "name". This function is useful when checking if a given name<br>
+/// pattern written in the linker script, i.e. ".text*", should match<br>
+/// ".text.anytext".<br>
+static bool wildcardMatch(StringRef pattern, StringRef name) {<br>
+  auto i = name.begin();<br>
+<br>
+  // Check if each char in pattern also appears in our input name, handling<br>
+  // special wildcard characters.<br>
+  for (auto j = pattern.begin(), e = pattern.end(); j != e; ++j) {<br>
+    if (i == name.end())<br>
+      return false;<br>
+<br>
+    switch (*j) {<br>
+    case '*':<br>
+      while (!wildcardMatch(pattern.drop_<u></u>front(j - pattern.begin() + 1),<br>
+                            name.drop_front(i - name.begin() + 1))) {<br>
+        if (i == name.end())<br>
+          return false;<br>
+        ++i;<br>
+      }<br>
+      break;<br>
+    case '?':<br>
+      // Matches any character<br>
+      break;<br>
+    case '[': {<br>
+      // Matches a range of characters specified between brackets<br>
+      size_t end = pattern.find(']', j - pattern.begin());<br>
+      if (end == pattern.size())<br>
+        return false;<br>
+<br>
+      StringRef chars = pattern.slice(j - pattern.begin(), end);<br>
+      if (chars.find(i) == StringRef::npos)<br>
+        return false;<br>
+<br>
+      j = pattern.begin() + end;<br>
+      break;<br>
+    }<br>
+    case '\\':<br>
+      ++j;<br>
+      if (*j != *i)<br>
+        return false;<br>
+      break;<br>
+    default:<br>
+      // No wildcard character means we must match exactly the same char<br>
+      if (*j != *i)<br>
+        return false;<br>
+      break;<br>
+    }<br>
+    ++i;<br>
+  }<br>
+<br>
+  // If our pattern has't consumed the entire string, it is not a match<br>
+  return i == name.end();<br>
+}<br>
+<br>
+int Sema::matchSectionName(int id, const SectionKey &key) const {<br>
+  const InputSectionsCmd *cmd = dyn_cast<InputSectionsCmd>(_<u></u>layoutCommands[id]);<br>
+<br>
+  if (!cmd || !wildcardMatch(cmd-><u></u>archiveName(), key.archivePath))<br>
+    return -1;<br>
+<br>
+  while ((size_t)++id < _layoutCommands.size() &&<br>
+         (isa<InputSection>(_<u></u>layoutCommands[id]))) {<br>
+    if (isa<InputSectionSortedGroup>(<u></u>_layoutCommands[id]))<br>
+      continue;<br>
+<br>
+    const InputSectionName *in =<br>
+        dyn_cast<InputSectionName>(_<u></u>layoutCommands[id]);<br>
+    if (wildcardMatch(in->name(), key.sectionName))<br>
+      return id;<br>
+  }<br>
+  return -1;<br>
+}<br>
+<br>
+int Sema::getLayoutOrder(const SectionKey &key, bool coarse) const {<br>
+  // First check if we already answered this layout question<br>
+  if (coarse) {<br>
+    auto entry = _cacheSectionOrder.find(key);<br>
+    if (entry != _cacheSectionOrder.end())<br>
+      return entry->second;<br>
+  } else {<br>
+    auto entry = _cacheExpressionOrder.find(<u></u>key);<br>
+    if (entry != _cacheExpressionOrder.end())<br>
+      return entry->second;<br>
+  }<br>
+<br>
+  // Try to match exact file name<br>
+  auto range = _memberToLayoutOrder.equal_<u></u>range(key.memberPath);<br>
+  for (auto I = range.first, E = range.second; I != E; ++I) {<br>
+    int order = I->second;<br>
+    int exprOrder = -1;<br>
+<br>
+    if ((exprOrder = matchSectionName(order, key)) >= 0) {<br>
+      if (coarse) {<br>
+        _cacheSectionOrder.insert(std:<u></u>:make_pair(key, order));<br>
+        return order;<br>
+      }<br>
+      _cacheExpressionOrder.insert(<u></u>std::make_pair(key, exprOrder));<br>
+      return exprOrder;<br>
+    }<br>
+  }<br>
+<br>
+  // If we still couldn't find a rule for this input section, try to match<br>
+  // wildcards<br>
+  for (auto I = _memberNameWildcards.begin(), E = _memberNameWildcards.end();<br>
+       I != E; ++I) {<br>
+    if (!wildcardMatch(I->first, key.memberPath))<br>
+      continue;<br>
+    int order = I->second;<br>
+    int exprOrder = -1;<br>
+<br>
+    if ((exprOrder = matchSectionName(order, key)) >= 0) {<br>
+      if (coarse) {<br>
+        _cacheSectionOrder.insert(std:<u></u>:make_pair(key, order));<br>
+        return order;<br>
+      }<br>
+      _cacheExpressionOrder.insert(<u></u>std::make_pair(key, exprOrder));<br>
+      return exprOrder;<br>
+    }<br>
+  }<br>
+<br>
+  _cacheSectionOrder.insert(std:<u></u>:make_pair(key, -1));<br>
+  _cacheExpressionOrder.insert(<u></u>std::make_pair(key, -1));<br>
+  return -1;<br>
+}<br>
+<br>
+static bool compareSortedNames(<u></u>WildcardSortMode sortMode, StringRef lhs,<br>
+                               StringRef rhs) {<br>
+  switch (sortMode) {<br>
+  case WildcardSortMode::None:<br>
+  case WildcardSortMode::NA:<br>
+    return false;<br>
+  case WildcardSortMode::ByAlignment:<br>
+  case WildcardSortMode::<u></u>ByInitPriority:<br>
+  case WildcardSortMode::<u></u>ByAlignmentAndName:<br>
+    assert(false && "Unimplemented sort order");<br>
+    break;<br>
+  case WildcardSortMode::ByName:<br>
+    return lhs.compare(rhs) < 0;<br>
+  case WildcardSortMode::<u></u>ByNameAndAlignment:<br>
+    int compare = lhs.compare(rhs);<br>
+    if (compare != 0)<br>
+      return compare < 0;<br>
+    return compareSortedNames(<u></u>WildcardSortMode::ByAlignment, lhs, rhs);<br>
+  }<br>
+  return false;<br>
+}<br>
+<br>
+static bool sortedGroupContains(const InputSectionSortedGroup *cmd,<br>
+                                const Sema::SectionKey &key) {<br>
+  for (const InputSection *child : *cmd) {<br>
+    if (auto i = dyn_cast<InputSectionName>(<u></u>child)) {<br>
+      if (wildcardMatch(i->name(), key.sectionName))<br>
+        return true;<br>
+      continue;<br>
+    }<br>
+<br>
+    auto *sortedGroup = dyn_cast<<u></u>InputSectionSortedGroup>(<u></u>child);<br>
+    assert(sortedGroup && "Expected InputSectionSortedGroup object");<br>
+<br>
+    if (sortedGroupContains(<u></u>sortedGroup, key))<br>
+      return true;<br>
+  }<br>
+<br>
+  return false;<br>
+}<br>
+<br>
+bool Sema::localCompare(int order, const SectionKey &lhs,<br>
+                        const SectionKey &rhs) const {<br>
+  const InputSectionsCmd *cmd =<br>
+      dyn_cast<InputSectionsCmd>(_<u></u>layoutCommands[order]);<br>
+<br>
+  assert(cmd && "Invalid InputSectionsCmd index");<br>
+<br>
+  if (lhs.archivePath != rhs.archivePath)<br>
+    return compareSortedNames(cmd-><u></u>archiveSortMode(), lhs.archivePath,<br>
+                              rhs.archivePath);<br>
+<br>
+  if (lhs.memberPath != rhs.memberPath)<br>
+    return compareSortedNames(cmd-><u></u>fileSortMode(), lhs.memberPath,<br>
+                              rhs.memberPath);<br>
+<br>
+  // Both sections come from the same exact same file and rule. Start walking<br>
+  // through input section names as written in the linker script and the<br>
+  // first one to match will have higher priority.<br>
+  for (const InputSection *inputSection : *cmd) {<br>
+    if (auto i = dyn_cast<InputSectionName>(<u></u>inputSection)) {<br>
+      // If both match, return false (both have equal priority)<br>
+      // If rhs match, return false (rhs has higher priority)<br>
+      if (wildcardMatch(i->name(), rhs.sectionName))<br>
+        return false;<br>
+      //  If lhs matches first, it has priority over rhs<br>
+      if (wildcardMatch(i->name(), lhs.sectionName))<br>
+        return true;<br>
+      continue;<br>
+    }<br>
+<br>
+    // Handle sorted subgroups specially<br>
+    auto *sortedGroup = dyn_cast<<u></u>InputSectionSortedGroup>(<u></u>inputSection);<br>
+    assert(sortedGroup && "Expected InputSectionSortedGroup object");<br>
+<br>
+    bool a = sortedGroupContains(<u></u>sortedGroup, lhs);<br>
+    bool b = sortedGroupContains(<u></u>sortedGroup, rhs);<br>
+    if (a && !b)<br>
+      return false;<br>
+    if (b && !a)<br>
+      return true;<br>
+    if (!a && !a)<br>
+      continue;<br>
+<br>
+    return compareSortedNames(<u></u>sortedGroup->sortMode(), lhs.sectionName,<br>
+                              rhs.sectionName);<br>
+  }<br>
+<br>
+  llvm_unreachable("");<br>
+  return false;<br>
+}<br>
+<br>
+static bool hasWildcard(StringRef name) {<br>
+  for (auto ch : name)<br>
+    if (ch == '*' || ch == '?' || ch == '[' || ch == '\\')<br>
+      return true;<br>
+  return false;<br>
+}<br>
+<br>
+void Sema::linearizeAST(const InputSection *inputSection) {<br>
+  if (isa<InputSectionName>(<u></u>inputSection)) {<br>
+    _layoutCommands.push_back(<u></u>inputSection);<br>
+    return;<br>
+  }<br>
+<br>
+  auto *sortedGroup = dyn_cast<<u></u>InputSectionSortedGroup>(<u></u>inputSection);<br>
+  assert(sortedGroup && "Expected InputSectionSortedGroup object");<br>
+<br>
+  for (const InputSection *child : *sortedGroup) {<br>
+    linearizeAST(child);<br>
+  }<br>
+}<br>
+<br>
+void Sema::linearizeAST(const InputSectionsCmd *inputSections) {<br>
+  StringRef memberName = inputSections->memberName();<br>
+  // Populate our maps for fast lookup of InputSectionsCmd<br>
+  if (hasWildcard(memberName))<br>
+    _memberNameWildcards.push_<u></u>back(<br>
+        std::make_pair(memberName, (int)_layoutCommands.size()));<br>
+  else if (!memberName.empty())<br>
+    _memberToLayoutOrder.insert(<br>
+        std::make_pair(memberName.str(<u></u>), (int)_layoutCommands.size()));<br>
+<br>
+  _layoutCommands.push_back(<u></u>inputSections);<br>
+  for (const InputSection *inputSection : *inputSections)<br>
+    linearizeAST(inputSection);<br>
+}<br>
+<br>
+void Sema::linearizeAST(const Sections *sections) {<br>
+  for (const Command *sectionCommand : *sections) {<br>
+    if (isa<SymbolAssignment>(<u></u>sectionCommand)) {<br>
+      _layoutCommands.push_back(<u></u>sectionCommand);<br>
+      continue;<br>
+    }<br>
+<br>
+    if (!isa<<u></u>OutputSectionDescription>(<u></u>sectionCommand))<br>
+      continue;<br>
+<br>
+    _layoutCommands.push_back(<u></u>sectionCommand);<br>
+    auto *outSection = dyn_cast<<u></u>OutputSectionDescription>(<u></u>sectionCommand);<br>
+<br>
+    for (const Command *outSecCommand : *outSection) {<br>
+      if (isa<SymbolAssignment>(<u></u>outSecCommand)) {<br>
+        _layoutCommands.push_back(<u></u>outSecCommand);<br>
+        continue;<br>
+      }<br>
+<br>
+      if (!isa<InputSectionsCmd>(<u></u>outSecCommand))<br>
+        continue;<br>
+<br>
+      linearizeAST(dyn_cast<<u></u>InputSectionsCmd>(<u></u>outSecCommand));<br>
+    }<br>
+  }<br>
+}<br>
+<br>
+void Sema::perform(const LinkerScript *ls) {<br>
+  for (const Command *c : ls->_commands) {<br>
+    if (const Sections *sec = dyn_cast<Sections>(c))<br>
+      linearizeAST(sec);<br>
+  }<br>
+}<br>
+<br>
+} // End namespace script<br>
  } // end namespace lld<br>
<br>
Modified: lld/trunk/unittests/<u></u>DriverTests/GnuLdDriverTest.<u></u>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp?rev=232402&r1=232401&r2=232402&view=diff" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/lld/trunk/unittests/<u></u>DriverTests/GnuLdDriverTest.<u></u>cpp?rev=232402&r1=232401&r2=<u></u>232402&view=diff</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- lld/trunk/unittests/<u></u>DriverTests/GnuLdDriverTest.<u></u>cpp (original)<br>
+++ lld/trunk/unittests/<u></u>DriverTests/GnuLdDriverTest.<u></u>cpp Mon Mar 16 14:55:15 2015<br>
@@ -246,9 +246,10 @@ TEST_F(LinkerScriptTest, ExprEval) {<br>
    parse("SECTIONS { symbol = 0x4000 + 0x40; \n"<br>
          ". = (symbol >= 0x4040)? (0x5001 * 2 & 0xFFF0) << 1 : 0}");<br>
  -  EXPECT_EQ((size_t)1, _ctx->scripts().size());<br>
+  EXPECT_EQ((size_t)1, _ctx->linkerScriptSema().<u></u>getLinkerScripts().size());<br>
  -  script::LinkerScript *ls = _ctx->scripts()[0]->get();<br>
+  script::LinkerScript *ls =<br>
+      _ctx->linkerScriptSema().<u></u>getLinkerScripts()[0]->get();<br>
    EXPECT_EQ((size_t)1, ls->_commands.size());<br>
      auto *secs = dyn_cast<const script::Sections>(*ls->_<u></u>commands.begin());<br>
<br>
<br>
______________________________<u></u>_________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu" target="_blank">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/<u></u>mailman/listinfo/llvm-commits</a><br>
<br>
</blockquote>
<br>
<br></div></div><span class="HOEnZb"><font color="#888888">
-- <br>
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by the Linux Foundation<br>
<br>
</font></span></blockquote></div><br></div>