[ELF] Fix unnecessary inclusion of unreferenced provide symbols
Previously, linker was unnecessarily including a PROVIDE symbol which was referenced by another unused PROVIDE symbol. For example, if a linker script contained the below code and 'not_used_sym' provide symbol is not included, then linker was still unnecessarily including 'foo' PROVIDE symbol because it was referenced by 'not_used_sym'. This commit fixes this behavior. PROVIDE(not_used_sym = foo) PROVIDE(foo = 0x1000) This commit fixes this behavior by using dfs-like algorithm to find all the symbols referenced in provide expressions of included provide symbols. This commit also fixes the issue of unused section not being garbage-collected if a symbol of the section is referenced by an unused PROVIDE symbol. Closes #74771 Closes #84730 Co-authored-by: Fangrui Song <i@maskray.me>
This commit is contained in:
committed by
Fangrui Song
parent
b6dfaf4c29
commit
ebb326a51f
@@ -198,15 +198,7 @@ static bool shouldDefineSym(SymbolAssignment *cmd) {
|
||||
if (cmd->name == ".")
|
||||
return false;
|
||||
|
||||
if (!cmd->provide)
|
||||
return true;
|
||||
|
||||
// If a symbol was in PROVIDE(), we need to define it only
|
||||
// when it is a referenced undefined symbol.
|
||||
Symbol *b = symtab.find(cmd->name);
|
||||
if (b && !b->isDefined() && !b->isCommon())
|
||||
return true;
|
||||
return false;
|
||||
return !cmd->provide || LinkerScript::shouldAddProvideSym(cmd->name);
|
||||
}
|
||||
|
||||
// Called by processSymbolAssignments() to assign definitions to
|
||||
@@ -1517,3 +1509,41 @@ void LinkerScript::checkFinalScriptConditions() const {
|
||||
checkMemoryRegion(lmaRegion, sec, sec->getLMA());
|
||||
}
|
||||
}
|
||||
|
||||
void LinkerScript::addScriptReferencedSymbolsToSymTable() {
|
||||
// Some symbols (such as __ehdr_start) are defined lazily only when there
|
||||
// are undefined symbols for them, so we add these to trigger that logic.
|
||||
auto reference = [](StringRef name) {
|
||||
Symbol *sym = symtab.addUnusedUndefined(name);
|
||||
sym->isUsedInRegularObj = true;
|
||||
sym->referenced = true;
|
||||
};
|
||||
for (StringRef name : referencedSymbols)
|
||||
reference(name);
|
||||
|
||||
// Keeps track of references from which PROVIDE symbols have been added to the
|
||||
// symbol table.
|
||||
DenseSet<StringRef> added;
|
||||
SmallVector<const SmallVector<StringRef, 0> *, 0> symRefsVec;
|
||||
for (const auto &[name, symRefs] : provideMap)
|
||||
if (LinkerScript::shouldAddProvideSym(name) && added.insert(name).second)
|
||||
symRefsVec.push_back(&symRefs);
|
||||
while (symRefsVec.size()) {
|
||||
for (StringRef name : *symRefsVec.pop_back_val()) {
|
||||
reference(name);
|
||||
// Prevent the symbol from being discarded by --gc-sections.
|
||||
script->referencedSymbols.push_back(name);
|
||||
auto it = script->provideMap.find(name);
|
||||
if (it != script->provideMap.end() &&
|
||||
LinkerScript::shouldAddProvideSym(name) &&
|
||||
added.insert(name).second) {
|
||||
symRefsVec.push_back(&it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LinkerScript::shouldAddProvideSym(StringRef symName) {
|
||||
Symbol *sym = symtab.find(symName);
|
||||
return sym && !sym->isDefined() && !sym->isCommon();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user