@@ -45,7 +45,21 @@ class RISCV final : public TargetInfo {
45
45
uint64_t val) const override ;
46
46
void relocateAlloc (InputSectionBase &sec, uint8_t *buf) const override ;
47
47
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 ;
48
57
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;
49
63
};
50
64
51
65
} // end anonymous namespace
@@ -956,6 +970,116 @@ bool RISCV::relaxOnce(int pass) const {
956
970
return changed;
957
971
}
958
972
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
+
959
1083
void RISCV::finalizeRelax (int passes) const {
960
1084
llvm::TimeTraceScope timeScope (" Finalize RISC-V relaxation" );
961
1085
Log (ctx) << " relaxation passes: " << passes;
0 commit comments