summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZaara Syeda <syzaara@ca.ibm.com>2018-04-27 15:41:19 +0000
committerZaara Syeda <syzaara@ca.ibm.com>2018-04-27 15:41:19 +0000
commit82dd99e08ed83f9e4bc9a12e4652d160b1873f30 (patch)
tree14a9349033b95e3b2843cac2bf7776c17c925671
parent50bf643cfb1a89429095be3ffcdd965f1d670561 (diff)
downloadbcm5719-llvm-82dd99e08ed83f9e4bc9a12e4652d160b1873f30.tar.gz
bcm5719-llvm-82dd99e08ed83f9e4bc9a12e4652d160b1873f30.zip
[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
-rw-r--r--lld/ELF/InputSection.cpp13
-rw-r--r--lld/test/ELF/Inputs/ppc64-func-global-entry.s35
-rw-r--r--lld/test/ELF/Inputs/ppc64-func-local-entry.s16
-rw-r--r--lld/test/ELF/ppc64-func-entry-points.s72
4 files changed, 135 insertions, 1 deletions
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 4717914d914..871832a4ef7 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -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;
diff --git a/lld/test/ELF/Inputs/ppc64-func-global-entry.s b/lld/test/ELF/Inputs/ppc64-func-global-entry.s
new file mode 100644
index 00000000000..5987db6b5c5
--- /dev/null
+++ b/lld/test/ELF/Inputs/ppc64-func-global-entry.s
@@ -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
diff --git a/lld/test/ELF/Inputs/ppc64-func-local-entry.s b/lld/test/ELF/Inputs/ppc64-func-local-entry.s
new file mode 100644
index 00000000000..fc0a72df762
--- /dev/null
+++ b/lld/test/ELF/Inputs/ppc64-func-local-entry.s
@@ -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
diff --git a/lld/test/ELF/ppc64-func-entry-points.s b/lld/test/ELF/ppc64-func-entry-points.s
new file mode 100644
index 00000000000..2f82baa36b5
--- /dev/null
+++ b/lld/test/ELF/ppc64-func-entry-points.s
@@ -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
OpenPOWER on IntegriCloud