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