mirror of
https://github.com/intel/llvm.git
synced 2026-02-07 16:11:27 +08:00
[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
This commit is contained in:
@@ -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");
|
||||
}
|
||||
|
||||
15
lld/test/ELF/Inputs/ppc64-callee-global-hidden.s
Normal file
15
lld/test/ELF/Inputs/ppc64-callee-global-hidden.s
Normal file
@@ -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
|
||||
124
lld/test/ELF/ppc64-pcrel-call-to-pcrel.s
Normal file
124
lld/test/ELF/ppc64-pcrel-call-to-pcrel.s
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user