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