-
Notifications
You must be signed in to change notification settings - Fork 14.7k
[ELF] -r: Synthesize R_RISCV_ALIGN at input section start #151639
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,7 +45,18 @@ 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 synthesizeAlignOne(uint64_t &dot, InputSection *sec, Relocs<RelTy> rels); | ||
template <class ELFT, class RelTy> | ||
void synthesizeAlignEnd(uint64_t &dot, InputSection *sec, Relocs<RelTy> rels); | ||
template <class ELFT> | ||
bool synthesizeAlignAux(uint64_t &dot, InputSection *sec); | ||
bool maybeSynthesizeAlign(uint64_t &dot, InputSection *sec) override; | ||
void finalizeRelax(int passes) const override; | ||
|
||
// Used by synthesized ALIGN relocations. | ||
InputSection *baseSec = nullptr; | ||
SmallVector<std::pair<uint64_t, uint64_t>, 0> synthesizedAligns; | ||
}; | ||
|
||
} // end anonymous namespace | ||
|
@@ -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, | ||
mysterymath marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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; | ||
mysterymath marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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, | ||
mysterymath marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do the I guess we're not doing this, and we wouldn't expect the output of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It doesn't. LLD sorts relocations by offset, so later ALIGN relocations are fine. GNU ld seems fine as well. |
||
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 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for (OutputSection *osec : ctx.outputSections) { | ||
if (!(osec->flags & SHF_EXECINSTR)) | ||
continue; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
# 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 d.s -o dc.o | ||
|
||
## No RELAX. Don't synthesize ALIGN. | ||
# RUN: ld.lld -r bc.o dc.o -o bd.ro | ||
# RUN: llvm-readelf -r bd.ro | FileCheck %s --check-prefix=NOREL | ||
|
||
# NOREL: no relocations | ||
|
||
# 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 | ||
|
||
# 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 | ||
|
||
## Test CREL. | ||
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax --crel a.s -o acrel.o | ||
# RUN: ld.lld -r acrel.o bc.o -o out1.ro | ||
# RUN: llvm-objdump -dr -M no-aliases out1.ro | FileCheck %s --check-prefix=CHECK2 | ||
|
||
# CHECK2: <_start>: | ||
# CHECK2-NEXT: 0: 00000097 auipc ra, 0x0 | ||
# CHECK2-NEXT: 0000000000000000: R_RISCV_CALL_PLT foo | ||
# CHECK2-NEXT: 0000000000000000: R_RISCV_RELAX *ABS* | ||
# CHECK2-NEXT: 4: 000080e7 jalr ra, 0x0(ra) <_start> | ||
# CHECK2-NEXT: 8: 0001 c.nop | ||
# CHECK2-NEXT: 0000000000000008: R_RISCV_ALIGN *ABS*+0x6 | ||
# CHECK2-NEXT: a: 0001 c.nop | ||
# CHECK2-NEXT: c: 0001 c.nop | ||
# CHECK2-EMPTY: | ||
# CHECK2-NEXT: <b0>: | ||
# CHECK2-NEXT: e: 00158513 addi a0, a1, 0x1 | ||
|
||
#--- 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 | ||
.balign 4 | ||
d0: | ||
addi a0, a1, 2 |
Uh oh!
There was an error while loading. Please reload this page.