[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 *> &sectionsCommands)
       : 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