diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp --- a/lld/ELF/Thunks.cpp +++ b/lld/ELF/Thunks.cpp @@ -312,6 +312,8 @@ uint32_t size() override { return getMayUseShortThunk() ? 8 : 32; } void writeTo(uint8_t *buf) override; void addSymbols(ThunkSection &isec) override; + bool isCompatibleWith(const InputSection &isec, + const Relocation &rel) const override; private: // Transitioning from long to short can create layout oscillations in @@ -333,6 +335,8 @@ uint32_t size() override { return 32; } void writeTo(uint8_t *buf) override; void addSymbols(ThunkSection &isec) override; + bool isCompatibleWith(const InputSection &isec, + const Relocation &rel) const override; }; // PPC64 PC-relative PLT Stub @@ -965,6 +969,11 @@ s->needsTocRestore = true; } +bool PPC64R2SaveStub::isCompatibleWith(const InputSection &isec, + const Relocation &rel) const { + return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14; +} + void PPC64R12SetupStub::writeTo(uint8_t *buf) { int64_t offset = destination.getVA() - getThunkTargetSym()->getVA(); if (!isInt<34>(offset)) @@ -995,6 +1004,11 @@ isec); } +bool PPC64R12SetupStub::isCompatibleWith(const InputSection &isec, + const Relocation &rel) const { + return rel.type == R_PPC64_REL24_NOTOC; +} + void PPC64PCRelPLTStub::writeTo(uint8_t *buf) { int nextInstOffset = 0; int64_t offset = destination.getGotPltVA() - getThunkTargetSym()->getVA(); diff --git a/lld/test/ELF/ppc64-pcrel-cross-link.s b/lld/test/ELF/ppc64-pcrel-cross-link.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/ppc64-pcrel-cross-link.s @@ -0,0 +1,140 @@ +# REQUIRES: ppc +# RUN: split-file %s %t + +# RUN: llvm-mc -filetype=obj -triple=powerpc64le %t/callees.s -o %t-callees.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64le %t/callertoc.s -o %t-callertoc.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64le %t/callernotoc.s -o %t-callernotoc.o +# RUN: ld.lld -T %t/lds %t-callees.o %t-callernotoc.o %t-callertoc.o -o %t-r12setup +# RUN: ld.lld -T %t/ldsswap %t-callees.o %t-callernotoc.o %t-callertoc.o -o %t-r2save + +# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t-r12setup | \ +# RUN: FileCheck %s --check-prefix=NOSWAP +# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t-r2save | \ +# RUN: FileCheck %s --check-prefix=SWAP + +## This test checks that it is possible to mix TOC and NOTOC functions and have +## the correct thunks for all of the calls. + +# NOSWAP-LABEL: 01001000 : +# NOSWAP-NEXT: blr +# NOSWAP-LABEL: 01002000 : +# NOSWAP: bl 0x1001000 +# NOSWAP: blr +# NOSWAP-LABEL: 01002018 : +# NOSWAP: bl 0x1001000 +# NOSWAP: blr +# NOSWAP-LABEL: 10030000 : +# NOSWAP-NEXT: bl 0x10030010 +# NOSWAP-NEXT: bl 0x10030030 +# NOSWAP-NEXT: blr +# NOSWAP-LABEL: 10030010 <__gep_setup_callee_toc>: +# NOSWAP: bctr +# NOSWAP-LABEL: 10030030 <__long_branch_pcrel_callee_notoc>: +# NOSWAP: bctr +# NOSWAP-LABEL: 10040000 : +# NOSWAP: bl 0x10040020 +# NOSWAP-NEXT: nop +# NOSWAP-NEXT: bl 0x10040040 +# NOSWAP-NEXT: ld 2, 24(1) +# NOSWAP-NEXT: blr +# NOSWAP-LABEL: 10040020 <__long_branch_callee_toc>: +# NOSWAP: bctr +# NOSWAP-LABEL: 10040040 <__toc_save_callee_notoc>: +# NOSWAP-NEXT: std 2, 24(1) +# NOSWAP: bctr + +# SWAP-LABEL: 01001000 : +# SWAP-NEXT: blr +# SWAP-LABEL: 01002000 : +# SWAP: bl 0x1001000 +# SWAP: blr +# SWAP-LABEL: 01002018 : +# SWAP: bl 0x1001000 +# SWAP: blr +# SWAP-LABEL: 10030000 : +# SWAP: bl 0x10030020 +# SWAP-NEXT: nop +# SWAP-NEXT: bl 0x10030040 +# SWAP-NEXT: ld 2, 24(1) +# SWAP-NEXT: blr +# SWAP-LABEL: 10030020 <__long_branch_callee_toc>: +# SWAP: bctr +# SWAP-LABEL: 10030040 <__toc_save_callee_notoc>: +# SWAP-NEXT: std 2, 24(1) +# SWAP: bctr +# SWAP-LABEL: 10040000 : +# SWAP-NEXT: bl 0x10040010 +# SWAP-NEXT: bl 0x10040030 +# SWAP-NEXT: blr +# SWAP-LABEL: 10040010 <__gep_setup_callee_toc>: +# SWAP: bctr +# SWAP-LABEL: 10040030 <__long_branch_pcrel_callee_notoc>: +# SWAP: bctr + +#--- lds +SECTIONS { + .text_func 0x1001000 : { *(.text_func) } + .text_callee 0x1002000 : { *(.text_callee) } + .text_caller_notoc 0x10030000 : { *(.text_caller_notoc) } + .text_caller_toc 0x10040000 : { *(.text_caller_toc) } +} + +#--- ldsswap +SECTIONS { + .text_func 0x1001000 : { *(.text_func) } + .text_callee 0x1002000 : { *(.text_callee) } + .text_caller_toc 0x10030000 : { *(.text_caller_toc) } + .text_caller_notoc 0x10040000 : { *(.text_caller_notoc) } +} + +#--- callees.s +.section .text_func, "ax", %progbits +func: + blr + +.globl callee_toc +.section .text_callee, "ax", %progbits +callee_toc: +.Lfunc_gep1: + addis 2, 12, .TOC.-.Lfunc_gep1@ha + addi 2, 2, .TOC.-.Lfunc_gep1@l +.Lfunc_lep1: + .localentry callee_toc, .Lfunc_lep1-.Lfunc_gep1 + bl func + addis 4, 2, global@toc@ha + lwz 4, global@toc@l(4) + blr + +.globl callee_notoc +callee_notoc: + .localentry callee_notoc, 1 + bl func + plwz 4, global@pcrel(0), 1 + blr + +## .globl global +global: + .long 0 + .size global, 4 + +#--- callernotoc.s +.section .text_caller_notoc, "ax", %progbits +caller_notoc: + .localentry caller, 1 + bl callee_toc@notoc + bl callee_notoc@notoc + blr + +#--- callertoc.s +.section .text_caller_toc, "ax", %progbits +caller_toc: +.Lfunc_gep2: + addis 2, 12, .TOC.-.Lfunc_gep2@ha + addi 2, 2, .TOC.-.Lfunc_gep2@l +.Lfunc_lep2: + .localentry caller_toc, .Lfunc_lep2-.Lfunc_gep2 + bl callee_toc + nop + bl callee_notoc + nop + blr