[lld] b3452f8 - [ELF] redirectSymbols: skip versioned symbol combine if config->versionDefinitions.size() == 2
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Sun Jul 31 17:47:14 PDT 2022
Author: Fangrui Song
Date: 2022-07-31T17:47:09-07:00
New Revision: b3452f8f1302e3f1a0f0db5c1d3723e7953e7f9d
URL: https://github.com/llvm/llvm-project/commit/b3452f8f1302e3f1a0f0db5c1d3723e7953e7f9d
DIFF: https://github.com/llvm/llvm-project/commit/b3452f8f1302e3f1a0f0db5c1d3723e7953e7f9d.diff
LOG: [ELF] redirectSymbols: skip versioned symbol combine if config->versionDefinitions.size() == 2
Added:
Modified:
lld/ELF/Driver.cpp
Removed:
################################################################################
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 826cbaeeed70..7cd8b2432c73 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -2245,6 +2245,49 @@ static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &args) {
return v;
}
+static void combineVersionedSymbol(Symbol &sym,
+ DenseMap<Symbol *, Symbol *> &map) {
+ const char *suffix1 = sym.getVersionSuffix();
+ if (suffix1[0] != '@' || suffix1[1] == '@')
+ return;
+
+ // Check the existing symbol foo. We have two special cases to handle:
+ //
+ // * There is a definition of foo at v1 and foo@@v1.
+ // * There is a definition of foo at v1 and foo.
+ Defined *sym2 = dyn_cast_or_null<Defined>(symtab->find(sym.getName()));
+ if (!sym2)
+ return;
+ const char *suffix2 = sym2->getVersionSuffix();
+ if (suffix2[0] == '@' && suffix2[1] == '@' &&
+ strcmp(suffix1 + 1, suffix2 + 2) == 0) {
+ // foo at v1 and foo@@v1 should be merged, so redirect foo at v1 to foo@@v1.
+ map.try_emplace(&sym, sym2);
+ // If both foo at v1 and foo@@v1 are defined and non-weak, report a
+ // duplicate definition error.
+ if (sym.isDefined())
+ sym2->checkDuplicate(cast<Defined>(sym));
+ sym2->resolve(sym);
+ // Eliminate foo at v1 from the symbol table.
+ sym.symbolKind = Symbol::PlaceholderKind;
+ sym.isUsedInRegularObj = false;
+ } else if (auto *sym1 = dyn_cast<Defined>(&sym)) {
+ if (sym2->versionId > VER_NDX_GLOBAL
+ ? config->versionDefinitions[sym2->versionId].name == suffix1 + 1
+ : sym1->section == sym2->section && sym1->value == sym2->value) {
+ // Due to an assembler design flaw, if foo is defined, .symver foo,
+ // foo at v1 defines both foo and foo at v1. Unless foo is bound to a
+ //
diff erent version, GNU ld makes foo at v1 canonical and eliminates
+ // foo. Emulate its behavior, otherwise we would have foo or foo@@v1
+ // beside foo at v1. foo at v1 and foo combining does not apply if they are
+ // not defined in the same place.
+ map.try_emplace(sym2, &sym);
+ sym2->symbolKind = Symbol::PlaceholderKind;
+ sym2->isUsedInRegularObj = false;
+ }
+ }
+}
+
// Do renaming for --wrap and foo at v1 by updating pointers to symbols.
//
// When this function is executed, only InputFiles and symbol table
@@ -2257,51 +2300,14 @@ static void redirectSymbols(ArrayRef<WrappedSymbol> wrapped) {
map[w.sym] = w.wrap;
map[w.real] = w.sym;
}
- for (Symbol *sym : symtab->symbols()) {
- // Enumerate symbols with a non-default version (foo at v1). hasVersionSuffix
- // filters out most symbols but is not sufficient.
- if (!sym->hasVersionSuffix)
- continue;
- const char *suffix1 = sym->getVersionSuffix();
- if (suffix1[0] != '@' || suffix1[1] == '@')
- continue;
- // Check the existing symbol foo. We have two special cases to handle:
- //
- // * There is a definition of foo at v1 and foo@@v1.
- // * There is a definition of foo at v1 and foo.
- Defined *sym2 = dyn_cast_or_null<Defined>(symtab->find(sym->getName()));
- if (!sym2)
- continue;
- const char *suffix2 = sym2->getVersionSuffix();
- if (suffix2[0] == '@' && suffix2[1] == '@' &&
- strcmp(suffix1 + 1, suffix2 + 2) == 0) {
- // foo at v1 and foo@@v1 should be merged, so redirect foo at v1 to foo@@v1.
- map.try_emplace(sym, sym2);
- // If both foo at v1 and foo@@v1 are defined and non-weak, report a duplicate
- // definition error.
- if (sym->isDefined())
- sym2->checkDuplicate(cast<Defined>(*sym));
- sym2->resolve(*sym);
- // Eliminate foo at v1 from the symbol table.
- sym->symbolKind = Symbol::PlaceholderKind;
- sym->isUsedInRegularObj = false;
- } else if (auto *sym1 = dyn_cast<Defined>(sym)) {
- if (sym2->versionId > VER_NDX_GLOBAL
- ? config->versionDefinitions[sym2->versionId].name == suffix1 + 1
- : sym1->section == sym2->section && sym1->value == sym2->value) {
- // Due to an assembler design flaw, if foo is defined, .symver foo,
- // foo at v1 defines both foo and foo at v1. Unless foo is bound to a
- //
diff erent version, GNU ld makes foo at v1 canonical and eliminates foo.
- // Emulate its behavior, otherwise we would have foo or foo@@v1 beside
- // foo at v1. foo at v1 and foo combining does not apply if they are not
- // defined in the same place.
- map.try_emplace(sym2, sym);
- sym2->symbolKind = Symbol::PlaceholderKind;
- sym2->isUsedInRegularObj = false;
- }
- }
- }
+ // If there are version definitions (versionDefinitions.size() > 2), enumerate
+ // symbols with a non-default version (foo at v1) and check whether it should be
+ // combined with foo or foo@@v1.
+ if (config->versionDefinitions.size() > 2)
+ for (Symbol *sym : symtab->symbols())
+ if (sym->hasVersionSuffix)
+ combineVersionedSymbol(*sym, map);
if (map.empty())
return;
More information about the llvm-commits
mailing list