@@ -45,7 +45,21 @@ class RISCV final : public TargetInfo {
4545 uint64_t val) const override ;
4646 void relocateAlloc (InputSectionBase &sec, uint8_t *buf) const override ;
4747 bool relaxOnce (int pass) const override ;
48+ template <class ELFT , class RelTy >
49+ bool synthesizeAlignForInput (uint64_t &dot, InputSection *sec,
50+ Relocs<RelTy> rels);
51+ template <class ELFT , class RelTy >
52+ void finalizeSynthesizeAligns (uint64_t &dot, InputSection *sec,
53+ Relocs<RelTy> rels);
54+ template <class ELFT >
55+ bool synthesizeAlignAux (uint64_t &dot, InputSection *sec);
56+ bool synthesizeAlign (uint64_t &dot, InputSection *sec) override ;
4857 void finalizeRelax (int passes) const override ;
58+
59+ // The following two variables are used by synthesized ALIGN relocations.
60+ InputSection *baseSec = nullptr ;
61+ // r_offset and r_addend pairs.
62+ SmallVector<std::pair<uint64_t , uint64_t >, 0 > synthesizedAligns;
4963};
5064
5165} // end anonymous namespace
@@ -956,6 +970,116 @@ bool RISCV::relaxOnce(int pass) const {
956970 return changed;
957971}
958972
973+ // If the section alignment is >= 4, advance `dot` to insert NOPs and synthesize
974+ // an ALIGN relocation. Otherwise, return false to use default handling.
975+ template <class ELFT , class RelTy >
976+ bool RISCV::synthesizeAlignForInput (uint64_t &dot, InputSection *sec,
977+ Relocs<RelTy> rels) {
978+ if (!baseSec) {
979+ // Record the first input section with RELAX relocations. We will synthesize
980+ // ALIGN relocations here.
981+ for (auto rel : rels) {
982+ if (rel.getType (false ) == R_RISCV_RELAX) {
983+ baseSec = sec;
984+ break ;
985+ }
986+ }
987+ } else if (sec->addralign >= 4 ) {
988+ // If the alignment is >= 4 and the section does not start with an ALIGN
989+ // relocation, synthesize one.
990+ bool hasAlignRel = llvm::any_of (rels, [](const RelTy &rel) {
991+ return rel.r_offset == 0 && rel.getType (false ) == R_RISCV_ALIGN;
992+ });
993+ if (!hasAlignRel) {
994+ synthesizedAligns.emplace_back (dot - baseSec->getVA (),
995+ sec->addralign - 2 );
996+ dot += sec->addralign - 2 ;
997+ return true ;
998+ }
999+ }
1000+ return false ;
1001+ }
1002+
1003+ // Finalize the relocation section by appending synthesized ALIGN relocations
1004+ // after processing all input sections.
1005+ template <class ELFT , class RelTy >
1006+ void RISCV::finalizeSynthesizeAligns (uint64_t &dot, InputSection *sec,
1007+ Relocs<RelTy> rels) {
1008+ auto *f = cast<ObjFile<ELFT>>(baseSec->file );
1009+ auto shdr = f->template getELFShdrs <ELFT>()[baseSec->relSecIdx ];
1010+ // Create a copy of InputSection.
1011+ sec = make<InputSection>(*f, shdr, baseSec->name );
1012+ auto *baseRelSec = cast<InputSection>(f->getSections ()[baseSec->relSecIdx ]);
1013+ *sec = *baseRelSec;
1014+ baseSec = nullptr ;
1015+
1016+ // Allocate buffer for original and synthesized relocations in RELA format.
1017+ // If CREL is used, OutputSection::finalizeNonAllocCrel will convert RELA to
1018+ // CREL.
1019+ auto newSize = rels.size () + synthesizedAligns.size ();
1020+ auto *relas = makeThreadLocalN<typename ELFT::Rela>(newSize);
1021+ sec->size = newSize * sizeof (typename ELFT::Rela);
1022+ sec->content_ = reinterpret_cast <uint8_t *>(relas);
1023+ sec->type = SHT_RELA;
1024+ // Copy original relocations to the new buffer, potentially converting CREL to
1025+ // RELA.
1026+ for (auto [i, r] : llvm::enumerate (rels)) {
1027+ relas[i].r_offset = r.r_offset ;
1028+ relas[i].setSymbolAndType (r.getSymbol (0 ), r.getType (0 ), false );
1029+ if constexpr (RelTy::HasAddend)
1030+ relas[i].r_addend = r.r_addend ;
1031+ }
1032+ // Append synthesized ALIGN relocations to the buffer.
1033+ for (auto [i, r] : llvm::enumerate (synthesizedAligns)) {
1034+ auto &rela = relas[rels.size () + i];
1035+ rela.r_offset = r.first ;
1036+ rela.setSymbolAndType (0 , R_RISCV_ALIGN, false );
1037+ rela.r_addend = r.second ;
1038+ }
1039+ // Replace the old relocation section with the new one in the output section.
1040+ // addOrphanSections ensures that the output relocation section is processed
1041+ // after osec.
1042+ for (SectionCommand *cmd : sec->getParent ()->commands ) {
1043+ auto *isd = dyn_cast<InputSectionDescription>(cmd);
1044+ if (!isd)
1045+ continue ;
1046+ for (auto *&isec : isd->sections )
1047+ if (isec == baseRelSec)
1048+ isec = sec;
1049+ }
1050+ }
1051+
1052+ template <class ELFT >
1053+ bool RISCV::synthesizeAlignAux (uint64_t &dot, InputSection *sec) {
1054+ bool ret = false ;
1055+ if (sec) {
1056+ invokeOnRelocs (*sec, ret = synthesizeAlignForInput<ELFT>, dot, sec);
1057+ } else if (baseSec) {
1058+ invokeOnRelocs (*baseSec, finalizeSynthesizeAligns<ELFT>, dot, sec);
1059+ }
1060+ return ret;
1061+ }
1062+
1063+ // Without linker relaxation enabled for a particular relocatable file or
1064+ // section, the assembler will not generate R_RISCV_ALIGN relocations for
1065+ // alignment directives. This becomes problematic in a two-stage linking
1066+ // process: ld -r a.o b.o -o ab.o; ld ab.o -o ab. This function synthesizes an
1067+ // R_RISCV_ALIGN relocation at section start when needed.
1068+ //
1069+ // When called with an input section (`sec` is not null): If the section
1070+ // alignment is >= 4, advance `dot` to insert NOPs and synthesize an ALIGN
1071+ // relocation.
1072+ //
1073+ // When called after all input sections are processed (`sec` is null): The
1074+ // output relocation section is updated with all the newly synthesized ALIGN
1075+ // relocations.
1076+ bool RISCV::synthesizeAlign (uint64_t &dot, InputSection *sec) {
1077+ assert (ctx.arg .relocatable );
1078+ if (ctx.arg .is64 )
1079+ return synthesizeAlignAux<ELF64LE>(dot, sec);
1080+ return synthesizeAlignAux<ELF32LE>(dot, sec);
1081+ }
1082+
9591083void RISCV::finalizeRelax (int passes) const {
9601084 llvm::TimeTraceScope timeScope (" Finalize RISC-V relaxation" );
9611085 Log (ctx) << " relaxation passes: " << passes;
0 commit comments