[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
llvm-svn: 275257
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp
index 2474bb3..b388724 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -567,6 +567,37 @@
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 @@
// 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 @@
// 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");
- continue;
- }
+ // 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();
- 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;
+ for (Version &V : Config->SymbolVersions) {
+ for (SymbolVersion Sym : V.Globals) {
+ if (hasWildcard(Sym.Name))
+ continue;
+ 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;