[lld] r232402 - [LinkerScript] Implement semantics for simple sections mappings

Shankar Easwaran shankare at codeaurora.org
Mon Mar 16 13:10:12 PDT 2015


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


-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by the Linux Foundation




More information about the llvm-commits mailing list