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