Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions lld/ELF/Arch/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,15 @@ class RISCV final : public TargetInfo {
uint64_t val) const override;
void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override;
bool relaxOnce(int pass) const override;
template <class ELFT, class RelTy>
bool synthesizeAlign(uint64_t &dot, InputSection *sec, Relocs<RelTy> rels);
template <class ELFT, class RelTy>
bool synthesizeAlignEnd(uint64_t &dot, InputSection *sec, Relocs<RelTy> rels);
bool maybeSynthesizeAlign(uint64_t &dot, InputSection *sec) override;
void finalizeRelax(int passes) const override;

InputSection *baseSec = nullptr;
SmallVector<std::pair<uint64_t, uint64_t>, 0> synthesizedAligns;
};

} // end anonymous namespace
Expand Down Expand Up @@ -959,10 +967,102 @@ bool RISCV::relaxOnce(int pass) const {
return changed;
}

template <class ELFT, class RelTy>
bool RISCV::synthesizeAlign(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;
break;
}
if (!alignRel) {
synthesizedAligns.emplace_back(dot - baseSec->getVA(),
sec->addralign - 2);
dot += sec->addralign - 2;
return true;
}
}
return false;
}

template <class ELFT, class RelTy>
bool 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];
sec = make<InputSection>(*f, shdr, baseSec->name);
auto *baseRelSec = cast<InputSection>(f->getSections()[baseSec->relSecIdx]);
baseSec = nullptr;
*sec = *baseRelSec;

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);
// Copy original relocations.
for (auto [i, r] : llvm::enumerate(rels)) {
relas[i].r_offset = r.r_offset;
relas[i].setRInfo(r.getRInfo(false), false);
relas[i].r_addend = r.r_addend;
}
// Append synthesized ALIGN relocations.
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;
}
// In the output relocation section, replace the old relocation section with
// the new one.
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;
}
return false;
}

bool RISCV::maybeSynthesizeAlign(uint64_t &dot, InputSection *sec) {
if (sec) {
if (ctx.arg.is64) {
const RelsOrRelas<ELF64LE> rs = sec->template relsOrRelas<ELF64LE>();
return synthesizeAlign<ELF64LE>(dot, sec, rs.relas);
} else {
const RelsOrRelas<ELF32LE> rs = sec->template relsOrRelas<ELF32LE>();
return synthesizeAlign<ELF32LE>(dot, sec, rs.relas);
}
}
if (!baseSec)
return false;
if (ctx.arg.is64) {
const RelsOrRelas<ELF64LE> rs = baseSec->template relsOrRelas<ELF64LE>();
return synthesizeAlignEnd<ELF64LE>(dot, sec, rs.relas);
} else {
const RelsOrRelas<ELF32LE> rs = baseSec->template relsOrRelas<ELF32LE>();
return synthesizeAlignEnd<ELF32LE>(dot, sec, rs.relas);
}
}

void RISCV::finalizeRelax(int passes) const {
llvm::TimeTraceScope timeScope("Finalize RISC-V relaxation");
Log(ctx) << "relaxation passes: " << passes;
SmallVector<InputSection *, 0> storage;

for (OutputSection *osec : ctx.outputSections) {
if (!(osec->flags & SHF_EXECINSTR))
continue;
Expand Down
12 changes: 11 additions & 1 deletion lld/ELF/LinkerScript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1230,6 +1230,9 @@ bool LinkerScript::assignOffsets(OutputSection *sec) {
if (sec->firstInOverlay)
state->overlaySize = 0;

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

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

if (synthesizeAlign) {
const uint64_t pos = dot;
ctx.target->maybeSynthesizeAlign(dot, nullptr);
expandOutputSection(dot - pos);
}

// Non-SHF_ALLOC sections do not affect the addresses of other OutputSections
// as they are not part of the process image.
if (!(sec->flags & SHF_ALLOC)) {
Expand Down
11 changes: 8 additions & 3 deletions lld/ELF/OutputSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -889,9 +889,14 @@ void OutputSection::sortInitFini() {
std::array<uint8_t, 4> OutputSection::getFiller(Ctx &ctx) {
if (filler)
return *filler;
if (flags & SHF_EXECINSTR)
return ctx.target->trapInstr;
return {0, 0, 0, 0};
if (!(flags & SHF_EXECINSTR))
return {0, 0, 0, 0};
if (ctx.arg.relocatable && ctx.arg.emachine == EM_RISCV) {
if (ctx.arg.eflags & EF_RISCV_RVC)
return {1, 0, 1, 0};
return {0x13, 0, 0, 0};
}
return ctx.target->trapInstr;
}

void OutputSection::checkDynRelAddends(Ctx &ctx) {
Expand Down
3 changes: 3 additions & 0 deletions lld/ELF/Target.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ class TargetInfo {

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

Expand Down
2 changes: 2 additions & 0 deletions lld/ELF/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1543,6 +1543,8 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {

uint32_t pass = 0, assignPasses = 0;
for (;;) {
if (ctx.arg.relocatable)
break;
bool changed = ctx.target->needsThunks
? tc.createThunks(pass, ctx.outputSections)
: ctx.target->relaxOnce(pass);
Expand Down
111 changes: 111 additions & 0 deletions lld/test/ELF/riscv-relocatable-align.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# RUN: rm -rf %t && split-file %s %t && cd %t
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax a.s -o ac.o
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax b.s -o bc.o
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax b1.s -o b1c.o
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax c.s -o cc.o
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax d.s -o dc.o
# RUN: ld.lld -r bc.o bc.o ac.o bc.o b1c.o cc.o dc.o -o out.ro
# RUN: llvm-objdump -dr -M no-aliases out.ro | FileCheck %s

# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax a.s -o a.o
# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax b.s -o b.o
# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax d.s -o d.o
# RUN: ld.lld -r a.o b.o d.o -o out0.ro
# RUN: ld.lld -Ttext=0x10000 out0.ro -o out0
# RUN: llvm-objdump -dr -M no-aliases out0 | FileCheck %s --check-prefix=CHECK1

# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax a.s -o acrel.o
# RUN: ld.lld -r bc.o bc.o ac.o bc.o b1c.o cc.o dc.o -o out.crel.ro

# CHECK: <b0>:
# CHECK-NEXT: 0: 00158513 addi a0, a1, 0x1
# CHECK-NEXT: 4: 0001 c.nop
# CHECK-NEXT: 6: 0001 c.nop
# CHECK-EMPTY:
# CHECK-NEXT: <b0>:
# CHECK-NEXT: 8: 00158513 addi a0, a1, 0x1
# CHECK-EMPTY:
# CHECK-NEXT: <_start>:
# CHECK-NEXT: c: 00000097 auipc ra, 0x0
# CHECK-NEXT: 000000000000000c: R_RISCV_CALL_PLT foo
# CHECK-NEXT: 000000000000000c: R_RISCV_RELAX *ABS*
# CHECK-NEXT: 10: 000080e7 jalr ra, 0x0(ra) <_start>
# CHECK-NEXT: 14: 0001 c.nop
# CHECK-NEXT: 0000000000000014: R_RISCV_ALIGN *ABS*+0x6
# CHECK-NEXT: 16: 0001 c.nop
# CHECK-NEXT: 18: 0001 c.nop
# CHECK-EMPTY:
# CHECK-NEXT: <b0>:
# CHECK-NEXT: 1a: 00158513 addi a0, a1, 0x1
# CHECK-NEXT: 1e: 0001 c.nop
# CHECK-NEXT: 20: 0001 c.nop
# CHECK-NEXT: 0000000000000020: R_RISCV_ALIGN *ABS*+0x6
# CHECK-NEXT: 22: 0001 c.nop
# CHECK-NEXT: 24: 00000013 addi zero, zero, 0x0
# CHECK-EMPTY:
# CHECK-NEXT: <b0>:
# CHECK-NEXT: 28: 00158513 addi a0, a1, 0x1
# CHECK-EMPTY:
# CHECK-NEXT: <c0>:
# CHECK-NEXT: 2c: 00000097 auipc ra, 0x0
# CHECK-NEXT: 000000000000002c: R_RISCV_CALL_PLT foo
# CHECK-NEXT: 000000000000002c: R_RISCV_RELAX *ABS*
# CHECK-NEXT: 30: 000080e7 jalr ra, 0x0(ra) <c0>
# CHECK-NEXT: 34: 0001 c.nop
# CHECK-NEXT: 0000000000000034: R_RISCV_ALIGN *ABS*+0x2
# CHECK-EMPTY:
# CHECK-NEXT: <d0>:
# CHECK-NEXT: 36: 00258513 addi a0, a1, 0x2

# CHECK1: <_start>:
# CHECK1-NEXT: 010000ef jal ra, 0x10010 <foo>
# CHECK1-NEXT: 00000013 addi zero, zero, 0x0
# CHECK1-EMPTY:
# CHECK1-NEXT: <b0>:
# CHECK1-NEXT: 00158513 addi a0, a1, 0x1
# CHECK1-EMPTY:
# CHECK1-NEXT: <d0>:
# CHECK1-NEXT: 00258513 addi a0, a1, 0x2

#--- a.s
.globl _start
_start:
call foo

.section .text1,"ax"
.globl foo
foo:

#--- b.s
## Needs synthesized ALIGN
.option push
.option norelax
.balign 8
b0:
addi a0, a1, 1
.option pop

#--- b1.s
.option push
.option norelax
.reloc ., R_RISCV_ALIGN, 6
addi x0, x0, 0
c.nop
.balign 8
b0:
addi a0, a1, 1
.option pop

#--- c.s
.balign 2
c0:
call foo

#--- d.s
## Needs synthesized ALIGN
.option push
.option norelax
.balign 4
d0:
addi a0, a1, 2
.option pop
Loading