return SymVector[V.Idx]->body();
}
-// Returns a list of defined symbols that match with a given regex.
+// Returns a list of defined symbols that match with a given pattern.
template <class ELFT>
std::vector<SymbolBody *> SymbolTable<ELFT>::findAll(const StringMatcher &M) {
std::vector<SymbolBody *> Res;
B->symbol()->ExportDynamic = true;
}
+// A helper function to set a version to a symbol.
+// Essentially, assigning two different versions to the same symbol is an error.
static void setVersionId(SymbolBody *Body, StringRef VersionName,
StringRef Name, uint16_t Version) {
if (!Body || Body->isUndefined()) {
Sym->VersionId = Version;
}
-// Returns a map from demangled symbols to symbol objects.
-// The relationship is 1:N instead of 1:1 because with the symbol
-// versioning, more than one symbol may have the same name.
+// Initialize DemangledSyms with a map from demangled symbols to symbol
+// objects. Used to handle "extern C++" directive in version scripts.
+//
+// The map will contain all demangled symbols. That can be very large,
+// and in LLD we generally want to avoid do anything for each symbol.
+// Then, why are we doing this? Here's why.
+//
+// Users can use "extern C++ {}" directive to match against demangled
+// C++ symbols. For example, you can write a pattern such as
+// "llvm::*::foo(int, ?)". Obviously, there's no way to handle this
+// other than trying to match a pattern against all demangled symbols.
+// So, if "extern C++" feature is used, we need to demangle all known
+// symbols.
template <class ELFT>
-std::map<std::string, std::vector<SymbolBody *>>
-SymbolTable<ELFT>::getDemangledSyms() {
- std::map<std::string, std::vector<SymbolBody *>> Result;
+void SymbolTable<ELFT>::initDemangledSyms() {
+ if (DemangledSyms)
+ return;
+ DemangledSyms.emplace();
+
for (Symbol *Sym : SymVector) {
SymbolBody *B = Sym->body();
- Result[demangle(B->getName())].push_back(B);
+ (*DemangledSyms)[demangle(B->getName())].push_back(B);
}
- return Result;
-}
-
-static bool hasExternCpp() {
- for (VersionDefinition &V : Config->VersionDefinitions)
- for (SymbolVersion Ver : V.Globals)
- if (Ver.IsExternCpp)
- return true;
- return false;
}
-static ArrayRef<SymbolBody *>
-findDemangled(std::map<std::string, std::vector<SymbolBody *>> &D,
- StringRef Name) {
- auto I = D.find(Name);
- if (I != D.end())
+template <class ELFT>
+ArrayRef<SymbolBody *> SymbolTable<ELFT>::findDemangled(StringRef Name) {
+ initDemangledSyms();
+ auto I = DemangledSyms->find(Name);
+ if (I != DemangledSyms->end())
return I->second;
return {};
}
-static std::vector<SymbolBody *>
-findAllDemangled(const std::map<std::string, std::vector<SymbolBody *>> &D,
- StringMatcher &M) {
+template <class ELFT>
+std::vector<SymbolBody *>
+SymbolTable<ELFT>::findAllDemangled(const StringMatcher &M) {
+ initDemangledSyms();
std::vector<SymbolBody *> Res;
- for (auto &P : D) {
- if (M.match(P.first))
+ for (auto &P : *DemangledSyms)
+ if (M.match(P.first()))
for (SymbolBody *Body : P.second)
if (!Body->isUndefined())
Res.push_back(Body);
- }
return Res;
}
B->symbol()->VersionId = VER_NDX_GLOBAL;
}
+template <class ELFT>
+void SymbolTable<ELFT>::assignWildcardVersion(SymbolVersion Ver,
+ size_t VersionId) {
+ if (!Ver.HasWildcards)
+ return;
+ StringMatcher M({Ver.Name});
+ std::vector<SymbolBody *> Syms =
+ Ver.IsExternCpp ? findAllDemangled(M) : findAll(M);
+
+ // Exact matching takes precendence over fuzzy matching,
+ // so we set a version to a symbol only if no version has been assigned
+ // to the symbol. This behavior is compatible with GNU.
+ for (SymbolBody *B : Syms)
+ if (B->symbol()->VersionId == Config->DefaultSymbolVersion)
+ B->symbol()->VersionId = VersionId;
+}
+
// This function processes version scripts by updating VersionId
// member of symbols.
template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
// Each version definition has a glob pattern, and all symbols that match
// with the pattern get that version.
- // Users can use "extern C++ {}" directive to match against demangled
- // C++ symbols. For example, you can write a pattern such as
- // "llvm::*::foo(int, ?)". Obviously, there's no way to handle this
- // other than trying to match a regexp against all demangled symbols.
- // So, if "extern C++" feature is used, we demangle all known symbols.
- std::map<std::string, std::vector<SymbolBody *>> Demangled;
- if (hasExternCpp())
- Demangled = getDemangledSyms();
-
// First, we assign versions to exact matching symbols,
// i.e. version definitions not containing any glob meta-characters.
for (VersionDefinition &V : Config->VersionDefinitions) {
StringRef N = Ver.Name;
if (Ver.IsExternCpp) {
- for (SymbolBody *B : findDemangled(Demangled, N))
+ for (SymbolBody *B : findDemangled(N))
setVersionId(B, V.Name, N, V.Id);
continue;
}
// i.e. version definitions containing glob meta-characters.
// Note that because the last match takes precedence over previous matches,
// we iterate over the definitions in the reverse order.
- auto assignFuzzyVersion = [&](SymbolVersion &Ver, size_t Version) {
- if (!Ver.HasWildcards)
- return;
- StringMatcher M({Ver.Name});
- std::vector<SymbolBody *> Syms =
- Ver.IsExternCpp ? findAllDemangled(Demangled, M) : findAll(M);
- // Exact matching takes precendence over fuzzy matching,
- // so we set a version to a symbol only if no version has been assigned
- // to the symbol. This behavior is compatible with GNU.
- for (SymbolBody *B : Syms)
- if (B->symbol()->VersionId == Config->DefaultSymbolVersion)
- B->symbol()->VersionId = Version;
- };
-
for (size_t I = Config->VersionDefinitions.size() - 1; I != (size_t)-1; --I) {
VersionDefinition &V = Config->VersionDefinitions[I];
for (SymbolVersion &Ver : V.Locals)
- assignFuzzyVersion(Ver, VER_NDX_LOCAL);
+ assignWildcardVersion(Ver, VER_NDX_LOCAL);
for (SymbolVersion &Ver : V.Globals)
- assignFuzzyVersion(Ver, V.Id);
+ assignWildcardVersion(Ver, V.Id);
}
}