Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -14,6 +14,9 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/ELF.h" +#include "Strings.h" + +#include #include namespace lld { @@ -35,8 +38,15 @@ enum class UnresolvedPolicy { NoUndef, Error, Warn, Ignore }; struct SymbolVersion { + SymbolVersion(llvm::StringRef Name, bool IsExternCpp) + : Name(Name), IsExternCpp(IsExternCpp) { + if (hasWildcard(Name)) + Wildcard = toRegex(Name); + } + llvm::StringRef Name; bool IsExternCpp; + std::regex Wildcard; }; // This struct contains symbols version definition that Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -17,6 +17,7 @@ #include "llvm/Support/Allocator.h" #include "llvm/Support/MemoryBuffer.h" #include +#include namespace lld { namespace elf { @@ -93,11 +94,11 @@ struct InputSectionDescription : BaseCommand { InputSectionDescription() : BaseCommand(InputSectionKind) {} static bool classof(const BaseCommand *C); - StringRef FilePattern; + std::regex FilePattern; SortKind SortOuter = SortNone; SortKind SortInner = SortNone; - std::vector ExcludedFiles; - std::vector SectionPatterns; + std::vector ExcludedFiles; + std::vector SectionPatterns; }; struct AssertCommand : BaseCommand { @@ -128,7 +129,7 @@ // List of section patterns specified with KEEP commands. They will // be kept even if they are unused and --gc-sections is specified. - std::vector KeptSections; + std::vector KeptSections; }; extern ScriptConfiguration *ScriptConfig; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -92,14 +92,14 @@ template bool LinkerScript::shouldKeep(InputSectionBase *S) { - for (StringRef Pat : Opt.KeptSections) + for (const std::regex &Pat : Opt.KeptSections) if (globMatch(Pat, S->getSectionName())) return true; return false; } -static bool match(ArrayRef Patterns, StringRef S) { - for (StringRef Pat : Patterns) +static bool match(ArrayRef Patterns, StringRef S) { + for (const std::regex &Pat : Patterns) if (globMatch(Pat, S)) return true; return false; @@ -116,7 +116,7 @@ template std::vector *> LinkerScript::getInputSections(const InputSectionDescription *I) { - ArrayRef Patterns = I->SectionPatterns; + ArrayRef Patterns = I->SectionPatterns; std::vector *> Ret; for (const std::unique_ptr> &F : Symtab::X->getObjectFiles()) { @@ -127,7 +127,9 @@ Ret.push_back(S); } - if (llvm::find(Patterns, "COMMON") != Patterns.end()) + if (llvm::find_if(Patterns, [](const std::regex &P) { + return globMatch(P, "COMMON"); + }) != Patterns.end()) Ret.push_back(CommonInputSection::X); return Ret; @@ -605,7 +607,7 @@ std::vector readOutputSectionFiller(); std::vector readOutputSectionPhdrs(); InputSectionDescription *readInputSectionDescription(); - std::vector readInputFilePatterns(); + std::vector readInputFilePatterns(); InputSectionDescription *readInputSectionRules(); unsigned readPhdrType(); SortKind readSortKind(); @@ -829,10 +831,10 @@ .Default(-1); } -std::vector ScriptParser::readInputFilePatterns() { - std::vector V; +std::vector ScriptParser::readInputFilePatterns() { + std::vector V; while (!Error && !skip(")")) - V.push_back(next()); + V.push_back(toRegex(next())); return V; } @@ -846,14 +848,14 @@ InputSectionDescription *ScriptParser::readInputSectionRules() { auto *Cmd = new InputSectionDescription; - Cmd->FilePattern = next(); + Cmd->FilePattern = toRegex(next()); expect("("); // Read EXCLUDE_FILE(). if (skip("EXCLUDE_FILE")) { expect("("); while (!Error && !skip(")")) - Cmd->ExcludedFiles.push_back(next()); + Cmd->ExcludedFiles.push_back(toRegex(next())); } // Read SORT(). Index: ELF/Strings.h =================================================================== --- ELF/Strings.h +++ ELF/Strings.h @@ -11,11 +11,14 @@ #define LLD_COFF_STRINGS_H #include "lld/Core/LLVM.h" +#include #include namespace lld { namespace elf { -bool globMatch(StringRef S, StringRef T); +std::regex toRegex(StringRef S); +bool globMatch(const std::regex& S, StringRef T); +bool hasWildcard(StringRef S); std::vector parseHex(StringRef S); bool isValidCIdentifier(StringRef S); Index: ELF/Strings.cpp =================================================================== --- ELF/Strings.cpp +++ ELF/Strings.cpp @@ -22,28 +22,29 @@ using namespace lld; using namespace lld::elf; -// Returns true if S matches T. S can contain glob meta-characters. -// The asterisk ('*') matches zero or more characters, and the question -// mark ('?') matches one character. -bool elf::globMatch(StringRef S, StringRef T) { - for (;;) { - if (S.empty()) - return T.empty(); - if (S[0] == '*') { - S = S.substr(1); - if (S.empty()) - // Fast path. If a pattern is '*', it matches anything. - return true; - for (size_t I = 0, E = T.size(); I < E; ++I) - if (globMatch(S, T.substr(I))) - return true; - return false; - } - if (T.empty() || (S[0] != T[0] && S[0] != '?')) - return false; +bool elf::hasWildcard(StringRef S) { + return S.find_first_of("?*") != StringRef::npos; +} + +// This is a hand-written state machine to convert +// a glob pattern to a regex. +std::regex elf::toRegex(StringRef S) { + std::string T; + while (!S.empty()) { + if (S[0] == '*') + T += ".*"; + else if (S[0] == '?') + T += '.'; + else + T += S[0]; S = S.substr(1); - T = T.substr(1); } + return std::regex(T, std::regex::basic | std::regex::optimize); +} + +// Returns true if S matches T. +bool elf::globMatch(const std::regex& S, StringRef T) { + return std::regex_match(T.begin(), T.end(), S); } // Converts a hex string (e.g. "deadbeef") to a vector. Index: ELF/SymbolTable.h =================================================================== --- ELF/SymbolTable.h +++ ELF/SymbolTable.h @@ -14,6 +14,8 @@ #include "LTO.h" #include "llvm/ADT/DenseMap.h" +#include + namespace lld { namespace elf { class Lazy; @@ -89,7 +91,7 @@ void wrap(StringRef Name); private: - std::vector findAll(StringRef Pattern); + std::vector findAll(const std::regex& Pattern); std::pair insert(StringRef &Name); std::pair insert(StringRef &Name, uint8_t Type, uint8_t Visibility, bool CanOmitFromDynSym, Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -483,7 +483,7 @@ // Returns a list of defined symbols that match with a given glob pattern. template -std::vector SymbolTable::findAll(StringRef Pattern) { +std::vector SymbolTable::findAll(const std::regex& Pattern) { std::vector Res; for (Symbol *Sym : SymVector) { SymbolBody *B = Sym->body(); @@ -576,10 +576,6 @@ B->symbol()->ExportDynamic = true; } -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()) { @@ -657,7 +653,7 @@ VersionDefinition &V = Config->VersionDefinitions[I]; for (SymbolVersion &Sym : V.Globals) if (hasWildcard(Sym.Name)) - for (SymbolBody *B : findAll(Sym.Name)) + for (SymbolBody *B : findAll(Sym.Wildcard)) if (B->symbol()->VersionId == Config->DefaultSymbolVersion) B->symbol()->VersionId = V.Id; }