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

George Rimar via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 13 00:46:01 PDT 2016


Author: grimar
Date: Wed Jul 13 02:46:00 2016
New Revision: 275257

URL: http://llvm.org/viewvc/llvm-project?rev=275257&view=rev
Log:
[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=275257&r1=275256&r2=275257&view=diff
==============================================================================
--- lld/trunk/ELF/Config.h (original)
+++ lld/trunk/ELF/Config.h Wed Jul 13 02:46:00 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 Version {
   Version(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=275257&r1=275256&r2=275257&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolListFile.cpp (original)
+++ lld/trunk/ELF/SymbolListFile.cpp Wed Jul 13 02:46:00 2016
@@ -77,6 +77,7 @@ public:
   void run();
 
 private:
+  void parseExtern(std::vector<SymbolVersion> *Globals);
   void parseVersion(StringRef Version);
   void parseLocal();
   void parseVersionSymbols(StringRef Version);
@@ -120,21 +121,38 @@ void VersionScriptParser::parseLocal() {
   Config->VersionScriptGlobalByDefault = false;
 }
 
+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::parseVersionSymbols(StringRef Version) {
-  std::vector<StringRef> *Globals;
+  std::vector<SymbolVersion> *Globals;
   if (Version.empty())
     Globals = &Config->VersionScriptGlobals;
   else
     Globals = &Config->SymbolVersions.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=275257&r1=275256&r2=275257&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.cpp (original)
+++ lld/trunk/ELF/SymbolTable.cpp Wed Jul 13 02:46:00 2016
@@ -567,6 +567,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 (Version& V : Config->SymbolVersions)
+    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.
@@ -574,8 +605,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;
   }
@@ -586,38 +617,35 @@ 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->SymbolVersions.size(); I < E; ++I) {
-    Version &V = Config->SymbolVersions[I];
-    for (StringRef Name : V.Globals) {
-      if (hasWildcard(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");
+  // 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 (Version &V : Config->SymbolVersions) {
+    for (SymbolVersion Sym : V.Globals) {
+      if (hasWildcard(Sym.Name))
         continue;
-      }
-
-      if (B->symbol()->VersionId != VER_NDX_GLOBAL &&
-          B->symbol()->VersionId != VER_NDX_LOCAL)
-        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->SymbolVersions.size() - 1; I != (size_t)-1; --I) {
     Version &V = Config->SymbolVersions[I];
-    for (StringRef Name : V.Globals) {
-      if (!hasWildcard(Name))
+    for (SymbolVersion Sym : V.Globals) {
+      if (!hasWildcard(Sym.Name))
         continue;
 
-      for (SymbolBody *B : findAll(Name))
+      for (SymbolBody *B : findAll(Sym.Name))
         if (B->symbol()->VersionId == VER_NDX_GLOBAL ||
             B->symbol()->VersionId == VER_NDX_LOCAL)
           B->symbol()->VersionId = V.Id;

Modified: lld/trunk/ELF/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.h?rev=275257&r1=275256&r2=275257&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.h (original)
+++ lld/trunk/ELF/SymbolTable.h Wed Jul 13 02:46:00 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=275257&r1=275256&r2=275257&view=diff
==============================================================================
--- lld/trunk/test/ELF/version-script-err.s (original)
+++ lld/trunk/test/ELF/version-script-err.s Wed Jul 13 02:46:00 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=275257&view=auto
==============================================================================
--- lld/trunk/test/ELF/version-script-extern.s (added)
+++ lld/trunk/test/ELF/version-script-extern.s Wed Jul 13 02:46:00 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()\";    \
+# RUN:         \"zed()\";    \
+# RUN:   };                  \
+# RUN: };                    \
+# RUN: LIBSAMPLE_2.0 {       \
+# RUN:   global:             \
+# RUN:     extern "C++" {    \
+# RUN:       \"bar()\";      \
+# 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: _Z3barv@@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: _Z3foov@@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: _Z3zedv@@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: _Z3barv@@LIBSAMPLE_2.0
+# DSO-NEXT:      }
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 2
+# DSO-NEXT:        Name: _Z3foov@@LIBSAMPLE_1.0
+# DSO-NEXT:      }
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 2
+# DSO-NEXT:        Name: _Z3zedv@@LIBSAMPLE_1.0
+# DSO-NEXT:      }
+# DSO-NEXT:    ]
+# DSO-NEXT:  }
+
+.text
+.globl _Z3foov
+.type _Z3foov, at function
+_Z3foov:
+retq
+
+.globl _Z3barv
+.type _Z3barv, at function
+_Z3barv:
+retq
+
+.globl _Z3zedv
+.type _Z3zedv, at function
+_Z3zedv:
+retq




More information about the llvm-commits mailing list