summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Huang <wei.huang@ibm.com>2020-07-10 06:47:47 -0500
committerVictor Huang <wei.huang@ibm.com>2020-07-10 07:23:32 -0500
commit118366dcb6c35239c1c816d109230d6f7f3660af (patch)
tree541d5bd9440c05d25e3b0a2000cf0b8fd9b1752e
parent4c5a93bd58bad70e91ac525b0e020bd5119a321a (diff)
downloadllvm-118366dcb6c35239c1c816d109230d6f7f3660af.tar.gz
[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
-rw-r--r--lld/ELF/Arch/PPC64.cpp27
-rw-r--r--lld/test/ELF/Inputs/ppc64-callee-global-hidden.s15
-rw-r--r--lld/test/ELF/ppc64-pcrel-call-to-pcrel.s124
3 files changed, 160 insertions, 6 deletions
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@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@notoc
+ b callee1_stother0_default@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@notoc
+ blr
+caller2:
+ .localentry caller2, 1
+ ## nop is not needed after bl for R_PPC64_REL24_NOTOC
+ bl callee2_stother1_default@notoc
+ b callee2_stother1_default@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@notoc
+ b callee3_stother0_hidden@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@notoc
+ b callee4_stother1_hidden@notoc
+.endif