Skip to content

Commit f1e85e2

Browse files
committed
ELF: Synthesize R_RISCV_ALIGN at input section start
1 parent 2abd58c commit f1e85e2

File tree

6 files changed

+235
-4
lines changed

6 files changed

+235
-4
lines changed

lld/ELF/Arch/RISCV.cpp

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,15 @@ 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 synthesizeAlign(uint64_t &dot, InputSection *sec, Relocs<RelTy> rels);
50+
template <class ELFT, class RelTy>
51+
bool synthesizeAlignEnd(uint64_t &dot, InputSection *sec, Relocs<RelTy> rels);
52+
bool maybeSynthesizeAlign(uint64_t &dot, InputSection *sec) override;
4853
void finalizeRelax(int passes) const override;
54+
55+
InputSection *baseSec = nullptr;
56+
SmallVector<std::pair<uint64_t, uint64_t>, 0> synthesizedAligns;
4957
};
5058

5159
} // end anonymous namespace
@@ -959,10 +967,102 @@ bool RISCV::relaxOnce(int pass) const {
959967
return changed;
960968
}
961969

970+
template <class ELFT, class RelTy>
971+
bool RISCV::synthesizeAlign(uint64_t &dot, InputSection *sec,
972+
Relocs<RelTy> rels) {
973+
if (!baseSec) {
974+
// Record the first section with RELAX relocations.
975+
for (auto rel : rels) {
976+
if (rel.getType(false) == R_RISCV_RELAX) {
977+
baseSec = sec;
978+
break;
979+
}
980+
}
981+
} else if (sec->addralign >= 4) {
982+
// If the alignment is >= 4 and the section does not start with an ALIGN
983+
// relocation, synthesize one.
984+
bool alignRel = false;
985+
for (auto rel : rels) {
986+
if (rel.r_offset == 0 && rel.getType(false) == R_RISCV_ALIGN)
987+
alignRel = true;
988+
break;
989+
}
990+
if (!alignRel) {
991+
synthesizedAligns.emplace_back(dot - baseSec->getVA(),
992+
sec->addralign - 2);
993+
dot += sec->addralign - 2;
994+
return true;
995+
}
996+
}
997+
return false;
998+
}
999+
1000+
template <class ELFT, class RelTy>
1001+
bool RISCV::synthesizeAlignEnd(uint64_t &dot, InputSection *sec,
1002+
Relocs<RelTy> rels) {
1003+
auto *f = cast<ObjFile<ELFT>>(baseSec->file);
1004+
auto shdr = f->template getELFShdrs<ELFT>()[baseSec->relSecIdx];
1005+
sec = make<InputSection>(*f, shdr, baseSec->name);
1006+
auto *baseRelSec = cast<InputSection>(f->getSections()[baseSec->relSecIdx]);
1007+
baseSec = nullptr;
1008+
*sec = *baseRelSec;
1009+
1010+
auto newSize = rels.size() + synthesizedAligns.size();
1011+
auto *relas = makeThreadLocalN<typename ELFT::Rela>(newSize);
1012+
sec->size = newSize * sizeof(typename ELFT::Rela);
1013+
sec->content_ = reinterpret_cast<uint8_t *>(relas);
1014+
// Copy original relocations.
1015+
for (auto [i, r] : llvm::enumerate(rels)) {
1016+
relas[i].r_offset = r.r_offset;
1017+
relas[i].setRInfo(r.getRInfo(false), false);
1018+
relas[i].r_addend = r.r_addend;
1019+
}
1020+
// Append synthesized ALIGN relocations.
1021+
for (auto [i, r] : llvm::enumerate(synthesizedAligns)) {
1022+
auto &rela = relas[rels.size() + i];
1023+
rela.r_offset = r.first;
1024+
rela.setSymbolAndType(0, R_RISCV_ALIGN, false);
1025+
rela.r_addend = r.second;
1026+
}
1027+
// In the output relocation section, replace the old relocation section with
1028+
// the new one.
1029+
for (SectionCommand *cmd : sec->getParent()->commands) {
1030+
auto *isd = dyn_cast<InputSectionDescription>(cmd);
1031+
if (!isd)
1032+
continue;
1033+
for (auto *&isec : isd->sections)
1034+
if (isec == baseRelSec)
1035+
isec = sec;
1036+
}
1037+
return false;
1038+
}
1039+
1040+
bool RISCV::maybeSynthesizeAlign(uint64_t &dot, InputSection *sec) {
1041+
if (sec) {
1042+
if (ctx.arg.is64) {
1043+
const RelsOrRelas<ELF64LE> rs = sec->template relsOrRelas<ELF64LE>();
1044+
return synthesizeAlign<ELF64LE>(dot, sec, rs.relas);
1045+
} else {
1046+
const RelsOrRelas<ELF32LE> rs = sec->template relsOrRelas<ELF32LE>();
1047+
return synthesizeAlign<ELF32LE>(dot, sec, rs.relas);
1048+
}
1049+
}
1050+
if (!baseSec)
1051+
return false;
1052+
if (ctx.arg.is64) {
1053+
const RelsOrRelas<ELF64LE> rs = baseSec->template relsOrRelas<ELF64LE>();
1054+
return synthesizeAlignEnd<ELF64LE>(dot, sec, rs.relas);
1055+
} else {
1056+
const RelsOrRelas<ELF32LE> rs = baseSec->template relsOrRelas<ELF32LE>();
1057+
return synthesizeAlignEnd<ELF32LE>(dot, sec, rs.relas);
1058+
}
1059+
}
1060+
9621061
void RISCV::finalizeRelax(int passes) const {
9631062
llvm::TimeTraceScope timeScope("Finalize RISC-V relaxation");
9641063
Log(ctx) << "relaxation passes: " << passes;
9651064
SmallVector<InputSection *, 0> storage;
1065+
9661066
for (OutputSection *osec : ctx.outputSections) {
9671067
if (!(osec->flags & SHF_EXECINSTR))
9681068
continue;

lld/ELF/LinkerScript.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1230,6 +1230,9 @@ bool LinkerScript::assignOffsets(OutputSection *sec) {
12301230
if (sec->firstInOverlay)
12311231
state->overlaySize = 0;
12321232

1233+
bool synthesizeAlign =
1234+
(sec->flags & SHF_EXECINSTR) && ctx.arg.relocatable && ctx.arg.relax &&
1235+
is_contained({EM_RISCV, EM_LOONGARCH}, ctx.arg.emachine);
12331236
// We visited SectionsCommands from processSectionCommands to
12341237
// layout sections. Now, we visit SectionsCommands again to fix
12351238
// section offsets.
@@ -1260,7 +1263,8 @@ bool LinkerScript::assignOffsets(OutputSection *sec) {
12601263
if (isa<PotentialSpillSection>(isec))
12611264
continue;
12621265
const uint64_t pos = dot;
1263-
dot = alignToPowerOf2(dot, isec->addralign);
1266+
if (!(synthesizeAlign && ctx.target->maybeSynthesizeAlign(dot, isec)))
1267+
dot = alignToPowerOf2(dot, isec->addralign);
12641268
isec->outSecOff = dot - sec->addr;
12651269
dot += isec->getSize();
12661270

@@ -1276,6 +1280,12 @@ bool LinkerScript::assignOffsets(OutputSection *sec) {
12761280
if (ctx.in.relroPadding && sec == ctx.in.relroPadding->getParent())
12771281
expandOutputSection(alignToPowerOf2(dot, ctx.arg.commonPageSize) - dot);
12781282

1283+
if (synthesizeAlign) {
1284+
const uint64_t pos = dot;
1285+
ctx.target->maybeSynthesizeAlign(dot, nullptr);
1286+
expandOutputSection(dot - pos);
1287+
}
1288+
12791289
// Non-SHF_ALLOC sections do not affect the addresses of other OutputSections
12801290
// as they are not part of the process image.
12811291
if (!(sec->flags & SHF_ALLOC)) {

lld/ELF/OutputSections.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -889,9 +889,14 @@ void OutputSection::sortInitFini() {
889889
std::array<uint8_t, 4> OutputSection::getFiller(Ctx &ctx) {
890890
if (filler)
891891
return *filler;
892-
if (flags & SHF_EXECINSTR)
893-
return ctx.target->trapInstr;
894-
return {0, 0, 0, 0};
892+
if (!(flags & SHF_EXECINSTR))
893+
return {0, 0, 0, 0};
894+
if (ctx.arg.relocatable && ctx.arg.emachine == EM_RISCV) {
895+
if (ctx.arg.eflags & EF_RISCV_RVC)
896+
return {1, 0, 1, 0};
897+
return {0x13, 0, 0, 0};
898+
}
899+
return ctx.target->trapInstr;
895900
}
896901

897902
void OutputSection::checkDynRelAddends(Ctx &ctx) {

lld/ELF/Target.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ class TargetInfo {
9696

9797
// Do a linker relaxation pass and return true if we changed something.
9898
virtual bool relaxOnce(int pass) const { return false; }
99+
virtual bool maybeSynthesizeAlign(uint64_t &dot, InputSection *sec) {
100+
return false;
101+
}
99102
// Do finalize relaxation after collecting relaxation infos.
100103
virtual void finalizeRelax(int passes) const {}
101104

lld/ELF/Writer.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,6 +1543,8 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
15431543

15441544
uint32_t pass = 0, assignPasses = 0;
15451545
for (;;) {
1546+
if (ctx.arg.relocatable)
1547+
break;
15461548
bool changed = ctx.target->needsThunks
15471549
? tc.createThunks(pass, ctx.outputSections)
15481550
: ctx.target->relaxOnce(pass);
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# RUN: rm -rf %t && split-file %s %t && cd %t
2+
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax a.s -o ac.o
3+
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax b.s -o bc.o
4+
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax b1.s -o b1c.o
5+
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax c.s -o cc.o
6+
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax d.s -o dc.o
7+
# RUN: ld.lld -r bc.o bc.o ac.o bc.o b1c.o cc.o dc.o -o out.ro
8+
# RUN: llvm-objdump -dr -M no-aliases out.ro | FileCheck %s
9+
10+
# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax a.s -o a.o
11+
# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax b.s -o b.o
12+
# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax d.s -o d.o
13+
# RUN: ld.lld -r a.o b.o d.o -o out0.ro
14+
# RUN: ld.lld -Ttext=0x10000 out0.ro -o out0
15+
# RUN: llvm-objdump -dr -M no-aliases out0 | FileCheck %s --check-prefix=CHECK1
16+
17+
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax a.s -o acrel.o
18+
# RUN: ld.lld -r bc.o bc.o ac.o bc.o b1c.o cc.o dc.o -o out.crel.ro
19+
20+
# CHECK: <b0>:
21+
# CHECK-NEXT: 0: 00158513 addi a0, a1, 0x1
22+
# CHECK-NEXT: 4: 0001 c.nop
23+
# CHECK-NEXT: 6: 0001 c.nop
24+
# CHECK-EMPTY:
25+
# CHECK-NEXT: <b0>:
26+
# CHECK-NEXT: 8: 00158513 addi a0, a1, 0x1
27+
# CHECK-EMPTY:
28+
# CHECK-NEXT: <_start>:
29+
# CHECK-NEXT: c: 00000097 auipc ra, 0x0
30+
# CHECK-NEXT: 000000000000000c: R_RISCV_CALL_PLT foo
31+
# CHECK-NEXT: 000000000000000c: R_RISCV_RELAX *ABS*
32+
# CHECK-NEXT: 10: 000080e7 jalr ra, 0x0(ra) <_start>
33+
# CHECK-NEXT: 14: 0001 c.nop
34+
# CHECK-NEXT: 0000000000000014: R_RISCV_ALIGN *ABS*+0x6
35+
# CHECK-NEXT: 16: 0001 c.nop
36+
# CHECK-NEXT: 18: 0001 c.nop
37+
# CHECK-EMPTY:
38+
# CHECK-NEXT: <b0>:
39+
# CHECK-NEXT: 1a: 00158513 addi a0, a1, 0x1
40+
# CHECK-NEXT: 1e: 0001 c.nop
41+
# CHECK-NEXT: 20: 0001 c.nop
42+
# CHECK-NEXT: 0000000000000020: R_RISCV_ALIGN *ABS*+0x6
43+
# CHECK-NEXT: 22: 0001 c.nop
44+
# CHECK-NEXT: 24: 00000013 addi zero, zero, 0x0
45+
# CHECK-EMPTY:
46+
# CHECK-NEXT: <b0>:
47+
# CHECK-NEXT: 28: 00158513 addi a0, a1, 0x1
48+
# CHECK-EMPTY:
49+
# CHECK-NEXT: <c0>:
50+
# CHECK-NEXT: 2c: 00000097 auipc ra, 0x0
51+
# CHECK-NEXT: 000000000000002c: R_RISCV_CALL_PLT foo
52+
# CHECK-NEXT: 000000000000002c: R_RISCV_RELAX *ABS*
53+
# CHECK-NEXT: 30: 000080e7 jalr ra, 0x0(ra) <c0>
54+
# CHECK-NEXT: 34: 0001 c.nop
55+
# CHECK-NEXT: 0000000000000034: R_RISCV_ALIGN *ABS*+0x2
56+
# CHECK-EMPTY:
57+
# CHECK-NEXT: <d0>:
58+
# CHECK-NEXT: 36: 00258513 addi a0, a1, 0x2
59+
60+
# CHECK1: <_start>:
61+
# CHECK1-NEXT: 010000ef jal ra, 0x10010 <foo>
62+
# CHECK1-NEXT: 00000013 addi zero, zero, 0x0
63+
# CHECK1-EMPTY:
64+
# CHECK1-NEXT: <b0>:
65+
# CHECK1-NEXT: 00158513 addi a0, a1, 0x1
66+
# CHECK1-EMPTY:
67+
# CHECK1-NEXT: <d0>:
68+
# CHECK1-NEXT: 00258513 addi a0, a1, 0x2
69+
70+
#--- a.s
71+
.globl _start
72+
_start:
73+
call foo
74+
75+
.section .text1,"ax"
76+
.globl foo
77+
foo:
78+
79+
#--- b.s
80+
## Needs synthesized ALIGN
81+
.option push
82+
.option norelax
83+
.balign 8
84+
b0:
85+
addi a0, a1, 1
86+
.option pop
87+
88+
#--- b1.s
89+
.option push
90+
.option norelax
91+
.reloc ., R_RISCV_ALIGN, 6
92+
addi x0, x0, 0
93+
c.nop
94+
.balign 8
95+
b0:
96+
addi a0, a1, 1
97+
.option pop
98+
99+
#--- c.s
100+
.balign 2
101+
c0:
102+
call foo
103+
104+
#--- d.s
105+
## Needs synthesized ALIGN
106+
.option push
107+
.option norelax
108+
.balign 4
109+
d0:
110+
addi a0, a1, 2
111+
.option pop

0 commit comments

Comments
 (0)