1; RUN: llc -mattr=harden-sls-retbr,harden-sls-blr -verify-machineinstrs -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,HARDEN,HARDEN-COMDAT,ISBDSB,ISBDSBDAGISEL 2; RUN: llc -mattr=harden-sls-retbr,harden-sls-blr,harden-sls-nocomdat -verify-machineinstrs -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,HARDEN,HARDEN-COMDAT-OFF,ISBDSB,ISBDSBDAGISEL 3; RUN: llc -mattr=harden-sls-retbr,harden-sls-blr -mattr=+sb -verify-machineinstrs -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,HARDEN,SB,SBDAGISEL 4; RUN: llc -global-isel -global-isel-abort=0 -mattr=harden-sls-retbr,harden-sls-blr -verify-machineinstrs -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,HARDEN,HARDEN-COMDAT,ISBDSB 5; RUN: llc -verify-machineinstrs -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,NOHARDEN 6; RUN: llc -global-isel -global-isel-abort=0 -mattr=harden-sls-retbr,harden-sls-blr,harden-sls-nocomdat -verify-machineinstrs -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,HARDEN,HARDEN-COMDAT-OFF,ISBDSB 7; RUN: llc -global-isel -global-isel-abort=0 -mattr=harden-sls-retbr,harden-sls-blr -mattr=+sb -verify-machineinstrs -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,HARDEN,SB 8 9; Function Attrs: norecurse nounwind readnone 10define dso_local i32 @double_return(i32 %a, i32 %b) local_unnamed_addr { 11entry: 12 %cmp = icmp sgt i32 %a, 0 13 br i1 %cmp, label %if.then, label %if.else 14 15if.then: ; preds = %entry 16 %div = sdiv i32 %a, %b 17 ret i32 %div 18 19if.else: ; preds = %entry 20 %div1 = sdiv i32 %b, %a 21 ret i32 %div1 22; CHECK-LABEL: double_return: 23; CHECK: {{ret$}} 24; ISBDSB-NEXT: dsb sy 25; ISBDSB-NEXT: isb 26; SB-NEXT: {{ sb$}} 27; CHECK: {{ret$}} 28; ISBDSB-NEXT: dsb sy 29; ISBDSB-NEXT: isb 30; SB-NEXT: {{ sb$}} 31; CHECK-NEXT: .Lfunc_end 32} 33 34@__const.indirect_branch.ptr = private unnamed_addr constant [2 x ptr] [ptr blockaddress(@indirect_branch, %return), ptr blockaddress(@indirect_branch, %l2)], align 8 35 36; Function Attrs: norecurse nounwind readnone 37define dso_local i32 @indirect_branch(i32 %a, i32 %b, i32 %i) { 38; CHECK-LABEL: indirect_branch: 39entry: 40 %idxprom = sext i32 %i to i64 41 %arrayidx = getelementptr inbounds [2 x ptr], ptr @__const.indirect_branch.ptr, i64 0, i64 %idxprom 42 %0 = load ptr, ptr %arrayidx, align 8 43 indirectbr ptr %0, [label %return, label %l2] 44; CHECK: br x 45; ISBDSB-NEXT: dsb sy 46; ISBDSB-NEXT: isb 47; SB-NEXT: {{ sb$}} 48 49l2: ; preds = %entry 50 br label %return 51; CHECK: {{ret$}} 52; ISBDSB-NEXT: dsb sy 53; ISBDSB-NEXT: isb 54; SB-NEXT: {{ sb$}} 55 56return: ; preds = %entry, %l2 57 %retval.0 = phi i32 [ 1, %l2 ], [ 0, %entry ] 58 ret i32 %retval.0 59; CHECK: {{ret$}} 60; ISBDSB-NEXT: dsb sy 61; ISBDSB-NEXT: isb 62; SB-NEXT: {{ sb$}} 63; CHECK-NEXT: .Lfunc_end 64} 65 66; Check that RETAA and RETAB instructions are also protected as expected. 67define dso_local i32 @ret_aa(i32 returned %a) local_unnamed_addr "target-features"="+neon,+v8.3a" "sign-return-address"="all" "sign-return-address-key"="a_key" { 68entry: 69; CHECK-LABEL: ret_aa: 70; CHECK: {{ retaa$}} 71; ISBDSB-NEXT: dsb sy 72; ISBDSB-NEXT: isb 73; SB-NEXT: {{ sb$}} 74; CHECK-NEXT: .Lfunc_end 75 ret i32 %a 76} 77 78define dso_local i32 @ret_ab(i32 returned %a) local_unnamed_addr "target-features"="+neon,+v8.3a" "sign-return-address"="all" "sign-return-address-key"="b_key" { 79entry: 80; CHECK-LABEL: ret_ab: 81; CHECK: {{ retab$}} 82; ISBDSB-NEXT: dsb sy 83; ISBDSB-NEXT: isb 84; SB-NEXT: {{ sb$}} 85; CHECK-NEXT: .Lfunc_end 86 ret i32 %a 87} 88 89define i32 @asmgoto() { 90entry: 91; CHECK-LABEL: asmgoto: 92 callbr void asm sideeffect "B $0", "!i"() 93 to label %asm.fallthrough [label %d] 94 ; The asm goto above produces a direct branch: 95; CHECK: //APP 96; CHECK-NEXT: {{^[ \t]+b }} 97; CHECK-NEXT: //NO_APP 98 ; For direct branches, no mitigation is needed. 99; ISDDSB-NOT: dsb sy 100; SB-NOT: {{ sb$}} 101 102asm.fallthrough: ; preds = %entry 103 ret i32 0 104; CHECK: {{ret$}} 105; ISBDSB-NEXT: dsb sy 106; ISBDSB-NEXT: isb 107; SB-NEXT: {{ sb$}} 108 109d: ; preds = %asm.fallthrough, %entry 110 ret i32 1 111; CHECK: {{ret$}} 112; ISBDSB-NEXT: dsb sy 113; ISBDSB-NEXT: isb 114; SB-NEXT: {{ sb$}} 115; CHECK-NEXT: .Lfunc_end 116} 117 118define dso_local i32 @indirect_call( 119ptr nocapture %f1, ptr nocapture %f2) { 120entry: 121; CHECK-LABEL: indirect_call: 122 %call = tail call i32 %f1() 123; HARDEN: bl {{__llvm_slsblr_thunk_x[0-9]+$}} 124 %call2 = tail call i32 %f2() 125; HARDEN: bl {{__llvm_slsblr_thunk_x[0-9]+$}} 126 %add = add nsw i32 %call2, %call 127 ret i32 %add 128; CHECK: .Lfunc_end 129} 130 131; verify calling through a function pointer. 132@a = dso_local local_unnamed_addr global ptr null, align 8 133@b = dso_local local_unnamed_addr global i32 0, align 4 134define dso_local void @indirect_call_global() local_unnamed_addr { 135; CHECK-LABEL: indirect_call_global: 136entry: 137 %0 = load ptr, ptr @a, align 8 138 %call = tail call i32 %0() nounwind 139; HARDEN: bl {{__llvm_slsblr_thunk_x[0-9]+$}} 140 store i32 %call, ptr @b, align 4 141 ret void 142; CHECK: .Lfunc_end 143} 144 145; Verify that neither x16 nor x17 are used when the BLR mitigation is enabled, 146; as a linker is allowed to clobber x16 or x17 on calls, which would break the 147; correct execution of the code sequence produced by the mitigation. The below 148; test attempts to force *%f into x16 using inline assembly. 149define i64 @check_x16(ptr nocapture readonly %fp, ptr nocapture readonly %fp2) "target-features"="+neon,+reserve-x10,+reserve-x11,+reserve-x12,+reserve-x13,+reserve-x14,+reserve-x15,+reserve-x18,+reserve-x20,+reserve-x21,+reserve-x22,+reserve-x23,+reserve-x24,+reserve-x25,+reserve-x26,+reserve-x27,+reserve-x28,+reserve-x30,+reserve-x9" { 150entry: 151; CHECK-LABEL: check_x16: 152 %f = load ptr, ptr %fp, align 8 153 %x16_f = tail call ptr asm "add $0, $1, #0", "={x16},{x16}"(ptr %f) nounwind 154 %call1 = call i64 %x16_f() 155; NOHARDEN: blr x16 156; ISBDSB-NOT: bl __llvm_slsblr_thunk_x16 157; SB-NOT: bl __llvm_slsblr_thunk_x16 158; CHECK 159 ret i64 %call1 160; CHECK: .Lfunc_end 161} 162 163; Verify that the transformation works correctly for x29 when it is not 164; reserved to be used as a frame pointer. 165; Since this is sensitive to register allocation choices, only check this with 166; DAGIsel to avoid too much accidental breaking of this test that is a bit 167; brittle. 168define i64 @check_x29(ptr nocapture readonly %fp, 169 ptr nocapture readonly %fp2, 170 ptr nocapture readonly %fp3) 171"target-features"="+neon,+reserve-x10,+reserve-x11,+reserve-x12,+reserve-x13,+reserve-x14,+reserve-x15,+reserve-x18,+reserve-x20,+reserve-x21,+reserve-x22,+reserve-x23,+reserve-x24,+reserve-x25,+reserve-x26,+reserve-x27,+reserve-x28,+reserve-x9" 172"frame-pointer"="none" 173{ 174entry: 175; CHECK-LABEL: check_x29: 176 %0 = load ptr, ptr %fp, align 8 177 %1 = load ptr, ptr %fp2, align 8 178 %2 = load ptr, ptr %fp2, align 8 179 %3 = load ptr, ptr %fp3, align 8 180 %4 = load ptr, ptr %fp3, align 8 181 %5 = load ptr, ptr %fp, align 8 182 %call = call i64 %0(ptr %1, ptr %3, i64 0, i64 0, i64 0, i64 0, i64 0, i64 0) 183 %call1 = call i64 %2(ptr %1, ptr %3, i64 0, i64 0, i64 0, i64 0, i64 0, i64 0) 184; NOHARDEN: blr x29 185; ISBDSBDAGISEL: bl __llvm_slsblr_thunk_x29 186; SBDAGISEL: bl __llvm_slsblr_thunk_x29 187; CHECK 188 %call2 = call i64 %4(ptr %1, ptr %5, i64 0, i64 0, i64 0, i64 0, i64 0, i64 0) 189 %add = add nsw i64 %call1, %call 190 %add1 = add nsw i64 %call2, %add 191 ret i64 %add1 192; CHECK: .Lfunc_end 193} 194 195; HARDEN-label: __llvm_slsblr_thunk_x0: 196; HARDEN: mov x16, x0 197; HARDEN: br x16 198; ISBDSB-NEXT: dsb sy 199; ISBDSB-NEXT: isb 200; SB-NEXT: dsb sy 201; SB-NEXT: isb 202; HARDEN-NEXT: .Lfunc_end 203; HARDEN-COMDAT: .section .text.__llvm_slsblr_thunk_x19 204; HARDEN-COMDAT: .hidden __llvm_slsblr_thunk_x19 205; HARDEN-COMDAT: .weak __llvm_slsblr_thunk_x19 206; HARDEN-COMDAT: .type __llvm_slsblr_thunk_x19,@function 207; HARDEN-COMDAT-OFF-NOT: .section .text.__llvm_slsblr_thunk_x19 208; HARDEN-COMDAT-OFF-NOT: .hidden __llvm_slsblr_thunk_x19 209; HARDEN-COMDAT-OFF-NOT: .weak __llvm_slsblr_thunk_x19 210; HARDEN-COMDAT-OFF: .type __llvm_slsblr_thunk_x19,@function 211; HARDEN-label: __llvm_slsblr_thunk_x19: 212; HARDEN: mov x16, x19 213; HARDEN: br x16 214; ISBDSB-NEXT: dsb sy 215; ISBDSB-NEXT: isb 216; SB-NEXT: dsb sy 217; SB-NEXT: isb 218; HARDEN-NEXT: .Lfunc_end 219