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 @@ -83,6 +83,17 @@ switch (type) { case R_MIPS_JALR: + // Older versions of clang would erroneously emit this relocation not only + // against functions (loaded from the GOT) but also against data symbols + // (e.g. a table of function pointers). When we encounter this, ignore the + // relocation and emit a warning instead. + if (!s.isFunc() && s.type != STT_NOTYPE) { + warn(getErrorLocation(loc) + + "found R_MIPS_JALR relocation against non-function symbol " + + toString(s) + ". This is invalid and most likely a compiler bug."); + return R_NONE; + } + // 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. diff --git a/lld/test/ELF/mips-jalr-non-functions.s b/lld/test/ELF/mips-jalr-non-functions.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/mips-jalr-non-functions.s @@ -0,0 +1,53 @@ +# REQUIRES: mips +## Check that we ignore R_MIPS_JALR relocations agains non-function symbols. +## Older versions of clang was erroneously generating them for function pointers +## loaded from any table (not just the GOT) as well as against TLS function +## pointers (when using the local-dynamic model), so we need to ignore these +## relocations to avoid generating binaries that crash when executed. + +# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.o +# RUN: ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s -check-prefix WARNING-MESSAGE +# RUN: llvm-objdump --no-show-raw-insn --no-leading-addr -d %t.so | FileCheck %s + +.set noreorder +test: + .reloc .Ltmp1, R_MIPS_JALR, tls_obj +.Ltmp1: + jr $t9 + nop +# WARNING-MESSAGE: warning: found R_MIPS_JALR relocation against non-function symbol tls_obj. This is invalid and most likely a compiler bug. + + .reloc .Ltmp2, R_MIPS_JALR, reg_obj +.Ltmp2: + jr $t9 + nop +# WARNING-MESSAGE: warning: found R_MIPS_JALR relocation against non-function symbol reg_obj. This is invalid and most likely a compiler bug. + + .reloc .Ltmp3, R_MIPS_JALR, untyped +.Ltmp3: + jr $t9 + nop + +## However, we do perform the optimization for untyped symbols: +untyped: + nop + + .type tls_obj,@object + .section .tbss,"awT",@nobits +tls_obj: + .word 0 + + .type reg_obj,@object + .data +reg_obj: + .word 0 + +# CHECK-LABEL: Disassembly of section .text: +# CHECK-EMPTY: +# CHECK-NEXT: test: +# CHECK-NEXT: jr $25 +# CHECK-NEXT: nop +# CHECK-NEXT: jr $25 +# CHECK-NEXT: nop +# CHECK-NEXT: b 8 +# CHECK-NEXT: nop