@@ -276,6 +276,8 @@ getSymbolAssignmentValues(ArrayRef<SectionCommand *> sectionCommands) {
276
276
assign->sym ->value ));
277
277
continue ;
278
278
}
279
+ if (isa<SectionClassDesc>(cmd))
280
+ continue ;
279
281
for (SectionCommand *subCmd : cast<OutputDesc>(cmd)->osec .commands )
280
282
if (auto *assign = dyn_cast<SymbolAssignment>(subCmd))
281
283
if (assign->sym )
@@ -347,6 +349,8 @@ void LinkerScript::declareSymbols() {
347
349
declareSymbol (assign);
348
350
continue ;
349
351
}
352
+ if (isa<SectionClassDesc>(cmd))
353
+ continue ;
350
354
351
355
// If the output section directive has constraints,
352
356
// we can't say for sure if it is going to be included or not.
@@ -490,99 +494,130 @@ static void sortInputSections(MutableArrayRef<InputSectionBase *> vec,
490
494
SmallVector<InputSectionBase *, 0 >
491
495
LinkerScript::computeInputSections (const InputSectionDescription *cmd,
492
496
ArrayRef<InputSectionBase *> sections,
493
- const OutputSection &outCmd) {
497
+ const SectionBase &outCmd) {
494
498
SmallVector<InputSectionBase *, 0 > ret;
495
- SmallVector<size_t , 0 > indexes;
496
- DenseSet<size_t > seen;
497
499
DenseSet<InputSectionBase *> spills;
498
- auto sortByPositionThenCommandLine = [&](size_t begin, size_t end) {
499
- llvm::sort (MutableArrayRef<size_t >(indexes).slice (begin, end - begin));
500
- for (size_t i = begin; i != end; ++i)
501
- ret[i] = sections[indexes[i]];
502
- sortInputSections (
503
- MutableArrayRef<InputSectionBase *>(ret).slice (begin, end - begin),
504
- config->sortSection , SortSectionPolicy::None);
500
+
501
+ const auto flagsMatch = [cmd](InputSectionBase *sec) {
502
+ return (sec->flags & cmd->withFlags ) == cmd->withFlags &&
503
+ (sec->flags & cmd->withoutFlags ) == 0 ;
505
504
};
506
505
507
506
// Collects all sections that satisfy constraints of Cmd.
508
- size_t sizeAfterPrevSort = 0 ;
509
- for (const SectionPattern &pat : cmd->sectionPatterns ) {
510
- size_t sizeBeforeCurrPat = ret.size ();
511
-
512
- for (size_t i = 0 , e = sections.size (); i != e; ++i) {
513
- // Skip if the section is dead or has been matched by a previous pattern
514
- // in this input section description.
515
- InputSectionBase *sec = sections[i];
516
- if (!sec->isLive () || seen.contains (i))
517
- continue ;
518
-
519
- // For --emit-relocs we have to ignore entries like
520
- // .rela.dyn : { *(.rela.data) }
521
- // which are common because they are in the default bfd script.
522
- // We do not ignore SHT_REL[A] linker-synthesized sections here because
523
- // want to support scripts that do custom layout for them.
524
- if (isa<InputSection>(sec) &&
525
- cast<InputSection>(sec)->getRelocatedSection ())
526
- continue ;
527
-
528
- // Check the name early to improve performance in the common case.
529
- if (!pat.sectionPat .match (sec->name ))
530
- continue ;
531
-
532
- if (!cmd->matchesFile (sec->file ) || pat.excludesFile (sec->file ) ||
533
- (sec->flags & cmd->withFlags ) != cmd->withFlags ||
534
- (sec->flags & cmd->withoutFlags ) != 0 )
535
- continue ;
536
-
537
- if (sec->parent ) {
538
- // Skip if not allowing multiple matches.
539
- if (!config->enableNonContiguousRegions )
507
+ if (cmd->className .empty ()) {
508
+ DenseSet<size_t > seen;
509
+ size_t sizeAfterPrevSort = 0 ;
510
+ SmallVector<size_t , 0 > indexes;
511
+ auto sortByPositionThenCommandLine = [&](size_t begin, size_t end) {
512
+ llvm::sort (MutableArrayRef<size_t >(indexes).slice (begin, end - begin));
513
+ for (size_t i = begin; i != end; ++i)
514
+ ret[i] = sections[indexes[i]];
515
+ sortInputSections (
516
+ MutableArrayRef<InputSectionBase *>(ret).slice (begin, end - begin),
517
+ config->sortSection , SortSectionPolicy::None);
518
+ };
519
+
520
+ for (const SectionPattern &pat : cmd->sectionPatterns ) {
521
+ size_t sizeBeforeCurrPat = ret.size ();
522
+
523
+ for (size_t i = 0 , e = sections.size (); i != e; ++i) {
524
+ // Skip if the section is dead or has been matched by a previous pattern
525
+ // in this input section description.
526
+ InputSectionBase *sec = sections[i];
527
+ if (!sec->isLive () || seen.contains (i))
540
528
continue ;
541
529
542
- // Disallow spilling into /DISCARD/; special handling would be needed
543
- // for this in address assignment, and the semantics are nebulous.
544
- if (outCmd.name == " /DISCARD/" )
530
+ // For --emit-relocs we have to ignore entries like
531
+ // .rela.dyn : { *(.rela.data) }
532
+ // which are common because they are in the default bfd script.
533
+ // We do not ignore SHT_REL[A] linker-synthesized sections here because
534
+ // want to support scripts that do custom layout for them.
535
+ if (isa<InputSection>(sec) &&
536
+ cast<InputSection>(sec)->getRelocatedSection ())
545
537
continue ;
546
538
547
- // Skip if the section's first match was /DISCARD/; such sections are
548
- // always discarded.
549
- if (sec->parent ->name == " /DISCARD/" )
539
+ // Check the name early to improve performance in the common case.
540
+ if (!pat.sectionPat .match (sec->name ))
550
541
continue ;
551
542
552
- // Skip if the section was already matched by a different input section
553
- // description within this output section.
554
- if (sec->parent == &outCmd)
543
+ if (!cmd->matchesFile (sec->file ) || pat.excludesFile (sec->file ) ||
544
+ !flagsMatch (sec))
555
545
continue ;
556
546
557
- spills.insert (sec);
547
+ if (sec->parent ) {
548
+ // Skip if not allowing multiple matches.
549
+ if (!config->enableNonContiguousRegions )
550
+ continue ;
551
+
552
+ // Disallow spilling out of or into section classes; that's already a
553
+ // mechanism for spilling.
554
+ if (isa<SectionClass>(sec->parent ) || isa<SectionClass>(outCmd))
555
+ continue ;
556
+
557
+ // Disallow spilling into /DISCARD/; special handling would be needed
558
+ // for this in address assignment, and the semantics are nebulous.
559
+ if (outCmd.name == " /DISCARD/" )
560
+ continue ;
561
+
562
+ // Skip if the section was already matched by a different input
563
+ // section description within this output section or class.
564
+ if (sec->parent == &outCmd)
565
+ continue ;
566
+
567
+ spills.insert (sec);
568
+ }
569
+
570
+ ret.push_back (sec);
571
+ indexes.push_back (i);
572
+ seen.insert (i);
558
573
}
559
574
560
- ret.push_back (sec);
561
- indexes.push_back (i);
562
- seen.insert (i);
575
+ if (pat.sortOuter == SortSectionPolicy::Default)
576
+ continue ;
577
+
578
+ // Matched sections are ordered by radix sort with the keys being (SORT*,
579
+ // --sort-section, input order), where SORT* (if present) is most
580
+ // significant.
581
+ //
582
+ // Matched sections between the previous SORT* and this SORT* are sorted
583
+ // by (--sort-alignment, input order).
584
+ sortByPositionThenCommandLine (sizeAfterPrevSort, sizeBeforeCurrPat);
585
+ // Matched sections by this SORT* pattern are sorted using all 3 keys.
586
+ // ret[sizeBeforeCurrPat,ret.size()) are already in the input order, so we
587
+ // just sort by sortOuter and sortInner.
588
+ sortInputSections (
589
+ MutableArrayRef<InputSectionBase *>(ret).slice (sizeBeforeCurrPat),
590
+ pat.sortOuter , pat.sortInner );
591
+ sizeAfterPrevSort = ret.size ();
563
592
}
564
593
565
- if (pat.sortOuter == SortSectionPolicy::Default)
566
- continue ;
594
+ // Matched sections after the last SORT* are sorted by (--sort-alignment,
595
+ // input order).
596
+ sortByPositionThenCommandLine (sizeAfterPrevSort, ret.size ());
597
+ } else {
598
+ SectionClassDesc *scd = script->sectionClasses .lookup (cmd->className );
599
+ if (!scd) {
600
+ error (" undefined section class '" + cmd->className + " '" );
601
+ return ret;
602
+ }
603
+ if (!scd->sc .assigned ) {
604
+ error (" section class '" + cmd->className + " ' used before assigned" );
605
+ return ret;
606
+ }
567
607
568
- // Matched sections are ordered by radix sort with the keys being (SORT*,
569
- // --sort-section, input order), where SORT* (if present) is most
570
- // significant.
571
- //
572
- // Matched sections between the previous SORT* and this SORT* are sorted by
573
- // (--sort-alignment, input order).
574
- sortByPositionThenCommandLine (sizeAfterPrevSort, sizeBeforeCurrPat);
575
- // Matched sections by this SORT* pattern are sorted using all 3 keys.
576
- // ret[sizeBeforeCurrPat,ret.size()) are already in the input order, so we
577
- // just sort by sortOuter and sortInner.
578
- sortInputSections (
579
- MutableArrayRef<InputSectionBase *>(ret).slice (sizeBeforeCurrPat),
580
- pat.sortOuter , pat.sortInner );
581
- sizeAfterPrevSort = ret.size ();
608
+ for (InputSectionDescription *isd : scd->sc .commands ) {
609
+ for (InputSectionBase *sec : isd->sectionBases ) {
610
+ if (sec->parent == &outCmd || !flagsMatch (sec))
611
+ continue ;
612
+ bool isSpill = sec->parent && isa<OutputSection>(sec->parent );
613
+ if (!sec->parent || (isSpill && outCmd.name == " /DISCARD/" ))
614
+ error (" section '" + sec->name + " ' cannot spill from/to /DISCARD/" );
615
+ if (isSpill)
616
+ spills.insert (sec);
617
+ ret.push_back (sec);
618
+ }
619
+ }
582
620
}
583
- // Matched sections after the last SORT* are sorted by (--sort-alignment,
584
- // input order).
585
- sortByPositionThenCommandLine (sizeAfterPrevSort, ret.size ());
586
621
587
622
// The flag --enable-non-contiguous-regions may cause sections to match an
588
623
// InputSectionDescription in more than one OutputSection. Matches after the
@@ -707,7 +742,7 @@ void LinkerScript::processSectionCommands() {
707
742
!map.try_emplace (CachedHashStringRef (osec->name ), osd).second )
708
743
warn (" OVERWRITE_SECTIONS specifies duplicate " + osec->name );
709
744
}
710
- for (SectionCommand *&base : sectionCommands)
745
+ for (SectionCommand *&base : sectionCommands) {
711
746
if (auto *osd = dyn_cast<OutputDesc>(base)) {
712
747
OutputSection *osec = &osd->osec ;
713
748
if (OutputDesc *overwrite = map.lookup (CachedHashStringRef (osec->name ))) {
@@ -717,14 +752,60 @@ void LinkerScript::processSectionCommands() {
717
752
} else if (process (osec)) {
718
753
osec->sectionIndex = i++;
719
754
}
755
+ } else if (auto *sc = dyn_cast<SectionClassDesc>(base)) {
756
+ for (InputSectionDescription *isd : sc->sc .commands ) {
757
+ isd->sectionBases =
758
+ computeInputSections (isd, ctx.inputSections , sc->sc );
759
+ for (InputSectionBase *s : isd->sectionBases )
760
+ s->parent = &sc->sc ;
761
+ }
762
+ sc->sc .assigned = true ;
720
763
}
764
+ }
765
+
766
+ // Check that input sections cannot spill into or out of INSERT,
767
+ // since the semantics are nebulous. This is also true for OVERWRITE_SECTIONS,
768
+ // but no check is needed, since the order of processing ensures they cannot
769
+ // legally reference classes.
770
+ if (!potentialSpillLists.empty ()) {
771
+ DenseSet<StringRef> insertNames;
772
+ for (InsertCommand &ic : insertCommands)
773
+ insertNames.insert (ic.names .begin (), ic.names .end ());
774
+ for (SectionCommand *&base : sectionCommands) {
775
+ auto *osd = dyn_cast<OutputDesc>(base);
776
+ if (!osd)
777
+ continue ;
778
+ OutputSection *os = &osd->osec ;
779
+ if (!insertNames.contains (os->name ))
780
+ continue ;
781
+ for (SectionCommand *sc : os->commands ) {
782
+ auto *isd = dyn_cast<InputSectionDescription>(sc);
783
+ if (!isd)
784
+ continue ;
785
+ for (InputSectionBase *isec : isd->sectionBases )
786
+ if (isa<PotentialSpillSection>(isec) ||
787
+ potentialSpillLists.contains (isec))
788
+ error (" section '" + isec->name +
789
+ " ' cannot spill from/to INSERT section '" + os->name + " '" );
790
+ }
791
+ }
792
+ }
721
793
722
794
// If an OVERWRITE_SECTIONS specified output section is not in
723
795
// sectionCommands, append it to the end. The section will be inserted by
724
796
// orphan placement.
725
797
for (OutputDesc *osd : overwriteSections)
726
798
if (osd->osec .partition == 1 && osd->osec .sectionIndex == UINT32_MAX)
727
799
sectionCommands.push_back (osd);
800
+
801
+ // Input sections cannot have a section class parent past this point; they
802
+ // must have been assigned to an output section.
803
+ for (const auto &[_, sc] : sectionClasses)
804
+ for (InputSectionDescription *isd : sc->sc .commands )
805
+ for (InputSectionBase *sec : isd->sectionBases )
806
+ if (sec->parent && isa<SectionClass>(sec->parent ))
807
+ error (" section '" + sec->name + " ' assigned to class '" +
808
+ sec->parent ->name + " ' but to no output section" );
728
809
}
729
810
730
811
void LinkerScript::processSymbolAssignments () {
@@ -745,8 +826,8 @@ void LinkerScript::processSymbolAssignments() {
745
826
for (SectionCommand *cmd : sectionCommands) {
746
827
if (auto *assign = dyn_cast<SymbolAssignment>(cmd))
747
828
addSymbol (assign);
748
- else
749
- for (SectionCommand *subCmd : cast<OutputDesc>(cmd) ->osec .commands )
829
+ else if ( auto *od = dyn_cast<OutputDesc>(cmd))
830
+ for (SectionCommand *subCmd : od ->osec .commands )
750
831
if (auto *assign = dyn_cast<SymbolAssignment>(subCmd))
751
832
addSymbol (assign);
752
833
}
@@ -1421,6 +1502,8 @@ LinkerScript::assignAddresses() {
1421
1502
assign->size = dot - assign->addr ;
1422
1503
continue ;
1423
1504
}
1505
+ if (isa<SectionClassDesc>(cmd))
1506
+ continue ;
1424
1507
if (assignOffsets (&cast<OutputDesc>(cmd)->osec ) && !changedOsec)
1425
1508
changedOsec = &cast<OutputDesc>(cmd)->osec ;
1426
1509
}
@@ -1441,7 +1524,7 @@ static bool hasRegionOverflowed(MemoryRegion *mr) {
1441
1524
// Under-estimates may cause unnecessary spills, but over-estimates can always
1442
1525
// be corrected on the next pass.
1443
1526
bool LinkerScript::spillSections () {
1444
- if (!config-> enableNonContiguousRegions )
1527
+ if (potentialSpillLists. empty () )
1445
1528
return false ;
1446
1529
1447
1530
bool spilled = false ;
0 commit comments