summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHiroshi Inoue <inouehrs@jp.ibm.com>2018-05-30 04:48:29 +0000
committerHiroshi Inoue <inouehrs@jp.ibm.com>2018-05-30 04:48:29 +0000
commit3872c6c63383d48a5f940bf535877df45b18027f (patch)
treeaca5849b17fc3421bddf24010c9bac15444b4aac
parent4c2aa9fb0bad1192ac038bb1ac42828238a68670 (diff)
downloadbcm5719-llvm-3872c6c63383d48a5f940bf535877df45b18027f.tar.gz
bcm5719-llvm-3872c6c63383d48a5f940bf535877df45b18027f.zip
[PowerPC] fix broken JIT-compiled code with tail call optimization
The relocation for branch instructions in the dynamic loader of ExecutionEngine assumes branch instructions with R_PPC64_REL24 relocation type are only bl. However, with the tail call optimization, b instructions can be also used to jump into another function. This patch makes the relocation to keep bits in the branch instruction other than the jump offset to avoid relocation rewrites a b instruction into bl. Differential Revision: https://reviews.llvm.org/D47456 llvm-svn: 333502
-rw-r--r--llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp5
-rw-r--r--llvm/test/ExecutionEngine/RuntimeDyld/PowerPC/ppc64_reloc.s48
2 files changed, 51 insertions, 2 deletions
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
index 322883f4fea..e15fd0b124b 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
@@ -772,8 +772,9 @@ void RuntimeDyldELF::resolvePPC64Relocation(const SectionEntry &Section,
int64_t delta = static_cast<int64_t>(Value - FinalAddress + Addend);
if (SignExtend64<26>(delta) != delta)
llvm_unreachable("Relocation R_PPC64_REL24 overflow");
- // Generates a 'bl <address>' instruction
- writeInt32BE(LocalAddress, 0x48000001 | (delta & 0x03FFFFFC));
+ // We preserve bits other than LI field, i.e. PO and AA/LK fields.
+ uint32_t Inst = readBytesUnaligned(LocalAddress, 4);
+ writeInt32BE(LocalAddress, (Inst & 0xFC000003) | (delta & 0x03FFFFFC));
} break;
case ELF::R_PPC64_REL32: {
uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
diff --git a/llvm/test/ExecutionEngine/RuntimeDyld/PowerPC/ppc64_reloc.s b/llvm/test/ExecutionEngine/RuntimeDyld/PowerPC/ppc64_reloc.s
new file mode 100644
index 00000000000..9a859ead22c
--- /dev/null
+++ b/llvm/test/ExecutionEngine/RuntimeDyld/PowerPC/ppc64_reloc.s
@@ -0,0 +1,48 @@
+# test for little endian
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=powerpc64le-unknown-linux-gnu -filetype=obj -o %t/ppc64_reloc.o %s
+# RUN: llvm-mc -triple=powerpc64le-unknown-linux-gnu -filetype=obj -o %t/ppc64_elf_module_b.o %S/Inputs/ppc64_elf_module_b.s
+# RUN: llvm-rtdyld -triple=powerpc64le-unknown-linux-gnu -verify -check=%s %t/ppc64_reloc.o %t/ppc64_elf_module_b.o
+# test for big endian
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=powerpc64-unknown-linux-gnu -filetype=obj -o %t/ppc64_reloc.o %s
+# RUN: llvm-mc -triple=powerpc64-unknown-linux-gnu -filetype=obj -o %t/ppc64_elf_module_b.o %S/Inputs/ppc64_elf_module_b.s
+# RUN: llvm-rtdyld -triple=powerpc64-unknown-linux-gnu -verify -check=%s %t/ppc64_reloc.o %t/ppc64_elf_module_b.o
+
+ .text
+ .abiversion 2
+ .file "test.c"
+ .globl func
+ .p2align 4
+ .type func,@function
+func: # @func
+.Lfunc_begin0:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry func, .Lfunc_lep0-.Lfunc_gep0
+ mflr 0
+ std 31, -8(1)
+ std 0, 16(1)
+ stdu 1, -112(1)
+ mr 31, 1
+# confirm that LK flag is set for bl
+# rtdyld-check: (*{4}call_bl) & 1 = 1
+call_bl:
+ bl foo
+ nop
+
+ li 3, 0
+ addi 1, 1, 112
+ ld 0, 16(1)
+ ld 31, -8(1)
+ mtlr 0
+# confirm that LK flag is not set for b
+# rtdyld-check: (*{4}call_b) & 1 = 0
+call_b:
+ b foo
+ .long 0
+ .quad 0
+.Lfunc_end0:
+ .size func, .Lfunc_end0-.Lfunc_begin0
OpenPOWER on IntegriCloud