// REQUIRES: aarch64
// RUN: split-file %s %t
// RUN: llvm-mc -filetype=obj -triple=aarch64 %t/asm -o %t.o
// RUN: ld.lld --script %t/lds --shared %t.o -o %t.so 2>&1
// RUN: llvm-objdump -d --no-show-raw-insn --print-imm-hex %t.so | FileCheck %s

// Check that Position Independent thunks are generated for shared libraries.

//--- asm
 .section .text_low, "ax", %progbits
 .globl low_target
 .type low_target, %function
low_target:
 // Need thunk to high_target@plt
 bl high_target
 ret
// CHECK: <low_target>:
// CHECK-NEXT:       d8:       bl      0xec <__AArch64ADRPThunk_high_target>
// CHECK-NEXT:                 ret

 .hidden low_target2
 .globl low_target2
 .type low_target2, %function
low_target2:
 // Need thunk to high_target2
 bl high_target2
 // .text_high+8 = high_target2
 bl .text_high+8
 ret
// CHECK: <low_target2>:
// CHECK-NEXT:       e0:       bl      0xf8 <__AArch64ADRPThunk_high_target2>
// CHECK-NEXT:       e4:       bl      0x104 <__AArch64ADRPThunk_>
// CHECK-NEXT:                 ret

// Expect range extension thunks for .text_low
// adrp calculation is (PC + signed immediate) & (!0xfff)
// CHECK: <__AArch64ADRPThunk_high_target>:
// CHECK-NEXT:       ec:       adrp    x16, #0x10000000
// CHECK-NEXT:                 add     x16, x16, #0x40
// CHECK-NEXT:                 br      x16
// CHECK: <__AArch64ADRPThunk_high_target2>:
// CHECK-NEXT:       f8:       adrp    x16, #0x10000000
// CHECK-NEXT:                 add     x16, x16, #0x8
// CHECK-NEXT:                 br      x16
/// Identical to the previous one, but for the target .text_high+8.
// CHECK: <__AArch64ADRPThunk_>:
// CHECK-NEXT:      104:       adrp    x16, #0x10000000
// CHECK-NEXT:                 add     x16, x16, #0x8
// CHECK-NEXT:                 br      x16


 .section .text_high, "ax", %progbits
 .globl high_target
 .type high_target, %function
high_target:
 // No thunk needed as we can reach low_target@plt
 bl low_target
 ret
// CHECK: <high_target>:
// CHECK-NEXT: 10000000:       bl 0x10000050 <low_target@plt>
// CHECK-NEXT:                 ret

 .hidden high_target2
 .globl high_target2
 .type high_target2, %function
high_target2:
 // Need thunk to low_target
 bl low_target2
 ret
// CHECK: <high_target2>:
// CHECK-NEXT: 10000008:       bl      0x10000010 <__AArch64ADRPThunk_low_target2>
// CHECK-NEXT:                 ret

// Expect Thunk for .text.high

// CHECK: <__AArch64ADRPThunk_low_target2>:
// CHECK-NEXT: 10000010:       adrp    x16, #-0x10000000
// CHECK-NEXT:                 add     x16, x16, #0xe0
// CHECK-NEXT:                 br      x16

// CHECK: Disassembly of section .plt:
// CHECK-EMPTY:
// CHECK-NEXT: <.plt>:
// CHECK-NEXT: 10000020:       stp     x16, x30, [sp, #-0x10]!
// CHECK-NEXT:                 adrp    x16, #0
// CHECK-NEXT:                 ldr     x17, [x16, #0x120]
// CHECK-NEXT:                 add     x16, x16, #0x120
// CHECK-NEXT:                 br      x17
// CHECK-NEXT:                 nop
// CHECK-NEXT:                 nop
// CHECK-NEXT:                 nop
// CHECK-EMPTY:
// CHECK-NEXT:   <high_target@plt>:
// CHECK-NEXT: 10000040:       adrp    x16, #0x0
// CHECK-NEXT:                 ldr     x17, [x16, #0x128]
// CHECK-NEXT:                 add     x16, x16, #0x128
// CHECK-NEXT:                 br      x17
// CHECK-EMPTY:
// CHECK-NEXT:   <low_target@plt>:
// CHECK-NEXT: 10000050:       adrp    x16, #0x0
// CHECK-NEXT:                 ldr     x17, [x16, #0x130]
// CHECK-NEXT:                 add     x16, x16, #0x130
// CHECK-NEXT:                 br      x17

//--- lds
PHDRS {
  low PT_LOAD FLAGS(0x1 | 0x4);
  high PT_LOAD FLAGS(0x1 | 0x4);
}
SECTIONS {
  .text_low : { *(.text_low) } :low
  .text_high 0x10000000 : { *(.text_high) } :high
}
