@@ -277,6 +277,8 @@ getSymbolAssignmentValues(ArrayRef<SectionCommand *> sectionCommands) {
277
277
assign->sym ->value ));
278
278
continue ;
279
279
}
280
+ if (isa<SectionClassDesc>(cmd))
281
+ continue ;
280
282
for (SectionCommand *subCmd : cast<OutputDesc>(cmd)->osec .commands )
281
283
if (auto *assign = dyn_cast<SymbolAssignment>(subCmd))
282
284
if (assign->sym )
@@ -348,6 +350,8 @@ void LinkerScript::declareSymbols() {
348
350
declareSymbol (assign);
349
351
continue ;
350
352
}
353
+ if (isa<SectionClassDesc>(cmd))
354
+ continue ;
351
355
352
356
// If the output section directive has constraints,
353
357
// we can't say for sure if it is going to be included or not.
@@ -491,104 +495,136 @@ static void sortInputSections(MutableArrayRef<InputSectionBase *> vec,
491
495
SmallVector<InputSectionBase *, 0 >
492
496
LinkerScript::computeInputSections (const InputSectionDescription *cmd,
493
497
ArrayRef<InputSectionBase *> sections,
494
- const OutputSection &outCmd) {
498
+ const SectionBase &outCmd) {
495
499
SmallVector<InputSectionBase *, 0 > ret;
496
- SmallVector<size_t , 0 > indexes;
497
- DenseSet<size_t > seen;
498
500
DenseSet<InputSectionBase *> spills;
499
- auto sortByPositionThenCommandLine = [&](size_t begin, size_t end) {
500
- llvm::sort (MutableArrayRef<size_t >(indexes).slice (begin, end - begin));
501
- for (size_t i = begin; i != end; ++i)
502
- ret[i] = sections[indexes[i]];
503
- sortInputSections (
504
- MutableArrayRef<InputSectionBase *>(ret).slice (begin, end - begin),
505
- config->sortSection , SortSectionPolicy::None);
501
+
502
+ // Returns whether an input section's flags match the input section
503
+ // description's specifiers.
504
+ auto flagsMatch = [cmd](InputSectionBase *sec) {
505
+ return (sec->flags & cmd->withFlags ) == cmd->withFlags &&
506
+ (sec->flags & cmd->withoutFlags ) == 0 ;
506
507
};
507
508
508
509
// Collects all sections that satisfy constraints of Cmd.
509
- size_t sizeAfterPrevSort = 0 ;
510
- for (const SectionPattern &pat : cmd->sectionPatterns ) {
511
- size_t sizeBeforeCurrPat = ret.size ();
512
-
513
- for (size_t i = 0 , e = sections.size (); i != e; ++i) {
514
- // Skip if the section is dead or has been matched by a previous pattern
515
- // in this input section description.
516
- InputSectionBase *sec = sections[i];
517
- if (!sec->isLive () || seen.contains (i))
518
- continue ;
519
-
520
- // For --emit-relocs we have to ignore entries like
521
- // .rela.dyn : { *(.rela.data) }
522
- // which are common because they are in the default bfd script.
523
- // We do not ignore SHT_REL[A] linker-synthesized sections here because
524
- // want to support scripts that do custom layout for them.
525
- if (isa<InputSection>(sec) &&
526
- cast<InputSection>(sec)->getRelocatedSection ())
527
- continue ;
528
-
529
- // Check the name early to improve performance in the common case.
530
- if (!pat.sectionPat .match (sec->name ))
531
- continue ;
532
-
533
- if (!cmd->matchesFile (sec->file ) || pat.excludesFile (sec->file ) ||
534
- (sec->flags & cmd->withFlags ) != cmd->withFlags ||
535
- (sec->flags & cmd->withoutFlags ) != 0 )
536
- continue ;
537
-
538
- if (sec->parent ) {
539
- // Skip if not allowing multiple matches.
540
- if (!config->enableNonContiguousRegions )
510
+ if (cmd->classRef .empty ()) {
511
+ DenseSet<size_t > seen;
512
+ size_t sizeAfterPrevSort = 0 ;
513
+ SmallVector<size_t , 0 > indexes;
514
+ auto sortByPositionThenCommandLine = [&](size_t begin, size_t end) {
515
+ llvm::sort (MutableArrayRef<size_t >(indexes).slice (begin, end - begin));
516
+ for (size_t i = begin; i != end; ++i)
517
+ ret[i] = sections[indexes[i]];
518
+ sortInputSections (
519
+ MutableArrayRef<InputSectionBase *>(ret).slice (begin, end - begin),
520
+ config->sortSection , SortSectionPolicy::None);
521
+ };
522
+
523
+ for (const SectionPattern &pat : cmd->sectionPatterns ) {
524
+ size_t sizeBeforeCurrPat = ret.size ();
525
+
526
+ for (size_t i = 0 , e = sections.size (); i != e; ++i) {
527
+ // Skip if the section is dead or has been matched by a previous pattern
528
+ // in this input section description.
529
+ InputSectionBase *sec = sections[i];
530
+ if (!sec->isLive () || seen.contains (i))
541
531
continue ;
542
532
543
- // Disallow spilling into /DISCARD/; special handling would be needed
544
- // for this in address assignment, and the semantics are nebulous.
545
- if (outCmd.name == " /DISCARD/" )
533
+ // For --emit-relocs we have to ignore entries like
534
+ // .rela.dyn : { *(.rela.data) }
535
+ // which are common because they are in the default bfd script.
536
+ // We do not ignore SHT_REL[A] linker-synthesized sections here because
537
+ // want to support scripts that do custom layout for them.
538
+ if (isa<InputSection>(sec) &&
539
+ cast<InputSection>(sec)->getRelocatedSection ())
546
540
continue ;
547
541
548
- // Skip if the section's first match was /DISCARD/; such sections are
549
- // always discarded.
550
- if (sec->parent ->name == " /DISCARD/" )
542
+ // Check the name early to improve performance in the common case.
543
+ if (!pat.sectionPat .match (sec->name ))
551
544
continue ;
552
545
553
- // Skip if the section was already matched by a different input section
554
- // description within this output section.
555
- if (sec->parent == &outCmd)
546
+ if (!cmd->matchesFile (sec->file ) || pat.excludesFile (sec->file ) ||
547
+ sec->parent == &outCmd || !flagsMatch (sec))
556
548
continue ;
557
549
558
- spills.insert (sec);
550
+ if (sec->parent ) {
551
+ // Skip if not allowing multiple matches.
552
+ if (!config->enableNonContiguousRegions )
553
+ continue ;
554
+
555
+ // Disallow spilling into /DISCARD/; special handling would be needed
556
+ // for this in address assignment, and the semantics are nebulous.
557
+ if (outCmd.name == " /DISCARD/" )
558
+ continue ;
559
+
560
+ // Class definitions cannot contain spills, nor can a class definition
561
+ // generate a spill in a subsequent match. Those behaviors belong to
562
+ // class references and additional matches.
563
+ if (!isa<SectionClass>(outCmd) && !isa<SectionClass>(sec->parent ))
564
+ spills.insert (sec);
565
+ }
566
+
567
+ ret.push_back (sec);
568
+ indexes.push_back (i);
569
+ seen.insert (i);
559
570
}
560
571
561
- ret.push_back (sec);
562
- indexes.push_back (i);
563
- seen.insert (i);
572
+ if (pat.sortOuter == SortSectionPolicy::Default)
573
+ continue ;
574
+
575
+ // Matched sections are ordered by radix sort with the keys being (SORT*,
576
+ // --sort-section, input order), where SORT* (if present) is most
577
+ // significant.
578
+ //
579
+ // Matched sections between the previous SORT* and this SORT* are sorted
580
+ // by (--sort-alignment, input order).
581
+ sortByPositionThenCommandLine (sizeAfterPrevSort, sizeBeforeCurrPat);
582
+ // Matched sections by this SORT* pattern are sorted using all 3 keys.
583
+ // ret[sizeBeforeCurrPat,ret.size()) are already in the input order, so we
584
+ // just sort by sortOuter and sortInner.
585
+ sortInputSections (
586
+ MutableArrayRef<InputSectionBase *>(ret).slice (sizeBeforeCurrPat),
587
+ pat.sortOuter , pat.sortInner );
588
+ sizeAfterPrevSort = ret.size ();
564
589
}
565
590
566
- if (pat.sortOuter == SortSectionPolicy::Default)
567
- continue ;
591
+ // Matched sections after the last SORT* are sorted by (--sort-alignment,
592
+ // input order).
593
+ sortByPositionThenCommandLine (sizeAfterPrevSort, ret.size ());
594
+ } else {
595
+ SectionClassDesc *scd =
596
+ script->sectionClasses .lookup (CachedHashStringRef (cmd->classRef ));
597
+ if (!scd) {
598
+ errorOrWarn (" undefined section class '" + cmd->classRef + " '" );
599
+ return ret;
600
+ }
601
+ if (!scd->sc .assigned ) {
602
+ errorOrWarn (" section class '" + cmd->classRef + " ' referenced by '" +
603
+ outCmd.name + " ' before class definition" );
604
+ return ret;
605
+ }
568
606
569
- // Matched sections are ordered by radix sort with the keys being (SORT*,
570
- // --sort-section, input order), where SORT* (if present) is most
571
- // significant.
572
- //
573
- // Matched sections between the previous SORT* and this SORT* are sorted by
574
- // (--sort-alignment, input order).
575
- sortByPositionThenCommandLine (sizeAfterPrevSort, sizeBeforeCurrPat);
576
- // Matched sections by this SORT* pattern are sorted using all 3 keys.
577
- // ret[sizeBeforeCurrPat,ret.size()) are already in the input order, so we
578
- // just sort by sortOuter and sortInner.
579
- sortInputSections (
580
- MutableArrayRef<InputSectionBase *>(ret).slice (sizeBeforeCurrPat),
581
- pat.sortOuter , pat.sortInner );
582
- sizeAfterPrevSort = ret.size ();
607
+ for (InputSectionDescription *isd : scd->sc .commands ) {
608
+ for (InputSectionBase *sec : isd->sectionBases ) {
609
+ if (sec->parent == &outCmd || !flagsMatch (sec))
610
+ continue ;
611
+ bool isSpill = sec->parent && isa<OutputSection>(sec->parent );
612
+ if (!sec->parent || (isSpill && outCmd.name == " /DISCARD/" )) {
613
+ errorOrWarn (" section '" + sec->name +
614
+ " ' cannot spill from/to /DISCARD/" );
615
+ continue ;
616
+ }
617
+ if (isSpill)
618
+ spills.insert (sec);
619
+ ret.push_back (sec);
620
+ }
621
+ }
583
622
}
584
- // Matched sections after the last SORT* are sorted by (--sort-alignment,
585
- // input order).
586
- sortByPositionThenCommandLine (sizeAfterPrevSort, ret.size ());
587
-
588
- // The flag --enable-non-contiguous-regions may cause sections to match an
589
- // InputSectionDescription in more than one OutputSection. Matches after the
590
- // first were collected in the spills set, so replace these with potential
591
- // spill sections.
623
+
624
+ // The flag --enable-non-contiguous-regions or the section CLASS syntax may
625
+ // cause sections to match an InputSectionDescription in more than one
626
+ // OutputSection. Matches after the first were collected in the spills set, so
627
+ // replace these with potential spill sections.
592
628
if (!spills.empty ()) {
593
629
for (InputSectionBase *&sec : ret) {
594
630
if (!spills.contains (sec))
@@ -708,7 +744,7 @@ void LinkerScript::processSectionCommands() {
708
744
!map.try_emplace (CachedHashStringRef (osec->name ), osd).second )
709
745
warn (" OVERWRITE_SECTIONS specifies duplicate " + osec->name );
710
746
}
711
- for (SectionCommand *&base : sectionCommands)
747
+ for (SectionCommand *&base : sectionCommands) {
712
748
if (auto *osd = dyn_cast<OutputDesc>(base)) {
713
749
OutputSection *osec = &osd->osec ;
714
750
if (OutputDesc *overwrite = map.lookup (CachedHashStringRef (osec->name ))) {
@@ -718,14 +754,72 @@ void LinkerScript::processSectionCommands() {
718
754
} else if (process (osec)) {
719
755
osec->sectionIndex = i++;
720
756
}
757
+ } else if (auto *sc = dyn_cast<SectionClassDesc>(base)) {
758
+ for (InputSectionDescription *isd : sc->sc .commands ) {
759
+ isd->sectionBases =
760
+ computeInputSections (isd, ctx.inputSections , sc->sc );
761
+ for (InputSectionBase *s : isd->sectionBases ) {
762
+ // A section class containing a section with different parent isn't
763
+ // necessarily an error due to --enable-non-contiguous-regions. Such
764
+ // sections all become potential spills when the class is referenced.
765
+ if (!s->parent )
766
+ s->parent = &sc->sc ;
767
+ }
768
+ }
769
+ sc->sc .assigned = true ;
770
+ }
771
+ }
772
+
773
+ // Check that input sections cannot spill into or out of INSERT,
774
+ // since the semantics are nebulous. This is also true for OVERWRITE_SECTIONS,
775
+ // but no check is needed, since the order of processing ensures they cannot
776
+ // legally reference classes.
777
+ if (!potentialSpillLists.empty ()) {
778
+ DenseSet<StringRef> insertNames;
779
+ for (InsertCommand &ic : insertCommands)
780
+ insertNames.insert (ic.names .begin (), ic.names .end ());
781
+ for (SectionCommand *&base : sectionCommands) {
782
+ auto *osd = dyn_cast<OutputDesc>(base);
783
+ if (!osd)
784
+ continue ;
785
+ OutputSection *os = &osd->osec ;
786
+ if (!insertNames.contains (os->name ))
787
+ continue ;
788
+ for (SectionCommand *sc : os->commands ) {
789
+ auto *isd = dyn_cast<InputSectionDescription>(sc);
790
+ if (!isd)
791
+ continue ;
792
+ for (InputSectionBase *isec : isd->sectionBases )
793
+ if (isa<PotentialSpillSection>(isec) ||
794
+ potentialSpillLists.contains (isec))
795
+ errorOrWarn (" section '" + isec->name +
796
+ " ' cannot spill from/to INSERT section '" + os->name +
797
+ " '" );
798
+ }
721
799
}
800
+ }
722
801
723
802
// If an OVERWRITE_SECTIONS specified output section is not in
724
803
// sectionCommands, append it to the end. The section will be inserted by
725
804
// orphan placement.
726
805
for (OutputDesc *osd : overwriteSections)
727
806
if (osd->osec .partition == 1 && osd->osec .sectionIndex == UINT32_MAX)
728
807
sectionCommands.push_back (osd);
808
+
809
+ // Input sections cannot have a section class parent past this point; they
810
+ // must have been assigned to an output section.
811
+ for (const auto &[_, sc] : sectionClasses) {
812
+ for (InputSectionDescription *isd : sc->sc .commands ) {
813
+ for (InputSectionBase *sec : isd->sectionBases ) {
814
+ if (sec->parent && isa<SectionClass>(sec->parent )) {
815
+ errorOrWarn (" section class '" + sec->parent ->name +
816
+ " ' is unreferenced" );
817
+ goto nextClass;
818
+ }
819
+ }
820
+ }
821
+ nextClass:;
822
+ }
729
823
}
730
824
731
825
void LinkerScript::processSymbolAssignments () {
@@ -746,8 +840,8 @@ void LinkerScript::processSymbolAssignments() {
746
840
for (SectionCommand *cmd : sectionCommands) {
747
841
if (auto *assign = dyn_cast<SymbolAssignment>(cmd))
748
842
addSymbol (assign);
749
- else
750
- for (SectionCommand *subCmd : cast<OutputDesc>(cmd) ->osec .commands )
843
+ else if ( auto *osd = dyn_cast<OutputDesc>(cmd))
844
+ for (SectionCommand *subCmd : osd ->osec .commands )
751
845
if (auto *assign = dyn_cast<SymbolAssignment>(subCmd))
752
846
addSymbol (assign);
753
847
}
@@ -1417,6 +1511,8 @@ LinkerScript::assignAddresses() {
1417
1511
assign->size = dot - assign->addr ;
1418
1512
continue ;
1419
1513
}
1514
+ if (isa<SectionClassDesc>(cmd))
1515
+ continue ;
1420
1516
if (assignOffsets (&cast<OutputDesc>(cmd)->osec ) && !changedOsec)
1421
1517
changedOsec = &cast<OutputDesc>(cmd)->osec ;
1422
1518
}
@@ -1437,15 +1533,15 @@ static bool hasRegionOverflowed(MemoryRegion *mr) {
1437
1533
// Under-estimates may cause unnecessary spills, but over-estimates can always
1438
1534
// be corrected on the next pass.
1439
1535
bool LinkerScript::spillSections () {
1440
- if (!config-> enableNonContiguousRegions )
1536
+ if (potentialSpillLists. empty () )
1441
1537
return false ;
1442
1538
1443
1539
bool spilled = false ;
1444
1540
for (SectionCommand *cmd : reverse (sectionCommands)) {
1445
- auto *od = dyn_cast<OutputDesc>(cmd);
1446
- if (!od )
1541
+ auto *osd = dyn_cast<OutputDesc>(cmd);
1542
+ if (!osd )
1447
1543
continue ;
1448
- OutputSection *osec = &od ->osec ;
1544
+ OutputSection *osec = &osd ->osec ;
1449
1545
if (!osec->memRegion )
1450
1546
continue ;
1451
1547
0 commit comments