diff options
Diffstat (limited to 'lld/ELF/SymbolTable.cpp')
-rw-r--r-- | lld/ELF/SymbolTable.cpp | 72 |
1 files changed, 50 insertions, 22 deletions
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index 2474bb35a54..b3887249be0 100644 --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -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<ELFT>::scanVersionScript() { // 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<ELFT>::scanVersionScript() { // 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; |