diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 2be71a7c8b6a27..baa96925775e0c 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 1c1adc50225f8c..f2cdf65b60c2bb 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 00000000000000..81153a61235ceb --- /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 +