[lld] [ELF] -r: Synthesize R_RISCV_ALIGN at input section start (PR #151639)
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 31 21:47:07 PDT 2025
================
@@ -959,10 +970,121 @@ bool RISCV::relaxOnce(int pass) const {
return changed;
}
+// If the section alignment is >= 4, advance `dot` to insert NOPs and synthesize
+// an ALIGN relocation. Otherwise, return false to use default handling.
+template <class ELFT, class RelTy>
+bool RISCV::synthesizeAlignOne(uint64_t &dot, InputSection *sec,
+ Relocs<RelTy> rels) {
+ if (!baseSec) {
+ // Record the first section with RELAX relocations.
+ for (auto rel : rels) {
+ if (rel.getType(false) == R_RISCV_RELAX) {
+ baseSec = sec;
+ break;
+ }
+ }
+ } else if (sec->addralign >= 4) {
+ // If the alignment is >= 4 and the section does not start with an ALIGN
+ // relocation, synthesize one.
+ bool alignRel = false;
+ for (auto rel : rels)
+ if (rel.r_offset == 0 && rel.getType(false) == R_RISCV_ALIGN)
+ alignRel = true;
+ if (!alignRel) {
+ synthesizedAligns.emplace_back(dot - baseSec->getVA(),
+ sec->addralign - 2);
+ dot += sec->addralign - 2;
+ return true;
+ }
+ }
+ return false;
+}
+
+// Finalize the relocation section by appending synthesized ALIGN relocations
+// after processing all input sections.
+template <class ELFT, class RelTy>
+void RISCV::synthesizeAlignEnd(uint64_t &dot, InputSection *sec,
+ Relocs<RelTy> rels) {
+ auto *f = cast<ObjFile<ELFT>>(baseSec->file);
+ auto shdr = f->template getELFShdrs<ELFT>()[baseSec->relSecIdx];
+ // Create a copy of InputSection.
+ sec = make<InputSection>(*f, shdr, baseSec->name);
+ auto *baseRelSec = cast<InputSection>(f->getSections()[baseSec->relSecIdx]);
+ *sec = *baseRelSec;
+ baseSec = nullptr;
+
+ // Allocate buffer for original and synthesized relocations in RELA format.
+ // If CREL is used, OutputSection::finalizeNonAllocCrel will convert RELA to
+ // CREL.
+ auto newSize = rels.size() + synthesizedAligns.size();
+ auto *relas = makeThreadLocalN<typename ELFT::Rela>(newSize);
+ sec->size = newSize * sizeof(typename ELFT::Rela);
+ sec->content_ = reinterpret_cast<uint8_t *>(relas);
+ sec->type = SHT_RELA;
+ // Copy original relocations to the new buffer, potentially converting CREL to
+ // RELA.
+ for (auto [i, r] : llvm::enumerate(rels)) {
+ relas[i].r_offset = r.r_offset;
+ relas[i].setSymbolAndType(r.getSymbol(0), r.getType(0), false);
+ if constexpr (RelTy::HasAddend)
+ relas[i].r_addend = r.r_addend;
+ }
+ // Append synthesized ALIGN relocations to the buffer.
+ for (auto [i, r] : llvm::enumerate(synthesizedAligns)) {
+ auto &rela = relas[rels.size() + i];
+ rela.r_offset = r.first;
+ rela.setSymbolAndType(0, R_RISCV_ALIGN, false);
+ rela.r_addend = r.second;
+ }
+ // Replace the old relocation section with the new one in the output section.
+ // addOrphanSections ensures that the output relocation section is processed
+ // after osec.
+ for (SectionCommand *cmd : sec->getParent()->commands) {
+ auto *isd = dyn_cast<InputSectionDescription>(cmd);
+ if (!isd)
+ continue;
+ for (auto *&isec : isd->sections)
+ if (isec == baseRelSec)
+ isec = sec;
+ }
+}
+
+template <class ELFT>
+bool RISCV::synthesizeAlignAux(uint64_t &dot, InputSection *sec) {
+ bool ret = false;
+ if (sec) {
+ invokeOnRelocs(*sec, ret = synthesizeAlignOne<ELFT>, dot, sec);
+ } else if (baseSec) {
+ invokeOnRelocs(*baseSec, synthesizeAlignEnd<ELFT>, dot, sec);
+ }
+ return ret;
+}
+
+// Without linker relaxation enabled for a particular relocatable file or
+// section, the assembler will not generate R_RISCV_ALIGN relocations for
+// alignment directives. This becomes problematic in a two-stage linking
+// process: ld -r a.o b.o -o ab.o; ld ab.o -o ab. This function synthesizes an
+// R_RISCV_ALIGN relocation at section start when needed.
+//
+// When called with an input section (`sec` is not null): If the section
+// alignment is >= 4, advance `dot` to insert NOPs and synthesize an ALIGN
+// relocation.
+//
+// When called after all input sections are processed (`sec` is null): The
+// output relocation section is updated with all the newly synthesized ALIGN
+// relocations.
+bool RISCV::maybeSynthesizeAlign(uint64_t &dot, InputSection *sec) {
+ assert(ctx.arg.relocatable);
+ if (ctx.arg.is64)
+ return synthesizeAlignAux<ELF64LE>(dot, sec);
+ return synthesizeAlignAux<ELF32LE>(dot, sec);
+}
+
void RISCV::finalizeRelax(int passes) const {
llvm::TimeTraceScope timeScope("Finalize RISC-V relaxation");
Log(ctx) << "relaxation passes: " << passes;
SmallVector<InputSection *, 0> storage;
+
----------------
MaskRay wrote:
unrelated: will delete
A previous version updated this function.
https://github.com/llvm/llvm-project/pull/151639
More information about the llvm-commits
mailing list