diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp --- a/lld/ELF/Arch/PPC64.cpp +++ b/lld/ELF/Arch/PPC64.cpp @@ -211,6 +211,7 @@ bool adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End, uint8_t StOther) const override; + uint32_t getThunkSectionSpacing() const override; }; } // namespace @@ -1051,6 +1052,25 @@ return true; } +uint32_t PPC64::getThunkSectionSpacing() const { + // PowerPC64 has the following basic branch instructions: + // + // - b[l,a] PPC64_REL24 range [33,554,432...33,554,428] + // - bc[l,a] PPC64_REL14 range [-32,768...32764] + // + // We take the less strict range, and intentionally use a lower + // size than the maximum branch range so the end of the ThunkSection + // is more likely to be within range of the branch instruction that + // is furthest away. + // + // Reducing it in 0x80000 allow creating 32,768 16 byte Thunks at any + // offset in a ThunkSection without risk of a branch to one of the + // Thunks going out of range. + // + // See comment in Arch/ARM.cpp for more detais of getThunkSectionSpacing(). + return 0x2000000 - 0x80000; +} + TargetInfo *elf::getPPC64TargetInfo() { static PPC64 Target; return &Target; diff --git a/lld/test/ELF/Inputs/ppc64-far-branch-rangethunk.s b/lld/test/ELF/Inputs/ppc64-far-branch-rangethunk.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/Inputs/ppc64-far-branch-rangethunk.s @@ -0,0 +1,9 @@ + +.section .init,"ax",@progbits,unique,2 +.align 2 +.global too_far1 +.type too_far1,%function + +// place too_far1 to + 64MB (should be above 32MB) +too_far1 = 0x10010000 + 0x4000000 + diff --git a/lld/test/ELF/ppc64-branch-thunkspacing.s b/lld/test/ELF/ppc64-branch-thunkspacing.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/ppc64-branch-thunkspacing.s @@ -0,0 +1,30 @@ +# REQUIRES: ppc + +# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-freebsd13.0 %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-freebsd13.0 %S/Inputs/ppc64-far-branch-rangethunk.s -o %tfar.o +# RUN: ld.lld %t.o %tfar.o -o %t2 +# RUN: llvm-readelf --symbols %t2 | FileCheck %s + +.section .init,"ax",@progbits +.align 2 +.globl _start +.type _start,@function + +_start: + stwu 1,-16(1) + mflr 0 + stw 31,12(1) + stw 0,20(1) + mr 31,1 + bl too_far1 + + +# When ThunkSpacing is applied, "__long_branch_too_far1" is shifted +# to an offset after "_start" + +# CHECK: Symbol table '.symtab' contains 4 entries: +# CHECK: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND +# CHECK-NEXT: 1: 0000000010010018 16 FUNC LOCAL DEFAULT 2 __long_branch_too_far1 +# CHECK-NEXT: 2: 0000000010010000 0 FUNC GLOBAL DEFAULT 2 _start +# CHECK-NEXT: 3: 0000000014010000 0 FUNC GLOBAL DEFAULT ABS too_far1 +