From 2a631a2192ad362107d5b84561b3391486fe9a80 Mon Sep 17 00:00:00 2001 From: Tom Stellard Date: Tue, 8 May 2018 02:41:21 +0000 Subject: [PATCH] Merging r329335, r329355, r329573: ------------------------------------------------------------------------ r329335 | lhames | 2018-04-05 12:37:05 -0700 (Thu, 05 Apr 2018) | 15 lines [RuntimeDyld][PowerPC] Use global entry points for calls between sections. Functions in different objects may use different TOCs, so calls between such functions should use the global entry point of the callee which updates the TOC pointer. This should fix a bug that the Numba developers encountered (see https://github.com/numba/numba/issues/2451). Patch by Olexa Bilaniuk. Thanks Olexa! No RuntimeDyld checker test case yet as I am not familiar enough with how RuntimeDyldELF fixes up call-sites, but I do not want to hold up landing this. I will continue to work on it and see if I can rope some powerpc experts in. ------------------------------------------------------------------------ ------------------------------------------------------------------------ r329355 | lhames | 2018-04-05 14:56:55 -0700 (Thu, 05 Apr 2018) | 4 lines [RuntimeDyld][PowerPC] Add a test case for r329335. Checks that calls to different sections go to the function's global entry point, rather than the local one. ------------------------------------------------------------------------ ------------------------------------------------------------------------ r329573 | krasimir | 2018-04-09 07:29:23 -0700 (Mon, 09 Apr 2018) | 11 lines [RuntimeDyld][PowerPC] Fix a newly added test in r329355 Summary: The bit widths are wrong. Reviewers: bkramer, lhames, hans Reviewed By: hans Subscribers: hans, nemanjai, kbarton, llvm-commits Differential Revision: https://reviews.llvm.org/D45361 ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/llvm/branches/release_60@331715 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../RuntimeDyld/RuntimeDyldELF.cpp | 22 +++++---- .../PowerPC/Inputs/ppc64_elf_module_b.s | 42 +++++++++++++++++ .../RuntimeDyld/PowerPC/ppc64_elf.s | 47 +++++++++++++++++++ 3 files changed, 102 insertions(+), 9 deletions(-) create mode 100644 test/ExecutionEngine/RuntimeDyld/PowerPC/Inputs/ppc64_elf_module_b.s create mode 100644 test/ExecutionEngine/RuntimeDyld/PowerPC/ppc64_elf.s diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index c0047d0cde6..2c57eee191d 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -1422,7 +1422,8 @@ RuntimeDyldELF::processRelocationRef( SectionEntry &Section = Sections[SectionID]; uint8_t *Target = Section.getAddressWithOffset(Offset); bool RangeOverflow = false; - if (!Value.SymbolName && SymType != SymbolRef::ST_Unknown) { + bool IsExtern = Value.SymbolName || SymType == SymbolRef::ST_Unknown; + if (!IsExtern) { if (AbiVariant != 2) { // In the ELFv1 ABI, a function call may point to the .opd entry, // so the final symbol value is calculated based on the relocation @@ -1432,21 +1433,24 @@ RuntimeDyldELF::processRelocationRef( } else { // In the ELFv2 ABI, a function symbol may provide a local entry // point, which must be used for direct calls. - uint8_t SymOther = Symbol->getOther(); - Value.Addend += ELF::decodePPC64LocalEntryOffset(SymOther); + if (Value.SectionID == SectionID){ + uint8_t SymOther = Symbol->getOther(); + Value.Addend += ELF::decodePPC64LocalEntryOffset(SymOther); + } } uint8_t *RelocTarget = Sections[Value.SectionID].getAddressWithOffset(Value.Addend); int64_t delta = static_cast(Target - RelocTarget); // If it is within 26-bits branch range, just set the branch target - if (SignExtend64<26>(delta) == delta) { + if (SignExtend64<26>(delta) != delta) { + RangeOverflow = true; + } else if ((AbiVariant != 2) || + (AbiVariant == 2 && Value.SectionID == SectionID)) { RelocationEntry RE(SectionID, Offset, RelType, Value.Addend); addRelocationForSection(RE, Value.SectionID); - } else { - RangeOverflow = true; } } - if (Value.SymbolName || SymType == SymbolRef::ST_Unknown || + if (IsExtern || (AbiVariant == 2 && Value.SectionID != SectionID) || RangeOverflow) { // It is an external symbol (either Value.SymbolName is set, or // SymType is SymbolRef::ST_Unknown) or out of range. @@ -1503,10 +1507,10 @@ RuntimeDyldELF::processRelocationRef( RelType, 0); Section.advanceStubOffset(getMaxStubSize()); } - if (Value.SymbolName || SymType == SymbolRef::ST_Unknown) { + if (IsExtern || (AbiVariant == 2 && Value.SectionID != SectionID)) { // Restore the TOC for external calls if (AbiVariant == 2) - writeInt32BE(Target + 4, 0xE8410018); // ld r2,28(r1) + writeInt32BE(Target + 4, 0xE8410018); // ld r2,24(r1) else writeInt32BE(Target + 4, 0xE8410028); // ld r2,40(r1) } diff --git a/test/ExecutionEngine/RuntimeDyld/PowerPC/Inputs/ppc64_elf_module_b.s b/test/ExecutionEngine/RuntimeDyld/PowerPC/Inputs/ppc64_elf_module_b.s new file mode 100644 index 00000000000..f47ddbd4136 --- /dev/null +++ b/test/ExecutionEngine/RuntimeDyld/PowerPC/Inputs/ppc64_elf_module_b.s @@ -0,0 +1,42 @@ +# This module contains a function with its local and global entry points +# exposed. It is used by the ppc64_elf test to verify that functions with +# different TOCs are called via their global entry points. + .text + .abiversion 2 + .file "ppc64_elf_module_b.ll" + .section .rodata.cst4,"aM",@progbits,4 + .p2align 2 # -- Begin function foo +.LCPI0_0: + .long 1093664768 # float 11 + .text + .globl foo + .p2align 4 + .type foo,@function +.Lfunc_toc0: # @foo + .quad .TOC.-foo_gep +foo: +.Lfunc_begin0: + .cfi_startproc + .globl foo_gep +foo_gep: + ld 2, .Lfunc_toc0-foo_gep(12) + add 2, 2, 12 + .globl foo_lep +foo_lep: + .localentry foo, foo_lep-foo_gep +# %bb.0: + addis 3, 2, .LC0@toc@ha + ld 3, .LC0@toc@l(3) + lfsx 1, 0, 3 + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size foo, .Lfunc_end0-.Lfunc_begin0 + .cfi_endproc + # -- End function + .section .toc,"aw",@progbits +.LC0: + .tc .LCPI0_0[TC],.LCPI0_0 + + .section ".note.GNU-stack","",@progbits diff --git a/test/ExecutionEngine/RuntimeDyld/PowerPC/ppc64_elf.s b/test/ExecutionEngine/RuntimeDyld/PowerPC/ppc64_elf.s new file mode 100644 index 00000000000..b43c84caf56 --- /dev/null +++ b/test/ExecutionEngine/RuntimeDyld/PowerPC/ppc64_elf.s @@ -0,0 +1,47 @@ +# RUN: rm -rf %t && mkdir -p %t +# RUN: llvm-mc -triple=powerpc64le-unknown-linux-gnu -filetype=obj -o %t/ppc64_elf.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_elf.o %t/ppc64_elf_module_b.o + + .text + .abiversion 2 + .file "Module2.ll" + .globl bar # -- Begin function bar + .p2align 4 + .type bar,@function +.Lfunc_toc0: # @bar + .quad .TOC.-.Lfunc_gep0 +bar: +.Lfunc_begin0: + .cfi_startproc +.Lfunc_gep0: + ld 2, .Lfunc_toc0-.Lfunc_gep0(12) + add 2, 2, 12 +.Lfunc_lep0: + .localentry bar, .Lfunc_lep0-.Lfunc_gep0 +# %bb.0: + mflr 0 + std 0, 16(1) + stdu 1, -32(1) + .cfi_def_cfa_offset 32 + .cfi_offset lr, 16 +# rtdyld-check: (*{4}(stub_addr(ppc64_elf.o, .text, foo) + 0)) [15:0] = foo_gep [63:48] +# rtdyld-check: (*{4}(stub_addr(ppc64_elf.o, .text, foo) + 4)) [15:0] = foo_gep [47:32] +# rtdyld-check: (*{4}(stub_addr(ppc64_elf.o, .text, foo) + 12)) [15:0] = foo_gep [31:16] +# rtdyld-check: (*{4}(stub_addr(ppc64_elf.o, .text, foo) + 16)) [15:0] = foo_gep [15:0] +# rtdyld-check: decode_operand(foo_call, 0) = (stub_addr(ppc64_elf.o, .text, foo) - foo_call) >> 2 +foo_call: + bl foo + nop + addi 1, 1, 32 + ld 0, 16(1) + mtlr 0 + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size bar, .Lfunc_end0-.Lfunc_begin0 + .cfi_endproc + # -- End function + + .section ".note.GNU-stack","",@progbits -- 2.40.0