[lld] [lld][ELF] Allow implicit wildcard in archive file name (PR #119293)

via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 16 16:14:17 PST 2024


https://github.com/amosher-nvidia updated https://github.com/llvm/llvm-project/pull/119293

>From 4c1215f4fcad0fbb730e63f91ba849921d8fccaf Mon Sep 17 00:00:00 2001
From: Avery Mosher <amosher at nvidia.com>
Date: Mon, 9 Dec 2024 23:41:22 +0000
Subject: [PATCH] [lld][ELF] Handle archive special casing in Input Sections

Co-authored-by: Peter Smith <peter.smith at arm.com>
---
 lld/ELF/LinkerScript.cpp                  | 17 +++++++++++++++--
 lld/ELF/LinkerScript.h                    | 19 +++++++++++++++++--
 lld/test/ELF/linkerscript/filename-spec.s | 13 ++++++++++---
 3 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index 7d24c6750b0d10..0d528343aa6cb9 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -406,12 +406,25 @@ static inline StringRef getFilename(const InputFile *file) {
   return file ? file->getNameForScript() : StringRef();
 }
 
+static inline StringRef getArchiveName(const InputFile *file) {
+  return file ? static_cast<StringRef>(file->archiveName) : StringRef();
+}
+
 bool InputSectionDescription::matchesFile(const InputFile *file) const {
   if (filePat.isTrivialMatchAll())
     return true;
 
-  if (!matchesFileCache || matchesFileCache->first != file)
-    matchesFileCache.emplace(file, filePat.match(getFilename(file)));
+  if (!matchesFileCache || matchesFileCache->first != file) {
+    if (matchType == MatchType::WholeArchive) {
+      matchesFileCache.emplace(file, filePat.match(getArchiveName(file)));
+    } else {
+      if (matchType == MatchType::ArchivesExcluded && file &&
+          !file->archiveName.empty())
+        matchesFileCache.emplace(file, false);
+      else
+        matchesFileCache.emplace(file, filePat.match(getFilename(file)));
+    }
+  }
 
   return matchesFileCache->second;
 }
diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h
index 328368fd3b4333..8d64b326abf7be 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 4fc4f2f4217528..a6953ec2a0f97c 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,12 @@
 # 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 doesn't 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 \
+# RUN:   combined.a
+# RUN: llvm-objdump -s 12 | FileCheck --check-prefix=SECONDFIRST %s
+
 #--- tx.s
 .global _start
 _start:



More information about the llvm-commits mailing list