From: Rui Ueyama Date: Tue, 15 Nov 2016 18:41:52 +0000 (+0000) Subject: Refactor symbol version assignmnt code. X-Git-Tag: llvmorg-4.0.0-rc1~4515 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=82492142998cc18b1a360de8f2177b5535a80102;p=platform%2Fupstream%2Fllvm.git Refactor symbol version assignmnt code. The code to handle symbol versions is getting tricky and hard to understand, so it is probably time to simplify it. This patch does the following. - Add `DemangledSyms` variable to SymbolTable so that we don't need to pass it around to findDemangled. - Define `initDemangledSyms` to initialize the variable lazily. - hasExternCpp is removed because we no longer have to initialize the map eagerly. - scanScriptVersion is split. - Comments are updated. llvm-svn: 287002 --- diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index e25e866..efbcba95 100644 --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -484,7 +484,7 @@ template SymbolBody *SymbolTable::find(StringRef Name) { 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 std::vector SymbolTable::findAll(const StringMatcher &M) { std::vector Res; @@ -579,6 +579,8 @@ template void SymbolTable::scanDynamicList() { 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()) { @@ -594,47 +596,50 @@ static void setVersionId(SymbolBody *Body, StringRef VersionName, 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 -std::map> -SymbolTable::getDemangledSyms() { - std::map> Result; +void SymbolTable::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 -findDemangled(std::map> &D, - StringRef Name) { - auto I = D.find(Name); - if (I != D.end()) +template +ArrayRef SymbolTable::findDemangled(StringRef Name) { + initDemangledSyms(); + auto I = DemangledSyms->find(Name); + if (I != DemangledSyms->end()) return I->second; return {}; } -static std::vector -findAllDemangled(const std::map> &D, - StringMatcher &M) { +template +std::vector +SymbolTable::findAllDemangled(const StringMatcher &M) { + initDemangledSyms(); std::vector 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; } @@ -661,6 +666,23 @@ template void SymbolTable::handleAnonymousVersion() { B->symbol()->VersionId = VER_NDX_GLOBAL; } +template +void SymbolTable::assignWildcardVersion(SymbolVersion Ver, + size_t VersionId) { + if (!Ver.HasWildcards) + return; + StringMatcher M({Ver.Name}); + std::vector 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 void SymbolTable::scanVersionScript() { @@ -677,15 +699,6 @@ template void SymbolTable::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> 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) { @@ -695,7 +708,7 @@ template void SymbolTable::scanVersionScript() { 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; } @@ -712,26 +725,12 @@ template void SymbolTable::scanVersionScript() { // 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 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); } } diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h index 1223750..d78287c 100644 --- a/lld/ELF/SymbolTable.h +++ b/lld/ELF/SymbolTable.h @@ -98,8 +98,12 @@ private: uint8_t Visibility, bool CanOmitFromDynSym, InputFile *File); - std::map> getDemangledSyms(); + ArrayRef findDemangled(StringRef Name); + std::vector findAllDemangled(const StringMatcher &M); + + void initDemangledSyms(); void handleAnonymousVersion(); + void assignWildcardVersion(SymbolVersion Ver, size_t VersionId); struct SymIndex { SymIndex(int Idx, bool Traced) : Idx(Idx), Traced(Traced) {} @@ -130,6 +134,13 @@ private: // Set of .so files to not link the same shared object file more than once. llvm::DenseSet SoNames; + // A map from demangled symbol names to their symbol objects. + // This mapping is 1:N because two symbols with different versions + // can have the same name. We use this map to handle "extern C++ {}" + // directive in version scripts. + llvm::Optional>> DemangledSyms; + + // For LTO. std::unique_ptr Lto; };