Index: include/lld/Core/Error.h =================================================================== --- include/lld/Core/Error.h +++ include/lld/Core/Error.h @@ -51,7 +51,9 @@ 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) { Index: include/lld/ReaderWriter/ELFLinkingContext.h =================================================================== --- include/lld/ReaderWriter/ELFLinkingContext.h +++ include/lld/ReaderWriter/ELFLinkingContext.h @@ -301,6 +301,10 @@ _scripts.push_back(std::move(script)); } + const std::vector> &scripts() const { + return _scripts; + } + // --wrap option. void addWrapForSymbol(StringRef sym) { _wrapCalls.insert(sym); } Index: include/lld/ReaderWriter/LinkerScript.h =================================================================== --- include/lld/ReaderWriter/LinkerScript.h +++ include/lld/ReaderWriter/LinkerScript.h @@ -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 @@ /// 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 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 evalExpr(SymbolTableTy &symbolTable) const = 0; virtual ~Expression() {} protected: @@ -388,6 +394,8 @@ return c->getKind() == Kind::Constant; } + ErrorOr evalExpr(SymbolTableTy &symbolTable) const override; + private: uint64_t _num; }; @@ -402,6 +410,8 @@ return c->getKind() == Kind::Symbol; } + ErrorOr evalExpr(SymbolTableTy &symbolTable) const override; + private: StringRef _name; }; @@ -424,6 +434,8 @@ return c->getKind() == Kind::FunctionCall; } + ErrorOr evalExpr(SymbolTableTy &symbolTable) const override; + private: StringRef _name; llvm::ArrayRef _args; @@ -444,6 +456,8 @@ return c->getKind() == Kind::Unary; } + ErrorOr evalExpr(SymbolTableTy &symbolTable) const override; + private: Operation _op; const Expression *_child; @@ -477,6 +491,8 @@ return c->getKind() == Kind::BinOp; } + ErrorOr evalExpr(SymbolTableTy &symbolTable) const override; + private: Operation _op; const Expression *_lhs; @@ -510,6 +526,8 @@ return c->getKind() == Kind::TernaryConditional; } + ErrorOr evalExpr(SymbolTableTy &symbolTable) const override; + private: const Expression *_conditional; const Expression *_trueExpr; @@ -530,7 +548,7 @@ 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 @@ } 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 @@ /// Represents all the contents of the SECTIONS {} construct. class Sections : public Command { public: + typedef llvm::ArrayRef::const_iterator const_iterator; + Sections(Parser &ctx, const SmallVectorImpl §ionsCommands) : Command(ctx, Kind::Sections) { @@ -765,6 +791,8 @@ } void dump(raw_ostream &os) const override; + const_iterator begin() const { return _sectionsCommands.begin(); } + const_iterator end() const { return _sectionsCommands.end(); } private: llvm::ArrayRef _sectionsCommands; Index: lib/Core/Error.cpp =================================================================== --- lib/Core/Error.cpp +++ lib/Core/Error.cpp @@ -86,6 +86,11 @@ 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."); Index: lib/ReaderWriter/LinkerScript.cpp =================================================================== --- lib/ReaderWriter/LinkerScript.cpp +++ lib/ReaderWriter/LinkerScript.cpp @@ -532,9 +532,20 @@ // Constant functions void Constant::dump(raw_ostream &os) const { os << _num; } +ErrorOr Constant::evalExpr(SymbolTableTy &symbolTable) const { + return _num; +} + // Symbol functions void Symbol::dump(raw_ostream &os) const { os << _name; } +ErrorOr 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 @@ os << ")"; } +ErrorOr 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 @@ os << ")"; } +ErrorOr 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 @@ os << ")"; } +ErrorOr 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,28 @@ _falseExpr->dump(os); } +ErrorOr +TernaryConditional::evalExpr(SymbolTableTy &symbolTable) const { + auto conditional = _conditional->evalExpr(symbolTable); + if (conditional.getError()) + return conditional.getError(); + if (*conditional) { + auto trueExpr = _trueExpr->evalExpr(symbolTable); + if (trueExpr.getError()) + return trueExpr.getError(); + return *trueExpr; + } + auto falseExpr = _falseExpr->evalExpr(symbolTable); + if (falseExpr.getError()) + return falseExpr.getError(); + return *falseExpr; +} + // 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 +1433,7 @@ _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; Index: unittests/DriverTests/GnuLdDriverTest.cpp =================================================================== --- unittests/DriverTests/GnuLdDriverTest.cpp +++ unittests/DriverTests/GnuLdDriverTest.cpp @@ -241,3 +241,43 @@ std::vector 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(*ls->_commands.begin()); + EXPECT_TRUE(secs != nullptr); + EXPECT_EQ(2, secs->end() - secs->begin()); + + auto command = secs->begin(); + auto *sa1 = dyn_cast(*command); + EXPECT_TRUE(sa1 != nullptr); + EXPECT_EQ(script::SymbolAssignment::Simple, sa1->assignmentKind()); + EXPECT_EQ(script::SymbolAssignment::Default, sa1->assignmentVisibility()); + + ++command; + auto *sa2 = dyn_cast(*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("."))); +} +