@@ -36,6 +36,8 @@ class LoongArch final : public TargetInfo {
36
36
bool usesOnlyLowPageBits (RelType type) const override ;
37
37
void relocate (uint8_t *loc, const Relocation &rel,
38
38
uint64_t val) const override ;
39
+ bool relaxOnce (int pass) const override ;
40
+ void finalizeRelax (int passes) const override ;
39
41
};
40
42
} // end anonymous namespace
41
43
@@ -467,6 +469,8 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
467
469
case R_LARCH_RELAX:
468
470
// LoongArch linker relaxation is not implemented yet.
469
471
return R_NONE;
472
+ case R_LARCH_ALIGN:
473
+ return R_RELAX_HINT;
470
474
471
475
// Other known relocs that are explicitly unimplemented:
472
476
//
@@ -659,6 +663,156 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
659
663
}
660
664
}
661
665
666
+ static bool relax (InputSection &sec) {
667
+ const uint64_t secAddr = sec.getVA ();
668
+ const MutableArrayRef<Relocation> relocs = sec.relocs ();
669
+ auto &aux = *sec.relaxAux ;
670
+ bool changed = false ;
671
+ ArrayRef<SymbolAnchor> sa = ArrayRef (aux.anchors );
672
+ uint64_t delta = 0 ;
673
+
674
+ std::fill_n (aux.relocTypes .get (), relocs.size (), R_LARCH_NONE);
675
+ aux.writes .clear ();
676
+ for (auto [i, r] : llvm::enumerate (relocs)) {
677
+ const uint64_t loc = secAddr + r.offset - delta;
678
+ uint32_t &cur = aux.relocDeltas [i], remove = 0 ;
679
+ switch (r.type ) {
680
+ case R_LARCH_ALIGN: {
681
+ const uint64_t addend =
682
+ r.sym ->isUndefined () ? Log2_64 (r.addend ) + 1 : r.addend ;
683
+ const uint64_t allBytes = (1 << (addend & 0xff )) - 4 ;
684
+ const uint64_t align = 1 << (addend & 0xff );
685
+ const uint64_t maxBytes = addend >> 8 ;
686
+ const uint64_t off = loc & (align - 1 );
687
+ const uint64_t curBytes = off == 0 ? 0 : align - off;
688
+ // All bytes beyond the alignment boundary should be removed.
689
+ // If emit bytes more than max bytes to emit, remove all.
690
+ if (maxBytes != 0 && curBytes > maxBytes)
691
+ remove = allBytes;
692
+ else
693
+ remove = allBytes - curBytes;
694
+ assert (static_cast <int32_t >(remove ) >= 0 &&
695
+ " R_LARCH_ALIGN needs expanding the content" );
696
+ break ;
697
+ }
698
+ }
699
+
700
+ // For all anchors whose offsets are <= r.offset, they are preceded by
701
+ // the previous relocation whose `relocDeltas` value equals `delta`.
702
+ // Decrease their st_value and update their st_size.
703
+ for (; sa.size () && sa[0 ].offset <= r.offset ; sa = sa.slice (1 )) {
704
+ if (sa[0 ].end )
705
+ sa[0 ].d ->size = sa[0 ].offset - delta - sa[0 ].d ->value ;
706
+ else
707
+ sa[0 ].d ->value = sa[0 ].offset - delta;
708
+ }
709
+ delta += remove ;
710
+ if (delta != cur) {
711
+ cur = delta;
712
+ changed = true ;
713
+ }
714
+ }
715
+
716
+ for (const SymbolAnchor &a : sa) {
717
+ if (a.end )
718
+ a.d ->size = a.offset - delta - a.d ->value ;
719
+ else
720
+ a.d ->value = a.offset - delta;
721
+ }
722
+ // Inform assignAddresses that the size has changed.
723
+ if (!isUInt<32 >(delta))
724
+ fatal (" section size decrease is too large: " + Twine (delta));
725
+ sec.bytesDropped = delta;
726
+ return changed;
727
+ }
728
+
729
+ // When relaxing just R_LARCH_ALIGN, relocDeltas is usually changed only once in
730
+ // the absence of a linker script. For call and load/store R_LARCH_RELAX, code
731
+ // shrinkage may reduce displacement and make more relocations eligible for
732
+ // relaxation. Code shrinkage may increase displacement to a call/load/store
733
+ // target at a higher fixed address, invalidating an earlier relaxation. Any
734
+ // change in section sizes can have cascading effect and require another
735
+ // relaxation pass.
736
+ bool LoongArch::relaxOnce (int pass) const {
737
+ if (config->relocatable )
738
+ return false ;
739
+
740
+ if (pass == 0 )
741
+ initSymbolAnchors ();
742
+
743
+ SmallVector<InputSection *, 0 > storage;
744
+ bool changed = false ;
745
+ for (OutputSection *osec : outputSections) {
746
+ if (!(osec->flags & SHF_EXECINSTR))
747
+ continue ;
748
+ for (InputSection *sec : getInputSections (*osec, storage))
749
+ changed |= relax (*sec);
750
+ }
751
+ return changed;
752
+ }
753
+
754
+ void LoongArch::finalizeRelax (int passes) const {
755
+ SmallVector<InputSection *, 0 > storage;
756
+ for (OutputSection *osec : outputSections) {
757
+ if (!(osec->flags & SHF_EXECINSTR))
758
+ continue ;
759
+ for (InputSection *sec : getInputSections (*osec, storage)) {
760
+ RelaxAux &aux = *sec->relaxAux ;
761
+ if (!aux.relocDeltas )
762
+ continue ;
763
+
764
+ MutableArrayRef<Relocation> rels = sec->relocs ();
765
+ ArrayRef<uint8_t > old = sec->content ();
766
+ size_t newSize = old.size () - aux.relocDeltas [rels.size () - 1 ];
767
+ uint8_t *p = context ().bAlloc .Allocate <uint8_t >(newSize);
768
+ uint64_t offset = 0 ;
769
+ int64_t delta = 0 ;
770
+ sec->content_ = p;
771
+ sec->size = newSize;
772
+ sec->bytesDropped = 0 ;
773
+
774
+ // Update section content: remove NOPs for R_LARCH_ALIGN and rewrite
775
+ // instructions for relaxed relocations.
776
+ for (size_t i = 0 , e = rels.size (); i != e; ++i) {
777
+ uint32_t remove = aux.relocDeltas [i] - delta;
778
+ delta = aux.relocDeltas [i];
779
+ if (remove == 0 && aux.relocTypes [i] == R_LARCH_NONE)
780
+ continue ;
781
+
782
+ // Copy from last location to the current relocated location.
783
+ const Relocation &r = rels[i];
784
+ uint64_t size = r.offset - offset;
785
+
786
+ // The rel.type may be fixed to R_LARCH_RELAX and the instruction
787
+ // will be deleted, then cause size<0
788
+ if (remove == 0 && (int64_t )size < 0 ) {
789
+ assert (aux.relocTypes [i] == R_LARCH_RELAX && " Unexpected size" );
790
+ continue ;
791
+ }
792
+
793
+ memcpy (p, old.data () + offset, size);
794
+ p += size;
795
+ offset = r.offset + remove ;
796
+ }
797
+ memcpy (p, old.data () + offset, old.size () - offset);
798
+
799
+ // Subtract the previous relocDeltas value from the relocation offset.
800
+ // For a pair of R_LARCH_XXX/R_LARCH_RELAX with the same offset, decrease
801
+ // their r_offset by the same delta.
802
+ delta = 0 ;
803
+ for (size_t i = 0 , e = rels.size (); i != e;) {
804
+ uint64_t cur = rels[i].offset ;
805
+ do {
806
+ rels[i].offset -= delta;
807
+ if (aux.relocTypes [i] != R_LARCH_NONE)
808
+ rels[i].type = aux.relocTypes [i];
809
+ } while (++i != e && rels[i].offset == cur);
810
+ delta = aux.relocDeltas [i - 1 ];
811
+ }
812
+ }
813
+ }
814
+ }
815
+
662
816
TargetInfo *elf::getLoongArchTargetInfo () {
663
817
static LoongArch target;
664
818
return ⌖
0 commit comments