diff --git a/lld/ELF/Arch/Mips.cpp b/lld/ELF/Arch/Mips.cpp --- a/lld/ELF/Arch/Mips.cpp +++ b/lld/ELF/Arch/Mips.cpp @@ -85,8 +85,14 @@ switch (type) { case R_MIPS_JALR: + // If the target symbol is not preemptible and is not microMIPS, + // it might be possible to replace jalr/jr instruction by bal/b. + // It depends on the target symbol's offset. + if (!s.isPreemptible && !(s.getVA() & 0x1)) + return R_PC; + return R_NONE; case R_MICROMIPS_JALR: - return R_HINT; + return R_NONE; case R_MIPS_GPREL16: case R_MIPS_GPREL32: case R_MICROMIPS_GPREL16: @@ -633,6 +639,20 @@ writeValue(loc, val + 0x800080008000, 16, 48); break; case R_MIPS_JALR: + val -= 4; + // Replace jalr/jr instructions by bal/b if the target + // offset fits into the 18-bit range. + if (isInt<18>(val)) { + switch (read32(loc)) { + case 0x0320f809: // jalr $25 => bal sym + write32(loc, 0x04110000 | ((val >> 2) & 0xffff)); + break; + case 0x03200008: // jr $25 => b sym + write32(loc, 0x10000000 | ((val >> 2) & 0xffff)); + break; + } + } + break; case R_MICROMIPS_JALR: // Ignore this optimization relocation for now break; diff --git a/lld/test/ELF/mips-jalr.s b/lld/test/ELF/mips-jalr.s --- a/lld/test/ELF/mips-jalr.s +++ b/lld/test/ELF/mips-jalr.s @@ -1,20 +1,56 @@ # REQUIRES: mips -# Check that lld ignores R_MIPS_JALR relocation for now. -# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o -# RUN: ld.lld %t.o -o %t.exe +# Check handling of the R_MIPS_JALR and R_MICROMIPS_JALR relocations. + +# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %t.o # RUN: llvm-readelf -r %t.o | FileCheck -check-prefix=REL %s -# RUN: llvm-objdump -d --no-show-raw-insn %t.exe | FileCheck %s -# REL: R_MIPS_CALL16 {{.*}} foo +# RUN: ld.lld %t.o -shared -o %t.so +# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck -check-prefix=SO %s + +# RUN: ld.lld %t.o --defsym=bar=__start -o %t.so +# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck -check-prefix=EXE %s + +# REL: R_MIPS_JALR {{.*}} bar # REL: R_MIPS_JALR {{.*}} foo +# REL: R_MIPS_JALR {{.*}} far + +# SO: jalr $25 +# SO: bal -24 +# SO: jalr $25 + +# SO: jr $25 +# SO: b -64 +# SO: jr $25 -# CHECK: jalr $25 +# EXE: bal -4 +# EXE: bal -24 +# EXE: jalr $25 + +# EXE: b -56 +# EXE: b -64 +# EXE: jr $25 .text - .global __start + .global bar + .global __start .option pic2 +far: + .space 0x4fff0 __start: - jal foo foo: + jal bar + nop + jal foo + nop + jal far nop +l1: + jr $25 + .reloc l1, R_MIPS_JALR, bar +l2: + jr $25 + .reloc l2, R_MIPS_JALR, foo +l3: + jr $25 + .reloc l3, R_MIPS_JALR, far