diff --git a/include/eld/Diagnostics/DiagVerbose.inc b/include/eld/Diagnostics/DiagVerbose.inc index 061ec0602..f7b489f5b 100644 --- a/include/eld/Diagnostics/DiagVerbose.inc +++ b/include/eld/Diagnostics/DiagVerbose.inc @@ -167,3 +167,7 @@ DIAG(verbose_loaded_plugin_config, DiagnosticEngine::Verbose, "Initialized plugin config for %0") DIAG(verbose_infer_target, DiagnosticEngine::Verbose, "Inferred target : %0") +DIAG(verbose_performing_layout_iteration, DiagnosticEngine::Verbose, + "Performing layout iteration %0") +DIAG(verbose_eval_pending_assignments, DiagnosticEngine::Verbose, + "Evaluating pending assignments") diff --git a/include/eld/Diagnostics/DiagnosticPrinter.h b/include/eld/Diagnostics/DiagnosticPrinter.h index 0a938566d..21fd42692 100644 --- a/include/eld/Diagnostics/DiagnosticPrinter.h +++ b/include/eld/Diagnostics/DiagnosticPrinter.h @@ -47,6 +47,7 @@ class DiagnosticPrinter { TraceMergeStrings = 0x8000, TraceLinkerScript = 0x10000, TraceSymDef = 0x100000, + TracePendingAssignments = 0x200000 }; enum Verbose : uint16_t { None = 0x0, Default = 0x1 }; @@ -68,6 +69,8 @@ class DiagnosticPrinter { bool traceAssignments() { return Trace & TraceAssignments; } + bool tracePendingAssignments() { return Trace & TracePendingAssignments; } + bool traceFiles() { return Trace & TraceFiles; } bool traceSymbols() { return Trace & TraceSymbols; } diff --git a/include/eld/Driver/GnuLinkerOptions.td b/include/eld/Driver/GnuLinkerOptions.td index 128bd7038..fa2c3c3ee 100644 --- a/include/eld/Driver/GnuLinkerOptions.td +++ b/include/eld/Driver/GnuLinkerOptions.td @@ -688,7 +688,8 @@ defm trace "\t\t\t --trace=trampolines : trace trampolines\n" "\t\t\t --trace=wrap-symbols : trace symbol wrap options\n" "\t\t\t --trace=symdef : trace symbol resolution from symdef files\n" - "\t\t\t --trace=dynamic-linking : trace dynamic linking">, + "\t\t\t --trace=dynamic-linking : trace dynamic linking\n" + "\t\t\t --trace=pending-assignments : trace pending symbol assignments evaluation">, MetaVarName<"">, Group; defm trace_symbol : smDashTwoWithOpt<"y", "trace-symbol", "trace_symbol", diff --git a/include/eld/Script/Assignment.h b/include/eld/Script/Assignment.h index 63e3443ef..f35f3a16d 100644 --- a/include/eld/Script/Assignment.h +++ b/include/eld/Script/Assignment.h @@ -73,20 +73,26 @@ class Assignment : public ScriptCommand { bool isDot() const; - // Does the assignment have any dot usage ? + // Does the assignment has any dot usage ? bool hasDot() const; static bool classof(const ScriptCommand *LinkerScriptCommand) { return LinkerScriptCommand->getKind() == ScriptCommand::ASSIGNMENT; } + /// Sets the expression context (location in the linker script) + /// and the assignment level. eld::Expected activate(Module &CurModule) override; /// assign - evaluate the rhs and assign the result to lhs. - bool assign(Module &CurModule, const ELFSection *Section); + bool assign(Module &CurModule, const ELFSection *Section, + bool EvaluatePendingOnly); LDSymbol *symbol() const { return ThisSymbol; } + /// Returns all the symbols that might be referenced by the rhs of this + /// assignment. No expression evaluation is performed. Hence, this may return + /// more symbols than what is actually referenced at runtime. void getSymbols(std::vector &Symbols) const; /// Query functions on Assignment Kinds. @@ -113,7 +119,9 @@ class Assignment : public ScriptCommand { bool isAssert() const { return ThisType == ASSERT; } - // Retrieve the symbol names referred by the assignment expression + /// Returns the symbol names that might be referenced by the rhs of this + /// assignment. No expression evaluation is performed. Hence, this may return + /// names of more symbols than what is actually referenced at runtime. std::unordered_set getSymbolNames() const; // Add all undefined references from assignmnent expressions diff --git a/include/eld/Script/Expression.h b/include/eld/Script/Expression.h index af6acd30a..7d05d3131 100644 --- a/include/eld/Script/Expression.h +++ b/include/eld/Script/Expression.h @@ -206,12 +206,42 @@ class Expression { /// The result is set to 0 if the evaluation fails. std::optional evaluateAndRaiseError(); + /// It is like evaluateAndRaiseError, but instead of doing + /// expression evaluation by scratch, it only evaluates the + /// subexpressions which could not be evaluated before. + /// Please note that this is not just an optimization. Completely + /// evaluating the expression, when only pending subexpression should be + /// evaluated, can give incorrect result. + std::optional evaluatePendingAndRaiseError(); + /// eval /// \brief Evaluate the expression, and return the value when /// evaluation is successful or an error when failed. Commit is /// not called. This method is intended to be recursively called by /// parent expression nodes. - eld::Expected eval(); + /// + /// \param EvaluatePendingOnly If EvaluatePendingOnly is true, then only + /// those subexpressions are evaluated which could not be evaluated before. + eld::Expected eval(bool EvaluatePendingOnly); + + /// Returns true if the expression was evaluated before but some parts + /// of the expression could not be evaluated due to forward references. + bool hasPendingEvaluation() const { return HasPendingEvaluation; } + + /// Returns true if no evaluation is needed and the previously computed + /// result can be reused as it is. + bool shouldReuseResult(bool EvaluatePendingOnly) { + return EvaluatePendingOnly && !HasPendingEvaluation && hasResult(); + } + + /// Calls Fn on each node in the expression. + virtual void visitExpression(std::function Fn) { + Fn(*this); + if (auto *E = getLeftExpression()) + Fn(*E); + if (auto *R = getRightExpression()) + Fn(*R); + } /// /// getBackend @@ -224,7 +254,11 @@ class Expression { /// should be to verify and evaluate the expression. eval() should /// return the value if evaluation is successful or raise an error /// and return an empty object otherwise. - virtual eld::Expected evalImpl() = 0; + /// + /// If EvaluatePendingOnly is true, then only those subexpressions are + /// evaluated which could not be evaluated before. + virtual eld::Expected + evalImpl(bool EvaluatePendingOnly) = 0; static std::unique_ptr addContextToDiagEntry(std::unique_ptr, @@ -306,6 +340,8 @@ class Expression { std::string MContext; // context is only set in the outermost expression std::optional MResult; /// committed result from the evaluation + bool HasPendingEvaluation = false; + private: uint64_t EvaluatedValue; /// temporary assignment to hold evaluation result }; @@ -323,7 +359,7 @@ class Symbol : public Expression { private: bool hasDot() const override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; /// Returns a set of all the symbol names contained in the expression. void getSymbolNames(std::unordered_set &SymbolTokens) override; @@ -349,7 +385,7 @@ class Integer : public Expression { private: bool hasDot() const override { return false; } void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return nullptr; } @@ -375,7 +411,7 @@ class Add : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return &LeftExpression; } @@ -402,7 +438,7 @@ class Subtract : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return &LeftExpression; } @@ -429,7 +465,7 @@ class Modulo : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return &LeftExpression; } @@ -456,7 +492,7 @@ class Multiply : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return &LeftExpression; } @@ -483,7 +519,7 @@ class Divide : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return &LeftExpression; } @@ -507,7 +543,7 @@ class SizeOf : public Expression { private: bool hasDot() const override { return false; } void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return nullptr; } @@ -530,7 +566,7 @@ class SizeOfHeaders : public Expression { private: bool hasDot() const override { return false; } void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return nullptr; } @@ -554,7 +590,7 @@ class OffsetOf : public Expression { private: bool hasDot() const override { return false; } void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return nullptr; } @@ -578,7 +614,7 @@ class Addr : public Expression { private: bool hasDot() const override { return false; } void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return nullptr; } @@ -601,7 +637,7 @@ class LoadAddr : public Expression { private: bool hasDot() const override { return false; } void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return nullptr; } @@ -630,7 +666,7 @@ class AlignExpr : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { @@ -663,7 +699,7 @@ class AlignOf : public Expression { private: bool hasDot() const override { return false; } void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return nullptr; } @@ -689,7 +725,7 @@ class Absolute : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return nullptr; } @@ -715,11 +751,18 @@ class Ternary : public Expression { Expression *getConditionalExpression() const { return &ConditionExpression; } + void visitExpression(std::function Fn) override { + Fn(*this); + Fn(ConditionExpression); + Fn(LeftExpression); + Fn(RightExpression); + } + private: bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return &LeftExpression; } @@ -748,7 +791,7 @@ class ConditionGT : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return &LeftExpression; } @@ -775,7 +818,7 @@ class ConditionLT : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return &LeftExpression; } @@ -802,7 +845,7 @@ class ConditionEQ : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return &LeftExpression; } @@ -831,7 +874,7 @@ class ConditionGTE : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return &LeftExpression; } @@ -860,7 +903,7 @@ class ConditionLTE : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return &LeftExpression; } @@ -887,7 +930,7 @@ class ConditionNEQ : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return &LeftExpression; } @@ -913,7 +956,7 @@ class Complement : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return nullptr; } @@ -941,7 +984,7 @@ class UnaryPlus : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return nullptr; } @@ -969,7 +1012,7 @@ class UnaryMinus : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return nullptr; } @@ -997,7 +1040,7 @@ class UnaryNot : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return nullptr; } @@ -1024,7 +1067,7 @@ class Constant : public Expression { private: bool hasDot() const override { return false; } void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return nullptr; } @@ -1050,7 +1093,7 @@ class SegmentStart : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return nullptr; } @@ -1081,7 +1124,7 @@ class AssertCmd : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return nullptr; } @@ -1111,7 +1154,7 @@ class RightShift : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return &LeftExpression; } @@ -1140,7 +1183,7 @@ class LeftShift : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return &LeftExpression; } @@ -1167,7 +1210,7 @@ class BitwiseOr : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return &LeftExpression; } @@ -1194,7 +1237,7 @@ class BitwiseAnd : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return &LeftExpression; } @@ -1221,7 +1264,7 @@ class BitwiseXor : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return &LeftExpression; } @@ -1246,7 +1289,7 @@ class Defined : public Expression { private: bool hasDot() const override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return nullptr; } @@ -1274,7 +1317,7 @@ class DataSegmentAlign : public Expression { bool hasDot() const override { return false; } void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return &MaxPageSize; } @@ -1307,7 +1350,7 @@ class DataSegmentRelRoEnd : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return &LeftExpression; } @@ -1336,7 +1379,7 @@ class DataSegmentEnd : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return nullptr; } @@ -1365,7 +1408,7 @@ class Max : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return &LeftExpression; } @@ -1392,7 +1435,7 @@ class Min : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return &LeftExpression; } @@ -1418,7 +1461,7 @@ class Fill : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return nullptr; } @@ -1446,7 +1489,7 @@ class Log2Ceil : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return nullptr; } @@ -1477,7 +1520,7 @@ class LogicalOp : public Expression { bool hasDot() const override; void commit() override; void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return &LeftExpression; } @@ -1504,7 +1547,7 @@ class QueryMemory : public Expression { private: bool hasDot() const override { return false; } void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return nullptr; } @@ -1528,7 +1571,7 @@ class NullExpression : public Expression { private: bool hasDot() const override { return false; } void dump(llvm::raw_ostream &Outs, bool WithValues = true) const override; - eld::Expected evalImpl() override; + eld::Expected evalImpl(bool EvaluatePendingOnly) override; void getSymbols(std::vector &Symbols) override; void getSymbolNames(std::unordered_set &SymbolTokens) override; Expression *getLeftExpression() const override { return nullptr; } diff --git a/include/eld/SymbolResolver/NamePool.h b/include/eld/SymbolResolver/NamePool.h index 4240940a0..5d26238dc 100644 --- a/include/eld/SymbolResolver/NamePool.h +++ b/include/eld/SymbolResolver/NamePool.h @@ -111,6 +111,15 @@ class NamePool { bool getSymbolTracingRequested() const; + // --------------------- Linker Script Symbols ---------------- + // Record a symbol that originates from a linker script / defsym. + void addScriptSymbol(ResolveInfo *RI) { ScriptSymbols.push_back(RI); } + + // Return all symbols that originates from linker script / defsym. + const std::vector &getScriptSymbols() const { + return ScriptSymbols; + } + /// --------------------- Symbol References and checks ---------------- bool canSymbolsBeResolved(const ResolveInfo *, const ResolveInfo *) const; bool checkTLSTypes(const ResolveInfo *, const ResolveInfo *) const; @@ -143,6 +152,9 @@ class NamePool { SymbolResolutionInfo SymbolResInfo; std::map SharedLibsSymbols; PluginManager &PM; + + // Symbols defined via linker scripts / defsym. + std::vector ScriptSymbols; }; } // namespace eld diff --git a/include/eld/Target/GNULDBackend.h b/include/eld/Target/GNULDBackend.h index ab46d82de..e02ff3907 100644 --- a/include/eld/Target/GNULDBackend.h +++ b/include/eld/Target/GNULDBackend.h @@ -824,6 +824,28 @@ class GNULDBackend { const ResolveInfo *findAbsolutePLT(ResolveInfo *I) const; + /// Returns true if the symbol is partially evaluated. That + /// is, the symbol assignment expression was partially evaluated. + bool isPartiallyEvaluated(const ResolveInfo *RI) const { + return PartiallyEvaluatedSymbols.count(RI); + } + + void addPartiallyEvaluatedSymbol(const ResolveInfo *RI) { + PartiallyEvaluatedSymbols.insert(RI); + } + + void removePartiallyEvaluatedSymbol(const ResolveInfo *RI) { + PartiallyEvaluatedSymbols.erase(RI); + } + + void resetPartiallyEvalAssignmentsAndSymbols() { + PartiallyEvaluatedAssignments.clear(); + PartiallyEvaluatedSymbols.clear(); + } + + /// Recursively evaluates the partially evaluated assignments. + void evaluatePendingAssignments(); + protected: virtual int numReservedSegments() const { return m_NumReservedSegments; } @@ -1002,6 +1024,14 @@ class GNULDBackend { // Setup TLS alignment and check for any layout issues bool setupTLS(); + /// Evaluates the assignment and tracks the partially evaluated assignments. + /// Partially evaluated assignments can be requested to be (recursively) + /// reevaluated using evaluatePendingAssignments. + void evaluateAssignmentAndTrackPartiallyEvalAssignments(Assignment &A, + const ELFSection *S); + + void resetScriptSymbols(); + protected: Module &m_Module; @@ -1132,6 +1162,12 @@ class GNULDBackend { bool m_NeedEhdr = false; bool m_NeedPhdr = false; + + std::unordered_set PartiallyEvaluatedSymbols; + + /// Stores the assignments which needs to be reevaluated later. + std::vector> + PartiallyEvaluatedAssignments; }; } // namespace eld diff --git a/lib/Config/GeneralOptions.cpp b/lib/Config/GeneralOptions.cpp index 1c47740ba..d81290b0e 100644 --- a/lib/Config/GeneralOptions.cpp +++ b/lib/Config/GeneralOptions.cpp @@ -230,6 +230,8 @@ eld::Expected GeneralOptions::setTrace(const char *PTraceType) { DiagEngine->getPrinter()->TraceDynamicLinking) .Case("linker-script", DiagEngine->getPrinter()->TraceLinkerScript) .Case("symdef", DiagEngine->getPrinter()->TraceSymDef) + .Case("pending-assignments", + DiagEngine->getPrinter()->TracePendingAssignments) .Default(std::nullopt); } // Warn if trace category is unknown. diff --git a/lib/Object/ObjectLinker.cpp b/lib/Object/ObjectLinker.cpp index dc1077ed5..250e1c368 100644 --- a/lib/Object/ObjectLinker.cpp +++ b/lib/Object/ObjectLinker.cpp @@ -892,7 +892,10 @@ bool ObjectLinker::createOutputSection(ObjectBuilder &Builder, // force input alignment from ldscript if any if (Output->prolog().hasSubAlign()) { - Output->prolog().subAlign().eval(); + // FIXME: eval() is an implementation function, it should not be + // used outside the component. Instead, evaluateAndReturnError and + // evaluateAndRaiseError should be used. + Output->prolog().subAlign().eval(/*EvaluatePendingOnly=*/false); Output->prolog().subAlign().commit(); InAlign = Output->prolog().subAlign().result(); HasSubAlign = true; @@ -1631,11 +1634,8 @@ bool ObjectLinker::addScriptSymbols() { bool Ret = true; // go through the entire symbol assignments for (auto &AssignCmd : Script.assignments()) { - InputFile *ScriptInput = ThisModule->getInternalInput(eld::Module::Script); - // FIXME: Ideally, assignCmd should always have a context. We should perhaps - // add an internal error if the context is missing. - if (AssignCmd->hasInputFileInContext()) - ScriptInput = AssignCmd->getInputFileInContext(); + InputFile *ScriptInput = AssignCmd->getInputFileInContext(); + ASSERT(ScriptInput, "Must always be non-null!"); llvm::StringRef SymName = AssignCmd->name(); ResolveInfo::Type Type = ResolveInfo::NoType; ResolveInfo::Visibility Vis = ResolveInfo::Default; diff --git a/lib/Script/Assignment.cpp b/lib/Script/Assignment.cpp index a03b762e6..d5bff3112 100644 --- a/lib/Script/Assignment.cpp +++ b/lib/Script/Assignment.cpp @@ -19,6 +19,7 @@ #include "eld/Readers/Section.h" #include "eld/Script/Expression.h" #include "eld/SymbolResolver/LDSymbol.h" +#include "eld/Target/GNULDBackend.h" #include "llvm/Support/Casting.h" #include @@ -197,8 +198,8 @@ void Assignment::getSymbols(std::vector &Symbols) const { ExpressionToEvaluate->getSymbols(Symbols); } -bool Assignment::assign(Module &CurModule, const ELFSection *Section) { - +bool Assignment::assign(Module &CurModule, const ELFSection *Section, + bool EvaluatePendingOnly) { if (Section && !Section->isAlloc() && isDot()) { CurModule.getConfig().raise(Diag::error_dot_lhs_in_non_alloc) << std::string(Section->name()) @@ -207,7 +208,11 @@ bool Assignment::assign(Module &CurModule, const ELFSection *Section) { } // evaluate, commit, then get the result of the expression - auto Result = ExpressionToEvaluate->evaluateAndRaiseError(); + std::optional Result; + if (EvaluatePendingOnly) + Result = ExpressionToEvaluate->evaluatePendingAndRaiseError(); + else + Result = ExpressionToEvaluate->evaluateAndRaiseError(); if (!Result) return false; ExpressionValue = *Result; @@ -216,13 +221,23 @@ bool Assignment::assign(Module &CurModule, const ELFSection *Section) { return false; LDSymbol *Sym = CurModule.getNamePool().findSymbol(Name); + // ASSERT(Sym, "Sym must exist!"); + // FIXME: Why is it okay for the Sym to be nullptr? if (Sym != nullptr) { ThisSymbol = Sym; ThisSymbol->setValue(ExpressionValue); ThisSymbol->setScriptValueDefined(); + GNULDBackend &Backend = CurModule.getBackend(); + const ResolveInfo *RI = ThisSymbol->resolveInfo(); + if (ExpressionToEvaluate->hasPendingEvaluation()) + Backend.addPartiallyEvaluatedSymbol(RI); + else + Backend.removePartiallyEvaluatedSymbol(RI); } - if (CurModule.getPrinter()->traceAssignments()) + auto DP = CurModule.getPrinter(); + if (DP->traceAssignments() || + (EvaluatePendingOnly && DP->tracePendingAssignments())) trace(llvm::outs()); return true; } diff --git a/lib/Script/Expression.cpp b/lib/Script/Expression.cpp index 1628f8e44..ca5d36175 100644 --- a/lib/Script/Expression.cpp +++ b/lib/Script/Expression.cpp @@ -63,7 +63,7 @@ eld::Expected Expression::evaluateAndReturnError() { // This is unfortunate, but hopefully context for expressions will be set // during parsing. ASSERT(!MContext.empty(), "Context not set for expression"); - auto Result = eval(); + auto Result = eval(/*EvaluatePendingOnly=*/false); if (!Result) return addContextToDiagEntry(std::move(Result.error()), MContext); commit(); @@ -72,7 +72,7 @@ eld::Expected Expression::evaluateAndReturnError() { std::optional Expression::evaluateAndRaiseError() { ASSERT(!MContext.empty(), "Context not set for expression"); - auto Result = eval(); + auto Result = eval(/*EvaluatePendingOnly=*/false); if (!Result) { // Even if evaluation fails, set the result (to zero) as // we don't expect the caller to exit due to this error. @@ -85,10 +85,34 @@ std::optional Expression::evaluateAndRaiseError() { return Result.value(); } -eld::Expected Expression::eval() { - auto V = evalImpl(); - if (V) +std::optional Expression::evaluatePendingAndRaiseError() { + ASSERT(!MContext.empty(), "Context not set for expression"); + auto Result = eval(/*EvaluatePendingOnly=*/true); + if (!Result) { + // Even if evaluation fails, set the result (to zero) as + // we don't expect the caller to exit due to this error. + ThisModule.getConfig().raiseDiagEntry( + addContextToDiagEntry(std::move(Result.error()), MContext)); + commit(); + return {}; + } + commit(); + return Result.value(); +} + +eld::Expected Expression::eval(bool EvaluatePendingOnly) { + if (shouldReuseResult(EvaluatePendingOnly)) { + return result(); + } + HasPendingEvaluation = false; + auto V = evalImpl(EvaluatePendingOnly); + if (V) { EvaluatedValue = V.value(); + visitExpression([this](Expression &E) { + if (E.hasPendingEvaluation()) + HasPendingEvaluation = true; + }); + } return V; } @@ -132,8 +156,7 @@ bool Symbol::hasDot() const { return ThisSymbol == ThisModule.getDotSymbol(); } -eld::Expected Symbol::evalImpl() { - +eld::Expected Symbol::evalImpl(bool EvaluatePendingOnly) { if (!ThisSymbol) ThisSymbol = ThisModule.getNamePool().findSymbol(Name); @@ -152,6 +175,13 @@ eld::Expected Symbol::evalImpl() { "using a symbol that points to a non allocatable section!"); return Section->addr() + FragRef->getOutputOffset(ThisModule); } + + GNULDBackend &Backend = ThisModule.getBackend(); + if (ThisSymbol->scriptDefined() && + (!ThisSymbol->scriptValueDefined() || + Backend.isPartiallyEvaluated(ThisSymbol->resolveInfo()))) + HasPendingEvaluation = true; + return ThisSymbol->value(); } @@ -184,7 +214,10 @@ void Integer::dump(llvm::raw_ostream &Outs, bool WithValues) const { if (ExpressionHasParenthesis) Outs << ")"; } -eld::Expected Integer::evalImpl() { return ExpressionValue; } +eld::Expected Integer::evalImpl(bool IsReevaluation) { + return ExpressionValue; +} + void Integer::getSymbols(std::vector &Symbols) {} void Integer::getSymbolNames(std::unordered_set &SymbolTokens) {} @@ -208,12 +241,12 @@ void Add::dump(llvm::raw_ostream &Outs, bool WithValues) const { if (ExpressionHasParenthesis) Outs << ")"; } -eld::Expected Add::evalImpl() { +eld::Expected Add::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Left = LeftExpression.eval(); + auto Left = LeftExpression.eval(EvaluatePendingOnly); if (!Left) return Left; - auto Right = RightExpression.eval(); + auto Right = RightExpression.eval(EvaluatePendingOnly); if (!Right) return Right; if (!ThisModule.getScript().phdrsSpecified() && @@ -262,16 +295,17 @@ void Subtract::dump(llvm::raw_ostream &Outs, bool WithValues) const { if (ExpressionHasParenthesis) Outs << ")"; } -eld::Expected Subtract::evalImpl() { +eld::Expected Subtract::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Left = LeftExpression.eval(); + auto Left = LeftExpression.eval(EvaluatePendingOnly); if (!Left) return Left; - auto Right = RightExpression.eval(); + auto Right = RightExpression.eval(EvaluatePendingOnly); if (!Right) return Right; return Left.value() - Right.value(); } + void Subtract::getSymbols(std::vector &Symbols) { LeftExpression.getSymbols(Symbols); RightExpression.getSymbols(Symbols); @@ -302,12 +336,12 @@ void Modulo::dump(llvm::raw_ostream &Outs, bool WithValues) const { if (ExpressionHasParenthesis) Outs << ")"; } -eld::Expected Modulo::evalImpl() { +eld::Expected Modulo::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Left = LeftExpression.eval(); + auto Left = LeftExpression.eval(EvaluatePendingOnly); if (!Left) return Left; - auto Right = RightExpression.eval(); + auto Right = RightExpression.eval(EvaluatePendingOnly); if (!Right) return Right; if (Right.value() == 0) { @@ -353,12 +387,12 @@ void Multiply::dump(llvm::raw_ostream &Outs, bool WithValues) const { if (ExpressionHasParenthesis) Outs << ")"; } -eld::Expected Multiply::evalImpl() { +eld::Expected Multiply::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Left = LeftExpression.eval(); + auto Left = LeftExpression.eval(EvaluatePendingOnly); if (!Left) return Left; - auto Right = RightExpression.eval(); + auto Right = RightExpression.eval(EvaluatePendingOnly); if (!Right) return Right; return Left.value() * Right.value(); @@ -396,12 +430,12 @@ void Divide::dump(llvm::raw_ostream &Outs, bool WithValues) const { if (ExpressionHasParenthesis) Outs << ")"; } -eld::Expected Divide::evalImpl() { +eld::Expected Divide::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Left = LeftExpression.eval(); + auto Left = LeftExpression.eval(EvaluatePendingOnly); if (!Left) return Left; - auto Right = RightExpression.eval(); + auto Right = RightExpression.eval(EvaluatePendingOnly); if (!Right) return Right; if (Right.value() == 0) { @@ -440,7 +474,7 @@ void SizeOf::dump(llvm::raw_ostream &Outs, bool WithValues) const { } Outs << ")"; } -eld::Expected SizeOf::evalImpl() { +eld::Expected SizeOf::evalImpl(bool EvaluatePendingOnly) { if (Name.size() && Name[0] == ':') { // If the name is a segment and we don't have PHDR's. SIZEOF on segment will @@ -505,7 +539,7 @@ void SizeOfHeaders::dump(llvm::raw_ostream &Outs, bool WithValues) const { } } -eld::Expected SizeOfHeaders::evalImpl() { +eld::Expected SizeOfHeaders::evalImpl(bool EvaluatePendingOnly) { uint64_t Offset = 0; std::vector Sections; if (!getTargetBackend().isEhdrNeeded()) @@ -535,7 +569,7 @@ void Addr::dump(llvm::raw_ostream &Outs, bool WithValues) const { } Outs << "\")"; } -eld::Expected Addr::evalImpl() { +eld::Expected Addr::evalImpl(bool EvaluatePendingOnly) { // As the section table is populated only during PostLayout, we have to // go the other way around to access the section. This is because size of // empty @@ -572,7 +606,7 @@ void LoadAddr::dump(llvm::raw_ostream &Outs, bool WithValues) const { } Outs << ")"; } -eld::Expected LoadAddr::evalImpl() { +eld::Expected LoadAddr::evalImpl(bool EvaluatePendingOnly) { // As the section table is populated only during PostLayout, we have to // go the other way around to access the section. This is because size of // empty @@ -601,7 +635,7 @@ void OffsetOf::dump(llvm::raw_ostream &Outs, bool WithValues) const { Outs.write_hex(resultOrZero()); } } -eld::Expected OffsetOf::evalImpl() { +eld::Expected OffsetOf::evalImpl(bool EvaluatePendingOnly) { // As the section table is populated only during PostLayout, we have to // go the other way around to access the section. This is because size of // empty @@ -622,8 +656,10 @@ void OffsetOf::getSymbolNames(std::unordered_set &SymbolTokens) {} /// Ternary void Ternary::commit() { ConditionExpression.commit(); - LeftExpression.commit(); - RightExpression.commit(); + if (ConditionExpression.result()) + LeftExpression.commit(); + else + RightExpression.commit(); Expression::commit(); } void Ternary::dump(llvm::raw_ostream &Outs, bool WithValues) const { @@ -637,11 +673,12 @@ void Ternary::dump(llvm::raw_ostream &Outs, bool WithValues) const { if (ExpressionHasParenthesis) Outs << ")"; } -eld::Expected Ternary::evalImpl() { - auto Cond = ConditionExpression.eval(); +eld::Expected Ternary::evalImpl(bool EvaluatePendingOnly) { + auto Cond = ConditionExpression.eval(EvaluatePendingOnly); if (!Cond) return Cond; - return Cond.value() ? LeftExpression.eval() : RightExpression.eval(); + return Cond.value() ? LeftExpression.eval(EvaluatePendingOnly) + : RightExpression.eval(EvaluatePendingOnly); } void Ternary::getSymbols(std::vector &Symbols) { @@ -688,12 +725,12 @@ void AlignExpr::dump(llvm::raw_ostream &Outs, bool WithValues) const { AlignmentExpression.dump(Outs, WithValues); Outs << ")"; } -eld::Expected AlignExpr::evalImpl() { +eld::Expected AlignExpr::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Expr = ExpressionToEvaluate.eval(); + auto Expr = ExpressionToEvaluate.eval(EvaluatePendingOnly); if (!Expr) return Expr; - auto Align = AlignmentExpression.eval(); + auto Align = AlignmentExpression.eval(EvaluatePendingOnly); if (!Align) return Align; uint64_t Value = Expr.value(); @@ -731,7 +768,7 @@ void AlignOf::getSymbols(std::vector &Symbols) {} void AlignOf::getSymbolNames(std::unordered_set &SymbolTokens) {} -eld::Expected AlignOf::evalImpl() { +eld::Expected AlignOf::evalImpl(bool EvaluatePendingOnly) { // As the section table is populated only during PostLayout, we have to // go the other way around to access the section. This is because size of // empty @@ -758,8 +795,8 @@ void Absolute::dump(llvm::raw_ostream &Outs, bool WithValues) const { ExpressionToEvaluate.dump(Outs, WithValues); Outs << ")"; } -eld::Expected Absolute::evalImpl() { - return ExpressionToEvaluate.eval(); +eld::Expected Absolute::evalImpl(bool EvaluatePendingOnly) { + return ExpressionToEvaluate.eval(EvaluatePendingOnly); } void Absolute::getSymbols(std::vector &Symbols) { ExpressionToEvaluate.getSymbols(Symbols); @@ -788,11 +825,11 @@ void ConditionGT::dump(llvm::raw_ostream &Outs, bool WithValues) const { if (ExpressionHasParenthesis) Outs << ")"; } -eld::Expected ConditionGT::evalImpl() { - auto Left = LeftExpression.eval(); +eld::Expected ConditionGT::evalImpl(bool EvaluatePendingOnly) { + auto Left = LeftExpression.eval(EvaluatePendingOnly); if (!Left) return Left; - auto Right = RightExpression.eval(); + auto Right = RightExpression.eval(EvaluatePendingOnly); if (!Right) return Right; return Left.value() > Right.value(); @@ -829,12 +866,12 @@ void ConditionLT::dump(llvm::raw_ostream &Outs, bool WithValues) const { if (ExpressionHasParenthesis) Outs << ")"; } -eld::Expected ConditionLT::evalImpl() { +eld::Expected ConditionLT::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Left = LeftExpression.eval(); + auto Left = LeftExpression.eval(EvaluatePendingOnly); if (!Left) return Left; - auto Right = RightExpression.eval(); + auto Right = RightExpression.eval(EvaluatePendingOnly); if (!Right) return Right; return Left.value() < Right.value(); @@ -871,12 +908,12 @@ void ConditionEQ::dump(llvm::raw_ostream &Outs, bool WithValues) const { if (ExpressionHasParenthesis) Outs << ")"; } -eld::Expected ConditionEQ::evalImpl() { +eld::Expected ConditionEQ::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Left = LeftExpression.eval(); + auto Left = LeftExpression.eval(EvaluatePendingOnly); if (!Left) return Left; - auto Right = RightExpression.eval(); + auto Right = RightExpression.eval(EvaluatePendingOnly); if (!Right) return Right; return Left.value() == Right.value(); @@ -913,12 +950,12 @@ void ConditionGTE::dump(llvm::raw_ostream &Outs, bool WithValues) const { if (ExpressionHasParenthesis) Outs << ")"; } -eld::Expected ConditionGTE::evalImpl() { +eld::Expected ConditionGTE::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Left = LeftExpression.eval(); + auto Left = LeftExpression.eval(EvaluatePendingOnly); if (!Left) return Left; - auto Right = RightExpression.eval(); + auto Right = RightExpression.eval(EvaluatePendingOnly); if (!Right) return Right; return Left.value() >= Right.value(); @@ -955,12 +992,12 @@ void ConditionLTE::dump(llvm::raw_ostream &Outs, bool WithValues) const { if (ExpressionHasParenthesis) Outs << ")"; } -eld::Expected ConditionLTE::evalImpl() { +eld::Expected ConditionLTE::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Left = LeftExpression.eval(); + auto Left = LeftExpression.eval(EvaluatePendingOnly); if (!Left) return Left; - auto Right = RightExpression.eval(); + auto Right = RightExpression.eval(EvaluatePendingOnly); if (!Right) return Right; return Left.value() <= Right.value(); @@ -997,12 +1034,12 @@ void ConditionNEQ::dump(llvm::raw_ostream &Outs, bool WithValues) const { if (ExpressionHasParenthesis) Outs << ")"; } -eld::Expected ConditionNEQ::evalImpl() { +eld::Expected ConditionNEQ::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Left = LeftExpression.eval(); + auto Left = LeftExpression.eval(EvaluatePendingOnly); if (!Left) return Left; - auto Right = RightExpression.eval(); + auto Right = RightExpression.eval(EvaluatePendingOnly); if (!Right) return Right; return Left.value() != Right.value(); @@ -1033,9 +1070,9 @@ void Complement::dump(llvm::raw_ostream &Outs, bool WithValues) const { Outs << Name; ExpressionToEvaluate.dump(Outs, WithValues); } -eld::Expected Complement::evalImpl() { +eld::Expected Complement::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Expr = ExpressionToEvaluate.eval(); + auto Expr = ExpressionToEvaluate.eval(EvaluatePendingOnly); if (!Expr) return Expr; return ~Expr.value(); @@ -1061,8 +1098,8 @@ void UnaryPlus::dump(llvm::raw_ostream &Outs, bool WithValues) const { Outs << Name; ExpressionToEvaluate.dump(Outs, WithValues); } -eld::Expected UnaryPlus::evalImpl() { - return ExpressionToEvaluate.eval(); +eld::Expected UnaryPlus::evalImpl(bool EvaluatePendingOnly) { + return ExpressionToEvaluate.eval(EvaluatePendingOnly); } void UnaryPlus::getSymbols(std::vector &Symbols) { ExpressionToEvaluate.getSymbols(Symbols); @@ -1084,9 +1121,9 @@ void UnaryMinus::dump(llvm::raw_ostream &Outs, bool WithValues) const { Outs << "-"; ExpressionToEvaluate.dump(Outs, WithValues); } -eld::Expected UnaryMinus::evalImpl() { +eld::Expected UnaryMinus::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Expr = ExpressionToEvaluate.eval(); + auto Expr = ExpressionToEvaluate.eval(EvaluatePendingOnly); if (!Expr) return Expr; return -Expr.value(); @@ -1111,9 +1148,9 @@ void UnaryNot::dump(llvm::raw_ostream &Outs, bool WithValues) const { Outs << Name; ExpressionToEvaluate.dump(Outs, WithValues); } -eld::Expected UnaryNot::evalImpl() { +eld::Expected UnaryNot::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Expr = ExpressionToEvaluate.eval(); + auto Expr = ExpressionToEvaluate.eval(EvaluatePendingOnly); if (!Expr) return Expr; return !Expr.value(); @@ -1133,7 +1170,7 @@ void Constant::dump(llvm::raw_ostream &Outs, bool WithValues) const { // format output for operator Outs << "CONSTANT(" << Name << ")"; } -eld::Expected Constant::evalImpl() { +eld::Expected Constant::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions switch (type()) { case Expression::MAXPAGESIZE: @@ -1162,7 +1199,7 @@ void SegmentStart::dump(llvm::raw_ostream &Outs, bool WithValues) const { ExpressionToEvaluate.dump(Outs, WithValues); Outs << ")"; } -eld::Expected SegmentStart::evalImpl() { +eld::Expected SegmentStart::evalImpl(bool EvaluatePendingOnly) { GeneralOptions::AddressMapType &AddressMap = ThisModule.getConfig().options().addressMap(); GeneralOptions::AddressMapType::const_iterator Addr; @@ -1178,7 +1215,7 @@ eld::Expected SegmentStart::evalImpl() { if (Addr != AddressMap.end()) return Addr->getValue(); - return ExpressionToEvaluate.eval(); + return ExpressionToEvaluate.eval(EvaluatePendingOnly); } void SegmentStart::getSymbols(std::vector &Symbols) {} @@ -1211,8 +1248,8 @@ void AssertCmd::dump(llvm::raw_ostream &Outs, bool WithValues) const { ExpressionToEvaluate.dump(Outs, WithValues); Outs << ", \"" << AssertionMessage << "\")"; } -eld::Expected AssertCmd::evalImpl() { - auto Expr = ExpressionToEvaluate.eval(); +eld::Expected AssertCmd::evalImpl(bool EvaluatePendingOnly) { + auto Expr = ExpressionToEvaluate.eval(EvaluatePendingOnly); if (!Expr) return Expr; return Expr.value() != 0; @@ -1246,12 +1283,12 @@ void RightShift::dump(llvm::raw_ostream &Outs, bool WithValues) const { if (ExpressionHasParenthesis) Outs << ")"; } -eld::Expected RightShift::evalImpl() { +eld::Expected RightShift::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Left = LeftExpression.eval(); + auto Left = LeftExpression.eval(EvaluatePendingOnly); if (!Left) return Left; - auto Right = RightExpression.eval(); + auto Right = RightExpression.eval(EvaluatePendingOnly); if (!Right) return Right; return Left.value() >> Right.value(); @@ -1290,12 +1327,12 @@ void LeftShift::dump(llvm::raw_ostream &Outs, bool WithValues) const { if (ExpressionHasParenthesis) Outs << ")"; } -eld::Expected LeftShift::evalImpl() { +eld::Expected LeftShift::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Left = LeftExpression.eval(); + auto Left = LeftExpression.eval(EvaluatePendingOnly); if (!Left) return Left; - auto Right = RightExpression.eval(); + auto Right = RightExpression.eval(EvaluatePendingOnly); if (!Right) return Right; return Left.value() << Right.value(); @@ -1333,12 +1370,12 @@ void BitwiseOr::dump(llvm::raw_ostream &Outs, bool WithValues) const { if (ExpressionHasParenthesis) Outs << ")"; } -eld::Expected BitwiseOr::evalImpl() { +eld::Expected BitwiseOr::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Left = LeftExpression.eval(); + auto Left = LeftExpression.eval(EvaluatePendingOnly); if (!Left) return Left; - auto Right = RightExpression.eval(); + auto Right = RightExpression.eval(EvaluatePendingOnly); if (!Right) return Right; return Left.value() | Right.value(); @@ -1376,12 +1413,12 @@ void BitwiseXor::dump(llvm::raw_ostream &Outs, bool WithValues) const { if (ExpressionHasParenthesis) Outs << ")"; } -eld::Expected BitwiseXor::evalImpl() { +eld::Expected BitwiseXor::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Left = LeftExpression.eval(); + auto Left = LeftExpression.eval(EvaluatePendingOnly); if (!Left) return Left; - auto Right = RightExpression.eval(); + auto Right = RightExpression.eval(EvaluatePendingOnly); if (!Right) return Right; return Left.value() ^ Right.value(); @@ -1419,12 +1456,12 @@ void BitwiseAnd::dump(llvm::raw_ostream &Outs, bool WithValues) const { if (ExpressionHasParenthesis) Outs << ")"; } -eld::Expected BitwiseAnd::evalImpl() { +eld::Expected BitwiseAnd::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Left = LeftExpression.eval(); + auto Left = LeftExpression.eval(EvaluatePendingOnly); if (!Left) return Left; - auto Right = RightExpression.eval(); + auto Right = RightExpression.eval(EvaluatePendingOnly); if (!Right) return Right; return Left.value() & Right.value(); @@ -1449,7 +1486,7 @@ void Defined::dump(llvm::raw_ostream &Outs, bool WithValues) const { // format output for operator Outs << "DEFINED(" << Name << ")"; } -eld::Expected Defined::evalImpl() { +eld::Expected Defined::evalImpl(bool EvaluatePendingOnly) { const LDSymbol *Symbol = ThisModule.getNamePool().findSymbol(Name); if (Symbol == nullptr) return 0; @@ -1486,11 +1523,11 @@ void DataSegmentAlign::dump(llvm::raw_ostream &Outs, bool WithValues) const { CommonPageSize.dump(Outs, WithValues); Outs << ")"; } -eld::Expected DataSegmentAlign::evalImpl() { - auto MaxPageSize = this->MaxPageSize.eval(); +eld::Expected DataSegmentAlign::evalImpl(bool EvaluatePendingOnly) { + auto MaxPageSize = this->MaxPageSize.eval(EvaluatePendingOnly); if (!MaxPageSize) return MaxPageSize; - auto CommonPageSize = this->CommonPageSize.eval(); + auto CommonPageSize = this->CommonPageSize.eval(EvaluatePendingOnly); if (!CommonPageSize) return CommonPageSize; uint64_t Dot = ThisModule.getDotSymbol()->value(); @@ -1528,14 +1565,14 @@ void DataSegmentRelRoEnd::dump(llvm::raw_ostream &Outs, bool WithValues) const { RightExpression.dump(Outs, WithValues); Outs << ")"; } -eld::Expected DataSegmentRelRoEnd::evalImpl() { - auto CommonPageSize = this->CommonPageSize.eval(); +eld::Expected DataSegmentRelRoEnd::evalImpl(bool EvaluatePendingOnly) { + auto CommonPageSize = this->CommonPageSize.eval(EvaluatePendingOnly); if (!CommonPageSize) return CommonPageSize; - auto Expr1 = LeftExpression.eval(); + auto Expr1 = LeftExpression.eval(EvaluatePendingOnly); if (!Expr1) return Expr1; - auto Expr2 = RightExpression.eval(); + auto Expr2 = RightExpression.eval(EvaluatePendingOnly); if (!Expr2) return Expr2; uint64_t Value = Expr1.value() + Expr2.value(); @@ -1569,9 +1606,9 @@ void DataSegmentEnd::dump(llvm::raw_ostream &Outs, bool WithValues) const { ExpressionToEvaluate.dump(Outs, WithValues); Outs << ")"; } -eld::Expected DataSegmentEnd::evalImpl() { +eld::Expected DataSegmentEnd::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Expr = ExpressionToEvaluate.eval(); + auto Expr = ExpressionToEvaluate.eval(EvaluatePendingOnly); if (!Expr) return Expr; return Expr.value() != 0; // TODO: What does this do? @@ -1606,12 +1643,12 @@ void Max::dump(llvm::raw_ostream &Outs, bool WithValues) const { if (ExpressionHasParenthesis) Outs << ")"; } -eld::Expected Max::evalImpl() { +eld::Expected Max::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Left = LeftExpression.eval(); + auto Left = LeftExpression.eval(EvaluatePendingOnly); if (!Left) return Left; - auto Right = RightExpression.eval(); + auto Right = RightExpression.eval(EvaluatePendingOnly); if (!Right) return Right; @@ -1648,12 +1685,12 @@ void Min::dump(llvm::raw_ostream &Outs, bool WithValues) const { if (ExpressionHasParenthesis) Outs << ")"; } -eld::Expected Min::evalImpl() { +eld::Expected Min::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Left = LeftExpression.eval(); + auto Left = LeftExpression.eval(EvaluatePendingOnly); if (!Left) return Left; - auto Right = RightExpression.eval(); + auto Right = RightExpression.eval(EvaluatePendingOnly); if (!Right) return Right; return Left.value() < Right.value() ? Left.value() : Right.value(); @@ -1683,7 +1720,7 @@ void Fill::dump(llvm::raw_ostream &Outs, bool WithValues) const { ExpressionToEvaluate.dump(Outs, WithValues); Outs << ")"; } -eld::Expected Fill::evalImpl() { return ExpressionToEvaluate.eval(); } +eld::Expected Fill::evalImpl(bool EvaluatePendingOnly) { return ExpressionToEvaluate.eval(EvaluatePendingOnly); } void Fill::getSymbols(std::vector &Symbols) { ExpressionToEvaluate.getSymbols(Symbols); @@ -1709,8 +1746,8 @@ void Log2Ceil::dump(llvm::raw_ostream &Outs, bool WithValues) const { Outs << ")"; } -eld::Expected Log2Ceil::evalImpl() { - auto Val = ExpressionToEvaluate.eval(); +eld::Expected Log2Ceil::evalImpl(bool EvaluatePendingOnly) { + auto Val = ExpressionToEvaluate.eval(EvaluatePendingOnly); if (!Val) return Val; return llvm::Log2_64_Ceil(std::max(Val.value(), UINT64_C(1))); @@ -1753,12 +1790,12 @@ void LogicalOp::dump(llvm::raw_ostream &Outs, bool WithValues) const { if (ExpressionHasParenthesis) Outs << ")"; } -eld::Expected LogicalOp::evalImpl() { +eld::Expected LogicalOp::evalImpl(bool EvaluatePendingOnly) { // evaluate sub expressions - auto Left = LeftExpression.eval(); + auto Left = LeftExpression.eval(EvaluatePendingOnly); if (!Left) return Left; - auto Right = RightExpression.eval(); + auto Right = RightExpression.eval(EvaluatePendingOnly); if (!Right) return Right; if (isLogicalAnd()) @@ -1795,7 +1832,7 @@ void QueryMemory::dump(llvm::raw_ostream &Outs, bool WithValues) const { Outs << ")"; } -eld::Expected QueryMemory::evalImpl() { +eld::Expected QueryMemory::evalImpl(bool EvaluatePendingOnly) { auto Region = ThisModule.getScript().getMemoryRegion(Name); if (!Region) return std::move(Region.error()); @@ -1818,7 +1855,7 @@ void NullExpression::dump(llvm::raw_ostream &Outs, bool WithValues) const { Outs << Name; } -eld::Expected NullExpression::evalImpl() { +eld::Expected NullExpression::evalImpl(bool EvaluatePendingOnly) { return std::make_unique( Diag::internal_error_null_expression, std::vector{}); } diff --git a/lib/SymbolResolver/IRBuilder.cpp b/lib/SymbolResolver/IRBuilder.cpp index 088de4066..cb1a686e8 100644 --- a/lib/SymbolResolver/IRBuilder.cpp +++ b/lib/SymbolResolver/IRBuilder.cpp @@ -547,6 +547,9 @@ LDSymbol *IRBuilder::addSymbol( Desc, /*isBitcode=*/false}); } + if (Input && Input->isLinkerScript()) + ThisModule.getNamePool().addScriptSymbol(OutputSym->resolveInfo()); + return OutputSym; } @@ -627,6 +630,10 @@ LDSymbol *IRBuilder::addSymbol( OutputSym->setValue(Value, false); } + // If symbol originates from a linker script, record it in NamePool. + if (Input && Input->isLinkerScript()) + ThisModule.getNamePool().addScriptSymbol(Result.Info); + return OutputSym; } diff --git a/lib/Target/CreateProgramHeaders.hpp b/lib/Target/CreateProgramHeaders.hpp index ad9b1ed31..cc0534194 100644 --- a/lib/Target/CreateProgramHeaders.hpp +++ b/lib/Target/CreateProgramHeaders.hpp @@ -150,6 +150,8 @@ bool GNULDBackend::createProgramHdrs() { outBegin = script.sectionMap().begin(); outEnd = script.sectionMap().end(); out = outBegin; + resetScriptSymbols(); + resetPartiallyEvalAssignmentsAndSymbols(); prev_flag = 0; prev = nullptr; prevOut = nullptr; @@ -694,6 +696,8 @@ bool GNULDBackend::createProgramHdrs() { ++out; } + evaluatePendingAssignments(); + if (dynamic && dynamic->size()) { ELFSegment *dyn_seg = make(llvm::ELF::PT_DYNAMIC, llvm::ELF::PF_R | llvm::ELF::PF_W); diff --git a/lib/Target/CreateScriptProgramHeaders.hpp b/lib/Target/CreateScriptProgramHeaders.hpp index 933634db6..98004192f 100644 --- a/lib/Target/CreateScriptProgramHeaders.hpp +++ b/lib/Target/CreateScriptProgramHeaders.hpp @@ -64,6 +64,8 @@ bool GNULDBackend::createScriptProgramHdrs() { outBegin = script.sectionMap().begin(); outEnd = script.sectionMap().end(); out = outBegin; + resetScriptSymbols(); + resetPartiallyEvalAssignmentsAndSymbols(); disconnect_lma_vma = false; last_seen_alloc_section = nullptr; is_previous_start_of_segment = false; @@ -387,6 +389,8 @@ bool GNULDBackend::createScriptProgramHdrs() { ++out; } + evaluatePendingAssignments(); + for (auto &seg : elfSegmentTable()) { // Handle empty segments if (!seg->size()) { diff --git a/lib/Target/GNULDBackend.cpp b/lib/Target/GNULDBackend.cpp index a68890486..aa7b30c4d 100644 --- a/lib/Target/GNULDBackend.cpp +++ b/lib/Target/GNULDBackend.cpp @@ -1718,7 +1718,8 @@ bool GNULDBackend::InsertAtSectionToEnd(ELFSection *OutSection, Assignment *assign = (*it); if (shouldskipAssert(assign)) continue; - (*it)->assign(m_Module, OutSection); + ASSERT(assign != nullptr, "assign must not be null!"); + evaluateAssignmentAndTrackPartiallyEvalAssignments(*assign, OutSection); if (OutSection->isAlloc()) NewOffset = dotSymbol->value() - OutSection->addr(); } @@ -1927,7 +1928,8 @@ void GNULDBackend::evaluateAssignments(OutputSectionEntry *out, if (padding.startOffset == -1) padding.startOffset = offset; uint64_t previousDotValue = dotSymbol->value(); - (*it)->assign(m_Module, OutSection); + ASSERT(assign != nullptr, "assign must not be null!"); + evaluateAssignmentAndTrackPartiallyEvalAssignments(*assign, OutSection); offset = dotSymbol->value() - OutSection->addr(); // Check for backward movement of dot symbol in the current output section if ((dotSymbol->value() < previousDotValue) && @@ -2076,6 +2078,7 @@ void GNULDBackend::evaluateAssignmentsAtEndOfOutputSection( ie = out->sectionendsymEnd(); it != ie; ++it) { Assignment *assign = (*it); + ASSERT(assign != nullptr, "assign must not be null!"); // We do not need to evaluate PROVIDE expressions for PROVIDE // symbols that are not being used in the link. if (assign->isProvideOrProvideHidden() && !isProvideSymBeingUsed(assign)) @@ -2090,7 +2093,7 @@ void GNULDBackend::evaluateAssignmentsAtEndOfOutputSection( } continue; } - (*it)->assign(m_Module, nullptr); + evaluateAssignmentAndTrackPartiallyEvalAssignments(*assign, /*S=*/nullptr); } } @@ -3937,6 +3940,7 @@ bool GNULDBackend::relax() { while (!finished) { auto start = std::chrono::steady_clock::now(); + config().raise(Diag::verbose_performing_layout_iteration) << iteration; { eld::RegisterTimer T("Assign Address", "Establish Layout", m_Module.getConfig().options().printTimingStats()); @@ -3997,6 +4001,7 @@ MemoryRegion GNULDBackend::getFileOutputRegion(llvm::FileOutputBuffer &pBuffer, void GNULDBackend::evaluateScriptAssignments(bool afterLayout) { auto &LS = m_Module.getScript(); for (auto &assign : m_Module.getScript().assignments()) { + ASSERT(assign != nullptr, "assign must not be null!"); if (LS.linkerScriptHasSectionsCommand()) { Assignment::Level AllowedLevel = (afterLayout ? Assignment::Level::AFTER_SECTIONS @@ -4018,12 +4023,13 @@ void GNULDBackend::evaluateScriptAssignments(bool afterLayout) { if (assign->isProvideOrProvideHidden() && !isProvideSymBeingUsed(assign)) continue; - assign->assign(m_Module, nullptr); + evaluateAssignmentAndTrackPartiallyEvalAssignments(*assign, /*S=*/nullptr); } } void GNULDBackend::evaluateAsserts() { for (auto &a : m_Module.getScript().assignments()) { + ASSERT(a != nullptr, "a must not be null!"); if (a->type() != Assignment::ASSERT) continue; if (a->hasDot()) { @@ -4041,7 +4047,7 @@ void GNULDBackend::evaluateAsserts() { a->dumpMap(SS, false, false); config().raise(Diag::executing_assert_after_layout) << SS.str(); } - a->assign(m_Module, nullptr); + evaluateAssignmentAndTrackPartiallyEvalAssignments(*a, /*S=*/nullptr); } } @@ -4604,11 +4610,7 @@ LDSymbol *GNULDBackend::canProvideSymbol(llvm::StringRef symName) { V = ResolveInfo::Hidden; resolverType = ResolveInfo::NoType; file = P->second->getInputFileInContext(); - // FIXME: We ideally should not need this. It is added so that the link - // does not fail if the provide command does not have input file context due - // to any corner case. - if (!file) - file = m_Module.getInternalInput(Module::Script); + ASSERT(file, "Must always be non-null!"); P->second->setUsed(true); } else if (isPSymDef) { resolverType = std::get<0>(PSymDef->second); @@ -5163,3 +5165,40 @@ bool GNULDBackend::setupTLS() { firstTLS->setAddrAlign(MaxAlignment); return seenTLS; } + +void GNULDBackend::evaluateAssignmentAndTrackPartiallyEvalAssignments( + Assignment &A, const ELFSection *S) { + A.assign(m_Module, S, /*EvaluatePendingOnly=*/false); + if (A.getExpression()->hasPendingEvaluation()) + PartiallyEvaluatedAssignments.push_back({&A, S}); +} + +void GNULDBackend::evaluatePendingAssignments() { + config().raise(Diag::verbose_eval_pending_assignments); + const std::size_t MaxIterations = 10; + for (std::size_t i = 0; i < MaxIterations; ++i) { + std::vector> + NewPartiallyEvalAssigns; + for (auto &P : PartiallyEvaluatedAssignments) { + auto *A = P.first; + auto *S = P.second; + A->assign(m_Module, S, /*EvaluatePendingOnly=*/true); + if (A->getExpression()->hasPendingEvaluation()) + NewPartiallyEvalAssigns.push_back({A, S}); + } + if (!(NewPartiallyEvalAssigns.size() < + PartiallyEvaluatedAssignments.size())) + break; + PartiallyEvaluatedAssignments = NewPartiallyEvalAssigns; + } + resetPartiallyEvalAssignmentsAndSymbols(); +} + +void GNULDBackend::resetScriptSymbols() { + const NamePool &NP = m_Module.getNamePool(); + const auto &ScriptSymbols = NP.getScriptSymbols(); + for (auto *RI : ScriptSymbols) { + RI->setValue(0, /*IsFinal=*/false); + RI->outSymbol()->setScriptValueDefined(false); + } +} diff --git a/test/Common/standalone/linkerscript/ExpressionEvaluation/ForwardReference.test b/test/Common/standalone/linkerscript/ExpressionEvaluation/ForwardReference.test new file mode 100644 index 000000000..e747d0037 --- /dev/null +++ b/test/Common/standalone/linkerscript/ExpressionEvaluation/ForwardReference.test @@ -0,0 +1,16 @@ +#---ForwardReference.test----------------------- Executable,LS --------------------# +#BEGIN_COMMENT +# This test checks that the linker performs correct expression evaluation +# when the expression contains a forward-reference. +#END_COMMENT +#START_TEST +RUN: %clang %clangopts -o %t1.1.o %p/Inputs/1.c -c -ffunction-sections +RUN: %link %linkopts -o %t1.1.out %t1.1.o -T %p/Inputs/script.ForwardReference.t +RUN: %readelf -s %t1.1.out 2>&1 | %filecheck %s +RUN: %link %linkopts -o %t1.1.phdr.out %t1.1.o -T %p/Inputs/script.ForwardReference.phdr.t +RUN: %readelf -s %t1.1.phdr.out 2>&1 | %filecheck %s +#END_TEST + +CHECK-DAG: [[VALUE:[0-9a-f]+]] {{.*}} ABS u +CHECK-DAG: [[VALUE]] {{.*}} ABS v + diff --git a/test/Common/standalone/linkerscript/ExpressionEvaluation/ForwardReferenceProvideSymbol.test b/test/Common/standalone/linkerscript/ExpressionEvaluation/ForwardReferenceProvideSymbol.test new file mode 100644 index 000000000..2b1e3ff8b --- /dev/null +++ b/test/Common/standalone/linkerscript/ExpressionEvaluation/ForwardReferenceProvideSymbol.test @@ -0,0 +1,20 @@ +#---ForwardReferenceProvideSymbol.test----------------------- Executable,LS --------------------# +#BEGIN_COMMENT +# This test checks that the linker performs correct expression evaluation +# when the expression contains a forward-reference of a PROVIDE symbol. +#END_COMMENT +#START_TEST +RUN: %clang %clangopts -o %t1.1.o %p/Inputs/1.c -c -ffunction-sections +RUN: %link %linkopts -o %t1.1.out %t1.1.o \ +RUN: -T %p/Inputs/script.ForwardReferenceProvideSymbol.t +RUN: %readelf -s %t1.1.out 2>&1 | %filecheck %s +RUN: %link %linkopts -o %t1.1.phdr.out %t1.1.o \ +RUN: -T %p/Inputs/script.ForwardReferenceProvideSymbol.phdr.t +RUN: %readelf -s %t1.1.phdr.out 2>&1 | %filecheck %s +#END_TEST + +CHECK-DAG: : [[#%x, START:]] {{.*}} start +CHECK-DAG: : [[#%x, END:]] {{.*}} end +CHECK-DAG: : {{0+}}[[#%x, V: END - START]] {{.*}} ABS v +CHECK-DAG: : {{0+}}[[#%x, V + 0x10]] {{.*}} ABS u + diff --git a/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/1.c b/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/1.c new file mode 100644 index 000000000..a60f28c10 --- /dev/null +++ b/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/1.c @@ -0,0 +1 @@ +int foo() { return 1; } diff --git a/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/2.c b/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/2.c new file mode 100644 index 000000000..6dfdf5903 --- /dev/null +++ b/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/2.c @@ -0,0 +1,11 @@ +int fn(); + +int foo() { return 11; } + +int bar() { return 13; } + +int baz() { return fn(); } + +int main() { + return baz(); +} diff --git a/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.ForwardReference.phdr.t b/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.ForwardReference.phdr.t new file mode 100644 index 000000000..4364993fc --- /dev/null +++ b/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.ForwardReference.phdr.t @@ -0,0 +1,13 @@ +PHDRS { + A PT_LOAD; +} + +SECTIONS { + u = v; + FOO (0x1000): { + start = .; + *(.text.foo) + end = .; + } :A + v = end - start; +} diff --git a/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.ForwardReference.t b/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.ForwardReference.t new file mode 100644 index 000000000..626f4e2c7 --- /dev/null +++ b/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.ForwardReference.t @@ -0,0 +1,9 @@ +SECTIONS { + u = v; + FOO (0x1000): { + start = .; + *(.text.foo) + end = .; + } + v = end - start; +} diff --git a/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.ForwardReferenceProvideSymbol.phdr.t b/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.ForwardReferenceProvideSymbol.phdr.t new file mode 100644 index 000000000..06a5db458 --- /dev/null +++ b/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.ForwardReferenceProvideSymbol.phdr.t @@ -0,0 +1,13 @@ +PHDRS { + A PT_LOAD; +} + +SECTIONS { + u = v ? v + 0x10 : 0x20; + FOO (0x1000): { + start = .; + *(.text.foo) + end = .; + } :A + PROVIDE(v = end - start); +} diff --git a/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.ForwardReferenceProvideSymbol.t b/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.ForwardReferenceProvideSymbol.t new file mode 100644 index 000000000..d3707dcd0 --- /dev/null +++ b/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.ForwardReferenceProvideSymbol.t @@ -0,0 +1,9 @@ +SECTIONS { + u = v ? v + 0x10 : 0x20; + FOO (0x1000): { + start = .; + *(.text.foo) + end = .; + } + PROVIDE(v = end - start); +} diff --git a/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.LayoutReset.phdr.t b/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.LayoutReset.phdr.t new file mode 100644 index 000000000..24ce270d9 --- /dev/null +++ b/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.LayoutReset.phdr.t @@ -0,0 +1,24 @@ +PHDRS { + A PT_LOAD; + B PT_LOAD; +} + +SECTIONS { + FOO (0x1000): { + fn = u; + u = bar; + *(.text.foo) + } :A + + BAR : { + u = baz; + *(.text.bar) + } :B + + BAZ : { + u = main; + *(.text.baz) + } :B + + u = foo; +} diff --git a/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.LayoutReset.t b/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.LayoutReset.t new file mode 100644 index 000000000..2b99711b6 --- /dev/null +++ b/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.LayoutReset.t @@ -0,0 +1,19 @@ +SECTIONS { + FOO (0x1000): { + fn = u; + u = bar; + *(.text.foo) + } + + BAR : { + u = baz; + *(.text.bar) + } + + BAZ : { + u = main; + *(.text.baz) + } + + u = foo; +} diff --git a/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.RecursivePendingEvaluation.phdr.t b/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.RecursivePendingEvaluation.phdr.t new file mode 100644 index 000000000..3fcb2b174 --- /dev/null +++ b/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.RecursivePendingEvaluation.phdr.t @@ -0,0 +1,17 @@ +PHDRS { + A PT_LOAD; +} + +SECTIONS { + FOO (0x1000) : { + fn = u; + u = v1; + *(.text.foo) + } :A + v1 = v2; + v2 = v3; + v3 = v4; + v4 = v5; + v5 = v6; + v6 = foo; +} diff --git a/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.RecursivePendingEvaluation.t b/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.RecursivePendingEvaluation.t new file mode 100644 index 000000000..41172c2cd --- /dev/null +++ b/test/Common/standalone/linkerscript/ExpressionEvaluation/Inputs/script.RecursivePendingEvaluation.t @@ -0,0 +1,13 @@ +SECTIONS { + FOO (0x1000) : { + fn = u; + u = v1; + *(.text.foo) + } + v1 = v2; + v2 = v3; + v3 = v4; + v4 = v5; + v5 = v6; + v6 = foo; +} diff --git a/test/Common/standalone/linkerscript/ExpressionEvaluation/LayoutResetForwardReference.test b/test/Common/standalone/linkerscript/ExpressionEvaluation/LayoutResetForwardReference.test new file mode 100644 index 000000000..35e5ff50e --- /dev/null +++ b/test/Common/standalone/linkerscript/ExpressionEvaluation/LayoutResetForwardReference.test @@ -0,0 +1,25 @@ +#---LayoutResetForwardReference.test----------------------- Executable,LS --------------------# +#BEGIN_COMMENT +# This test checks that the linker performs correct expression evaluation +# when the expression contains a forward-reference, and the layout reset +# during the layout may cause incorrect expression evaluation by incorrectly +# providing intermediate values to pending assignments. +#END_COMMENT +#START_TEST +RUN: %clang %clangopts -o %t1.2.o %p/Inputs/2.c -c -ffunction-sections +RUN: %link %linkopts -o %t1.2.out %t1.2.o -T %p/Inputs/script.LayoutReset.t \ +RUN: --trace=pending-assignments --verbose 2>&1 | %filecheck %s +RUN: %readelf -s %t1.2.out 2>&1 | %filecheck %s --check-prefix READELF +RUN: %link %linkopts -o %t1.2.phdr.out %t1.2.o -T %p/Inputs/script.LayoutReset.phdr.t \ +RUN: --trace=pending-assignments --verbose 2>&1 | %filecheck %s +RUN: %readelf -s %t1.2.phdr.out 2>&1 | %filecheck %s --check-prefix READELF +#END_TEST + +CHECK-DAG: Verbose: Performing layout iteration 0 +CHECK-DAG: Verbose: Evaluating pending assignments +CHECK-DAG: INSIDE_OUTPUT_SECTION >> fn(4096) = u(0x1000); + +READELF-DAG: {{0+}}1000 {{.*}} u +READELF-DAG: {{0+}}1000 {{.*}} foo +READELF-DAG: {{0+}}1000 {{.*}} fn + diff --git a/test/Common/standalone/linkerscript/ExpressionEvaluation/RecursivePendingEvaluation.test b/test/Common/standalone/linkerscript/ExpressionEvaluation/RecursivePendingEvaluation.test new file mode 100644 index 000000000..3883d1a87 --- /dev/null +++ b/test/Common/standalone/linkerscript/ExpressionEvaluation/RecursivePendingEvaluation.test @@ -0,0 +1,59 @@ +#---RecursivePendingEvaluation.test----------------------- Executable,LS --------------------# +#BEGIN_COMMENT +# This test checks that the linker performs correct expression evaluation +# when there is a chain of forward reference expression such that +# the pending assignments evaluation rounds needs several iterations +# to resolve all the pending assignments. +#END_COMMENT +#START_TEST +RUN: %clang %clangopts -o %t1.2.o %p/Inputs/2.c -c -ffunction-sections +RUN: %link %linkopts -o %t1.2.out %t1.2.o \ +RUN: -T %p/Inputs/script.RecursivePendingEvaluation.t \ +RUN: --trace=pending-assignments --verbose 2>&1 | %filecheck %s +RUN: %readelf -s %t1.2.out 2>&1 | %filecheck %s --check-prefix READELF +RUN: %link %linkopts -o %t1.2.phdr.out %t1.2.o \ +RUN: -T %p/Inputs/script.RecursivePendingEvaluation.phdr.t \ +RUN: --trace=pending-assignments --verbose 2>&1 | %filecheck %s +RUN: %readelf -s %t1.2.phdr.out 2>&1 | %filecheck %s --check-prefix READELF +#END_TEST + +CHECK-DAG: Verbose: Performing layout iteration 0 +CHECK: INSIDE_OUTPUT_SECTION >> fn(0) = u(0x0); +CHECK: INSIDE_OUTPUT_SECTION >> u(0) = v1(0x0); +CHECK: OUTPUT_SECTION(EPILOGUE) >> v1(0) = v2(0x0); +CHECK: OUTPUT_SECTION(EPILOGUE) >> v2(0) = v3(0x0); +CHECK: OUTPUT_SECTION(EPILOGUE) >> v3(0) = v4(0x0); +CHECK: OUTPUT_SECTION(EPILOGUE) >> v4(0) = v5(0x0); +CHECK: OUTPUT_SECTION(EPILOGUE) >> v5(4096) = v6(0x1000); +CHECK: INSIDE_OUTPUT_SECTION >> fn(0) = u(0x0); +CHECK: INSIDE_OUTPUT_SECTION >> u(0) = v1(0x0); +CHECK: OUTPUT_SECTION(EPILOGUE) >> v1(0) = v2(0x0); +CHECK: OUTPUT_SECTION(EPILOGUE) >> v2(0) = v3(0x0); +CHECK: OUTPUT_SECTION(EPILOGUE) >> v3(0) = v4(0x0); +CHECK: OUTPUT_SECTION(EPILOGUE) >> v4(4096) = v5(0x1000); +CHECK: INSIDE_OUTPUT_SECTION >> fn(0) = u(0x0); +CHECK: INSIDE_OUTPUT_SECTION >> u(0) = v1(0x0); +CHECK: OUTPUT_SECTION(EPILOGUE) >> v1(0) = v2(0x0); +CHECK: OUTPUT_SECTION(EPILOGUE) >> v2(0) = v3(0x0); +CHECK: OUTPUT_SECTION(EPILOGUE) >> v3(4096) = v4(0x1000); +CHECK: INSIDE_OUTPUT_SECTION >> fn(0) = u(0x0); +CHECK: INSIDE_OUTPUT_SECTION >> u(0) = v1(0x0); +CHECK: OUTPUT_SECTION(EPILOGUE) >> v1(0) = v2(0x0); +CHECK: OUTPUT_SECTION(EPILOGUE) >> v2(4096) = v3(0x1000); +CHECK: INSIDE_OUTPUT_SECTION >> fn(0) = u(0x0); +CHECK: INSIDE_OUTPUT_SECTION >> u(0) = v1(0x0); +CHECK: OUTPUT_SECTION(EPILOGUE) >> v1(4096) = v2(0x1000); +CHECK: INSIDE_OUTPUT_SECTION >> fn(0) = u(0x0); +CHECK: INSIDE_OUTPUT_SECTION >> u(4096) = v1(0x1000); +CHECK: INSIDE_OUTPUT_SECTION >> fn(4096) = u(0x1000); + +READELF-DAG: {{0+}}1000 {{.*}} u +READELF-DAG: {{0+}}1000 {{.*}} foo +READELF-DAG: {{0+}}1000 {{.*}} fn +READELF-DAG: {{0+}}1000 {{.*}} v1 +READELF-DAG: {{0+}}1000 {{.*}} v2 +READELF-DAG: {{0+}}1000 {{.*}} v3 +READELF-DAG: {{0+}}1000 {{.*}} v4 +READELF-DAG: {{0+}}1000 {{.*}} v5 +READELF-DAG: {{0+}}1000 {{.*}} v6 +