[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