[lld] r231707 - [LinkerScript] Implement linker script expression evaluation
Rafael Auler
rafaelauler at gmail.com
Mon Mar 9 14:43:36 PDT 2015
Author: rafauler
Date: Mon Mar 9 16:43:35 2015
New Revision: 231707
URL: http://llvm.org/viewvc/llvm-project?rev=231707&view=rev
Log:
[LinkerScript] Implement linker script expression evaluation
The expression evaluation is needed when interpreting linker scripts, in order
to calculate the value for new symbols or to determine a new position to load
sections in memory. This commit extends Expression nodes from the linker script
AST with evaluation functions, and also contains a unit test.
http://reviews.llvm.org/D8156
Modified:
lld/trunk/include/lld/Core/Error.h
lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h
lld/trunk/include/lld/ReaderWriter/LinkerScript.h
lld/trunk/lib/Core/Error.cpp
lld/trunk/lib/ReaderWriter/LinkerScript.cpp
lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp
Modified: lld/trunk/include/lld/Core/Error.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/Error.h?rev=231707&r1=231706&r2=231707&view=diff
==============================================================================
--- lld/trunk/include/lld/Core/Error.h (original)
+++ lld/trunk/include/lld/Core/Error.h Mon Mar 9 16:43:35 2015
@@ -51,7 +51,9 @@ const std::error_category &LinkerScriptR
enum class LinkerScriptReaderError {
success = 0,
- parse_error
+ parse_error,
+ unknown_symbol_in_expr,
+ unrecognized_function_in_expr
};
inline std::error_code make_error_code(LinkerScriptReaderError e) {
Modified: lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h?rev=231707&r1=231706&r2=231707&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h (original)
+++ lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h Mon Mar 9 16:43:35 2015
@@ -301,6 +301,10 @@ public:
_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); }
Modified: lld/trunk/include/lld/ReaderWriter/LinkerScript.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/LinkerScript.h?rev=231707&r1=231706&r2=231707&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/LinkerScript.h (original)
+++ lld/trunk/include/lld/ReaderWriter/LinkerScript.h Mon Mar 9 16:43:35 2015
@@ -18,6 +18,7 @@
#include "lld/Core/Error.h"
#include "lld/Core/LLVM.h"
#include "lld/Core/range.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -360,11 +361,16 @@ private:
///
class Expression {
public:
+ // The symbol table does not need to own its string keys and the use of StringMap
+ // here is an overkill.
+ typedef llvm::StringMap<int64_t, llvm::BumpPtrAllocator> SymbolTableTy;
+
enum class Kind { Constant, Symbol, FunctionCall, Unary, BinOp,
TernaryConditional };
Kind getKind() const { return _kind; }
inline llvm::BumpPtrAllocator &getAllocator() const;
virtual void dump(raw_ostream &os) const = 0;
+ virtual ErrorOr<int64_t> evalExpr(SymbolTableTy &symbolTable) const = 0;
virtual ~Expression() {}
protected:
@@ -388,6 +394,8 @@ public:
return c->getKind() == Kind::Constant;
}
+ ErrorOr<int64_t> evalExpr(SymbolTableTy &symbolTable) const override;
+
private:
uint64_t _num;
};
@@ -402,6 +410,8 @@ public:
return c->getKind() == Kind::Symbol;
}
+ ErrorOr<int64_t> evalExpr(SymbolTableTy &symbolTable) const override;
+
private:
StringRef _name;
};
@@ -424,6 +434,8 @@ public:
return c->getKind() == Kind::FunctionCall;
}
+ ErrorOr<int64_t> evalExpr(SymbolTableTy &symbolTable) const override;
+
private:
StringRef _name;
llvm::ArrayRef<const Expression *> _args;
@@ -444,6 +456,8 @@ public:
return c->getKind() == Kind::Unary;
}
+ ErrorOr<int64_t> evalExpr(SymbolTableTy &symbolTable) const override;
+
private:
Operation _op;
const Expression *_child;
@@ -477,6 +491,8 @@ public:
return c->getKind() == Kind::BinOp;
}
+ ErrorOr<int64_t> evalExpr(SymbolTableTy &symbolTable) const override;
+
private:
Operation _op;
const Expression *_lhs;
@@ -510,6 +526,8 @@ public:
return c->getKind() == Kind::TernaryConditional;
}
+ ErrorOr<int64_t> evalExpr(SymbolTableTy &symbolTable) const override;
+
private:
const Expression *_conditional;
const Expression *_trueExpr;
@@ -530,7 +548,7 @@ private:
class SymbolAssignment : public Command {
public:
enum AssignmentKind { Simple, Sum, Sub, Mul, Div, Shl, Shr, And, Or };
- enum AssignmentVisibility { Normal, Hidden, Provide, ProvideHidden };
+ enum AssignmentVisibility { Default, Hidden, Provide, ProvideHidden };
SymbolAssignment(Parser &ctx, StringRef name, const Expression *expr,
AssignmentKind kind, AssignmentVisibility visibility)
@@ -542,6 +560,12 @@ public:
}
void dump(raw_ostream &os) const override;
+ const Expression *expr() const { return _expression; }
+ StringRef symbol() const { return _symbol; }
+ AssignmentKind assignmentKind() const { return _assignmentKind; }
+ AssignmentVisibility assignmentVisibility() const {
+ return _assignmentVisibility;
+ }
private:
const Expression *_expression;
@@ -749,6 +773,8 @@ public:
/// Represents all the contents of the SECTIONS {} construct.
class Sections : public Command {
public:
+ typedef llvm::ArrayRef<const Command *>::const_iterator const_iterator;
+
Sections(Parser &ctx,
const SmallVectorImpl<const Command *> §ionsCommands)
: Command(ctx, Kind::Sections) {
@@ -765,6 +791,8 @@ public:
}
void dump(raw_ostream &os) const override;
+ const_iterator begin() const { return _sectionsCommands.begin(); }
+ const_iterator end() const { return _sectionsCommands.end(); }
private:
llvm::ArrayRef<const Command *> _sectionsCommands;
Modified: lld/trunk/lib/Core/Error.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/Error.cpp?rev=231707&r1=231706&r2=231707&view=diff
==============================================================================
--- lld/trunk/lib/Core/Error.cpp (original)
+++ lld/trunk/lib/Core/Error.cpp Mon Mar 9 16:43:35 2015
@@ -86,6 +86,11 @@ public:
return "Success";
case LinkerScriptReaderError::parse_error:
return "Error parsing linker script";
+ case LinkerScriptReaderError::unknown_symbol_in_expr:
+ return "Unknown symbol found when evaluating linker script expression";
+ case LinkerScriptReaderError::unrecognized_function_in_expr:
+ return "Unrecognized function call when evaluating linker script "
+ "expression";
}
llvm_unreachable("An enumerator of LinkerScriptReaderError does not have a "
"message defined.");
Modified: lld/trunk/lib/ReaderWriter/LinkerScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/LinkerScript.cpp?rev=231707&r1=231706&r2=231707&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/LinkerScript.cpp (original)
+++ lld/trunk/lib/ReaderWriter/LinkerScript.cpp Mon Mar 9 16:43:35 2015
@@ -532,9 +532,20 @@ void Lexer::skipWhitespace() {
// Constant functions
void Constant::dump(raw_ostream &os) const { os << _num; }
+ErrorOr<int64_t> Constant::evalExpr(SymbolTableTy &symbolTable) const {
+ return _num;
+}
+
// Symbol functions
void Symbol::dump(raw_ostream &os) const { os << _name; }
+ErrorOr<int64_t> Symbol::evalExpr(SymbolTableTy &symbolTable) const {
+ auto it = symbolTable.find(_name);
+ if (it == symbolTable.end())
+ return LinkerScriptReaderError::unknown_symbol_in_expr;
+ return it->second;
+}
+
// FunctionCall functions
void FunctionCall::dump(raw_ostream &os) const {
os << _name << "(";
@@ -546,6 +557,10 @@ void FunctionCall::dump(raw_ostream &os)
os << ")";
}
+ErrorOr<int64_t> FunctionCall::evalExpr(SymbolTableTy &symbolTable) const {
+ return LinkerScriptReaderError::unrecognized_function_in_expr;
+}
+
// Unary functions
void Unary::dump(raw_ostream &os) const {
os << "(";
@@ -557,6 +572,22 @@ void Unary::dump(raw_ostream &os) const
os << ")";
}
+ErrorOr<int64_t> Unary::evalExpr(SymbolTableTy &symbolTable) const {
+ auto child = _child->evalExpr(symbolTable);
+ if (child.getError())
+ return child.getError();
+
+ int64_t childRes = *child;
+ switch (_op) {
+ case Unary::Minus:
+ return -childRes;
+ case Unary::Not:
+ return ~childRes;
+ }
+
+ llvm_unreachable("");
+}
+
// BinOp functions
void BinOp::dump(raw_ostream &os) const {
os << "(";
@@ -611,6 +642,37 @@ void BinOp::dump(raw_ostream &os) const
os << ")";
}
+ErrorOr<int64_t> BinOp::evalExpr(SymbolTableTy &symbolTable) const {
+ auto lhs = _lhs->evalExpr(symbolTable);
+ if (lhs.getError())
+ return lhs.getError();
+ auto rhs = _rhs->evalExpr(symbolTable);
+ if (rhs.getError())
+ return rhs.getError();
+
+ int64_t lhsRes = *lhs;
+ int64_t rhsRes = *rhs;
+
+ switch(_op) {
+ case And: return lhsRes & rhsRes;
+ case CompareDifferent: return lhsRes != rhsRes;
+ case CompareEqual: return lhsRes == rhsRes;
+ case CompareGreater: return lhsRes > rhsRes;
+ case CompareGreaterEqual: return lhsRes >= rhsRes;
+ case CompareLess: return lhsRes < rhsRes;
+ case CompareLessEqual: return lhsRes <= rhsRes;
+ case Div: return lhsRes / rhsRes;
+ case Mul: return lhsRes * rhsRes;
+ case Or: return lhsRes | rhsRes;
+ case Shl: return lhsRes << rhsRes;
+ case Shr: return lhsRes >> rhsRes;
+ case Sub: return lhsRes - rhsRes;
+ case Sum: return lhsRes + rhsRes;
+ }
+
+ llvm_unreachable("");
+}
+
// TernaryConditional functions
void TernaryConditional::dump(raw_ostream &os) const {
_conditional->dump(os);
@@ -620,11 +682,21 @@ void TernaryConditional::dump(raw_ostrea
_falseExpr->dump(os);
}
+ErrorOr<int64_t>
+TernaryConditional::evalExpr(SymbolTableTy &symbolTable) const {
+ auto conditional = _conditional->evalExpr(symbolTable);
+ if (conditional.getError())
+ return conditional.getError();
+ if (*conditional)
+ return _trueExpr->evalExpr(symbolTable);
+ return _falseExpr->evalExpr(symbolTable);
+}
+
// SymbolAssignment functions
void SymbolAssignment::dump(raw_ostream &os) const {
int numParen = 0;
- if (_assignmentVisibility != Normal) {
+ if (_assignmentVisibility != Default) {
switch (_assignmentVisibility) {
case Hidden:
os << "HIDDEN(";
@@ -1354,7 +1426,7 @@ const SymbolAssignment *Parser::parseSym
_tok._kind == Token::kw_provide ||
_tok._kind == Token::kw_provide_hidden) &&
"Expected identifier!");
- SymbolAssignment::AssignmentVisibility visibility = SymbolAssignment::Normal;
+ SymbolAssignment::AssignmentVisibility visibility = SymbolAssignment::Default;
SymbolAssignment::AssignmentKind kind;
int numParen = 0;
Modified: lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp?rev=231707&r1=231706&r2=231707&view=diff
==============================================================================
--- lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp (original)
+++ lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp Mon Mar 9 16:43:35 2015
@@ -241,3 +241,43 @@ TEST_F(LinkerScriptTest, IgnoreSearchDir
std::vector<StringRef> paths = _ctx->getSearchPaths();
EXPECT_EQ((size_t)0, paths.size());
}
+
+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());
+
+ script::LinkerScript *ls = _ctx->scripts()[0]->get();
+ EXPECT_EQ((size_t)1, ls->_commands.size());
+
+ auto *secs = dyn_cast<const script::Sections>(*ls->_commands.begin());
+ EXPECT_TRUE(secs != nullptr);
+ EXPECT_EQ(2, secs->end() - secs->begin());
+
+ auto command = secs->begin();
+ auto *sa1 = dyn_cast<const script::SymbolAssignment>(*command);
+ EXPECT_TRUE(sa1 != nullptr);
+ EXPECT_EQ(script::SymbolAssignment::Simple, sa1->assignmentKind());
+ EXPECT_EQ(script::SymbolAssignment::Default, sa1->assignmentVisibility());
+
+ ++command;
+ auto *sa2 = dyn_cast<const script::SymbolAssignment>(*command);
+ EXPECT_TRUE(sa2 != nullptr);
+ EXPECT_EQ(script::SymbolAssignment::Simple, sa2->assignmentKind());
+ EXPECT_EQ(script::SymbolAssignment::Default, sa2->assignmentVisibility());
+
+ script::Expression::SymbolTableTy mySymbolTable;
+ auto ans = sa1->expr()->evalExpr(mySymbolTable);
+ EXPECT_FALSE(ans.getError());
+ int64_t result = *ans;
+ EXPECT_EQ(0x4040, result);
+ mySymbolTable[sa1->symbol()] = result;
+
+ auto ans2 = sa2->expr()->evalExpr(mySymbolTable);
+ EXPECT_FALSE(ans2.getError());
+ result = *ans2;
+ EXPECT_EQ(0x14000, result);
+ EXPECT_EQ(0, sa2->symbol().compare(StringRef(".")));
+}
+
More information about the llvm-commits
mailing list