[PPC64] Add offset to local entry point when calling functions without plt

PPC64 V2 ABI describes two entry points to a function. The global entry point
sets up the TOC base pointer. When calling a local function, the call should
branch to the local entry point rather than the global entry point.
Section 3.4.1 describes using the 3 most significant bits of the st_other
field to find out how many instructions there are between the local and global
entry point. This patch adds the correct offset required to branch to the local
entry point of a function.

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

llvm-svn: 331046
This commit is contained in:
Zaara Syeda 2018-04-27 15:41:19 +00:00
parent 50bf643cfb
commit 82dd99e08e
4 changed files with 135 additions and 1 deletions

View File

@ -584,7 +584,18 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
if (InOpd)
SymVA = read64be(&Out::OpdBuf[SymVA - OpdStart]);
}
return SymVA - P;
// PPC64 V2 ABI describes two entry points to a function. The global entry
// point sets up the TOC base pointer. When calling a local function, the
// call should branch to the local entry point rather than the global entry
// point. Section 3.4.1 describes using the 3 most significant bits of the
// st_other field to find out how many instructions there are between the
// local and global entry point.
uint8_t StOther = (Sym.StOther >> 5) & 7;
if (StOther == 0 || StOther == 1)
return SymVA - P;
return SymVA - P + (1 << StOther);
}
case R_PPC_TOC:
return getPPC64TocBase() + A;

View File

@ -0,0 +1,35 @@
.text
.abiversion 2
.globl foo_external_diff # -- Begin function foo_external_diff
.p2align 4
.type foo_external_diff,@function
foo_external_diff: # @foo_external_diff
.Lfunc_begin0:
.Lfunc_gep0:
addis 2, 12, .TOC.-.Lfunc_gep0@ha
addi 2, 2, .TOC.-.Lfunc_gep0@l
.Lfunc_lep0:
.localentry foo_external_diff, .Lfunc_lep0-.Lfunc_gep0
# %bb.0: # %entry
addis 5, 2, .LC0@toc@ha
add 3, 4, 3
ld 5, .LC0@toc@l(5)
lwz 5, 0(5)
add 3, 3, 5
extsw 3, 3
blr
.long 0
.quad 0
.Lfunc_end0:
.size foo_external_diff, .Lfunc_end0-.Lfunc_begin0
# -- End function
.section .toc,"aw",@progbits
.LC0:
.tc glob2[TC],glob2
.type glob2,@object # @glob2
.data
.globl glob2
.p2align 2
glob2:
.long 10 # 0xa
.size glob2, 4

View File

@ -0,0 +1,16 @@
.text
.abiversion 2
.globl foo_external_same # -- Begin function foo_external_same
.p2align 4
.type foo_external_same,@function
foo_external_same: # @foo_external_same
.Lfunc_begin0:
# %bb.0: # %entry
add 3, 4, 3
extsw 3, 3
blr
.long 0
.quad 0
.Lfunc_end0:
.size foo_external_same, .Lfunc_end0-.Lfunc_begin0
# -- End function

View File

@ -0,0 +1,72 @@
// REQUIRES: ppc
// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-func-global-entry.s -o %t2.o
// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-func-local-entry.s -o %t3.o
// RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.o %t3.o -o %t
// RUN: llvm-objdump -d %t | FileCheck %s
.text
.abiversion 2
.globl _start # -- Begin function _start
.p2align 4
.type _start,@function
_start: # @_start
.Lfunc_begin0:
.Lfunc_gep0:
addis 2, 12, .TOC.-.Lfunc_gep0@ha
addi 2, 2, .TOC.-.Lfunc_gep0@l
.Lfunc_lep0:
.localentry _start, .Lfunc_lep0-.Lfunc_gep0
# %bb.0: # %entry
mflr 0
std 0, 16(1)
stdu 1, -48(1)
li 3, 1
li 4, 1
std 30, 32(1) # 8-byte Folded Spill
bl foo_external_same
nop
mr 30, 3
li 3, 2
li 4, 2
bl foo_external_diff
nop
addis 4, 2, .LC0@toc@ha
add 3, 3, 30
ld 30, 32(1) # 8-byte Folded Reload
ld 4, .LC0@toc@l(4)
lwz 4, 0(4)
add 3, 3, 4
extsw 3, 3
addi 1, 1, 48
ld 0, 16(1)
li 0, 1
sc
.long 0
.quad 0
.Lfunc_end0:
.size _start, .Lfunc_end0-.Lfunc_begin0
# -- End function
.section .toc,"aw",@progbits
.LC0:
.tc glob[TC],glob
.type glob,@object # @glob
.data
.globl glob
.p2align 2
glob:
.long 10 # 0xa
.size glob, 4
# Check that foo_external_diff has a global entry point and we branch to
# foo_external_diff+8. Also check that foo_external_same has no global entry
# point and we branch to start of foo_external_same.
// CHECK: _start:
// CHECK: 10010020: 91 00 00 48 bl .+144
// CHECK: 10010034: 55 00 00 48 bl .+84
// CHECK: foo_external_diff:
// CHECK-NEXT: 10010080: 02 00 4c 3c addis 2, 12, 2
// CHECK-NEXT: 10010084: 80 7f 42 38 addi 2, 2, 32640
// CHECK-NEXT: 10010088: ff ff a2 3c addis 5, 2, -1
// CHECK: foo_external_same:
// CHECK-NEXT: 100100b0: 14 1a 64 7c add 3, 4, 3