diff options
Diffstat (limited to 'lld/ELF/SymbolTable.cpp')
| -rw-r--r-- | lld/ELF/SymbolTable.cpp | 56 |
1 files changed, 36 insertions, 20 deletions
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index ab5ff8b7870..2feb1a9b12f 100644 --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -460,15 +460,6 @@ template <class ELFT> SymbolBody *SymbolTable<ELFT>::find(StringRef Name) { // Returns a list of defined symbols that match with a given glob pattern. template <class ELFT> std::vector<SymbolBody *> SymbolTable<ELFT>::findAll(StringRef Pattern) { - // Fast-path. Fallback to find() if Pattern doesn't contain any wildcard - // characters. - if (Pattern.find_first_of("?*") == StringRef::npos) { - if (SymbolBody *B = find(Pattern)) - if (!B->isUndefined()) - return {B}; - return {}; - } - std::vector<SymbolBody *> Res; for (auto &It : Symtab) { StringRef Name = It.first.Val; @@ -561,6 +552,10 @@ template <class ELFT> void SymbolTable<ELFT>::scanDynamicList() { B->symbol()->ExportDynamic = true; } +static bool hasWildcard(StringRef S) { + return S.find_first_of("?*") != StringRef::npos; +} + // 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,27 +569,48 @@ template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() { return; } + if (Config->SymbolVersions.empty()) + return; + // If we have symbols version declarations, we should // assign version references for each symbol. - size_t I = 2; - for (Version &V : Config->SymbolVersions) { + // Current rules are: + // * If there is an exact match for the mangled name, 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) { - std::vector<SymbolBody *> Syms = findAll(Name); - if (Syms.empty()) { + 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; } - for (SymbolBody *B : Syms) { - if (B->symbol()->VersionId != VER_NDX_GLOBAL && - B->symbol()->VersionId != VER_NDX_LOCAL) - warning("duplicate symbol " + Name + " in version script"); - B->symbol()->VersionId = I; - } + if (B->symbol()->VersionId != VER_NDX_GLOBAL && + B->symbol()->VersionId != VER_NDX_LOCAL) + warning("duplicate symbol " + Name + " in version script"); + B->symbol()->VersionId = I + 2; + } + } + + 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)) + continue; + + for (SymbolBody *B : findAll(Name)) + if (B->symbol()->VersionId == VER_NDX_GLOBAL || + B->symbol()->VersionId == VER_NDX_LOCAL) + B->symbol()->VersionId = I + 2; } - ++I; } } |

