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,22 +92,24 @@ template bool LinkerScript::shouldKeep(InputSectionBase *S) { - for (StringRef Pat : Opt.KeptSections) - if (globMatch(Pat, S->getSectionName())) + for (const std::regex &Pat : Opt.KeptSections) { + StringRef Name = S->getSectionName(); + if (std::regex_match(Name.begin(), Name.end(), Pat)) return true; + } return false; } -static bool match(ArrayRef Patterns, StringRef S) { - for (StringRef Pat : Patterns) - if (globMatch(Pat, S)) +static bool match(ArrayRef Patterns, StringRef S) { + for (const std::regex &Pat : Patterns) + if (std::regex_match(S.begin(), S.end(), Pat)) return true; return false; } static bool fileMatches(const InputSectionDescription *Desc, StringRef Filename) { - if (!globMatch(Desc->FilePattern, Filename)) + if (!std::regex_match(Filename.begin(), Filename.end(), Desc->FilePattern)) return false; return Desc->ExcludedFiles.empty() || !match(Desc->ExcludedFiles, Filename); } @@ -116,7 +118,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 +129,9 @@ Ret.push_back(S); } - if (llvm::find(Patterns, "COMMON") != Patterns.end()) + if (llvm::find_if(Patterns, [](const std::regex &P) { + return std::regex_match("COMMON", P); + }) != Patterns.end()) Ret.push_back(CommonInputSection::X); return Ret; @@ -605,7 +609,7 @@ std::vector readOutputSectionFiller(); std::vector readOutputSectionPhdrs(); InputSectionDescription *readInputSectionDescription(); - std::vector readInputFilePatterns(); + std::vector readInputFilePatterns(); InputSectionDescription *readInputSectionRules(); unsigned readPhdrType(); SortKind readSortKind(); @@ -829,10 +833,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 +850,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,13 @@ #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 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,27 @@ 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()) { + char F = S.front(); + if (F == '*') + T += ".*"; + else if (F == '?') + T += '.'; + else if (F == '.') + T += "\\."; + else + T += F; S = S.substr(1); - T = T.substr(1); } + return std::regex(T, std::regex::basic | std::regex::optimize); } // 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,11 +483,13 @@ // 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(); - if (!B->isUndefined() && globMatch(Pattern, B->getName())) + StringRef Name = B->getName(); + if (!B->isUndefined() && + std::regex_match(Name.begin(), Name.end(), Pattern)) Res.push_back(B); } return Res; @@ -576,10 +578,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 +655,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(toRegex(Sym.Name))) if (B->symbol()->VersionId == Config->DefaultSymbolVersion) B->symbol()->VersionId = V.Id; } Index: test/ELF/wildcards2.s =================================================================== --- test/ELF/wildcards2.s +++ test/ELF/wildcards2.s @@ -0,0 +1,25 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t + +## Check that aabc is not included in text. +# RUN: echo "SECTIONS { \ +# RUN: .text : { *(.abc) } }" > %t.script +# RUN: ld.lld -o %t.out --script %t.script %t +# RUN: llvm-objdump -section-headers %t.out | \ +# RUN: FileCheck %s +# CHECK: Sections: +# CHECK-NEXT: Idx Name Size Address Type +# CHECK-NEXT: 0 00000000 0000000000000000 +# CHECK-NEXT: 1 .text 00000004 0000000000000120 TEXT DATA +# CHECK-NEXT: 2 aabc 00000004 0000000000000124 TEXT DATA + +.text +.section .abc,"ax",@progbits +.long 0 + +.text +.section aabc,"ax",@progbits +.long 0 + +.globl _start +_start: