@@ -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
@@ -465,8 +467,9 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
465467 case R_LARCH_TLS_GD_HI20:
466468 return R_TLSGD_GOT;
467469 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;
470473
471474 // Other known relocs that are explicitly unimplemented:
472475 //
@@ -659,6 +662,155 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
659662 }
660663}
661664
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+
662814TargetInfo *elf::getLoongArchTargetInfo () {
663815 static LoongArch target;
664816 return ⌖
0 commit comments