Skip to content

Commit 1807860

Browse files
[lld][ELF] Handle archive special casing in Input Sections (llvm#119293)
According to the binutils spec: https://sourceware.org/binutils/docs/ld/Input-Section-Basics.html You should be able to specify all files in an archive using this syntax `archivename:` , however, lld currently will only accept `archivename:*` to match all files within an archive. This patch will, only when necessary, create a copy of the file specification and add an implicit wildcard `*` to the end. It also updates the filename-spec linkerscript test to check for this behavior. --------- Co-authored-by: Peter Smith <[email protected]>
1 parent 0de18e7 commit 1807860

File tree

3 files changed

+36
-7
lines changed

3 files changed

+36
-7
lines changed

lld/ELF/LinkerScript.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,8 +406,16 @@ bool InputSectionDescription::matchesFile(const InputFile &file) const {
406406
if (filePat.isTrivialMatchAll())
407407
return true;
408408

409-
if (!matchesFileCache || matchesFileCache->first != &file)
410-
matchesFileCache.emplace(&file, filePat.match(file.getNameForScript()));
409+
if (!matchesFileCache || matchesFileCache->first != &file) {
410+
if (matchType == MatchType::WholeArchive) {
411+
matchesFileCache.emplace(&file, filePat.match(file.archiveName));
412+
} else {
413+
if (matchType == MatchType::ArchivesExcluded && !file.archiveName.empty())
414+
matchesFileCache.emplace(&file, false);
415+
else
416+
matchesFileCache.emplace(&file, filePat.match(file.getNameForScript()));
417+
}
418+
}
411419

412420
return matchesFileCache->second;
413421
}

lld/ELF/LinkerScript.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ class SectionPattern {
194194
};
195195

196196
class InputSectionDescription : public SectionCommand {
197+
enum class MatchType { Trivial, WholeArchive, ArchivesExcluded } matchType;
197198
SingleStringMatcher filePat;
198199

199200
// Cache of the most recent input argument and result of matchesFile().
@@ -202,10 +203,24 @@ class InputSectionDescription : public SectionCommand {
202203
public:
203204
InputSectionDescription(StringRef filePattern, uint64_t withFlags = 0,
204205
uint64_t withoutFlags = 0, StringRef classRef = {})
205-
: SectionCommand(InputSectionKind), filePat(filePattern),
206-
classRef(classRef), withFlags(withFlags), withoutFlags(withoutFlags) {
206+
: SectionCommand(InputSectionKind), matchType(MatchType::Trivial),
207+
filePat(filePattern), classRef(classRef), withFlags(withFlags),
208+
withoutFlags(withoutFlags) {
207209
assert((filePattern.empty() || classRef.empty()) &&
208210
"file pattern and class reference are mutually exclusive");
211+
212+
// The matching syntax for whole archives and files outside of an archive
213+
// can't be handled by SingleStringMatcher, and instead are handled
214+
// manually within matchesFile()
215+
if (!filePattern.empty()) {
216+
if (filePattern.back() == ':') {
217+
matchType = MatchType::WholeArchive;
218+
filePat = filePattern.drop_back();
219+
} else if (filePattern.front() == ':') {
220+
matchType = MatchType::ArchivesExcluded;
221+
filePat = filePattern.drop_front();
222+
}
223+
}
209224
}
210225

211226
static bool classof(const SectionCommand *c) {

lld/test/ELF/linkerscript/filename-spec.s

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# RUN: llvm-mc -filetype=obj -triple=x86_64 tx.s -o tx.o
55
# RUN: llvm-mc -filetype=obj -triple=x86_64 ty.s -o ty.o
66

7-
# RUN: echo 'SECTIONS{.foo :{ KEEP(*x.o(.foo)) KEEP(*y.o(.foo)) }}' > 1.t
7+
# RUN: echo 'SECTIONS{.foo :{ KEEP(:*x.o(.foo)) KEEP(*y.o(.foo)) }}' > 1.t
88
# RUN: ld.lld -o 1 -T 1.t tx.o ty.o
99
# RUN: llvm-objdump -s 1 | FileCheck --check-prefix=FIRSTY %s
1010
# FIRSTY: Contents of section .foo:
@@ -18,7 +18,7 @@
1818

1919
## Now the same tests but without KEEP. Checking that file name inside
2020
## KEEP is parsed fine.
21-
# RUN: echo 'SECTIONS{.foo :{ *x.o(.foo) *y.o(.foo) }}' > 3.t
21+
# RUN: echo 'SECTIONS{.foo :{ :*x.o(.foo) *y.o(.foo) }}' > 3.t
2222
# RUN: ld.lld -o 3 -T 3.t tx.o ty.o
2323
# RUN: llvm-objdump -s 3 | FileCheck --check-prefix=FIRSTY %s
2424

@@ -41,6 +41,7 @@
4141
# RUN: cp ty.o dir2/filename-spec2.o
4242
# RUN: llvm-ar rc dir1/lib1.a dir1/filename-spec1.o
4343
# RUN: llvm-ar rc dir2/lib2.a dir2/filename-spec2.o
44+
# RUN: llvm-ar rc combined.a tx.o ty.o
4445

4546
## Verify matching of archive library names.
4647
# RUN: echo 'SECTIONS{.foo :{ *lib2*(.foo) *lib1*(.foo) }}' > 7.t
@@ -55,7 +56,7 @@
5556
# RUN: llvm-objdump -s 8 | FileCheck --check-prefix=SECONDFIRST %s
5657

5758
## Verify matching of archive library names in KEEP.
58-
# RUN: echo 'SECTIONS{.foo :{ KEEP(*lib2*(.foo)) KEEP(*lib1*(.foo)) }}' > 9.t
59+
# RUN: echo 'SECTIONS{.foo :{ KEEP(*lib2.a:(.foo)) KEEP(*lib1*(.foo)) }}' > 9.t
5960
# RUN: ld.lld -o 9 -T 9.t --whole-archive \
6061
# RUN: dir1/lib1.a dir2/lib2.a
6162
# RUN: llvm-objdump -s 9 | FileCheck --check-prefix=SECONDFIRST %s
@@ -72,6 +73,11 @@
7273
# RUN: ld.lld -o 11 -T 11.t --whole-archive 'lib1().a' dir2/lib2.a
7374
# RUN: llvm-objdump -s 11 | FileCheck --check-prefix=SECONDFIRST %s
7475

76+
## Verify that matching files excluded from an archive will not match files within one.
77+
# RUN: echo 'SECTIONS{.foo :{ KEEP(:*x.o(.foo)) KEEP(*y.o(.foo)) KEEP(*x.o(.foo)) }}' > 12.t
78+
# RUN: ld.lld -o 12 -T 12.t --whole-archive combined.a
79+
# RUN: llvm-objdump -s 12 | FileCheck --check-prefix=SECONDFIRST %s
80+
7581
#--- tx.s
7682
.global _start
7783
_start:

0 commit comments

Comments
 (0)