blob: 0cd55682d7cb2a65a953845b82db2dfba6756678 [file] [edit]
; RUN: llc -mtriple=aarch64-windows -verify-machineinstrs %s -o - | FileCheck %s --check-prefixes=CHECK,HINT
; RUN: llc -mtriple=aarch64-windows -mattr=+pauth -verify-machineinstrs %s -o - | FileCheck %s --check-prefixes=CHECK,PAUTH
; RUN: llc -mtriple=aarch64-windows -filetype=obj %s -o %t.obj
; RUN: llvm-readobj --unwind %t.obj | FileCheck %s --check-prefix=UNWIND
; When a tail call, or a return from a function with callee-popped stack
; arguments, changes the stack argument size, the epilogue doesn't leave SP at
; its value on entry. The Windows unwinder applies the pac_sign_lr unwind code
; using whatever SP it has at that point, which wouldn't be the SP that the
; return address was signed with, so the return address is authenticated before
; the epilogue starts, where the prologue's unwind codes still apply, and the
; authenticated return address stays in LR rather than being restored by
; the epilogue. Its unwind codes then have no pac_sign_lr.
declare swifttailcc void @callee12(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64)
declare swifttailcc void @callee1(i64)
declare void @use(ptr)
declare void @clobber()
; In each function below, the prologue signs the return address with pacibsp.
; The return address is then authenticated against the SP it was signed with
; (computed into x16) before the epilogue starts, and the epilogue itself
; neither authenticates nor restores LR. The authentication is a single
; autib with PAuth, or a sequence through x17 in hint space without.
; CHECK-LABEL: pac_grow:
; HINT: hint #27
; PAUTH: pacibsp
; CHECK-NEXT: .seh_pac_sign_lr
; CHECK: .seh_endprologue
; HINT: ldr x17, [sp]
; PAUTH: ldr x30, [sp]
; CHECK: add x16, sp, #48
; HINT: hint #14
; HINT-NEXT: mov x30, x17
; PAUTH: autib x30, x16
; CHECK: .seh_startepilogue
; CHECK-NOT: x30
; CHECK-NOT: .seh_pac_sign_lr
; CHECK: add sp, sp, #16
; CHECK: .seh_end_c
; CHECK-NEXT: .seh_stackalloc 32
; CHECK-NEXT: .seh_endepilogue
; CHECK-NEXT: b callee12
define swifttailcc void @pac_grow(i64 %a) "sign-return-address"="all" {
call void @clobber()
musttail call swifttailcc void @callee12(i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a)
ret void
}
; This function receives stack arguments the tail callee doesn't take.
; CHECK-LABEL: pac_shrink:
; HINT: hint #27
; PAUTH: pacibsp
; CHECK-NEXT: .seh_pac_sign_lr
; CHECK: .seh_endprologue
; HINT: ldr x17, [sp]
; PAUTH: ldr x30, [sp]
; CHECK: add x16, sp, #16
; HINT: hint #14
; HINT-NEXT: mov x30, x17
; PAUTH: autib x30, x16
; CHECK: .seh_startepilogue
; CHECK-NOT: x30
; CHECK-NOT: .seh_pac_sign_lr
; CHECK: add sp, sp, #32
; CHECK: .seh_endepilogue
; CHECK-NEXT: b callee1
define swifttailcc void @pac_shrink(i64 %a, i64, i64, i64, i64, i64, i64, i64, i64, i64) "sign-return-address"="all" {
call void @clobber()
musttail call swifttailcc void @callee1(i64 %a)
ret void
}
; Callee-popped stack arguments, with a normal return.
; CHECK-LABEL: pac_ret:
; HINT: hint #27
; PAUTH: pacibsp
; CHECK-NEXT: .seh_pac_sign_lr
; CHECK: .seh_endprologue
; HINT: ldr x17, [sp]
; PAUTH: ldr x30, [sp]
; CHECK: add x16, sp, #16
; HINT: hint #14
; HINT-NEXT: mov x30, x17
; PAUTH: autib x30, x16
; CHECK: .seh_startepilogue
; CHECK-NOT: x30
; CHECK-NOT: .seh_pac_sign_lr
; CHECK: add sp, sp, #32
; CHECK: .seh_endepilogue
; CHECK-NEXT: ret
define swifttailcc void @pac_ret(i64 %a, i64, i64, i64, i64, i64, i64, i64, i64, i64) "sign-return-address"="all" {
call void @clobber()
ret void
}
; With dynamic allocation, the frame record is found using the frame pointer.
; CHECK-LABEL: pac_alloca:
; HINT: hint #27
; PAUTH: pacibsp
; CHECK-NEXT: .seh_pac_sign_lr
; CHECK: .seh_endprologue
; HINT: ldr x17, [x29, #8]
; PAUTH: ldr x30, [x29, #8]
; CHECK: add x16, x29, #48
; HINT: hint #14
; HINT-NEXT: mov x30, x17
; PAUTH: autib x30, x16
; CHECK: .seh_startepilogue
; CHECK-NOT: x30
; CHECK-NOT: .seh_pac_sign_lr
; CHECK: mov sp, x29
; CHECK-NEXT: .seh_set_fp
; CHECK: add sp, sp, #16
; CHECK: .seh_end_c
; CHECK-NEXT: .seh_stackalloc 32
; CHECK-NEXT: .seh_endepilogue
; CHECK-NEXT: b callee12
define swifttailcc void @pac_alloca(i64 %a, i64 %n) "sign-return-address"="all" {
%buf = alloca i64, i64 %n
call void @use(ptr %buf)
musttail call swifttailcc void @callee12(i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a)
ret void
}
; The same goes for a stack that is dynamically realigned.
; CHECK-LABEL: pac_align:
; HINT: hint #27
; PAUTH: pacibsp
; CHECK-NEXT: .seh_pac_sign_lr
; CHECK: .seh_endprologue
; HINT: ldr x17, [x29, #8]
; PAUTH: ldr x30, [x29, #8]
; CHECK: add x16, x29, #48
; HINT: hint #14
; HINT-NEXT: mov x30, x17
; PAUTH: autib x30, x16
; CHECK: .seh_startepilogue
; CHECK-NOT: x30
; CHECK-NOT: .seh_pac_sign_lr
; CHECK: mov sp, x29
; CHECK-NEXT: .seh_set_fp
; CHECK: add sp, sp, #16
; CHECK: .seh_end_c
; CHECK-NEXT: .seh_stackalloc 32
; CHECK-NEXT: .seh_endepilogue
; CHECK-NEXT: b callee12
define swifttailcc void @pac_align(i64 %a) "sign-return-address"="all" {
%buf = alloca [4 x i64], align 64
call void @use(ptr %buf)
musttail call swifttailcc void @callee12(i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a)
ret void
}
; The return address is paired with another register, and not at offset 0.
; CHECK-LABEL: pac_csr:
; HINT: hint #27
; PAUTH: pacibsp
; CHECK-NEXT: .seh_pac_sign_lr
; CHECK: stp x25, x30, [sp, #32]
; CHECK-NEXT: .seh_save_lrpair x25, 32
; CHECK: .seh_endprologue
; HINT: ldr x17, [sp, #40]
; PAUTH: ldr x30, [sp, #40]
; CHECK: add x16, sp, #96
; HINT: hint #14
; HINT-NEXT: mov x30, x17
; PAUTH: autib x30, x16
; CHECK: .seh_startepilogue
; CHECK-NOT: x30
; CHECK-NOT: .seh_pac_sign_lr
; CHECK: ldr x25, [sp, #32]
; CHECK: add sp, sp, #64
; CHECK: .seh_end_c
; CHECK-NEXT: .seh_stackalloc 32
; CHECK-NEXT: .seh_endepilogue
; CHECK-NEXT: b callee12
define swifttailcc void @pac_csr(i64 %a) "sign-return-address"="all" {
call void asm sideeffect "", "~{x19},~{x21},~{x23},~{x24},~{x25},~{d8},~{d9}"()
call void @clobber()
musttail call swifttailcc void @callee12(i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a)
ret void
}
; The return address is never spilled, so it is still in LR. The epilogue
; has no instructions, but its unwind codes still pop the tail callee's
; arguments.
; CHECK-LABEL: pac_leaf:
; HINT: hint #27
; PAUTH: pacibsp
; CHECK-NEXT: .seh_pac_sign_lr
; CHECK: .seh_endprologue
; HINT: mov x17, x30
; CHECK: add x16, sp, #32
; HINT: hint #14
; HINT-NEXT: mov x30, x17
; PAUTH: autib x30, x16
; CHECK: .seh_startepilogue
; CHECK-NEXT: .seh_end_c
; CHECK-NEXT: .seh_stackalloc 32
; CHECK-NEXT: .seh_endepilogue
; CHECK-NEXT: b callee12
define swifttailcc void @pac_leaf(i64 %a) "sign-return-address"="all" {
musttail call swifttailcc void @callee12(i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a)
ret void
}
; The prologue's unwind codes still have pac_sign_lr; the epilogue's don't, and
; they don't restore LR either, as the authenticated return address stays in LR.
; UNWIND-LABEL: Function: pac_grow (
; UNWIND: Prologue [
; UNWIND: pacibsp
; UNWIND: ]
; UNWIND-NEXT: EpilogueScopes [
; UNWIND-NEXT: EpilogueScope {
; UNWIND: Opcodes [
; UNWIND-NEXT: add sp, #16
; UNWIND-NEXT: end_c
; UNWIND-NEXT: add sp, #32
; UNWIND-NEXT: end
; UNWIND-NEXT: ]
; UNWIND-LABEL: Function: pac_shrink (
; UNWIND: Epilogue [
; UNWIND-NEXT: add sp, #32
; UNWIND-NEXT: end
; UNWIND-NEXT: ]
; UNWIND-LABEL: Function: pac_ret (
; UNWIND: Epilogue [
; UNWIND-NEXT: add sp, #32
; UNWIND-NEXT: end
; UNWIND-NEXT: ]
; UNWIND-LABEL: Function: pac_alloca (
; UNWIND: Opcodes [
; UNWIND-NEXT: mov sp, fp
; UNWIND-NEXT: ldr x29, [sp, #0]
; UNWIND-NEXT: add sp, #16
; UNWIND-NEXT: end_c
; UNWIND-NEXT: add sp, #32
; UNWIND-NEXT: end
; UNWIND-NEXT: ]
; UNWIND-LABEL: Function: pac_align (
; UNWIND: Opcodes [
; UNWIND-NEXT: mov sp, fp
; UNWIND-NEXT: ldr x29, [sp, #0]
; UNWIND-NEXT: add sp, #16
; UNWIND-NEXT: end_c
; UNWIND-NEXT: add sp, #32
; UNWIND-NEXT: end
; UNWIND-NEXT: ]
; UNWIND-LABEL: Function: pac_csr (
; UNWIND: Opcodes [
; UNWIND-NEXT: ldp d8, d9, [sp, #48]
; UNWIND-NEXT: ldr x25, [sp, #32]
; UNWIND-NEXT: ldp x23, x24, [sp, #16]
; UNWIND-NEXT: ldr x21, [sp, #8]
; UNWIND-NEXT: ldr x19, [sp, #0]
; UNWIND-NEXT: add sp, #64
; UNWIND-NEXT: end_c
; UNWIND-NEXT: add sp, #32
; UNWIND-NEXT: end
; UNWIND-NEXT: ]
; The epilogue has no instructions of its own here, as the tail callee's
; arguments take all of the frame, but its unwind codes must still pop the
; callee's arguments after end_c. They replace the prologue's, which would
; authenticate the return address again.
declare swifttailcc void @callee15(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64)
; CHECK-LABEL: pac_leaf_grow:
; CHECK: .seh_endprologue
; CHECK: .seh_startepilogue
; CHECK-NEXT: .seh_end_c
; CHECK-NEXT: .seh_stackalloc 64
; CHECK-NEXT: .seh_endepilogue
; CHECK-NEXT: b callee15
define swifttailcc void @pac_leaf_grow(i64 %a, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64) "sign-return-address"="all" {
musttail call swifttailcc void @callee15(i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a, i64 %a)
ret void
}
; UNWIND-LABEL: Function: pac_leaf_grow (
; UNWIND: Opcodes [
; UNWIND-NEXT: end_c
; UNWIND-NEXT: add sp, #64
; UNWIND-NEXT: end
; UNWIND-NEXT: ]