[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 *> §ions)
> : 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 *> §ions)
> - : 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