Skip to content

Commit 82dd99e

Browse files
committed
[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
1 parent 50bf643 commit 82dd99e

File tree

4 files changed

+135
-1
lines changed

4 files changed

+135
-1
lines changed

lld/ELF/InputSection.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,18 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
584584
if (InOpd)
585585
SymVA = read64be(&Out::OpdBuf[SymVA - OpdStart]);
586586
}
587-
return SymVA - P;
587+
588+
// PPC64 V2 ABI describes two entry points to a function. The global entry
589+
// point sets up the TOC base pointer. When calling a local function, the
590+
// call should branch to the local entry point rather than the global entry
591+
// point. Section 3.4.1 describes using the 3 most significant bits of the
592+
// st_other field to find out how many instructions there are between the
593+
// local and global entry point.
594+
uint8_t StOther = (Sym.StOther >> 5) & 7;
595+
if (StOther == 0 || StOther == 1)
596+
return SymVA - P;
597+
598+
return SymVA - P + (1 << StOther);
588599
}
589600
case R_PPC_TOC:
590601
return getPPC64TocBase() + A;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
.text
2+
.abiversion 2
3+
.globl foo_external_diff # -- Begin function foo_external_diff
4+
.p2align 4
5+
.type foo_external_diff,@function
6+
foo_external_diff: # @foo_external_diff
7+
.Lfunc_begin0:
8+
.Lfunc_gep0:
9+
addis 2, 12, .TOC.-.Lfunc_gep0@ha
10+
addi 2, 2, .TOC.-.Lfunc_gep0@l
11+
.Lfunc_lep0:
12+
.localentry foo_external_diff, .Lfunc_lep0-.Lfunc_gep0
13+
# %bb.0: # %entry
14+
addis 5, 2, .LC0@toc@ha
15+
add 3, 4, 3
16+
ld 5, .LC0@toc@l(5)
17+
lwz 5, 0(5)
18+
add 3, 3, 5
19+
extsw 3, 3
20+
blr
21+
.long 0
22+
.quad 0
23+
.Lfunc_end0:
24+
.size foo_external_diff, .Lfunc_end0-.Lfunc_begin0
25+
# -- End function
26+
.section .toc,"aw",@progbits
27+
.LC0:
28+
.tc glob2[TC],glob2
29+
.type glob2,@object # @glob2
30+
.data
31+
.globl glob2
32+
.p2align 2
33+
glob2:
34+
.long 10 # 0xa
35+
.size glob2, 4
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
.text
2+
.abiversion 2
3+
.globl foo_external_same # -- Begin function foo_external_same
4+
.p2align 4
5+
.type foo_external_same,@function
6+
foo_external_same: # @foo_external_same
7+
.Lfunc_begin0:
8+
# %bb.0: # %entry
9+
add 3, 4, 3
10+
extsw 3, 3
11+
blr
12+
.long 0
13+
.quad 0
14+
.Lfunc_end0:
15+
.size foo_external_same, .Lfunc_end0-.Lfunc_begin0
16+
# -- End function
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// REQUIRES: ppc
2+
// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
3+
// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-func-global-entry.s -o %t2.o
4+
// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-func-local-entry.s -o %t3.o
5+
// RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.o %t3.o -o %t
6+
// RUN: llvm-objdump -d %t | FileCheck %s
7+
.text
8+
.abiversion 2
9+
.globl _start # -- Begin function _start
10+
.p2align 4
11+
.type _start,@function
12+
_start: # @_start
13+
.Lfunc_begin0:
14+
.Lfunc_gep0:
15+
addis 2, 12, .TOC.-.Lfunc_gep0@ha
16+
addi 2, 2, .TOC.-.Lfunc_gep0@l
17+
.Lfunc_lep0:
18+
.localentry _start, .Lfunc_lep0-.Lfunc_gep0
19+
# %bb.0: # %entry
20+
mflr 0
21+
std 0, 16(1)
22+
stdu 1, -48(1)
23+
li 3, 1
24+
li 4, 1
25+
std 30, 32(1) # 8-byte Folded Spill
26+
bl foo_external_same
27+
nop
28+
mr 30, 3
29+
li 3, 2
30+
li 4, 2
31+
bl foo_external_diff
32+
nop
33+
addis 4, 2, .LC0@toc@ha
34+
add 3, 3, 30
35+
ld 30, 32(1) # 8-byte Folded Reload
36+
ld 4, .LC0@toc@l(4)
37+
lwz 4, 0(4)
38+
add 3, 3, 4
39+
extsw 3, 3
40+
addi 1, 1, 48
41+
ld 0, 16(1)
42+
li 0, 1
43+
sc
44+
.long 0
45+
.quad 0
46+
.Lfunc_end0:
47+
.size _start, .Lfunc_end0-.Lfunc_begin0
48+
# -- End function
49+
.section .toc,"aw",@progbits
50+
.LC0:
51+
.tc glob[TC],glob
52+
.type glob,@object # @glob
53+
.data
54+
.globl glob
55+
.p2align 2
56+
glob:
57+
.long 10 # 0xa
58+
.size glob, 4
59+
60+
# Check that foo_external_diff has a global entry point and we branch to
61+
# foo_external_diff+8. Also check that foo_external_same has no global entry
62+
# point and we branch to start of foo_external_same.
63+
64+
// CHECK: _start:
65+
// CHECK: 10010020: 91 00 00 48 bl .+144
66+
// CHECK: 10010034: 55 00 00 48 bl .+84
67+
// CHECK: foo_external_diff:
68+
// CHECK-NEXT: 10010080: 02 00 4c 3c addis 2, 12, 2
69+
// CHECK-NEXT: 10010084: 80 7f 42 38 addi 2, 2, 32640
70+
// CHECK-NEXT: 10010088: ff ff a2 3c addis 5, 2, -1
71+
// CHECK: foo_external_same:
72+
// CHECK-NEXT: 100100b0: 14 1a 64 7c add 3, 4, 3

0 commit comments

Comments
 (0)