# RUN: llc -verify-machineinstrs -mtriple=aarch64-none-linux-gnu \ # RUN: -start-before aarch64-sls-hardening -o - %s \ # RUN: -asm-verbose=0 \ # RUN: | FileCheck %s \ # RUN: --implicit-check-not=__llvm_slsblr_thunk_aa_x5_x8 \ # RUN: --implicit-check-not=__llvm_slsblr_thunk_ab_x5_x8 \ # RUN: --implicit-check-not=__llvm_slsblr_thunk_aaz_x5 \ # RUN: --implicit-check-not=__llvm_slsblr_thunk_abz_x5 # Pointer Authentication extension introduces more branch-with-link-to-register # instructions for the BLR SLS hardening to handle, namely BLRAA, BLRAB, BLRAAZ # and BLRABZ. Unlike the non-authenticating BLR instruction, BLRAA and BLRAB # accept two register operands (almost 900 combinations for each instruction). # For that reason, it is not practical to create all possible thunks. # Check that the BLR SLS hardening transforms BLRA* instructions into # unconditional BL calls to the correct thunk functions. # Check that only relevant thunk functions are generated. --- | define void @test_instructions() #0 { entry: ret void } define void @test_no_redef() #0 { entry: ret void } define void @test_regs() #0 { entry: ret void } attributes #0 = { "target-features"="+pauth,+harden-sls-blr" } ... # Test that all BLRA* instructions are handled. --- name: test_instructions tracksRegLiveness: true body: | bb.0.entry: liveins: $lr, $x0, $x1, $x2, $x3 BLRAA $x0, $x1, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 BLRAB $x1, $x2, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 BLRAAZ $x2, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 BLRABZ $x3, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 RET undef $lr ... # Test that the same thunk function is not created twice. --- name: test_no_redef tracksRegLiveness: true body: | bb.0.entry: liveins: $lr, $x0, $x1, $x2, $x3, $x4 ; thunk used by @test_instructions BLRAB $x1, $x2, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 ; thunk used by this function twice BLRAB $x3, $x4, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 BLRAB $x3, $x4, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 RET undef $lr ... # Test that all xN registers (except x16, x17, x30 and xzr) are handled. --- name: test_regs tracksRegLiveness: true body: | bb.0.entry: liveins: $lr, $x0, $x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17, $x18, $x19, $x20, $x21, $x22, $x23, $x24, $x25, $x26, $x27, $x28, $fp BLRAA $x0, $x1, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 BLRAA $x2, $x3, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 BLRAA $x4, $x5, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 BLRAA $x6, $x7, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 BLRAA $x8, $x9, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 BLRAA $x10, $x11, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 BLRAA $x12, $x13, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 BLRAA $x14, $x15, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 ; skipping x16 and x17 BLRAA $x18, $x19, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 BLRAA $x20, $x21, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 BLRAA $x22, $x23, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 BLRAA $x24, $x25, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 BLRAA $x26, $x27, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 BLRAA $x28, $fp, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 RET undef $lr ... # CHECK-LABEL: test_instructions: # CHECK-NEXT: .cfi_startproc # CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x0_x1 # CHECK-NEXT: bl __llvm_slsblr_thunk_ab_x1_x2 # CHECK-NEXT: bl __llvm_slsblr_thunk_aaz_x2 # CHECK-NEXT: bl __llvm_slsblr_thunk_abz_x3 # CHECK-NEXT: ret # CHECK-LABEL: test_no_redef: # CHECK-NEXT: .cfi_startproc # CHECK-NEXT: bl __llvm_slsblr_thunk_ab_x1_x2 # CHECK-NEXT: bl __llvm_slsblr_thunk_ab_x3_x4 # CHECK-NEXT: bl __llvm_slsblr_thunk_ab_x3_x4 # CHECK-NEXT: ret # CHECK-LABEL: test_regs: # CHECK-NEXT: .cfi_startproc # CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x0_x1 # CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x2_x3 # CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x4_x5 # CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x6_x7 # CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x8_x9 # CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x10_x11 # CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x12_x13 # CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x14_x15 # skipping x16 and x17 # CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x18_x19 # CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x20_x21 # CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x22_x23 # CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x24_x25 # CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x26_x27 # CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x28_x29 # CHECK-NEXT: ret # CHECK-LABEL: __llvm_slsblr_thunk_aa_x0_x1: # CHECK-NEXT: mov x16, x0 # CHECK-NEXT: braa x16, x1 # CHECK-NEXT: dsb sy # CHECK-NEXT: isb # CHECK-LABEL: __llvm_slsblr_thunk_ab_x1_x2: # CHECK-NEXT: mov x16, x1 # CHECK-NEXT: brab x16, x2 # CHECK-NEXT: dsb sy # CHECK-NEXT: isb # CHECK-LABEL: __llvm_slsblr_thunk_aaz_x2: # CHECK-NEXT: mov x16, x2 # CHECK-NEXT: braaz x16 # CHECK-NEXT: dsb sy # CHECK-NEXT: isb # CHECK-LABEL: __llvm_slsblr_thunk_abz_x3: # CHECK-NEXT: mov x16, x3 # CHECK-NEXT: brabz x16 # CHECK-NEXT: dsb sy # CHECK-NEXT: isb # The instruction *operands* should correspond to the thunk function *name* # (check that the name is parsed correctly when populating the thunk). # CHECK-LABEL: __llvm_slsblr_thunk_aa_x2_x3: # CHECK-NEXT: mov x16, x2 # CHECK: braa x16, x3 # CHECK-LABEL: __llvm_slsblr_thunk_aa_x4_x5: # CHECK-NEXT: mov x16, x4 # CHECK: braa x16, x5 # CHECK-LABEL: __llvm_slsblr_thunk_aa_x6_x7: # CHECK-NEXT: mov x16, x6 # CHECK: braa x16, x7 # CHECK-LABEL: __llvm_slsblr_thunk_aa_x8_x9: # CHECK-NEXT: mov x16, x8 # CHECK: braa x16, x9 # CHECK-LABEL: __llvm_slsblr_thunk_aa_x10_x11: # CHECK-NEXT: mov x16, x10 # CHECK: braa x16, x11 # CHECK-LABEL: __llvm_slsblr_thunk_aa_x12_x13: # CHECK-NEXT: mov x16, x12 # CHECK: braa x16, x13 # CHECK-LABEL: __llvm_slsblr_thunk_aa_x14_x15: # CHECK-NEXT: mov x16, x14 # CHECK: braa x16, x15 # skipping x16 and x17 # CHECK-LABEL: __llvm_slsblr_thunk_aa_x18_x19: # CHECK-NEXT: mov x16, x18 # CHECK: braa x16, x19 # CHECK-LABEL: __llvm_slsblr_thunk_aa_x20_x21: # CHECK-NEXT: mov x16, x20 # CHECK: braa x16, x21 # CHECK-LABEL: __llvm_slsblr_thunk_aa_x22_x23: # CHECK-NEXT: mov x16, x22 # CHECK: braa x16, x23 # CHECK-LABEL: __llvm_slsblr_thunk_aa_x24_x25: # CHECK-NEXT: mov x16, x24 # CHECK: braa x16, x25 # CHECK-LABEL: __llvm_slsblr_thunk_aa_x26_x27: # CHECK-NEXT: mov x16, x26 # CHECK: braa x16, x27 # CHECK-LABEL: __llvm_slsblr_thunk_aa_x28_x29: # CHECK-NEXT: mov x16, x28 # CHECK: braa x16, x29