From 215483b841729335eadfeaf01d6151a1bd24342f Mon Sep 17 00:00:00 2001 From: Andrija Date: Mon, 7 Oct 2024 12:10:33 +0200 Subject: [PATCH] [nanoMIPS][LLD] emit relocs with transformations 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. --- lld/ELF/InputSection.cpp | 6 +++++- lld/ELF/NanoMipsTransformations.cpp | 23 +++++++++++++++++--- lld/test/ELF/nanomips-emit-relocs.s | 33 +++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 lld/test/ELF/nanomips-emit-relocs.s diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 2be71a7c8b6a27a..baa96925775e0ca 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -351,9 +351,13 @@ InputSectionBase *InputSection::getRelocatedSection() const { template 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(buf, llvm::make_range(sec->relocations.begin(), sec->relocations.end())); diff --git a/lld/ELF/NanoMipsTransformations.cpp b/lld/ELF/NanoMipsTransformations.cpp index 81875b23a3b6527..353eaf392fd42e5 100644 --- a/lld/ELF/NanoMipsTransformations.cpp +++ b/lld/ELF/NanoMipsTransformations.cpp @@ -519,7 +519,7 @@ SmallVector 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) { @@ -531,14 +531,14 @@ SmallVector 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; @@ -553,9 +553,26 @@ SmallVector 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" diff --git a/lld/test/ELF/nanomips-emit-relocs.s b/lld/test/ELF/nanomips-emit-relocs.s new file mode 100644 index 000000000000000..81153a61235cebc --- /dev/null +++ b/lld/test/ELF/nanomips-emit-relocs.s @@ -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 +