@@ -36,6 +36,8 @@ class LoongArch final : public TargetInfo {
3636 bool usesOnlyLowPageBits (RelType type) const override ;
3737 void relocate (uint8_t *loc, const Relocation &rel,
3838 uint64_t val) const override ;
39+ bool relaxOnce (int pass) const override ;
40+ void finalizeRelax (int passes) const override ;
3941};
4042} // end anonymous namespace
4143
@@ -521,8 +523,9 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
521523 case R_LARCH_TLS_GD_HI20:
522524 return R_TLSGD_GOT;
523525 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;
526529
527530 // Other known relocs that are explicitly unimplemented:
528531 //
@@ -696,6 +699,155 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
696699 }
697700}
698701
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+
699851TargetInfo *elf::getLoongArchTargetInfo () {
700852 static LoongArch target;
701853 return ⌖
0 commit comments