[lld] 118366d - [PowerPC] Implement R_PPC64_REL24_NOTOC calls, callee also has no TOC

Victor Huang via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 10 05:24:45 PDT 2020


Author: Victor Huang
Date: 2020-07-10T07:23:32-05:00
New Revision: 118366dcb6c35239c1c816d109230d6f7f3660af

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

LOG: [PowerPC] Implement R_PPC64_REL24_NOTOC calls, callee also has no TOC

The PC Relative code allows for calls that are marked with the relocation
R_PPC64_REL24_NOTOC. This indicates that the caller does not have a valid TOC
pointer in R2 and does not require R2 to be restored after the call.

This patch is added to support local calls to callees tha also do not have a TOC.

Reviewed By: sfertile, MaskRay, stefanp

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

Added: 
    lld/test/ELF/Inputs/ppc64-callee-global-hidden.s
    lld/test/ELF/ppc64-pcrel-call-to-pcrel.s

Modified: 
    lld/ELF/Arch/PPC64.cpp

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp
index cf58b322bb3a..71c568088fb9 100644
--- a/lld/ELF/Arch/PPC64.cpp
+++ b/lld/ELF/Arch/PPC64.cpp
@@ -681,6 +681,8 @@ RelExpr PPC64::getRelExpr(RelType type, const Symbol &s,
   case R_PPC64_REL14:
   case R_PPC64_REL24:
     return R_PPC64_CALL_PLT;
+  case R_PPC64_REL24_NOTOC:
+    return R_PLT_PC;
   case R_PPC64_REL16_LO:
   case R_PPC64_REL16_HA:
   case R_PPC64_REL16_HI:
@@ -993,7 +995,8 @@ void PPC64::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
     write32(loc, (read32(loc) & ~mask) | (val & mask));
     break;
   }
-  case R_PPC64_REL24: {
+  case R_PPC64_REL24:
+  case R_PPC64_REL24_NOTOC: {
     uint32_t mask = 0x03FFFFFC;
     checkInt(loc, val, 26, rel);
     checkAlignment(loc, val, 4, rel);
@@ -1032,16 +1035,28 @@ void PPC64::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
 
 bool PPC64::needsThunk(RelExpr expr, RelType type, const InputFile *file,
                        uint64_t branchAddr, const Symbol &s, int64_t a) const {
-  if (type != R_PPC64_REL14 && type != R_PPC64_REL24)
+  if (type != R_PPC64_REL14 && type != R_PPC64_REL24 &&
+      type != R_PPC64_REL24_NOTOC)
     return false;
 
+  // FIXME: Remove the fatal error once the call protocol is implemented.
+  if (type == R_PPC64_REL24_NOTOC && s.isInPlt())
+    fatal("unimplemented feature: external function call with the reltype"
+          " R_PPC64_REL24_NOTOC");
+
   // If a function is in the Plt it needs to be called with a call-stub.
   if (s.isInPlt())
     return true;
 
-  // This check looks at the st_other bits of the callee. If the value is 1
-  // then the callee clobbers the TOC and we need an R2 save stub.
-  if ((s.stOther >> 5) == 1)
+  // FIXME: Remove the fatal error once the call protocol is implemented.
+  if (type == R_PPC64_REL24_NOTOC && (s.stOther >> 5) > 1)
+    fatal("unimplemented feature: local function call with the reltype"
+          " R_PPC64_REL24_NOTOC and the callee needs toc-pointer setup");
+
+  // This check looks at the st_other bits of the callee with relocation
+  // R_PPC64_REL14 or R_PPC64_REL24. If the value is 1, then the callee
+  // clobbers the TOC and we need an R2 save stub.
+  if (type != R_PPC64_REL24_NOTOC && (s.stOther >> 5) == 1)
     return true;
 
   // If a symbol is a weak undefined and we are compiling an executable
@@ -1069,7 +1084,7 @@ bool PPC64::inBranchRange(RelType type, uint64_t src, uint64_t dst) const {
   int64_t offset = dst - src;
   if (type == R_PPC64_REL14)
     return isInt<16>(offset);
-  if (type == R_PPC64_REL24)
+  if (type == R_PPC64_REL24 || type == R_PPC64_REL24_NOTOC)
     return isInt<26>(offset);
   llvm_unreachable("unsupported relocation type used in branch");
 }

diff  --git a/lld/test/ELF/Inputs/ppc64-callee-global-hidden.s b/lld/test/ELF/Inputs/ppc64-callee-global-hidden.s
new file mode 100644
index 000000000000..e33d191f226d
--- /dev/null
+++ b/lld/test/ELF/Inputs/ppc64-callee-global-hidden.s
@@ -0,0 +1,15 @@
+func_extern:
+  blr
+
+.hidden callee3_stother0_hidden
+.globl callee3_stother0_hidden
+callee3_stother0_hidden:
+  blr
+
+.hidden callee4_stother1_hidden
+.globl callee4_stother1_hidden
+callee4_stother1_hidden:
+  .localentry callee4_stother1_hidden, 1
+  ## nop is not needed after bl for R_PPC64_REL24_NOTOC
+  bl func_extern at notoc
+  blr

diff  --git a/lld/test/ELF/ppc64-pcrel-call-to-pcrel.s b/lld/test/ELF/ppc64-pcrel-call-to-pcrel.s
new file mode 100644
index 000000000000..3b0d9e31fb7b
--- /dev/null
+++ b/lld/test/ELF/ppc64-pcrel-call-to-pcrel.s
@@ -0,0 +1,124 @@
+# REQUIRES: ppc
+# RUN: echo 'SECTIONS { \
+# RUN:   .text_default_stother0 0x10010000: { *(.text_default_stother0) } \
+# RUN:   .text_default_stother1 0x10020000: { *(.text_default_stother1) } \
+# RUN:   .text_hidden_stother0 0x10030000: { *(.text_hidden_stother0) } \
+# RUN:   .text_hidden_stother1 0x10040000: { *(.text_hidden_stother1) } \
+# RUN:   }' > %t.script
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le -defsym HIDDEN=1 %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le %p/Inputs/ppc64-callee-global-hidden.s -o %t2.o
+# RUN: ld.lld -T %t.script -shared %t1.o %t2.o -o %t.so
+# RUN: llvm-readelf -s %t.so | FileCheck %s --check-prefix=SYMBOL
+# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t.so | FileCheck --check-prefix=CHECK --check-prefix=CHECK-HIDDEN %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le -defsym GLOBAL=1 %s -o %t3.o
+# RUN: ld.lld -T %t.script %t3.o -o %t
+# RUN: llvm-readelf -s %t | FileCheck %s --check-prefix=SYMBOL-GLOBAL
+# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64 -defsym HIDDEN=1 %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64 %p/Inputs/ppc64-callee-global-hidden.s -o %t2.o
+# RUN: ld.lld -T %t.script -shared %t1.o %t2.o -o %t.so
+# RUN: llvm-readelf -s %t.so | FileCheck %s --check-prefix=SYMBOL
+# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t.so | FileCheck --check-prefix=CHECK --check-prefix=CHECK-HIDDEN %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64 -defsym GLOBAL=1 %s -o %t3.o
+# RUN: ld.lld -T %t.script %t3.o -o %t
+# RUN: llvm-readelf -s %t | FileCheck %s --check-prefix=SYMBOL-GLOBAL
+# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t | FileCheck %s
+
+# SYMBOL:      2: 0000000010010000 0 NOTYPE LOCAL DEFAULT 5 callee1_stother0_default
+# SYMBOL-NEXT: 3: 0000000010020004 0 NOTYPE LOCAL DEFAULT [<other: 0x20>] 6 callee2_stother1_default
+# SYMBOL-NEXT: 4: 0000000010010004 0 NOTYPE LOCAL DEFAULT [<other: 0x20>] 5 caller1
+# SYMBOL-NEXT: 5: 000000001002000c 0 NOTYPE LOCAL DEFAULT [<other: 0x20>] 6 caller2
+# SYMBOL-NEXT: 6: 0000000010030000 0 NOTYPE LOCAL DEFAULT [<other: 0x20>] 7 caller3
+# SYMBOL-NEXT: 7: 0000000010040000 0 NOTYPE LOCAL DEFAULT [<other: 0x20>] 8 caller4
+# SYMBOL-NEXT: 8: 0000000010020000 0 NOTYPE LOCAL DEFAULT 6 func_local
+# SYMBOL-NEXT: 9: 0000000010040008 0 NOTYPE LOCAL DEFAULT 9 func_extern
+# SYMBOL-NEXT: 10: 000000001004000c 0 NOTYPE LOCAL HIDDEN 9 callee3_stother0_hidden
+# SYMBOL-NEXT: 11: 0000000010040010 0 NOTYPE LOCAL HIDDEN [<other: 0x22>] 9 callee4_stother1_hidden
+
+# SYMBOL-GLOBAL:      2: 0000000010010004 0 NOTYPE LOCAL DEFAULT [<other: 0x20>] 1 caller1
+# SYMBOL-GLOBAL-NEXT: 3: 000000001002000c 0 NOTYPE LOCAL DEFAULT [<other: 0x20>] 2 caller2
+# SYMBOL-GLOBAL-NEXT: 4: 0000000010020000 0 NOTYPE LOCAL DEFAULT 2 func_local
+# SYMBOL-GLOBAL-NEXT: 5: 0000000010010000 0 NOTYPE GLOBAL DEFAULT 1 callee1_stother0_default
+# SYMBOL-GLOBAL-NEXT: 6: 0000000010020004 0 NOTYPE GLOBAL DEFAULT [<other: 0x20>] 2 callee2_stother1_default
+
+# CHECK-LABEL: <callee1_stother0_default>:
+# CHECK-NEXT:  10010000: blr
+
+# CHECK-LABEL: <caller1>:
+# CHECK:       10010004: bl 0x10010000
+# CHECK-NEXT:  10010008: b 0x10010000
+.section .text_default_stother0, "ax", %progbits
+.ifdef GLOBAL
+.globl callee1_stother0_default
+.endif
+callee1_stother0_default:
+  blr
+caller1:
+  .localentry caller1, 1
+  ## nop is not needed after bl for R_PPC64_REL24_NOTOC
+  bl callee1_stother0_default at notoc
+  b callee1_stother0_default at notoc
+
+# CHECK-LABEL: <func_local>:
+# CHECK-NEXT:  10020000: blr
+
+# CHECK-LABEL: <callee2_stother1_default>:
+# CHECK-NEXT:  10020004: bl 0x10020000
+# CHECK-NEXT:  10020008: blr
+
+# CHECK-LABEL: <caller2>:
+# CHECK:       1002000c: bl 0x10020004
+# CHECK-NEXT:  10020010: b 0x10020004
+.section .text_default_stother1, "ax", %progbits
+func_local:
+  blr
+.ifdef GLOBAL
+.globl callee2_stother1_default
+.endif
+callee2_stother1_default:
+  .localentry callee2_stother1_default, 1
+  ## nop is not needed after bl for R_PPC64_REL24_NOTOC
+  bl func_local at notoc
+  blr
+caller2:
+  .localentry caller2, 1
+  ## nop is not needed after bl for R_PPC64_REL24_NOTOC
+  bl callee2_stother1_default at notoc
+  b callee2_stother1_default at notoc
+
+# CHECK-HIDDEN-LABEL: <caller3>:
+# CHECK-HIDDEN-NEXT:  10030000: bl 0x1004000c
+# CHECK-HIDDEN-NEXT:  10030004: b 0x1004000c
+
+# CHECK-HIDDEN-LABEL: <caller4>:
+# CHECK-HIDDEN-NEXT:  10040000: bl 0x10040010
+# CHECK-HIDDEN-NEXT:  10040004: b 0x10040010
+
+# CHECK-HIDDEN-LABEL: <func_extern>:
+# CHECK-HIDDEN-NEXT:  10040008: blr
+
+# CHECK-HIDDEN-LABEL: <callee3_stother0_hidden>:
+# CHECK-HIDDEN-NEXT:  1004000c: blr
+
+# CHECK-HIDDEN-LABEL: <callee4_stother1_hidden>:
+# CHECK-HIDDEN-NEXT:  10040010: bl 0x10040008
+# CHECK-HIDDEN-NEXT:  10040014: blr
+.ifdef HIDDEN
+.section .text_hidden_stother0, "ax", %progbits
+caller3:
+  .localentry caller3, 1
+  ## nop is not needed after bl for R_PPC64_REL24_NOTOC
+  bl callee3_stother0_hidden at notoc
+  b callee3_stother0_hidden at notoc
+
+.section .text_hidden_stother1, "ax", %progbits
+caller4:
+  .localentry caller4, 1
+  ## nop is not needed after bl for R_PPC64_REL24_NOTOC
+  bl callee4_stother1_hidden at notoc
+  b callee4_stother1_hidden at notoc
+.endif


        


More information about the llvm-commits mailing list