diff --git a/lld/ELF/Arch/Hexagon.cpp b/lld/ELF/Arch/Hexagon.cpp index 45b5188845b1..46d1c24c3757 100644 --- a/lld/ELF/Arch/Hexagon.cpp +++ b/lld/ELF/Arch/Hexagon.cpp @@ -48,6 +48,7 @@ public: bool needsThunk(RelExpr expr, RelType type, const InputFile *file, uint64_t branchAddr, const Symbol &s, int64_t a) const override; + uint32_t getThunkSectionSpacing() const override; bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override; void relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const override; @@ -387,13 +388,22 @@ bool Hexagon::needsThunk(RelExpr expr, RelType type, const InputFile *file, case R_HEX_LD_PLT_B22_PCREL: case R_HEX_B15_PCREL: case R_HEX_B13_PCREL: - case R_HEX_B9_PCREL: - return !ctx.target->inBranchRange(type, branchAddr, s.getVA(ctx, a)); + case R_HEX_B9_PCREL: { + uint64_t dst = expr == R_PLT_PC ? s.getPltVA(ctx) : s.getVA(ctx, a); + return !ctx.target->inBranchRange(type, branchAddr, dst); + } default: return false; } } +uint32_t Hexagon::getThunkSectionSpacing() const { + // B22_PCREL has a range of +/- 8 MiB (22-bit signed offset * 4). + // Pre-create ThunkSections at intervals below this to leave room for + // thunk growth. + return 0x800000 - 0x30000; +} + void Hexagon::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { switch (rel.type) { diff --git a/lld/test/ELF/hexagon-thunk-range-plt.s b/lld/test/ELF/hexagon-thunk-range-plt.s index 3a8f50b681d8..86909a523120 100644 --- a/lld/test/ELF/hexagon-thunk-range-plt.s +++ b/lld/test/ELF/hexagon-thunk-range-plt.s @@ -2,74 +2,61 @@ # RUN: rm -rf %t && split-file %s %t && cd %t # RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf external.s -o external.o # RUN: ld.lld -shared external.o -soname external.so -o external.so + +## PLT calls within range (2 MiB padding) — no thunks needed. # RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf main.s -o main.o # RUN: ld.lld main.o external.so -o test -# RUN: llvm-objdump -d --no-show-raw-insn test | FileCheck %s +# RUN: llvm-objdump -d --no-show-raw-insn test | \ +# RUN: FileCheck --check-prefix=INRANGE %s + +## PLT calls out of range (>8 MiB padding) — thunks required. +# RUN: llvm-mc -filetype=obj \ +# RUN: -triple=hexagon-unknown-elf main-large.s -o main-large.o +# RUN: ld.lld main-large.o external.so -o test-large +# RUN: llvm-objdump -d --no-show-raw-insn test-large | \ +# RUN: FileCheck --check-prefix=OUTRANGE %s ## Test thunk range scenarios for Hexagon R_HEX_PLT_B22_PCREL relocations. -## PLT calls use the same ±8MB range as regular calls but go through PLT entries. -## This test verifies thunk generation for PLT calls at range boundaries. +## PLT calls use the same +/- 8 MiB range as regular B22_PCREL calls. +## When the PLT entry is beyond this range, a thunk must be created. #--- external.s -.globl extern_within_range, extern_beyond_range, extern_close -.type extern_within_range, @function -.type extern_beyond_range, @function -.type extern_close, @function - -extern_within_range: - jumpr r31 - -extern_beyond_range: - jumpr r31 - -extern_close: +.globl extern_func +.type extern_func, @function +extern_func: jumpr r31 #--- main.s +## Within-range case: 2 MiB padding keeps PLT entries reachable. .globl _start .type _start, @function _start: - ## Test PLT calls to external functions at various ranges - call extern_within_range@PLT - call extern_beyond_range@PLT - call extern_close@PLT + call extern_func@PLT jumpr r31 .skip 0x200000 -# CHECK: Disassembly of section .text: -# CHECK: <_start>: -# CHECK-NEXT: 2021c: { call 0x220250 } -# CHECK-NEXT: { call 0x220260 } -# CHECK-NEXT: { call 0x220270 } -# CHECK-NEXT: { jumpr r31 } +#--- main-large.s +## Out-of-range case: >8 MiB padding pushes PLT entries beyond B22_PCREL range. +.globl _start +.type _start, @function +_start: + call extern_func@PLT + jumpr r31 -## Verify PLT header and entries are created with exact addresses -# CHECK: Disassembly of section .plt: -# CHECK: <.plt>: -# CHECK-NEXT: 220230: { immext(#0x20080) -# CHECK-NEXT: r28 = add(pc,##0x200b8) } -# CHECK-NEXT: { r14 -= add(r28,#0x10) -# CHECK-NEXT: r15 = memw(r28+#0x8) -# CHECK-NEXT: r28 = memw(r28+#0x4) } -# CHECK-NEXT: { r14 = asr(r14,#0x2) -# CHECK-NEXT: jumpr r28 } -# CHECK-NEXT: { trap0(#0xdb) } +.skip 0x900000 -# CHECK: : -# CHECK-NEXT: 220250: { immext(#0x20080) -# CHECK-NEXT: r14 = add(pc,##0x200a8) } -# CHECK-NEXT: { r28 = memw(r14+#0x0) } -# CHECK-NEXT: { jumpr r28 } +## Within-range: _start calls the PLT entry directly (no thunk). +# INRANGE: <_start>: +# INRANGE-NEXT: 201ac: { call 0x2201e0 } +# INRANGE-NEXT: { jumpr r31 } -# CHECK: : -# CHECK-NEXT: 220260: { immext(#0x20080) -# CHECK-NEXT: r14 = add(pc,##0x2009c) } -# CHECK-NEXT: { r28 = memw(r14+#0x0) } -# CHECK-NEXT: { jumpr r28 } +## Out-of-range: thunk uses immext+jump to reach the PLT entry. +# OUTRANGE: <__hexagon_thunk_extern_func_from_.text.thunk>: +# OUTRANGE-NEXT: 201ac: { immext(#0x900000) +# OUTRANGE-NEXT: jump 0x9201e0 } -# CHECK: : -# CHECK-NEXT: 220270: { immext(#0x20080) -# CHECK-NEXT: r14 = add(pc,##0x20090) } -# CHECK-NEXT: { r28 = memw(r14+#0x0) } -# CHECK-NEXT: { jumpr r28 } +## _start calls the thunk instead of the PLT entry directly. +# OUTRANGE: <_start>: +# OUTRANGE-NEXT: 201b4: { call 0x201ac <__hexagon_thunk_extern_func_from_.text.thunk> } +# OUTRANGE-NEXT: { jumpr r31 } diff --git a/lld/test/ELF/hexagon-thunks-packets.s b/lld/test/ELF/hexagon-thunks-packets.s index c8aaad4341ff..6d4a19c3bfcf 100644 --- a/lld/test/ELF/hexagon-thunks-packets.s +++ b/lld/test/ELF/hexagon-thunks-packets.s @@ -15,18 +15,9 @@ # CHECK: Disassembly of section .text: -# CHECK-NONPIC: 000200b4 <__hexagon_thunk_myfn_a_from_.text.thunk>: -# CHECK-NONPIC: { immext(#0x1000040) -# CHECK-NONPIC: jump 0x1020110 } - -# CHECK-PIC: 00010150 <__hexagon_thunk_myfn_a_from_.text.thunk>: -# CHECK-PIC-NEXT: { immext(#0x1000040) -# CHECK-PIC-NEXT: r14 = add(pc,##0x1000060) } -# CHECK-PIC-NEXT: { jumpr r14 } - -# CHECK-NONPIC: 000200bc : +# CHECK-NONPIC: 000200b4 : # CHECK-NONPIC: { jumpr r31 } -# CHECK-PIC: 0001015c : +# CHECK-PIC: 00010150 : # CHECK-PIC: { jumpr r31 } .globl myfn_b .type myfn_b, @function @@ -34,47 +25,47 @@ myfn_b: jumpr r31 .size myfn_b, .-myfn_b -# CHECK-PIC: 00010160
: +# CHECK-PIC: 00010154
: .globl main .type main, @function main: { r0 = #0 call myfn_a } -# CHECK-PIC: { call 0x10150 <__hexagon_thunk_myfn_a_from_.text.thunk> -# CHECK-NONPIC: { call 0x200b4 <__hexagon_thunk_myfn_a_from_.text.thunk> +# CHECK-PIC: { call 0x101a4 <__hexagon_thunk_myfn_a_from_.text.thunk> +# CHECK-NONPIC: { call 0x20108 <__hexagon_thunk_myfn_a_from_.text.thunk> # CHECK-NEXT: r0 = #0x0 } call myfn_a -# CHECK-PIC: call 0x10150 <__hexagon_thunk_myfn_a_from_.text.thunk> -# CHECK-NONPIC: call 0x200b4 <__hexagon_thunk_myfn_a_from_.text.thunk> +# CHECK-PIC: call 0x101a4 <__hexagon_thunk_myfn_a_from_.text.thunk> +# CHECK-NONPIC: call 0x20108 <__hexagon_thunk_myfn_a_from_.text.thunk> call myfn_b -# CHECK-PIC-NEXT: call 0x1015c -# CHECK-NONPIC-NEXT: call 0x200bc +# CHECK-PIC-NEXT: call 0x10150 +# CHECK-NONPIC-NEXT: call 0x200b4 { r2 = add(r0, r1) if (p0) call #myfn_b if (!p0) call #myfn_a } -# CHECK-PIC-NEXT: { if (p0) call 0x1015c -# CHECK-PIC-NEXT: if (!p0) call 0x10150 <__hexagon_thunk_myfn_a_from_.text.thunk> -# CHECK-NONPIC-NEXT: { if (p0) call 0x200bc -# CHECK-NONPIC-NEXT: if (!p0) call 0x200b4 <__hexagon_thunk_myfn_a_from_.text.thunk> +# CHECK-PIC-NEXT: { if (p0) call 0x10150 +# CHECK-PIC-NEXT: if (!p0) call 0x101a4 <__hexagon_thunk_myfn_a_from_.text.thunk> +# CHECK-NONPIC-NEXT: { if (p0) call 0x200b4 +# CHECK-NONPIC-NEXT: if (!p0) call 0x20108 <__hexagon_thunk_myfn_a_from_.text.thunk> # CHECK-NEXT: r2 = add(r0,r1) } { r2 = add(r0, r1) if (p0) call #myfn_a if (!p0) call #myfn_a } -# CHECK-PIC-NEXT: { if (p0) call 0x10150 <__hexagon_thunk_myfn_a_from_.text.thunk> -# CHECK-PIC-NEXT: if (!p0) call 0x10150 <__hexagon_thunk_myfn_a_from_.text.thunk> -# CHECK-NONPIC-NEXT: { if (p0) call 0x200b4 <__hexagon_thunk_myfn_a_from_.text.thunk> -# CHECK-NONPIC-NEXT: if (!p0) call 0x200b4 <__hexagon_thunk_myfn_a_from_.text.thunk> +# CHECK-PIC-NEXT: { if (p0) call 0x101a4 <__hexagon_thunk_myfn_a_from_.text.thunk> +# CHECK-PIC-NEXT: if (!p0) call 0x101a4 <__hexagon_thunk_myfn_a_from_.text.thunk> +# CHECK-NONPIC-NEXT: { if (p0) call 0x20108 <__hexagon_thunk_myfn_a_from_.text.thunk> +# CHECK-NONPIC-NEXT: if (!p0) call 0x20108 <__hexagon_thunk_myfn_a_from_.text.thunk> # CHECK-NEXT: r2 = add(r0,r1) } { r2 = add(r0, r1) r1 = r4 r4 = r5 if (r0 == #0) jump:t #myfn_a } -# CHECK-PIC-NEXT: { if (r0==#0) jump:t 0x10150 -# CHECK-NONPIC-NEXT: { if (r0==#0) jump:t 0x200b4 +# CHECK-PIC-NEXT: { if (r0==#0) jump:t 0x101a4 +# CHECK-NONPIC-NEXT: { if (r0==#0) jump:t 0x20108 # CHECK-NEXT: r2 = add(r0,r1) # CHECK-NEXT: r1 = r4; r4 = r5 } @@ -82,19 +73,19 @@ main: r4 = r5 if (r0 <= #0) jump:t #myfn_a p1 = cmp.eq(r0, #0); if (p1.new) jump:nt #myfn_a } -# CHECK-NONPIC-NEXT: { if (r0<=#0) jump:t 0x200b4 -# CHECK-NONPIC-NEXT: p1 = cmp.eq(r0,#0x0); if (p1.new) jump:nt 0x200b4 <__hexagon_thunk_myfn_a_from_.text.thunk> -# CHECK-PIC-NEXT: { if (r0<=#0) jump:t 0x10150 -# CHECK-PIC-NEXT: p1 = cmp.eq(r0,#0x0); if (p1.new) jump:nt 0x10150 <__hexagon_thunk_myfn_a_from_.text.thunk> +# CHECK-NONPIC-NEXT: { if (r0<=#0) jump:t 0x20108 +# CHECK-NONPIC-NEXT: p1 = cmp.eq(r0,#0x0); if (p1.new) jump:nt 0x20108 <__hexagon_thunk_myfn_a_from_.text.thunk> +# CHECK-PIC-NEXT: { if (r0<=#0) jump:t 0x101a4 +# CHECK-PIC-NEXT: p1 = cmp.eq(r0,#0x0); if (p1.new) jump:nt 0x101a4 <__hexagon_thunk_myfn_a_from_.text.thunk> # CHECK-NEXT: r2 = add(r0,r1) # CHECK-NEXT: r4 = r5 } {r0 = #0; jump #myfn_a} -# CHECK-PIC-NEXT: { r0 = #0x0 ; jump 0x10150 <__hexagon_thunk_myfn_a_from_.text.thunk> } -# CHECK-NONPIC-NEXT: { r0 = #0x0 ; jump 0x200b4 <__hexagon_thunk_myfn_a_from_.text.thunk> } +# CHECK-PIC-NEXT: { r0 = #0x0 ; jump 0x101a4 <__hexagon_thunk_myfn_a_from_.text.thunk> } +# CHECK-NONPIC-NEXT: { r0 = #0x0 ; jump 0x20108 <__hexagon_thunk_myfn_a_from_.text.thunk> } {r0 = #0; jump #myfn_b} -# CHECK-PIC-NEXT: { r0 = #0x0 ; jump 0x1015c } -# CHECK-NONPIC-NEXT: { r0 = #0x0 ; jump 0x200bc } +# CHECK-PIC-NEXT: { r0 = #0x0 ; jump 0x10150 } +# CHECK-NONPIC-NEXT: { r0 = #0x0 ; jump 0x200b4 } jumpr r31 .size main, .-main @@ -108,15 +99,28 @@ myfn_a: jumpr r31 .size myfn_a, .-myfn_a +# CHECK-NONPIC: 00020108 <__hexagon_thunk_myfn_a_from_.text.thunk>: +# CHECK-NONPIC-NEXT: { immext(#0x1000000) +# CHECK-NONPIC-NEXT: jump 0x1020110 } + +# CHECK-PIC: 000101a4 <__hexagon_thunk_myfn_a_from_.text.thunk>: +# CHECK-PIC-NEXT: { immext(#0x1000000) +# CHECK-PIC-NEXT: r14 = add(pc,##0x100000c) } +# CHECK-PIC-NEXT: { jumpr r14 } + # CHECK-NONPIC: 01020110 : # CHECK-NONPIC-NEXT: { r0 = #0x0 ; jump 0x1020118 <__hexagon_thunk_myfn_b_from_.text.thunk> } # CHECK-NONPIC-NEXT: { jumpr r31 } # CHECK-NONPIC: 01020118 <__hexagon_thunk_myfn_b_from_.text.thunk>: # CHECK-NONPIC-NEXT: { immext(#0xfeffff80) -# CHECK-NONPIC-NEXT: jump 0x200bc } +# CHECK-NONPIC-NEXT: jump 0x200b4 } + +# CHECK-PIC: 010101b0 : +# CHECK-PIC-NEXT: { r0 = #0x0 ; jump 0x10101b8 <__hexagon_thunk_myfn_b_from_.text.thunk> } +# CHECK-PIC-NEXT: { jumpr r31 } # CHECK-PIC: 010101b8 <__hexagon_thunk_myfn_b_from_.text.thunk>: # CHECK-PIC-NEXT: { immext(#0xfeffff80) -# CHECK-PIC-NEXT: r14 = add(pc,##0xfeffffa4) } +# CHECK-PIC-NEXT: r14 = add(pc,##0xfeffff98) } # CHECK-PIC-NEXT: { jumpr r14 } diff --git a/lld/test/ELF/hexagon-thunks.s b/lld/test/ELF/hexagon-thunks.s index 211074e1784b..9f6cdbd60392 100644 --- a/lld/test/ELF/hexagon-thunks.s +++ b/lld/test/ELF/hexagon-thunks.s @@ -29,19 +29,17 @@ myfn: # CHECK: Disassembly of section .text_low: -# CHECK: <__hexagon_thunk_myfn_from_.text.thunk>: -# CHECK-NONPIC-NEXT: 200b4: { immext(#0x1000000) -# CHECK-NONPIC-NEXT: jump 0x10200bc } -# CHECK-PIC-NEXT: 200b4: { immext(#0x1000000) -# CHECK-PIC-NEXT: r14 = add(pc,##0x1000008) } -# CHECK-PIC-NEXT: { jumpr r14 } - -# CHECK-NONPIC:
: -# CHECK-NONPIC-NEXT: 200bc: { call 0x200b4 <__hexagon_thunk_myfn_from_.text.thunk> } -# CHECK-PIC:
: -# CHECK-PIC-NEXT: 200c0: { call 0x200b4 <__hexagon_thunk_myfn_from_.text.thunk> } +# CHECK:
: +# CHECK-NEXT: 200b4: { call 0x200bc <__hexagon_thunk_myfn_from_.text.thunk> } # CHECK-NEXT: { jumpr r31 } +# CHECK: <__hexagon_thunk_myfn_from_.text.thunk>: +# CHECK-NONPIC-NEXT: 200bc: { immext(#0x1000000) +# CHECK-NONPIC-NEXT: jump 0x10200bc } +# CHECK-PIC-NEXT: 200bc: { immext(#0x1000000) +# CHECK-PIC-NEXT: r14 = add(pc,##0x1000000) } +# CHECK-PIC-NEXT: { jumpr r14 } + # CHECK: Disassembly of section .text_high: # CHECK: : # CHECK-NEXT: 10200bc: { jumpr r31 }