[lld] 7924b38 - [ELF] Add Symbol::hasVersionSuffix

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Sun Dec 26 17:26:00 PST 2021


Author: Fangrui Song
Date: 2021-12-26T17:25:54-08:00
New Revision: 7924b3814f40747cafff7aec24e6b16fda02af44

URL: https://github.com/llvm/llvm-project/commit/7924b3814f40747cafff7aec24e6b16fda02af44
DIFF: https://github.com/llvm/llvm-project/commit/7924b3814f40747cafff7aec24e6b16fda02af44.diff

LOG: [ELF] Add Symbol::hasVersionSuffix

"Process symbol versions" may take 2+% time.
"Redirect symbols" may take 0.6% time.
This change speeds up the two passes and makes `*sym.getVersionSuffix()
== '@'` in the `undefined reference` diagnostic cleaner.

Linking chrome (no debug info) and another large program is 1.5% faster.

For empty-ver2.s: the behavior now matches GNU ld, though I'd consider the input
invalid and the exact behavior does not matter.

Added: 
    

Modified: 
    lld/ELF/Driver.cpp
    lld/ELF/Relocations.cpp
    lld/ELF/SymbolTable.cpp
    lld/ELF/Symbols.cpp
    lld/ELF/Symbols.h
    lld/test/ELF/empty-ver2.s

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 6b689f50cce7d..2923d45018c4f 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -2006,7 +2006,8 @@ template <class ELFT> void LinkerDriver::compileBitcodeFiles() {
     // Parse '@' in symbol names for non-relocatable output.
     if (!config->relocatable)
       for (Symbol *sym : obj->getGlobalSymbols())
-        sym->parseSymbolVersion();
+        if (sym->hasVersionSuffix)
+          sym->parseSymbolVersion();
     objectFiles.push_back(obj);
   }
 }
@@ -2080,8 +2081,10 @@ static void redirectSymbols(ArrayRef<WrappedSymbol> wrapped) {
     map[w.real] = w.sym;
   }
   for (Symbol *sym : symtab->symbols()) {
-    // Enumerate symbols with a non-default version (foo at v1).
-    StringRef name = sym->getName();
+    // 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;
@@ -2090,7 +2093,7 @@ static void redirectSymbols(ArrayRef<WrappedSymbol> wrapped) {
     //
     // * 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(name));
+    Defined *sym2 = dyn_cast_or_null<Defined>(symtab->find(sym->getName()));
     if (!sym2)
       continue;
     const char *suffix2 = sym2->getVersionSuffix();

diff  --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 33227bd2447be..d7eef68800c5b 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -741,7 +741,7 @@ static bool maybeReportUndefined(Symbol &sym, InputSectionBase &sec,
                                  uint64_t offset) {
   // If versioned, issue an error (even if the symbol is weak) because we don't
   // know the defining filename which is required to construct a Verneed entry.
-  if (*sym.getVersionSuffix() == '@') {
+  if (sym.hasVersionSuffix) {
     undefs.push_back({&sym, {{&sec, offset}}, false});
     return true;
   }

diff  --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp
index a12c5f22c4fef..c93a166daa6e4 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -72,8 +72,10 @@ Symbol *SymbolTable::insert(StringRef name) {
   auto p = symMap.insert({CachedHashStringRef(stem), (int)symVector.size()});
   if (!p.second) {
     Symbol *sym = symVector[p.first->second];
-    if (stem.size() != name.size())
+    if (stem.size() != name.size()) {
       sym->setName(name);
+      sym->hasVersionSuffix = true;
+    }
     return sym;
   }
 
@@ -93,6 +95,8 @@ Symbol *SymbolTable::insert(StringRef name) {
   sym->referenced = false;
   sym->traced = false;
   sym->scriptDefined = false;
+  if (pos != StringRef::npos)
+    sym->hasVersionSuffix = true;
   sym->partition = 1;
   return sym;
 }
@@ -316,7 +320,8 @@ void SymbolTable::scanVersionScript() {
   // can contain versions in the form of <name>@<version>.
   // Let them parse and update their names to exclude version suffix.
   for (Symbol *sym : symVector)
-    sym->parseSymbolVersion();
+    if (sym->hasVersionSuffix)
+      sym->parseSymbolVersion();
 
   // isPreemptible is false at this point. To correctly compute the binding of a
   // Defined (which is used by includeInDynsym()), we need to know if it is

diff  --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index 20301497a059e..9d8ff8aa4c199 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -216,12 +216,13 @@ void Symbol::parseSymbolVersion() {
   if (pos == StringRef::npos)
     return;
   StringRef verstr = s.substr(pos + 1);
-  if (verstr.empty())
-    return;
 
   // Truncate the symbol name so that it doesn't include the version string.
   nameSize = pos;
 
+  if (verstr.empty())
+    return;
+
   // If this is not in this DSO, it is not a definition.
   if (!isDefined())
     return;

diff  --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index 27c36eedce805..e2dc76f576af7 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -144,6 +144,9 @@ class Symbol {
   // True if this symbol is specified by --trace-symbol option.
   uint8_t traced : 1;
 
+  // True if the name contains '@'.
+  uint8_t hasVersionSuffix : 1;
+
   inline void replace(const Symbol &newSym);
 
   bool includeInDynsym() const;
@@ -246,10 +249,11 @@ class Symbol {
         type(type), stOther(stOther), symbolKind(k), visibility(stOther & 3),
         isUsedInRegularObj(!file || file->kind() == InputFile::ObjKind),
         exportDynamic(isExportDynamic(k, visibility)), inDynamicList(false),
-        canInline(false), referenced(false), traced(false), isInIplt(false),
-        gotInIgot(false), isPreemptible(false), used(!config->gcSections),
-        folded(false), needsTocRestore(false), scriptDefined(false),
-        needsCopy(false), needsGot(false), needsPlt(false), needsTlsDesc(false),
+        canInline(false), referenced(false), traced(false),
+        hasVersionSuffix(false), isInIplt(false), gotInIgot(false),
+        isPreemptible(false), used(!config->gcSections), folded(false),
+        needsTocRestore(false), scriptDefined(false), needsCopy(false),
+        needsGot(false), needsPlt(false), needsTlsDesc(false),
         needsTlsGd(false), needsTlsGdToIe(false), needsTlsLd(false),
         needsGotDtprel(false), needsTlsIe(false), hasDirectReloc(false) {}
 
@@ -575,6 +579,7 @@ void Symbol::replace(const Symbol &newSym) {
   canInline = old.canInline;
   referenced = old.referenced;
   traced = old.traced;
+  hasVersionSuffix = old.hasVersionSuffix;
   isPreemptible = old.isPreemptible;
   scriptDefined = old.scriptDefined;
   partition = old.partition;

diff  --git a/lld/test/ELF/empty-ver2.s b/lld/test/ELF/empty-ver2.s
index 8692e049c9474..c28b3ae83b2fa 100644
--- a/lld/test/ELF/empty-ver2.s
+++ b/lld/test/ELF/empty-ver2.s
@@ -12,7 +12,7 @@
 # CHECK-NEXT:   }
 # CHECK-NEXT:   Symbol {
 # CHECK-NEXT:     Version: 1
-# CHECK-NEXT:     Name: bar@
+# CHECK-NEXT:     Name: bar{{$}}
 # CHECK-NEXT:   }
 # CHECK-NEXT: ]
 


        


More information about the llvm-commits mailing list