diff options
Diffstat (limited to 'lld/ELF/LinkerScript.cpp')
-rw-r--r-- | lld/ELF/LinkerScript.cpp | 45 |
1 files changed, 44 insertions, 1 deletions
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index a489943d62c..2fc9b0b091d 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -210,6 +210,44 @@ static void declareSymbol(SymbolAssignment *cmd) { sym->scriptDefined = true; } +using SymbolAssignmentMap = + DenseMap<const Defined *, std::pair<SectionBase *, uint64_t>>; + +// Collect section/value pairs of linker-script-defined symbols. This is used to +// check whether symbol values converge. +static SymbolAssignmentMap +getSymbolAssignmentValues(const std::vector<BaseCommand *> §ionCommands) { + SymbolAssignmentMap ret; + for (BaseCommand *base : sectionCommands) { + if (auto *cmd = dyn_cast<SymbolAssignment>(base)) { + if (cmd->sym) // sym is nullptr for dot. + ret.try_emplace(cmd->sym, + std::make_pair(cmd->sym->section, cmd->sym->value)); + continue; + } + for (BaseCommand *sub_base : cast<OutputSection>(base)->sectionCommands) + if (auto *cmd = dyn_cast<SymbolAssignment>(sub_base)) + if (cmd->sym) + ret.try_emplace(cmd->sym, + std::make_pair(cmd->sym->section, cmd->sym->value)); + } + return ret; +} + +// Returns the lexicographical smallest (for determinism) Defined whose +// section/value has changed. +static const Defined * +getChangedSymbolAssignment(const SymbolAssignmentMap &oldValues) { + const Defined *changed = nullptr; + for (auto &it : oldValues) { + const Defined *sym = it.first; + if (std::make_pair(sym->section, sym->value) != it.second && + (!changed || sym->getName() < changed->getName())) + changed = sym; + } + return changed; +} + // This method is used to handle INSERT AFTER statement. Here we rebuild // the list of script commands to mix sections inserted into. void LinkerScript::processInsertCommands() { @@ -1051,7 +1089,9 @@ static uint64_t getInitialDot() { // Here we assign addresses as instructed by linker script SECTIONS // sub-commands. Doing that allows us to use final VA values, so here // we also handle rest commands like symbol assignments and ASSERTs. -void LinkerScript::assignAddresses() { +// Returns a symbol that has changed its section or value, or nullptr if no +// symbol has changed. +const Defined *LinkerScript::assignAddresses() { dot = getInitialDot(); auto deleter = std::make_unique<AddressState>(); @@ -1059,6 +1099,7 @@ void LinkerScript::assignAddresses() { errorOnMissingSection = true; switchTo(aether); + SymbolAssignmentMap oldValues = getSymbolAssignmentValues(sectionCommands); for (BaseCommand *base : sectionCommands) { if (auto *cmd = dyn_cast<SymbolAssignment>(base)) { cmd->addr = dot; @@ -1068,7 +1109,9 @@ void LinkerScript::assignAddresses() { } assignOffsets(cast<OutputSection>(base)); } + ctx = nullptr; + return getChangedSymbolAssignment(oldValues); } // Creates program headers as instructed by PHDRS linker script command. |