diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index a8e3d6486353d..120f5271cf229 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -406,8 +406,16 @@ bool InputSectionDescription::matchesFile(const InputFile &file) const { if (filePat.isTrivialMatchAll()) return true; - if (!matchesFileCache || matchesFileCache->first != &file) - matchesFileCache.emplace(&file, filePat.match(file.getNameForScript())); + if (!matchesFileCache || matchesFileCache->first != &file) { + if (matchType == MatchType::WholeArchive) { + matchesFileCache.emplace(&file, filePat.match(file.archiveName)); + } else { + if (matchType == MatchType::ArchivesExcluded && !file.archiveName.empty()) + matchesFileCache.emplace(&file, false); + else + matchesFileCache.emplace(&file, filePat.match(file.getNameForScript())); + } + } return matchesFileCache->second; } diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index 721425166296a..0a2dda13f4ef8 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -194,6 +194,7 @@ class SectionPattern { }; class InputSectionDescription : public SectionCommand { + enum class MatchType { Trivial, WholeArchive, ArchivesExcluded } matchType; SingleStringMatcher filePat; // Cache of the most recent input argument and result of matchesFile(). @@ -202,10 +203,24 @@ class InputSectionDescription : public SectionCommand { public: InputSectionDescription(StringRef filePattern, uint64_t withFlags = 0, uint64_t withoutFlags = 0, StringRef classRef = {}) - : SectionCommand(InputSectionKind), filePat(filePattern), - classRef(classRef), withFlags(withFlags), withoutFlags(withoutFlags) { + : SectionCommand(InputSectionKind), matchType(MatchType::Trivial), + filePat(filePattern), classRef(classRef), withFlags(withFlags), + withoutFlags(withoutFlags) { assert((filePattern.empty() || classRef.empty()) && "file pattern and class reference are mutually exclusive"); + + // The matching syntax for whole archives and files outside of an archive + // can't be handled by SingleStringMatcher, and instead are handled + // manually within matchesFile() + if (!filePattern.empty()) { + if (filePattern.back() == ':') { + matchType = MatchType::WholeArchive; + filePat = filePattern.drop_back(); + } else if (filePattern.front() == ':') { + matchType = MatchType::ArchivesExcluded; + filePat = filePattern.drop_front(); + } + } } static bool classof(const SectionCommand *c) { diff --git a/lld/test/ELF/linkerscript/filename-spec.s b/lld/test/ELF/linkerscript/filename-spec.s index 4fc4f2f421752..6d5761f67f9f3 100644 --- a/lld/test/ELF/linkerscript/filename-spec.s +++ b/lld/test/ELF/linkerscript/filename-spec.s @@ -4,7 +4,7 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64 tx.s -o tx.o # RUN: llvm-mc -filetype=obj -triple=x86_64 ty.s -o ty.o -# RUN: echo 'SECTIONS{.foo :{ KEEP(*x.o(.foo)) KEEP(*y.o(.foo)) }}' > 1.t +# RUN: echo 'SECTIONS{.foo :{ KEEP(:*x.o(.foo)) KEEP(*y.o(.foo)) }}' > 1.t # RUN: ld.lld -o 1 -T 1.t tx.o ty.o # RUN: llvm-objdump -s 1 | FileCheck --check-prefix=FIRSTY %s # FIRSTY: Contents of section .foo: @@ -18,7 +18,7 @@ ## Now the same tests but without KEEP. Checking that file name inside ## KEEP is parsed fine. -# RUN: echo 'SECTIONS{.foo :{ *x.o(.foo) *y.o(.foo) }}' > 3.t +# RUN: echo 'SECTIONS{.foo :{ :*x.o(.foo) *y.o(.foo) }}' > 3.t # RUN: ld.lld -o 3 -T 3.t tx.o ty.o # RUN: llvm-objdump -s 3 | FileCheck --check-prefix=FIRSTY %s @@ -41,6 +41,7 @@ # RUN: cp ty.o dir2/filename-spec2.o # RUN: llvm-ar rc dir1/lib1.a dir1/filename-spec1.o # RUN: llvm-ar rc dir2/lib2.a dir2/filename-spec2.o +# RUN: llvm-ar rc combined.a tx.o ty.o ## Verify matching of archive library names. # RUN: echo 'SECTIONS{.foo :{ *lib2*(.foo) *lib1*(.foo) }}' > 7.t @@ -55,7 +56,7 @@ # RUN: llvm-objdump -s 8 | FileCheck --check-prefix=SECONDFIRST %s ## Verify matching of archive library names in KEEP. -# RUN: echo 'SECTIONS{.foo :{ KEEP(*lib2*(.foo)) KEEP(*lib1*(.foo)) }}' > 9.t +# RUN: echo 'SECTIONS{.foo :{ KEEP(*lib2.a:(.foo)) KEEP(*lib1*(.foo)) }}' > 9.t # RUN: ld.lld -o 9 -T 9.t --whole-archive \ # RUN: dir1/lib1.a dir2/lib2.a # RUN: llvm-objdump -s 9 | FileCheck --check-prefix=SECONDFIRST %s @@ -72,6 +73,11 @@ # RUN: ld.lld -o 11 -T 11.t --whole-archive 'lib1().a' dir2/lib2.a # RUN: llvm-objdump -s 11 | FileCheck --check-prefix=SECONDFIRST %s +## Verify that matching files excluded from an archive will not match files within one. +# RUN: echo 'SECTIONS{.foo :{ KEEP(:*x.o(.foo)) KEEP(*y.o(.foo)) KEEP(*x.o(.foo)) }}' > 12.t +# RUN: ld.lld -o 12 -T 12.t --whole-archive combined.a +# RUN: llvm-objdump -s 12 | FileCheck --check-prefix=SECONDFIRST %s + #--- tx.s .global _start _start: