Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions include/eld/Diagnostics/DiagVerbose.inc
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,9 @@ DIAG(verbose_linker_script_output_file, DiagnosticEngine::Verbose,
"Using output file name '%0' specified in the linker script '%1'")
DIAG(verbose_rule_matching_cache_func_hash, DiagnosticEngine::Verbose,
"Rule-matching cache-functionailty hash: %0")
DIAG(verbose_performing_layout_iteration, DiagnosticEngine::Verbose,
"Performing layout iteration %0")
DIAG(verbose_eval_pending_assignments, DiagnosticEngine::Verbose,
"Evaluating pending assignments")
DIAG(verbose_reset_tracked_assignment, DiagnosticEngine::Verbose,
"Resetting tracked assignments")
3 changes: 3 additions & 0 deletions include/eld/Diagnostics/DiagnosticPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class DiagnosticPrinter {
TraceMergeStrings = 0x8000,
TraceLinkerScript = 0x10000,
TraceSymDef = 0x100000,
TracePendingAssignments = 0x200000
};

enum Verbose : uint16_t { None = 0x0, Default = 0x1 };
Expand All @@ -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; }
Expand Down
3 changes: 2 additions & 1 deletion include/eld/Driver/GnuLinkerOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,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<"<trace-type>">,
Group<grp_diagopts>;
defm trace_symbol : smDashTwoWithOpt<"y", "trace-symbol", "trace_symbol",
Expand Down
17 changes: 14 additions & 3 deletions include/eld/Script/Assignment.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<void> 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<ResolveInfo *> &Symbols) const;

/// Query functions on Assignment Kinds.
Expand Down Expand Up @@ -117,7 +123,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<std::string> getSymbolNames() const;

// Add all undefined references from assignmnent expressions
Expand All @@ -128,6 +136,9 @@ class Assignment : public ScriptCommand {

bool isUsed() const { return IsUsed; }

/// Reset the assignment value and the expression node.
void reset();

private:
bool checkLinkerScript(Module &CurModule);

Expand Down
162 changes: 115 additions & 47 deletions include/eld/Script/Expression.h

Large diffs are not rendered by default.

74 changes: 74 additions & 0 deletions include/eld/Target/GNULDBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,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 resetPartiallyEvalAssignsAndSymbols() {
PartiallyEvaluatedAssignments.clear();
PartiallyEvaluatedSymbols.clear();
}

/// Recursively evaluates the partially evaluated assignments.
void evaluatePendingAssignments();

protected:
virtual int numReservedSegments() const { return m_NumReservedSegments; }

Expand Down Expand Up @@ -1000,6 +1022,34 @@ 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);

/// Reset the tracked assignments and the TrackedAssignments vector.
/// Resetting an assignment resets the assignment node and all the
/// expression nodes contained in the assignment.
void resetTrackedAssignments();

/// Stores the snapshot of linker script symbols.
void takeLSSymbolsSnapshot();

/// Restores the value of linker script symbols using the linker script symbol
/// snapshot stored using takeLSSymbolsSnapshot.
void restoreLSSymbolsUsingSnapshot();

void takePartiallyEvalAssignsAndSymbolsSnapshot() {
PartiallyEvaluatedAssignmentsSnapshot = PartiallyEvaluatedAssignments;
PartiallyEvaluatedSymbolsSnapshot = PartiallyEvaluatedSymbols;
}

void restorePartiallyEvalAssignsAndSymbolsUsingSnapshot() {
PartiallyEvaluatedAssignments = PartiallyEvaluatedAssignmentsSnapshot;
PartiallyEvaluatedSymbols = PartiallyEvaluatedSymbolsSnapshot;
}

protected:
Module &m_Module;

Expand Down Expand Up @@ -1130,6 +1180,30 @@ class GNULDBackend {
bool m_NeedEhdr = false;

bool m_NeedPhdr = false;

std::unordered_set<const ResolveInfo *> PartiallyEvaluatedSymbols;

/// Stores the assignments which needs to be reevaluated later.
std::vector<std::pair<Assignment *, const ELFSection *>>
PartiallyEvaluatedAssignments;

std::unordered_set<const ResolveInfo *> PartiallyEvaluatedSymbolsSnapshot;

/// Stores the assignments which needs to be reevaluated later.
std::vector<std::pair<Assignment *, const ELFSection *>>
PartiallyEvaluatedAssignmentsSnapshot;

/// TrackedAssignments stores the assignments which gets evaluated if
/// TrackAssignments is true. It is used to reset the evaluated assignments.
bool TrackAssignments = false;
std::vector<Assignment *> TrackedAssignments;

struct LSSymbolInfo {
ResolveInfo *RI = nullptr;
uint64_t Value = 0;
bool HasScriptValue = false;
};
std::vector<LSSymbolInfo> LSSymbolsSnapshot;
};

} // namespace eld
Expand Down
2 changes: 2 additions & 0 deletions lib/Config/GeneralOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,8 @@ eld::Expected<void> 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.
Expand Down
4 changes: 3 additions & 1 deletion lib/LinkerWrapper/LinkerWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,9 @@ eld::Expected<void> LinkerWrapper::finishAssignOutputSections() {
eld::Expected<void> LinkerWrapper::reassignVirtualAddresses() {
if (getState() != State::CreatingSegments)
RETURN_INVALID_LINK_STATE_ERR("CreatingSegments");
m_Module.getBackend().createScriptProgramHdrs();
auto &Backend = m_Module.getBackend();
Backend.createScriptProgramHdrs();
Backend.evaluatePendingAssignments();
return {};
}

Expand Down
5 changes: 4 additions & 1 deletion lib/Object/ObjectLinker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
29 changes: 26 additions & 3 deletions lib/Script/Assignment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <cassert>

Expand Down Expand Up @@ -205,7 +206,8 @@ void Assignment::getSymbols(std::vector<ResolveInfo *> &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)
Expand All @@ -215,7 +217,11 @@ bool Assignment::assign(Module &CurModule, const ELFSection *Section) {
}

// evaluate, commit, then get the result of the expression
auto Result = ExpressionToEvaluate->evaluateAndRaiseError();
std::optional<uint64_t> Result;
if (EvaluatePendingOnly)
Result = ExpressionToEvaluate->evaluatePendingAndRaiseError();
else
Result = ExpressionToEvaluate->evaluateAndRaiseError();
if (!Result)
return false;
ExpressionValue = *Result;
Expand All @@ -224,13 +230,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;
}
Expand Down Expand Up @@ -276,3 +292,10 @@ std::unordered_set<std::string> Assignment::getSymbolNames() const {
ExpressionToEvaluate->getSymbolNames(SymbolNames);
return SymbolNames;
}

void Assignment::reset() {
ExpressionValue = 0;
ThisSymbol = nullptr;
if (ExpressionToEvaluate)
ExpressionToEvaluate->resetRecursively();
}
Loading
Loading