Skip to content

Commit

Permalink
[nanoMIPS][LLD] emit relocs with transformations
Browse files Browse the repository at this point in the history
Similar to RISC-V relaxations, nanoMIPS transformations change
relocations and they need to be updated before writing them down to
output. One difference is that nanoMIPS can add new relocations, not
just change them like RISC-V, so during linker transformations size of
reloc sections need to be updated if --emit-relocs option is on.
  • Loading branch information
AndrijaSyrmia committed Oct 30, 2024
1 parent 6cabcac commit 4099547
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 4 deletions.
6 changes: 5 additions & 1 deletion lld/ELF/InputSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -351,9 +351,13 @@ InputSectionBase *InputSection::getRelocatedSection() const {

template <class ELFT, class RelTy>
void InputSection::copyRelocations(uint8_t *buf) {
if (config->relax && !config->relocatable && config->emachine == EM_RISCV) {
if ((config->relax && !config->relocatable && config->emachine == EM_RISCV) ||
((config->relax || config->expand) && !config->relocatable &&
config->emachine == EM_NANOMIPS)) {
// On RISC-V, relaxation might change relocations: copy from internal ones
// that are updated by relaxation.
// Similar to RISC-V, nanoMIPS also copies from internal ones that are
// updated by transformations
InputSectionBase *sec = getRelocatedSection();
copyRelocations<ELFT, RelTy>(buf, llvm::make_range(sec->relocations.begin(),
sec->relocations.end()));
Expand Down
23 changes: 20 additions & 3 deletions lld/ELF/NanoMipsTransformations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ SmallVector<NewInsnToWrite, 3> NanoMipsTransform::getTransformInsns(
uint32_t offset = reloc->offset - (relocProperty->getInstSize() == 6 ? 2 : 0);

// Whether we are inserting a new reloc, or just changing the existing one
bool newReloc = false;
int newRelocsCnt = 0;
auto instructionList =
ArrayRef(transformTemplate->getInsns(), transformTemplate->getInsCount());
for (auto &insTemplate : instructionList) {
Expand All @@ -531,14 +531,14 @@ SmallVector<NewInsnToWrite, 3> NanoMipsTransform::getTransformInsns(
"There is a reloc for a DISCARD relaxation!");

uint32_t newROffset = (insTemplate.getSize() == 6 ? offset + 2 : offset);
if (!newReloc) {
if (!newRelocsCnt) {
reloc->offset = newROffset;
reloc->type = newRelType;
// Only param needed is relType, other ones are not important for
// nanoMIPS
reloc->expr = target->getRelExpr(newRelType, *reloc->sym,
isec->content().data() + newROffset);
newReloc = true;
++newRelocsCnt;
} else {
Relocation newRelocation;
newRelocation.addend = reloc->addend;
Expand All @@ -553,9 +553,26 @@ SmallVector<NewInsnToWrite, 3> NanoMipsTransform::getTransformInsns(
isec->relocations.push_back(newRelocation);
// Because we add a relocation, it might invalidate our previous reloc
reloc = &isec->relocations[relNum];
++newRelocsCnt;
}
}

// Need to increase reloc section sizes in output section
// if --emit-relocs is called
if (config->emitRelocs) {
InputSectionBase *relocIsec = isec->file->getSections()[isec->relSecIdx];
// TODO: relocSize, is a constant, can be used as a template parameter
// or a constant function argument, or increase size after transformations
// -1 is because the first relocation has replaced the previous reloc
int relocSize =
relocIsec->size / (isec->relocations.size() - newRelocsCnt + 1);
int sizeToAdd = (newRelocsCnt - 1) * relocSize;
// Note: It should be okay to just increase the size of reloc sections
// as their contents are not used anymore, relocations vector from input
// section is used to write the relocations (if emit relocs is used)
relocIsec->size += sizeToAdd;
}

newInsns.emplace_back(newInsn, offset, insTemplate.getSize());
LLVM_DEBUG(llvm::dbgs() << "New instruction " << insTemplate.getName()
<< ": 0x" << utohexstr(newInsn) << " to offset: 0x"
Expand Down
33 changes: 33 additions & 0 deletions lld/test/ELF/nanomips-emit-relocs.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# REQUIRES: nanomips

# RUN: llvm-mc -filetype=obj -triple nanomips-elf -mcpu=i7200 -mattr=+pcrel %s -o %t.o
# RUN: ld.lld --emit-relocs --section-start .text=0x1000 --defsym far=0x04000000 --defsym bbeqzc_far=0x4000 %t.o -o %t
# RUN: llvm-objdump -dr %t | FileCheck %s

# CHECK: beqic
# CHECK-NEXT: R_NANOMIPS_PC11_S1 label
# CHECK: lapc
# CHECK-NEXT: R_NANOMIPS_PC_I32 far
# CHECK: bbnezc
# CHECK-NEXT: R_NANOMIPS_PC11_S1 {{.*}}skip_bc
# CHECK-NEXT: bc
# CHECK-NEXT: R_NANOMIPS_PC25_S1 bbeqzc_far


.linkrelax
.section .text, "ax", @progbits
.align 1
.globl _start
.ent _start

_start:
beqic $a2, 2, label
addiu $a1, $a2, 3
lapc $a1, far
label:
bbeqzc $a1, 2, bbeqzc_far
addiu $a1, $a2, 3

.end _start
.size _start, .-_start

0 comments on commit 4099547

Please sign in to comment.