[lld] r275682 - Recommit r275257 "[ELF] - Implement extern "c++" version script tag"

George Rimar via llvm-commits llvm-commits at lists.llvm.org
Sat Jul 16 05:26:40 PDT 2016


Author: grimar
Date: Sat Jul 16 07:26:39 2016
New Revision: 275682

URL: http://llvm.org/viewvc/llvm-project?rev=275682&view=rev
Log:
Recommit r275257 "[ELF] - Implement extern "c++" version script tag"

BSD toolchain contains a bug:
https://sourceforge.net/p/elftoolchain/tickets/491/

In short demangler works differently, fix was to update the testcase.
It should fix the FreeBSD bot failture:
http://lab.llvm.org:8011/builders/lld-x86_64-freebsd/builds/19432/steps/test_lld/logs/stdio

Original commit message was:
[ELF] - Implement extern "c++" version script tag

Patch implements 'extern' version script tag.
Currently only values in quotes(") are supported.

Matching of externs is performed in the same pass as exact match of globals.

Differential revision: http://reviews.llvm.org/D21930

Added:
    lld/trunk/test/ELF/version-script-extern.s
Modified:
    lld/trunk/ELF/Config.h
    lld/trunk/ELF/SymbolListFile.cpp
    lld/trunk/ELF/SymbolTable.cpp
    lld/trunk/ELF/SymbolTable.h
    lld/trunk/test/ELF/version-script-err.s

Modified: lld/trunk/ELF/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Config.h?rev=275682&r1=275681&r2=275682&view=diff
==============================================================================
--- lld/trunk/ELF/Config.h (original)
+++ lld/trunk/ELF/Config.h Sat Jul 16 07:26:39 2016
@@ -35,13 +35,18 @@ enum class BuildIdKind { None, Fnv1, Md5
 
 enum class UnresolvedPolicy { NoUndef, Error, Warn, Ignore };
 
+struct SymbolVersion {
+  llvm::StringRef Name;
+  bool IsExternCpp;
+};
+
 // This struct contains symbols version definition that
 // can be found in version script if it is used for link.
 struct VersionDefinition {
   VersionDefinition(llvm::StringRef Name, size_t Id) : Name(Name), Id(Id) {}
   llvm::StringRef Name;
   size_t Id;
-  std::vector<llvm::StringRef> Globals;
+  std::vector<SymbolVersion> Globals;
   size_t NameOff; // Offset in string table.
 };
 
@@ -68,7 +73,7 @@ struct Configuration {
   std::vector<llvm::StringRef> DynamicList;
   std::vector<llvm::StringRef> SearchPaths;
   std::vector<llvm::StringRef> Undefined;
-  std::vector<llvm::StringRef> VersionScriptGlobals;
+  std::vector<SymbolVersion> VersionScriptGlobals;
   std::vector<uint8_t> BuildIdVector;
   bool AllowMultipleDefinition;
   bool AsNeeded = false;

Modified: lld/trunk/ELF/SymbolListFile.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolListFile.cpp?rev=275682&r1=275681&r2=275682&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolListFile.cpp (original)
+++ lld/trunk/ELF/SymbolListFile.cpp Sat Jul 16 07:26:39 2016
@@ -69,6 +69,7 @@ public:
   void run();
 
 private:
+  void parseExtern(std::vector<SymbolVersion> *Globals);
   void parseVersion(StringRef VerStr);
   void parseGlobal(StringRef VerStr);
   void parseLocal();
@@ -106,21 +107,38 @@ void VersionScriptParser::parseLocal() {
   expect(";");
 }
 
+void VersionScriptParser::parseExtern(std::vector<SymbolVersion> *Globals) {
+  expect("extern");
+  expect("C++");
+  expect("{");
+
+  for (;;) {
+    if (peek() == "}" || Error)
+      break;
+    Globals->push_back({next(), true});
+    expect(";");
+  }
+
+  expect("}");
+  expect(";");
+}
+
 void VersionScriptParser::parseGlobal(StringRef VerStr) {
-  std::vector<StringRef> *Globals;
+  std::vector<SymbolVersion> *Globals;
   if (VerStr.empty())
     Globals = &Config->VersionScriptGlobals;
   else
     Globals = &Config->VersionDefinitions.back().Globals;
 
   for (;;) {
+    if (peek() == "extern")
+      parseExtern(Globals);
+
     StringRef Cur = peek();
-    if (Cur == "extern")
-      setError("extern keyword is not supported");
     if (Cur == "}" || Cur == "local:" || Error)
       return;
     next();
-    Globals->push_back(Cur);
+    Globals->push_back({Cur, false});
     expect(";");
   }
 }

Modified: lld/trunk/ELF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.cpp?rev=275682&r1=275681&r2=275682&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.cpp (original)
+++ lld/trunk/ELF/SymbolTable.cpp Sat Jul 16 07:26:39 2016
@@ -566,6 +566,37 @@ static bool hasWildcard(StringRef S) {
   return S.find_first_of("?*") != StringRef::npos;
 }
 
+static void setVersionId(SymbolBody *Body, StringRef VersionName,
+                         StringRef Name, uint16_t Version) {
+  if (!Body || Body->isUndefined()) {
+    if (Config->NoUndefinedVersion)
+      error("version script assignment of " + VersionName + " to symbol " +
+            Name + " failed: symbol not defined");
+    return;
+  }
+
+  Symbol *Sym = Body->symbol();
+  if (Sym->VersionId != VER_NDX_GLOBAL && Sym->VersionId != VER_NDX_LOCAL)
+    warning("duplicate symbol " + Name + " in version script");
+  Sym->VersionId = Version;
+}
+
+template <class ELFT>
+std::map<std::string, SymbolBody *> SymbolTable<ELFT>::getDemangledSyms() {
+  std::map<std::string, SymbolBody *> Result;
+  for (std::pair<SymName, unsigned> Sym : Symtab)
+    Result[demangle(Sym.first.Val)] = SymVector[Sym.second]->body();
+  return Result;
+}
+
+static bool hasExternCpp() {
+  for (VersionDefinition &V : Config->VersionDefinitions)
+    for (SymbolVersion Sym : V.Globals)
+      if (Sym.IsExternCpp)
+        return true;
+  return false;
+}
+
 // This function processes the --version-script option by marking all global
 // symbols with the VersionScriptGlobal flag, which acts as a filter on the
 // dynamic symbol table.
@@ -573,8 +604,8 @@ template <class ELFT> void SymbolTable<E
   // If version script does not contain versions declarations,
   // we just should mark global symbols.
   if (!Config->VersionScriptGlobals.empty()) {
-    for (StringRef S : Config->VersionScriptGlobals)
-      if (SymbolBody *B = find(S))
+    for (SymbolVersion &Sym : Config->VersionScriptGlobals)
+      if (SymbolBody *B = find(Sym.Name))
         B->symbol()->VersionId = VER_NDX_GLOBAL;
     return;
   }
@@ -585,35 +616,32 @@ template <class ELFT> void SymbolTable<E
   // If we have symbols version declarations, we should
   // assign version references for each symbol.
   // Current rules are:
-  // * If there is an exact match for the mangled name, we use it.
+  // * If there is an exact match for the mangled name or we have extern C++
+  //   exact match, then we use it.
   // * Otherwise, we look through the wildcard patterns. We look through the
   //   version tags in reverse order. We use the first match we find (the last
   //   matching version tag in the file).
-  for (size_t I = 0, E = Config->VersionDefinitions.size(); I < E; ++I) {
-    VersionDefinition &V = Config->VersionDefinitions[I];
-    for (StringRef Name : V.Globals) {
-      if (hasWildcard(Name))
+  // Handle exact matches and build a map of demangled externs for
+  // quick search during next step.
+  std::map<std::string, SymbolBody *> Demangled;
+  if (hasExternCpp())
+    Demangled = getDemangledSyms();
+
+  for (VersionDefinition &V : Config->VersionDefinitions) {
+    for (SymbolVersion Sym : V.Globals) {
+      if (hasWildcard(Sym.Name))
         continue;
-
-      SymbolBody *B = find(Name);
-      if (!B || B->isUndefined()) {
-        if (Config->NoUndefinedVersion)
-          error("version script assignment of " + V.Name + " to symbol " +
-                Name + " failed: symbol not defined");
-        continue;
-      }
-
-      if (B->symbol()->VersionId != Config->DefaultSymbolVersion)
-        warning("duplicate symbol " + Name + " in version script");
-      B->symbol()->VersionId = V.Id;
+      SymbolBody *B = Sym.IsExternCpp ? Demangled[Sym.Name] : find(Sym.Name);
+      setVersionId(B, V.Name, Sym.Name, V.Id);
     }
   }
 
+  // Handle wildcards.
   for (size_t I = Config->VersionDefinitions.size() - 1; I != (size_t)-1; --I) {
     VersionDefinition &V = Config->VersionDefinitions[I];
-    for (StringRef Name : V.Globals)
-      if (hasWildcard(Name))
-        for (SymbolBody *B : findAll(Name))
+    for (SymbolVersion &Sym : V.Globals)
+      if (hasWildcard(Sym.Name))
+        for (SymbolBody *B : findAll(Sym.Name))
           if (B->symbol()->VersionId == Config->DefaultSymbolVersion)
             B->symbol()->VersionId = V.Id;
   }

Modified: lld/trunk/ELF/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.h?rev=275682&r1=275681&r2=275682&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.h (original)
+++ lld/trunk/ELF/SymbolTable.h Sat Jul 16 07:26:39 2016
@@ -97,6 +97,8 @@ private:
   std::string conflictMsg(SymbolBody *Existing, InputFile *NewFile);
   void reportDuplicate(SymbolBody *Existing, InputFile *NewFile);
 
+  std::map<std::string, SymbolBody *> getDemangledSyms();
+
   // The order the global symbols are in is not defined. We can use an arbitrary
   // order, but it has to be reproducible. That is true even when cross linking.
   // The default hashing of StringRef produces different results on 32 and 64

Modified: lld/trunk/test/ELF/version-script-err.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/version-script-err.s?rev=275682&r1=275681&r2=275682&view=diff
==============================================================================
--- lld/trunk/test/ELF/version-script-err.s (original)
+++ lld/trunk/test/ELF/version-script-err.s Sat Jul 16 07:26:39 2016
@@ -8,8 +8,3 @@
 // RUN: not ld.lld --version-script %terr1.script -shared %t.o -o %t.so 2>&1 | \
 // RUN:   FileCheck -check-prefix=ERR1 %s
 // ERR1: unclosed quote
-
-// RUN: echo "VERSION { extern "C++" {}; }; " > %terr2.script
-// RUN: not ld.lld --version-script %terr2.script -shared %t.o -o %t.so 2>&1 | \
-// RUN:   FileCheck -check-prefix=ERR2 %s
-// ERR2: extern keyword is not supported

Added: lld/trunk/test/ELF/version-script-extern.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/version-script-extern.s?rev=275682&view=auto
==============================================================================
--- lld/trunk/test/ELF/version-script-extern.s (added)
+++ lld/trunk/test/ELF/version-script-extern.s Sat Jul 16 07:26:39 2016
@@ -0,0 +1,98 @@
+# REQUIRES: x86
+# XFAIL: win32
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "LIBSAMPLE_1.0 { \
+# RUN:   global:             \
+# RUN:      extern "C++" {   \
+# RUN:         \"foo(int)\";    \
+# RUN:         \"zed(int)\";    \
+# RUN:   };                  \
+# RUN: };                    \
+# RUN: LIBSAMPLE_2.0 {       \
+# RUN:   global:             \
+# RUN:     extern "C++" {    \
+# RUN:       \"bar(int)\";      \
+# RUN:   };                  \
+# RUN: }; " > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-readobj -V -dyn-symbols %t.so | FileCheck --check-prefix=DSO %s
+
+# DSO:      DynamicSymbols [
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: @
+# DSO-NEXT:      Value: 0x0
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Local
+# DSO-NEXT:      Type: None
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: Undefined
+# DSO-NEXT:    }
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: _Z3bari@@LIBSAMPLE_2.0
+# DSO-NEXT:      Value: 0x1001
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Global
+# DSO-NEXT:      Type: Function
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: .text
+# DSO-NEXT:    }
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: _Z3fooi@@LIBSAMPLE_1.0
+# DSO-NEXT:      Value: 0x1000
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Global
+# DSO-NEXT:      Type: Function
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: .text
+# DSO-NEXT:    }
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: _Z3zedi@@LIBSAMPLE_1.0
+# DSO-NEXT:      Value: 0x1002
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Global (0x1)
+# DSO-NEXT:      Type: Function (0x2)
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: .text (0x6)
+# DSO-NEXT:    }
+# DSO-NEXT:  ]
+# DSO-NEXT:  Version symbols {
+# DSO-NEXT:    Section Name: .gnu.version
+# DSO-NEXT:    Address: 0x228
+# DSO-NEXT:    Offset: 0x228
+# DSO-NEXT:    Link: 1
+# DSO-NEXT:    Symbols [
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 0
+# DSO-NEXT:        Name: @
+# DSO-NEXT:      }
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 3
+# DSO-NEXT:        Name: _Z3bari@@LIBSAMPLE_2.0
+# DSO-NEXT:      }
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 2
+# DSO-NEXT:        Name: _Z3fooi@@LIBSAMPLE_1.0
+# DSO-NEXT:      }
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 2
+# DSO-NEXT:        Name: _Z3zedi@@LIBSAMPLE_1.0
+# DSO-NEXT:      }
+# DSO-NEXT:    ]
+# DSO-NEXT:  }
+
+.text
+.globl _Z3fooi
+.type _Z3fooi, at function
+_Z3fooi:
+retq
+
+.globl _Z3bari
+.type _Z3bari, at function
+_Z3bari:
+retq
+
+.globl _Z3zedi
+.type _Z3zedi, at function
+_Z3zedi:
+retq




More information about the llvm-commits mailing list