diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -971,8 +971,16 @@ // Patch a nop (0x60000000) to a ld. if (rel.sym->needsTocRestore) { - if (bufLoc + 8 > bufEnd || read32(bufLoc + 4) != 0x60000000) { - error(getErrorLocation(bufLoc) + "call lacks nop, can't restore toc"); + // gcc/gfortran 5.4, 6.3 and earlier versions do not add nop for + // recursive calls even if the function is preemptible. This is not + // wrong in the common case where the function is not preempted at + // runtime. Just ignore. + if ((bufLoc + 8 > bufEnd || read32(bufLoc + 4) != 0x60000000) && + rel.sym->file != file) { + // Use substr(6) to remove the "__plt_" prefix. + errorOrWarn(getErrorLocation(bufLoc) + "call to " + + lld::toString(*rel.sym).substr(6) + + " lacks nop, can't restore toc"); break; } write32(bufLoc + 4, 0xe8410018); // ld %r2, 24(%r1) diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp --- a/lld/ELF/Thunks.cpp +++ b/lld/ELF/Thunks.cpp @@ -786,6 +786,7 @@ Defined *s = addSymbol(saver.save("__plt_" + destination.getName()), STT_FUNC, 0, isec); s->needsTocRestore = true; + s->file = destination.file; } void PPC64LongBranchThunk::writeTo(uint8_t *buf) { diff --git a/lld/test/ELF/ppc64-bsymbolic-toc-restore.s b/lld/test/ELF/ppc64-bsymbolic-toc-restore.s --- a/lld/test/ELF/ppc64-bsymbolic-toc-restore.s +++ b/lld/test/ELF/ppc64-bsymbolic-toc-restore.s @@ -12,7 +12,7 @@ # RUN: llvm-objdump -d -r %t | FileCheck %s # RUN: not ld.lld -shared %t1.o %t2.o -o %t 2>&1 | FileCheck --check-prefix=FAIL %s -# FAIL: call lacks nop, can't restore toc +# FAIL: call to def lacks nop, can't restore toc # Test to document the toc-restore behavior with -Bsymbolic option. Since # -Bsymbolic causes the call to bind to the internal defintion we know the diff --git a/lld/test/ELF/ppc64-error-toc-restore.s b/lld/test/ELF/ppc64-error-toc-restore.s --- a/lld/test/ELF/ppc64-error-toc-restore.s +++ b/lld/test/ELF/ppc64-error-toc-restore.s @@ -11,7 +11,7 @@ // RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s # Calling external function bar needs a nop -// CHECK: call lacks nop, can't restore toc +// CHECK: call to foo lacks nop, can't restore toc .text .abiversion 2 diff --git a/lld/test/ELF/ppc64-error-toc-tail-call.s b/lld/test/ELF/ppc64-error-toc-tail-call.s --- a/lld/test/ELF/ppc64-error-toc-tail-call.s +++ b/lld/test/ELF/ppc64-error-toc-tail-call.s @@ -11,10 +11,16 @@ // RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s # A tail call to an external function without a nop should issue an error. -// CHECK: call lacks nop, can't restore toc +// CHECK: call to foo lacks nop, can't restore toc +// CHECK-NOT: lacks nop .text .abiversion 2 .global _start _start: b foo + + // gcc/gfortran 5.4, 6.3 and earlier versions do not add nop for recursive + // calls. + b _start + b _start