summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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