Skip to content

Commit 6b68da2

Browse files
committed
Address review feedback
- Add an explicit test that CLASS(a b) doesn't parse as a reference. - Add SORT_BY_ALIGNMENT in class def to demonstrate more complex matching. - Rename InputSectionDescription className to classRef to make it clearer that the class is being referenced, not defined. - Define the interaction between --enable-non-contiguous-regions and CLASS and add tests. - Add alreadyAssignedToOutCmd lambda to centralize comments.
1 parent 760a375 commit 6b68da2

File tree

4 files changed

+88
-27
lines changed

4 files changed

+88
-27
lines changed

lld/ELF/LinkerScript.cpp

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -497,13 +497,20 @@ LinkerScript::computeInputSections(const InputSectionDescription *cmd,
497497
SmallVector<InputSectionBase *, 0> ret;
498498
DenseSet<InputSectionBase *> spills;
499499

500+
// Returns whether an input section was already assigned to an earlier input
501+
// section description in this output section or section class.
502+
const auto alreadyAssignedToOutCmd =
503+
[&outCmd](InputSectionBase *sec) { return sec->parent == &outCmd; };
504+
505+
// Returns whether an input section's flags match the input section
506+
// description's specifiers.
500507
const auto flagsMatch = [cmd](InputSectionBase *sec) {
501508
return (sec->flags & cmd->withFlags) == cmd->withFlags &&
502509
(sec->flags & cmd->withoutFlags) == 0;
503510
};
504511

505512
// Collects all sections that satisfy constraints of Cmd.
506-
if (cmd->className.empty()) {
513+
if (cmd->classRef.empty()) {
507514
DenseSet<size_t> seen;
508515
size_t sizeAfterPrevSort = 0;
509516
SmallVector<size_t, 0> indexes;
@@ -540,30 +547,24 @@ LinkerScript::computeInputSections(const InputSectionDescription *cmd,
540547
continue;
541548

542549
if (!cmd->matchesFile(sec->file) || pat.excludesFile(sec->file) ||
543-
!flagsMatch(sec))
550+
alreadyAssignedToOutCmd(sec) || !flagsMatch(sec))
544551
continue;
545552

546553
if (sec->parent) {
547554
// Skip if not allowing multiple matches.
548555
if (!config->enableNonContiguousRegions)
549556
continue;
550557

551-
// Disallow spilling out of or into section classes; that's already a
552-
// mechanism for spilling.
553-
if (isa<SectionClass>(sec->parent) || isa<SectionClass>(outCmd))
554-
continue;
555-
556558
// Disallow spilling into /DISCARD/; special handling would be needed
557559
// for this in address assignment, and the semantics are nebulous.
558560
if (outCmd.name == "/DISCARD/")
559561
continue;
560562

561-
// Skip if the section was already matched by a different input
562-
// section description within this output section or class.
563-
if (sec->parent == &outCmd)
564-
continue;
565-
566-
spills.insert(sec);
563+
// Class definitions cannot contain spills, nor can a class definition
564+
// generate a spill in a subsequent match. Those behaviors belong to
565+
// class references and additional matches.
566+
if (!isa<SectionClass>(outCmd) && !isa<SectionClass>(sec->parent))
567+
spills.insert(sec);
567568
}
568569

569570
ret.push_back(sec);
@@ -594,20 +595,20 @@ LinkerScript::computeInputSections(const InputSectionDescription *cmd,
594595
// input order).
595596
sortByPositionThenCommandLine(sizeAfterPrevSort, ret.size());
596597
} else {
597-
SectionClassDesc *scd = script->sectionClasses.lookup(cmd->className);
598+
SectionClassDesc *scd = script->sectionClasses.lookup(cmd->classRef);
598599
if (!scd) {
599-
error("undefined section class '" + cmd->className + "'");
600+
error("undefined section class '" + cmd->classRef + "'");
600601
return ret;
601602
}
602603
if (!scd->sc.assigned) {
603-
error("section class '" + cmd->className + "' referenced by '" +
604+
error("section class '" + cmd->classRef + "' referenced by '" +
604605
outCmd.name + "' before class definition");
605606
return ret;
606607
}
607608

608609
for (InputSectionDescription *isd : scd->sc.commands) {
609610
for (InputSectionBase *sec : isd->sectionBases) {
610-
if (sec->parent == &outCmd || !flagsMatch(sec))
611+
if (alreadyAssignedToOutCmd(sec) || !flagsMatch(sec))
611612
continue;
612613
bool isSpill = sec->parent && isa<OutputSection>(sec->parent);
613614
if (!sec->parent || (isSpill && outCmd.name == "/DISCARD/"))
@@ -756,8 +757,12 @@ void LinkerScript::processSectionCommands() {
756757
for (InputSectionDescription *isd : sc->sc.commands) {
757758
isd->sectionBases =
758759
computeInputSections(isd, ctx.inputSections, sc->sc);
759-
for (InputSectionBase *s : isd->sectionBases)
760-
s->parent = &sc->sc;
760+
for (InputSectionBase *s : isd->sectionBases) {
761+
// Section classes with --enable-non-contiguous-regions may contain
762+
// parented classes; spills for these are generated on reference.
763+
if (!s->parent)
764+
s->parent = &sc->sc;
765+
}
761766
}
762767
sc->sc.assigned = true;
763768
}

lld/ELF/LinkerScript.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -201,11 +201,11 @@ class InputSectionDescription : public SectionCommand {
201201

202202
public:
203203
InputSectionDescription(StringRef filePattern, uint64_t withFlags = 0,
204-
uint64_t withoutFlags = 0, StringRef className = {})
204+
uint64_t withoutFlags = 0, StringRef classRef = {})
205205
: SectionCommand(InputSectionKind), filePat(filePattern),
206-
withFlags(withFlags), withoutFlags(withoutFlags), className(className) {
207-
assert((filePattern.empty() || className.empty()) &&
208-
"file pattern and class name are mutually exclusive");
206+
withFlags(withFlags), withoutFlags(withoutFlags), classRef(classRef) {
207+
assert((filePattern.empty() || classRef.empty()) &&
208+
"file pattern and class reference are mutually exclusive");
209209
}
210210

211211
static bool classof(const SectionCommand *c) {
@@ -237,7 +237,7 @@ class InputSectionDescription : public SectionCommand {
237237

238238
// If present, input section matching uses class membership instead of file
239239
// and section patterns (mutually exclusive).
240-
StringRef className;
240+
StringRef classRef;
241241
};
242242

243243
// Represents BYTE(), SHORT(), LONG(), or QUAD().

lld/ELF/ScriptParser.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -620,9 +620,9 @@ SectionClassDesc *ScriptParser::readSectionClassDescription() {
620620
setError("expected filename pattern");
621621
else if (peek() == "(") {
622622
InputSectionDescription *isd = readInputSectionDescription(tok);
623-
if (!isd->className.empty())
623+
if (!isd->classRef.empty())
624624
setError("section class '" + name + "' references class '" +
625-
isd->className + "'");
625+
isd->classRef + "'");
626626
desc->sc.commands.push_back(isd);
627627
}
628628
}

lld/test/ELF/linkerscript/section-class.test

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# RUN: llvm-readobj -x .rodata -x .rodata.d matching | FileCheck %s --check-prefix=MATCHING
1313

1414
# MATCHING: .rodata
15-
# MATCHING-NEXT: 020301
15+
# MATCHING-NEXT: 020301cc 0605
1616
# MATCHING: .rodata.d
1717
# MATCHING-NEXT: 04
1818

@@ -34,6 +34,14 @@
3434
# MISSING-FILENAME-PATTERN: error: missing-filename-pattern.ld:2: expected filename pattern
3535

3636

37+
## An error is reported when more than one class is mentioned in a reference.
38+
39+
# RUN: not ld.lld -T multiple-class-names.ld matching.o 2>&1 | \
40+
# RUN: FileCheck %s --check-prefix=MULTIPLE-CLASS-NAMES --implicit-check-not=error:
41+
42+
# MULTIPLE-CLASS-NAMES: error: multiple-class-names.ld:4: ) expected, but got b
43+
44+
3745
## An error is reported when the content of section classes is demanded before
3846
## its definition is processed.
3947

@@ -113,6 +121,19 @@
113121
# SPILL-EARLIER-NEXT: .last_chance PROGBITS 0000000000000002 001002 000001
114122

115123

124+
## Class definitions do not preclude additional matches when used with
125+
## --enable-non-contiguous-regions, and additional matches in class
126+
## definitions become spills at class references.
127+
128+
# RUN: ld.lld -T enable-non-contiguous-regions.ld spill.o -o enable-non-contiguous-regions --enable-non-contiguous-regions
129+
# RUN: llvm-readelf -S enable-non-contiguous-regions | FileCheck %s --check-prefix=ENABLE-NON-CONTIGUOUS-REGIONS
130+
131+
# ENABLE-NON-CONTIGUOUS-REGIONS: Name Type Address Off Size
132+
# ENABLE-NON-CONTIGUOUS-REGIONS: .first_chance PROGBITS 0000000000000000 000190 000000
133+
# ENABLE-NON-CONTIGUOUS-REGIONS-NEXT: .last_chance PROGBITS 0000000000000001 001001 000002
134+
# ENABLE-NON-CONTIGUOUS-REGIONS-NEXT: .one_byte_section PROGBITS 0000000000000003 001003 000001
135+
136+
116137
## SHF_MERGEd sections are spilled according to the class refs of the first
117138
## merged input section (the one giving the resulting section its name).
118139

@@ -179,14 +200,23 @@
179200
.section .rodata.d,"a",@progbits
180201
.byte 4
181202

203+
.section .rodata.e,"a",@progbits
204+
.byte 5
205+
206+
.section .rodata.f,"a",@progbits
207+
.balign 2
208+
.byte 6
209+
182210
#--- matching.ld
183211
SECTIONS {
184212
CLASS(a) { *(.rodata.a) }
185213
CLASS(cd) { *(.rodata.c) *(.rodata.d) }
214+
CLASS(ef) { *(SORT_BY_ALIGNMENT(.rodata.e .rodata.f)) }
186215
.rodata : {
187216
*(.rodata.*)
188217
INPUT_SECTION_FLAGS(SHF_EXECINSTR) CLASS(cd)
189218
CLASS(a)
219+
CLASS(ef)
190220
}
191221
OVERLAY : { .rodata.d { INPUT_SECTION_FLAGS(!SHF_EXECINSTR) CLASS(cd) } }
192222
}
@@ -202,6 +232,13 @@ SECTIONS {
202232
CLASS(a) { (.rodata.a) }
203233
}
204234

235+
#--- multiple-class-names.ld
236+
SECTIONS {
237+
CLASS(a) { *(.rodata.a) }
238+
CLASS(b) { *(.rodata.b) }
239+
.rodata : { CLASS(a b) }
240+
}
241+
205242
#--- referenced-before-defined.ld
206243
SECTIONS {
207244
.rodata : { CLASS(a) }
@@ -290,6 +327,25 @@ SECTIONS {
290327
.last_chance : { CLASS(c) } >b
291328
}
292329

330+
#--- enable-non-contiguous-regions.ld
331+
MEMORY {
332+
a : ORIGIN = 0, LENGTH = 1
333+
b : ORIGIN = 1, LENGTH = 2
334+
c : ORIGIN = 3, LENGTH = 1
335+
}
336+
337+
SECTIONS {
338+
.first_chance : { *(.two_byte_section) } >a
339+
/* An additional match in a class defers a spill. */
340+
CLASS(two) { *(.two_byte_section) }
341+
/* A class references actualizes deferred spills. */
342+
.last_chance : { CLASS(two) } >b
343+
344+
/* Section classes do not preclude other matches. */
345+
CLASS(one) { *(.one_byte_section) }
346+
.one_byte_section : { *(.one_byte_section) } >c
347+
}
348+
293349
#--- merge.s
294350
.section .a,"aM",@progbits,1
295351
.byte 0x12, 0x34

0 commit comments

Comments
 (0)