[lld] r232402 - [LinkerScript] Implement semantics for simple sections mappings
Rafael Auler
rafaelauler at gmail.com
Mon Mar 16 13:11:23 PDT 2015
Yes, I missed them. Sorry. I committed the missed tests shortly after I
realized this in 232404.
On Mon, Mar 16, 2015 at 5:10 PM, Shankar Easwaran <shankare at codeaurora.org>
wrote:
> 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
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20150316/98b8476a/attachment.html>
More information about the llvm-commits
mailing list