[lld] bb87364 - [ELF][PPC64] Improve "call lacks nop" diagnostic and make it compatible with GCC<5.5 and GCC<6.4

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Sun Dec 29 23:05:42 PST 2019


Author: Fangrui Song
Date: 2019-12-29T23:05:11-08:00
New Revision: bb87364f26ce6b1fbb2cc5e155fd8ff82aafbe8d

URL: https://github.com/llvm/llvm-project/commit/bb87364f26ce6b1fbb2cc5e155fd8ff82aafbe8d
DIFF: https://github.com/llvm/llvm-project/commit/bb87364f26ce6b1fbb2cc5e155fd8ff82aafbe8d.diff

LOG: [ELF][PPC64] Improve "call lacks nop" diagnostic and make it compatible with GCC<5.5 and GCC<6.4

GCC before r245813 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79439)
did not emit nop after b/bl. This can happen with recursive calls.
r245813 was back ported to GCC 5.5 and GCC 6.4.

This is common, for example, libstdc++.a(locale.o) shipped with GCC 4.9
and many objects in netlib lapack can cause lld to error.  gold allows
such calls to the same section. Our __plt_foo symbol's `section` field
is used for ThunkSection, so we can't implement a similar loosen rule
easily. But we can make use of its `file` field which is currently NULL.

Differential Revision: https://reviews.llvm.org/D71639

Added: 
    

Modified: 
    lld/ELF/InputSection.cpp
    lld/ELF/Thunks.cpp
    lld/test/ELF/ppc64-bsymbolic-toc-restore.s
    lld/test/ELF/ppc64-error-toc-restore.s
    lld/test/ELF/ppc64-error-toc-tail-call.s

Removed: 
    


################################################################################
diff  --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 959dcb8533d6..7dceddb5659d 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -971,8 +971,16 @@ void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd) {
 
       // 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
index 446c88c92d9e..7b927a434e36 100644
--- a/lld/ELF/Thunks.cpp
+++ b/lld/ELF/Thunks.cpp
@@ -786,6 +786,7 @@ void PPC64PltCallStub::addSymbols(ThunkSection &isec) {
   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
index ff5eb1482730..929c82cd24b8 100644
--- 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
index 19153b730ce1..9700322a5e6d 100644
--- 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
index da8fea26cc23..b303810b81d0 100644
--- 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


        


More information about the llvm-commits mailing list