diff --git a/lld/Common/Strings.cpp b/lld/Common/Strings.cpp --- a/lld/Common/Strings.cpp +++ b/lld/Common/Strings.cpp @@ -31,18 +31,28 @@ return demangle(name); } -StringMatcher::StringMatcher(ArrayRef pat) { - for (StringRef s : pat) { - Expected pat = GlobPattern::create(s); - if (!pat) - error(toString(pat.takeError())); - else - patterns.push_back(*pat); +SingleStringMatcher::SingleStringMatcher(StringRef Pattern) { + if (Pattern.size() > 2 && Pattern.startswith("\"") && + Pattern.endswith("\"")) { + ExactMatch = true; + ExactPattern = Pattern.substr(1, Pattern.size() - 2); + } else { + Expected Glob = GlobPattern::create(Pattern); + if (!Glob) { + error(toString(Glob.takeError())); + return; + } + ExactMatch = false; + GlobPatternMatcher = *Glob; } } +bool SingleStringMatcher::match(StringRef s) const { + return ExactMatch ? (ExactPattern == s) : GlobPatternMatcher.match(s); +} + bool StringMatcher::match(StringRef s) const { - for (const GlobPattern &pat : patterns) + for (const SingleStringMatcher &pat : patterns) if (pat.match(s)) return true; return false; diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -162,7 +162,7 @@ return c->kind == InputSectionKind; } - StringMatcher filePat; + SingleStringMatcher filePat; // Input sections that matches at least one of SectionPatterns // will be associated with this InputSectionDescription. diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -593,10 +593,11 @@ } StringMatcher ScriptParser::readFilePatterns() { - std::vector v; + StringMatcher Matcher; + while (!errorCount() && !consume(")")) - v.push_back(next()); - return StringMatcher(v); + Matcher.addPattern(SingleStringMatcher(next())); + return Matcher; } SortSectionPolicy ScriptParser::readSortKind() { @@ -633,12 +634,15 @@ excludeFilePat = readFilePatterns(); } - std::vector v; - while (!errorCount() && peek() != ")" && peek() != "EXCLUDE_FILE") - v.push_back(unquote(next())); + bool SectionPatternFound = false; + StringMatcher SectionMatcher; + while (!errorCount() && peek() != ")" && peek() != "EXCLUDE_FILE") { + SectionMatcher.addPattern(unquote(next())); + SectionPatternFound = true; + } - if (!v.empty()) - ret.push_back({std::move(excludeFilePat), StringMatcher(v)}); + if (SectionPatternFound) + ret.push_back({std::move(excludeFilePat), std::move(SectionMatcher)}); else setError("section pattern is expected"); } @@ -842,7 +846,7 @@ // commonly used syntax, but still acceptable. In that case, all sections // from the file will be included. auto *isd = make(tok); - isd->sectionPatterns.push_back({{}, StringMatcher({"*"})}); + isd->sectionPatterns.push_back({{}, StringMatcher("*")}); cmd->sectionCommands.push_back(isd); } } diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -139,7 +139,7 @@ std::vector SymbolTable::findAllByVersion(SymbolVersion ver) { std::vector res; - StringMatcher m(ver.name); + SingleStringMatcher m(ver.name); if (ver.isExternCpp) { for (auto &p : getDemangledSyms()) diff --git a/lld/include/lld/Common/Strings.h b/lld/include/lld/Common/Strings.h --- a/lld/include/lld/Common/Strings.h +++ b/lld/include/lld/Common/Strings.h @@ -27,16 +27,50 @@ // Write the contents of the a buffer to a file void saveBuffer(llvm::StringRef buffer, const llvm::Twine &path); -// This class represents multiple glob patterns. -class StringMatcher { +// A single pattern to match against. A pattern can either be double-quoted +// text that should be matched exactly after removing the quoting marks or a +// glob pattern in the sense of GlobPattern. +class SingleStringMatcher { public: - StringMatcher() = default; - explicit StringMatcher(llvm::ArrayRef pat); + // Create a StringPattern from Pattern to be matched exactly irregardless + // of globbing characters if ExactMatch is true. + SingleStringMatcher(llvm::StringRef Pattern); + // Match s against this pattern, exactly if ExactMatch is true. bool match(llvm::StringRef s) const; private: - std::vector patterns; + // Whether to do an exact match irregardless of the presence of wildcard + // character. + bool ExactMatch; + + // GlobPattern object if not doing an exact match. + llvm::GlobPattern GlobPatternMatcher; + + // StringRef to match exactly if doing an exact match. + llvm::StringRef ExactPattern; +}; + +// This class represents multiple patterns to match against. A pattern can +// either be a double-quoted text that should be matched exactly after removing +// the quoted marks or a glob pattern. +class StringMatcher { +private: + // Patterns to match against. + std::vector patterns; + +public: + StringMatcher() = default; + + // Matcher for a single pattern. + StringMatcher(llvm::StringRef Pattern) + : patterns({SingleStringMatcher(Pattern)}) {} + + // Add a new pattern to the existing ones to match against. + void addPattern(SingleStringMatcher Matcher) { patterns.push_back(Matcher); } + + // Match s against the patterns. + bool match(llvm::StringRef s) const; }; } // namespace lld diff --git a/lld/test/ELF/linkerscript/filename-spec.s b/lld/test/ELF/linkerscript/filename-spec.s --- a/lld/test/ELF/linkerscript/filename-spec.s +++ b/lld/test/ELF/linkerscript/filename-spec.s @@ -30,12 +30,12 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ # RUN: %p/Inputs/filename-spec.s -o %t.dir/filename-spec2.o -# RUN: echo "SECTIONS{.foo :{ %/t.dir/filename-spec2.o(.foo) %/t.dir/filename-spec1.o(.foo) }}" > %t5.script +# RUN: echo "SECTIONS{.foo :{ \"%/t.dir/filename-spec2.o\"(.foo) \"%/t.dir/filename-spec1.o\"(.foo) }}" > %t5.script # RUN: ld.lld -o %t5 --script %t5.script \ # RUN: %/t.dir/filename-spec1.o %/t.dir/filename-spec2.o # RUN: llvm-objdump -s %t5 | FileCheck --check-prefix=SECONDFIRST %s -# RUN: echo "SECTIONS{.foo :{ %/t.dir/filename-spec1.o(.foo) %/t.dir/filename-spec2.o(.foo) }}" > %t6.script +# RUN: echo "SECTIONS{.foo :{ \"%/t.dir/filename-spec1.o\"(.foo) \"%/t.dir/filename-spec2.o\"(.foo) }}" > %t6.script # RUN: ld.lld -o %t6 --script %t6.script \ # RUN: %/t.dir/filename-spec1.o %/t.dir/filename-spec2.o # RUN: llvm-objdump -s %t6 | FileCheck --check-prefix=FIRSTY %s