@@ -39,6 +39,7 @@ class LoongArch final : public TargetInfo {
3939 void relocate (uint8_t *loc, const Relocation &rel,
4040 uint64_t val) const override ;
4141 bool relaxOnce (int pass) const override ;
42+ bool synthesizeAlign (uint64_t &dot, InputSection *sec) override ;
4243 RelExpr adjustTlsExpr (RelType type, RelExpr expr) const override ;
4344 void relocateAlloc (InputSectionBase &sec, uint8_t *buf) const override ;
4445 void finalizeRelax (int passes) const override ;
@@ -48,6 +49,19 @@ class LoongArch final : public TargetInfo {
4849 void tlsdescToLe (uint8_t *loc, const Relocation &rel, uint64_t val) const ;
4950 bool tryGotToPCRel (uint8_t *loc, const Relocation &rHi20,
5051 const Relocation &rLo12, uint64_t secAddr) const ;
52+ template <class ELFT , class RelTy >
53+ bool synthesizeAlignForInput (uint64_t &dot, InputSection *sec,
54+ Relocs<RelTy> rels);
55+ template <class ELFT , class RelTy >
56+ void finalizeSynthesizeAligns (uint64_t &dot, InputSection *sec,
57+ Relocs<RelTy> rels);
58+ template <class ELFT >
59+ bool synthesizeAlignAux (uint64_t &dot, InputSection *sec);
60+
61+ // The following two variables are used by synthesized ALIGN relocations.
62+ InputSection *baseSec = nullptr ;
63+ // r_offset and r_addend pairs.
64+ SmallVector<std::pair<uint64_t , uint64_t >, 0 > synthesizedAligns;
5165};
5266} // end anonymous namespace
5367
@@ -766,6 +780,117 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
766780 }
767781}
768782
783+ // If the section alignment is > 4, advance `dot` to insert NOPs and synthesize
784+ // an ALIGN relocation. Otherwise, return false to use default handling.
785+ template <class ELFT , class RelTy >
786+ bool LoongArch::synthesizeAlignForInput (uint64_t &dot, InputSection *sec,
787+ Relocs<RelTy> rels) {
788+ if (!baseSec) {
789+ // Record the first input section with RELAX relocations. We will synthesize
790+ // ALIGN relocations here.
791+ for (auto rel : rels) {
792+ if (rel.getType (false ) == R_LARCH_RELAX) {
793+ baseSec = sec;
794+ break ;
795+ }
796+ }
797+ } else if (sec->addralign > 4 ) {
798+ // If the alignment is > 4 and the section does not start with an ALIGN
799+ // relocation, synthesize one.
800+ bool hasAlignRel = llvm::any_of (rels, [](const RelTy &rel) {
801+ return rel.r_offset == 0 && rel.getType (false ) == R_LARCH_ALIGN;
802+ });
803+ if (!hasAlignRel) {
804+ synthesizedAligns.emplace_back (dot - baseSec->getVA (),
805+ sec->addralign - 4 );
806+ dot += sec->addralign - 4 ;
807+ return true ;
808+ }
809+ }
810+ return false ;
811+ }
812+
813+ // Finalize the relocation section by appending synthesized ALIGN relocations
814+ // after processing all input sections.
815+ template <class ELFT , class RelTy >
816+ void LoongArch::finalizeSynthesizeAligns (uint64_t &dot, InputSection *sec,
817+ Relocs<RelTy> rels) {
818+ auto *f = cast<ObjFile<ELFT>>(baseSec->file );
819+ auto shdr = f->template getELFShdrs <ELFT>()[baseSec->relSecIdx ];
820+ // Create a copy of InputSection.
821+ sec = make<InputSection>(*f, shdr, baseSec->name );
822+ auto *baseRelSec = cast<InputSection>(f->getSections ()[baseSec->relSecIdx ]);
823+ *sec = *baseRelSec;
824+ baseSec = nullptr ;
825+
826+ // Allocate buffer for original and synthesized relocations in RELA format.
827+ // If CREL is used, OutputSection::finalizeNonAllocCrel will convert RELA to
828+ // CREL.
829+ auto newSize = rels.size () + synthesizedAligns.size ();
830+ auto *relas = makeThreadLocalN<typename ELFT::Rela>(newSize);
831+ sec->size = newSize * sizeof (typename ELFT::Rela);
832+ sec->content_ = reinterpret_cast <uint8_t *>(relas);
833+ sec->type = SHT_RELA;
834+ // Copy original relocations to the new buffer, potentially converting CREL to
835+ // RELA.
836+ for (auto [i, r] : llvm::enumerate (rels)) {
837+ relas[i].r_offset = r.r_offset ;
838+ relas[i].setSymbolAndType (r.getSymbol (0 ), r.getType (0 ), false );
839+ if constexpr (RelTy::HasAddend)
840+ relas[i].r_addend = r.r_addend ;
841+ }
842+ // Append synthesized ALIGN relocations to the buffer.
843+ for (auto [i, r] : llvm::enumerate (synthesizedAligns)) {
844+ auto &rela = relas[rels.size () + i];
845+ rela.r_offset = r.first ;
846+ rela.setSymbolAndType (0 , R_LARCH_ALIGN, false );
847+ rela.r_addend = r.second ;
848+ }
849+ synthesizedAligns.clear ();
850+ // Replace the old relocation section with the new one in the output section.
851+ // addOrphanSections ensures that the output relocation section is processed
852+ // after osec.
853+ for (SectionCommand *cmd : sec->getParent ()->commands ) {
854+ auto *isd = dyn_cast<InputSectionDescription>(cmd);
855+ if (!isd)
856+ continue ;
857+ for (auto *&isec : isd->sections )
858+ if (isec == baseRelSec)
859+ isec = sec;
860+ }
861+ }
862+
863+ template <class ELFT >
864+ bool LoongArch::synthesizeAlignAux (uint64_t &dot, InputSection *sec) {
865+ bool ret = false ;
866+ if (sec) {
867+ invokeOnRelocs (*sec, ret = synthesizeAlignForInput<ELFT>, dot, sec);
868+ } else if (baseSec) {
869+ invokeOnRelocs (*baseSec, finalizeSynthesizeAligns<ELFT>, dot, sec);
870+ }
871+ return ret;
872+ }
873+
874+ // Without linker relaxation enabled for a particular relocatable file or
875+ // section, the assembler will not generate R_LARCH_ALIGN relocations for
876+ // alignment directives. This becomes problematic in a two-stage linking
877+ // process: ld -r a.o b.o -o ab.o; ld ab.o -o ab. This function synthesizes an
878+ // R_LARCH_ALIGN relocation at section start when needed.
879+ //
880+ // When called with an input section (`sec` is not null): If the section
881+ // alignment is > 4, advance `dot` to insert NOPs and synthesize an ALIGN
882+ // relocation.
883+ //
884+ // When called after all input sections are processed (`sec` is null): The
885+ // output relocation section is updated with all the newly synthesized ALIGN
886+ // relocations.
887+ bool LoongArch::synthesizeAlign (uint64_t &dot, InputSection *sec) {
888+ assert (ctx.arg .relocatable );
889+ if (ctx.arg .is64 )
890+ return synthesizeAlignAux<ELF64LE>(dot, sec);
891+ return synthesizeAlignAux<ELF32LE>(dot, sec);
892+ }
893+
769894static bool relaxable (ArrayRef<Relocation> relocs, size_t i) {
770895 return i + 1 < relocs.size () && relocs[i + 1 ].type == R_LARCH_RELAX;
771896}
0 commit comments