7
7
// ===----------------------------------------------------------------------===//
8
8
9
9
#include " InputFiles.h"
10
+ #include " OutputSections.h"
10
11
#include " Symbols.h"
11
12
#include " SyntheticSections.h"
12
13
#include " Target.h"
14
+ #include " llvm/Support/TimeProfiler.h"
13
15
14
16
using namespace llvm ;
15
17
using namespace llvm ::object;
@@ -36,6 +38,7 @@ class RISCV final : public TargetInfo {
36
38
const uint8_t *loc) const override ;
37
39
void relocate (uint8_t *loc, const Relocation &rel,
38
40
uint64_t val) const override ;
41
+ bool relaxOnce (int pass) const override ;
39
42
};
40
43
41
44
} // end anonymous namespace
@@ -271,12 +274,7 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
271
274
case R_RISCV_TPREL_ADD:
272
275
return R_NONE;
273
276
case R_RISCV_ALIGN:
274
- // Not just a hint; always padded to the worst-case number of NOPs, so may
275
- // not currently be aligned, and without linker relaxation support we can't
276
- // delete NOPs to realign.
277
- errorOrWarn (getErrorLocation (loc) + " relocation R_RISCV_ALIGN requires "
278
- " unimplemented linker relaxation; recompile with -mno-relax" );
279
- return R_NONE;
277
+ return R_RELAX_HINT;
280
278
default :
281
279
error (getErrorLocation (loc) + " unknown relocation (" + Twine (type) +
282
280
" ) against symbol " + toString (s));
@@ -476,6 +474,233 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
476
474
}
477
475
}
478
476
477
+ namespace {
478
+ struct SymbolAnchor {
479
+ uint64_t offset;
480
+ Defined *d;
481
+ bool end; // true for the anchor of st_value+st_size
482
+ };
483
+ } // namespace
484
+
485
+ struct elf ::RISCVRelaxAux {
486
+ // This records symbol start and end offsets which will be adjusted according
487
+ // to the nearest relocDeltas element.
488
+ SmallVector<SymbolAnchor, 0 > anchors;
489
+ // For relocations[i], the actual offset is r_offset - (i ? relocDeltas[i-1] :
490
+ // 0).
491
+ std::unique_ptr<uint32_t []> relocDeltas;
492
+ };
493
+
494
+ static void initSymbolAnchors () {
495
+ SmallVector<InputSection *, 0 > storage;
496
+ for (OutputSection *osec : outputSections) {
497
+ if (!(osec->flags & SHF_EXECINSTR))
498
+ continue ;
499
+ for (InputSection *sec : getInputSections (*osec, storage)) {
500
+ sec->relaxAux = make<RISCVRelaxAux>();
501
+ if (sec->relocations .size ())
502
+ sec->relaxAux ->relocDeltas =
503
+ std::make_unique<uint32_t []>(sec->relocations .size ());
504
+ }
505
+ }
506
+ // Store anchors (st_value and st_value+st_size) for symbols relative to text
507
+ // sections.
508
+ for (InputFile *file : ctx->objectFiles )
509
+ for (Symbol *sym : file->getSymbols ()) {
510
+ auto *d = dyn_cast<Defined>(sym);
511
+ if (!d || d->file != file)
512
+ continue ;
513
+ if (auto *sec = dyn_cast_or_null<InputSection>(d->section ))
514
+ if (sec->flags & SHF_EXECINSTR && sec->relaxAux ) {
515
+ // If sec is discarded, relaxAux will be nullptr.
516
+ sec->relaxAux ->anchors .push_back ({d->value , d, false });
517
+ sec->relaxAux ->anchors .push_back ({d->value + d->size , d, true });
518
+ }
519
+ }
520
+ // Sort anchors by offset so that we can find the closest relocation
521
+ // efficiently. For a zero size symbol, ensure that its start anchor precedes
522
+ // its end anchor. For two symbols with anchors at the same offset, their
523
+ // order does not matter.
524
+ for (OutputSection *osec : outputSections) {
525
+ if (!(osec->flags & SHF_EXECINSTR))
526
+ continue ;
527
+ for (InputSection *sec : getInputSections (*osec, storage)) {
528
+ llvm::sort (sec->relaxAux ->anchors , [](auto &a, auto &b) {
529
+ return std::make_pair (a.offset , a.end ) <
530
+ std::make_pair (b.offset , b.end );
531
+ });
532
+ }
533
+ }
534
+ }
535
+
536
+ static bool relax (InputSection &sec) {
537
+ const uint64_t secAddr = sec.getVA ();
538
+ auto &aux = *sec.relaxAux ;
539
+ bool changed = false ;
540
+
541
+ // Restore original st_value for symbols relative to this section.
542
+ ArrayRef<SymbolAnchor> sa = makeArrayRef (aux.anchors );
543
+ uint32_t delta = 0 ;
544
+ for (auto it : llvm::enumerate (sec.relocations )) {
545
+ for (; sa.size () && sa[0 ].offset <= it.value ().offset ; sa = sa.slice (1 ))
546
+ if (!sa[0 ].end )
547
+ sa[0 ].d ->value += delta;
548
+ delta = aux.relocDeltas [it.index ()];
549
+ }
550
+ for (const SymbolAnchor &sa : sa)
551
+ if (!sa.end )
552
+ sa.d ->value += delta;
553
+ sa = makeArrayRef (aux.anchors );
554
+ delta = 0 ;
555
+
556
+ for (auto it : llvm::enumerate (sec.relocations )) {
557
+ Relocation &r = it.value ();
558
+ const size_t i = it.index ();
559
+ const uint64_t loc = secAddr + r.offset - delta;
560
+ uint32_t &cur = aux.relocDeltas [i], remove = 0 ;
561
+ switch (r.type ) {
562
+ case R_RISCV_ALIGN: {
563
+ const uint64_t nextLoc = loc + r.addend ;
564
+ const uint64_t align = PowerOf2Ceil (r.addend + 2 );
565
+ // All bytes beyond the alignment boundary should be removed.
566
+ remove = nextLoc - ((loc + align - 1 ) & -align);
567
+ assert (static_cast <int32_t >(remove ) >= 0 &&
568
+ " R_RISCV_ALIGN needs expanding the content" );
569
+ break ;
570
+ }
571
+ }
572
+
573
+ // For all anchors whose offsets are <= r.offset, they are preceded by
574
+ // the previous relocation whose `relocDeltas` value equals `delta`.
575
+ // Decrease their st_value and update their st_size.
576
+ if (remove ) {
577
+ for (; sa.size () && sa[0 ].offset <= r.offset ; sa = sa.slice (1 )) {
578
+ if (sa[0 ].end )
579
+ sa[0 ].d ->size = sa[0 ].offset - delta - sa[0 ].d ->value ;
580
+ else
581
+ sa[0 ].d ->value -= delta;
582
+ }
583
+ }
584
+ delta += remove ;
585
+ if (delta != cur) {
586
+ cur = delta;
587
+ changed = true ;
588
+ }
589
+ }
590
+
591
+ for (const SymbolAnchor &a : sa) {
592
+ if (a.end )
593
+ a.d ->size = a.offset - delta - a.d ->value ;
594
+ else
595
+ a.d ->value -= delta;
596
+ }
597
+ // Inform assignAddresses that the size has changed.
598
+ if (!isUInt<16 >(delta))
599
+ fatal (" section size decrease is too large" );
600
+ sec.bytesDropped = delta;
601
+ return changed;
602
+ }
603
+
604
+ // When relaxing just R_RISCV_ALIGN, relocDeltas is usually changed only once in
605
+ // the absence of a linker script. For call and load/store R_RISCV_RELAX, code
606
+ // shrinkage may reduce displacement and make more relocations eligible for
607
+ // relaxation. Code shrinkage may increase displacement to a call/load/store
608
+ // target at a higher fixed address, invalidating an earlier relaxation. Any
609
+ // change in section sizes can have cascading effect and require another
610
+ // relaxation pass.
611
+ bool RISCV::relaxOnce (int pass) const {
612
+ llvm::TimeTraceScope timeScope (" RISC-V relaxOnce" );
613
+ if (config->relocatable )
614
+ return false ;
615
+
616
+ if (pass == 0 )
617
+ initSymbolAnchors ();
618
+
619
+ SmallVector<InputSection *, 0 > storage;
620
+ bool changed = false ;
621
+ for (OutputSection *osec : outputSections) {
622
+ if (!(osec->flags & SHF_EXECINSTR))
623
+ continue ;
624
+ for (InputSection *sec : getInputSections (*osec, storage))
625
+ changed |= relax (*sec);
626
+ }
627
+ return changed;
628
+ }
629
+
630
+ void elf::riscvFinalizeRelax (int passes) {
631
+ llvm::TimeTraceScope timeScope (" Finalize RISC-V relaxation" );
632
+ log (" relaxation passes: " + Twine (passes));
633
+ SmallVector<InputSection *, 0 > storage;
634
+ for (OutputSection *osec : outputSections) {
635
+ if (!(osec->flags & SHF_EXECINSTR))
636
+ continue ;
637
+ for (InputSection *sec : getInputSections (*osec, storage)) {
638
+ RISCVRelaxAux &aux = *sec->relaxAux ;
639
+ if (!aux.relocDeltas )
640
+ continue ;
641
+
642
+ auto &rels = sec->relocations ;
643
+ ArrayRef<uint8_t > old = sec->rawData ;
644
+ size_t newSize =
645
+ old.size () - aux.relocDeltas [sec->relocations .size () - 1 ];
646
+ uint8_t *p = context ().bAlloc .Allocate <uint8_t >(newSize);
647
+ uint64_t offset = 0 ;
648
+ int64_t delta = 0 ;
649
+ sec->rawData = makeArrayRef (p, newSize);
650
+ sec->bytesDropped = 0 ;
651
+
652
+ // Update section content: remove NOPs for R_RISCV_ALIGN and rewrite
653
+ // instructions for relaxed relocations.
654
+ for (size_t i = 0 , e = rels.size (); i != e; ++i) {
655
+ uint32_t remove = aux.relocDeltas [i] - delta;
656
+ delta = aux.relocDeltas [i];
657
+ if (remove == 0 )
658
+ continue ;
659
+
660
+ // Copy from last location to the current relocated location.
661
+ const Relocation &r = rels[i];
662
+ uint64_t size = r.offset - offset;
663
+ memcpy (p, old.data () + offset, size);
664
+ p += size;
665
+
666
+ // For R_RISCV_ALIGN, we will place `offset` in a location (among NOPs)
667
+ // to satisfy the alignment requirement. If `remove` is a multiple of 4,
668
+ // it is as if we have skipped some NOPs. Otherwise we are in the middle
669
+ // of a 4-byte NOP, and we need to rewrite the NOP sequence.
670
+ int64_t skip = 0 ;
671
+ if (r.type == R_RISCV_ALIGN) {
672
+ if (remove % 4 != 0 ) {
673
+ skip = r.addend - remove ;
674
+ int64_t j = 0 ;
675
+ for (; j + 4 <= skip; j += 4 )
676
+ write32le (p + j, 0x00000013 ); // nop
677
+ if (j != skip) {
678
+ assert (j + 2 == skip);
679
+ write16le (p + j, 0x0001 ); // c.nop
680
+ }
681
+ }
682
+ }
683
+
684
+ p += skip;
685
+ offset = r.offset + skip + remove ;
686
+ }
687
+ memcpy (p, old.data () + offset, old.size () - offset);
688
+
689
+ // Substract the previous relocDeltas value from the relocation offset.
690
+ // For a pair of R_RISCV_CALL/R_RISCV_RELAX with the same offset, decrease
691
+ // their r_offset by the same delta.
692
+ delta = 0 ;
693
+ for (size_t i = 0 , e = rels.size (); i != e;) {
694
+ uint64_t cur = rels[i].offset ;
695
+ do {
696
+ rels[i].offset -= delta;
697
+ } while (++i != e && rels[i].offset == cur);
698
+ delta = aux.relocDeltas [i - 1 ];
699
+ }
700
+ }
701
+ }
702
+ }
703
+
479
704
TargetInfo *elf::getRISCVTargetInfo () {
480
705
static RISCV target;
481
706
return ⌖
0 commit comments