xref: /llvm-project/llvm/test/CodeGen/ARM/speculation-hardening-sls.ll (revision 3770b4aa3c5a06efbf43b5c22b2b641794a41dca)
1; RUN: llc -mattr=harden-sls-retbr -mattr=harden-sls-blr -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,ARM,HARDEN,HARDEN-COMDAT,ISBDSB -dump-input-context=100
2; RUN: llc -mattr=harden-sls-retbr -mattr=harden-sls-blr -verify-machineinstrs -mtriple=thumbv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,THUMB,HARDENTHUMB,HARDEN,HARDEN-COMDAT,ISBDSB -dump-input-context=100
3; RUN: llc -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=+sb -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,ARM,HARDEN,HARDEN-COMDAT,SB -dump-input-context=100
4; RUN: llc -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=+sb -verify-machineinstrs -mtriple=thumbv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,THUMB,HARDENTHUMB,HARDEN,HARDEN-COMDAT,SB -dump-input-context=100
5; RUN: llc -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=harden-sls-nocomdat -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,ARM,HARDEN,HARDEN-COMDAT-OFF,ISBDSB -dump-input-context=100
6; RUN: llc -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=harden-sls-nocomdat -verify-machineinstrs -mtriple=thumbv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,THUMB,HARDENTHUMB,HARDEN,HARDEN-COMDAT-OFF,ISBDSB -dump-input-context=100
7; RUN: llc -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=harden-sls-nocomdat -mattr=+sb -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,ARM,HARDEN,HARDEN-COMDAT-OFF,SB -dump-input-context=100
8; RUN: llc -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=harden-sls-nocomdat -mattr=+sb -verify-machineinstrs -mtriple=thumbv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,THUMB,HARDENTHUMB,HARDEN,HARDEN-COMDAT-OFF,SB -dump-input-context=100
9; RUN: llc -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,ARM,NOHARDENARM -dump-input-context=100
10; RUN: llc -verify-machineinstrs -mtriple=thumbv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,THUMB,NOHARDENTHUMB
11; RUN: llc -global-isel -global-isel-abort=0 -mattr=harden-sls-retbr -mattr=harden-sls-blr -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,ARM,HARDEN,HARDEN-COMDAT,ISBDSB
12; RUN: llc -global-isel -global-isel-abort=0 -mattr=harden-sls-retbr -mattr=harden-sls-blr -verify-machineinstrs -mtriple=thumbv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,THUMB,HARDENTHUMB,HARDEN,HARDEN-COMDAT,ISBDSB
13; RUN: llc -global-isel -global-isel-abort=0 -mattr=harden-sls-retbr -mattr=harden-sls-nocomdat -mattr=harden-sls-blr -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,ARM,HARDEN,HARDEN-COMDAT-OFF,ISBDSB
14; RUN: llc -global-isel -global-isel-abort=0 -mattr=harden-sls-retbr -mattr=harden-sls-nocomdat -mattr=harden-sls-blr -verify-machineinstrs -mtriple=thumbv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,THUMB,HARDENTHUMB,HARDEN,HARDEN-COMDAT-OFF,ISBDSB
15; RUN: llc -global-isel -global-isel-abort=0 -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=+sb -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,ARM,HARDEN,SB
16; RUN: llc -global-isel -global-isel-abort=0 -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=+sb -verify-machineinstrs -mtriple=thumbv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,THUMB,HARDENTHUMB,HARDEN,SB
17; RUN: llc -fast-isel -mattr=harden-sls-retbr -mattr=harden-sls-blr -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,ARM,HARDEN,HARDEN-COMDAT,ISBDSB
18; RUN: llc -fast-isel -mattr=harden-sls-retbr -mattr=harden-sls-blr -verify-machineinstrs -mtriple=thumbv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,THUMB,HARDENTHUMB,HARDEN,HARDEN-COMDAT,ISBDSB
19; RUN: llc -fast-isel -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=harden-sls-nocomdat -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,ARM,HARDEN,HARDEN-COMDAT-OFF,ISBDSB
20; RUN: llc -fast-isel -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=harden-sls-nocomdat -verify-machineinstrs -mtriple=thumbv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,THUMB,HARDENTHUMB,HARDEN,HARDEN-COMDAT-OFF,ISBDSB
21; RUN: llc -fast-isel -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=+sb -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,ARM,HARDEN,SB
22; RUN: llc -fast-isel -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=+sb -verify-machineinstrs -mtriple=thumbv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,THUMB,HARDENTHUMB,HARDEN,SB
23
24; Function Attrs: norecurse nounwind readnone
25define dso_local i32 @double_return(i32 %a, i32 %b) local_unnamed_addr {
26entry:
27  %cmp = icmp sgt i32 %a, 0
28  br i1 %cmp, label %if.then, label %if.else
29
30if.then:                                          ; preds = %entry
31  ; Make a very easy, very likely to predicate return (BX LR), to test that
32  ; it will not get predicated when sls-hardening is enabled.
33  %mul = mul i32 %b, %a
34  ret i32 %mul
35; CHECK-LABEL: double_return:
36; HARDEN:          {{bx lr$}}
37; NOHARDENARM:     {{bxgt lr$}}
38; NOHARDENTHUMB:   {{bxgt lr$}}
39; ISBDSB-NEXT: dsb sy
40; ISBDSB-NEXT: isb
41; SB-NEXT:     {{ sb$}}
42
43if.else:                                          ; preds = %entry
44  %div3 = sdiv i32 %a, %b
45  %div2 = sdiv i32 %a, %div3
46  %div1 = sdiv i32 %a, %div2
47  ret i32 %div1
48
49; CHECK:       {{bx lr$}}
50; ISBDSB-NEXT: dsb sy
51; ISBDSB-NEXT: isb
52; SB-NEXT:     {{ sb$}}
53; CHECK-NEXT: .Lfunc_end
54}
55
56@__const.indirect_branch.ptr = private unnamed_addr constant [2 x ptr] [ptr blockaddress(@indirect_branch, %return), ptr blockaddress(@indirect_branch, %l2)], align 8
57
58; Function Attrs: norecurse nounwind readnone
59define dso_local i32 @indirect_branch(i32 %a, i32 %b, i32 %i) {
60; CHECK-LABEL: indirect_branch:
61entry:
62  %idxprom = sext i32 %i to i64
63  %arrayidx = getelementptr inbounds [2 x ptr], ptr @__const.indirect_branch.ptr, i64 0, i64 %idxprom
64  %0 = load ptr, ptr %arrayidx, align 8
65  indirectbr ptr %0, [label %return, label %l2]
66; ARM:       bx r0
67; THUMB:     mov pc, r0
68; ISBDSB-NEXT: dsb sy
69; ISBDSB-NEXT: isb
70; SB-NEXT:     {{ sb$}}
71
72l2:                                               ; preds = %entry
73  br label %return
74; CHECK:       {{bx lr$}}
75; ISBDSB-NEXT: dsb sy
76; ISBDSB-NEXT: isb
77; SB-NEXT:     {{ sb$}}
78
79return:                                           ; preds = %entry, %l2
80  %retval.0 = phi i32 [ 1, %l2 ], [ 0, %entry ]
81  ret i32 %retval.0
82; CHECK:       {{bx lr$}}
83; ISBDSB-NEXT: dsb sy
84; ISBDSB-NEXT: isb
85; SB-NEXT:     {{ sb$}}
86; CHECK-NEXT: .Lfunc_end
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:       {{bx lr$}}
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:       {{bx lr$}}
112; ISBDSB-NEXT: dsb sy
113; ISBDSB-NEXT: isb
114; SB-NEXT:     {{ sb$}}
115; CHECK-NEXT: .Lfunc_end
116}
117
118; Check that indirect branches produced through switch jump tables are also
119; hardened:
120define dso_local i32 @jumptable(i32 %a, i32 %b) {
121; CHECK-LABEL: jumptable:
122entry:
123  switch i32 %b, label %sw.epilog [
124    i32 0, label %sw.bb
125    i32 1, label %sw.bb1
126    i32 3, label %sw.bb3
127    i32 4, label %sw.bb5
128  ]
129; ARM:             ldr pc, [{{r[0-9]}}, {{r[0-9]}}, lsl #2]
130; NOHARDENTHUMB:   tbb [pc, {{r[0-9]}}]
131; HARDENTHUMB:     mov pc, {{r[0-9]}}
132; ISBDSB-NEXT:     dsb sy
133; ISBDSB-NEXT:     isb
134; SB-NEXT:         {{ sb$}}
135
136
137sw.bb:                                            ; preds = %entry
138  %add = shl nsw i32 %a, 1
139  br label %sw.bb1
140
141sw.bb1:                                           ; preds = %entry, %sw.bb
142  %a.addr.0 = phi i32 [ %a, %entry ], [ %add, %sw.bb ]
143  %add2 = shl nsw i32 %a.addr.0, 1
144  br label %sw.bb3
145
146sw.bb3:                                           ; preds = %entry, %sw.bb1
147  %a.addr.1 = phi i32 [ %a, %entry ], [ %add2, %sw.bb1 ]
148  %add4 = shl nsw i32 %a.addr.1, 1
149  br label %sw.bb5
150
151sw.bb5:                                           ; preds = %entry, %sw.bb3
152  %a.addr.2 = phi i32 [ %a, %entry ], [ %add4, %sw.bb3 ]
153  %add6 = shl nsw i32 %a.addr.2, 1
154  br label %sw.epilog
155
156sw.epilog:                                        ; preds = %sw.bb5, %entry
157  %a.addr.3 = phi i32 [ %a, %entry ], [ %add6, %sw.bb5 ]
158  ret i32 %a.addr.3
159; CHECK:       {{bx lr$}}
160; ISBDSB-NEXT: dsb sy
161; ISBDSB-NEXT: isb
162; SB-NEXT:     {{ sb$}}
163}
164
165define dso_local i32 @indirect_call(
166ptr nocapture %f1, ptr nocapture %f2) {
167entry:
168; CHECK-LABEL: indirect_call:
169  %call = tail call i32 %f1()
170; HARDENARM: bl {{__llvm_slsblr_thunk_arm_r[0-9]+$}}
171; HARDENTHUMB: bl {{__llvm_slsblr_thunk_thumb_r[0-9]+$}}
172  %call2 = tail call i32 %f2()
173; HARDENARM: bl {{__llvm_slsblr_thunk_arm_r[0-9]+$}}
174; HARDENTHUMB: bl {{__llvm_slsblr_thunk_thumb_r[0-9]+$}}
175  %add = add nsw i32 %call2, %call
176  ret i32 %add
177; CHECK: .Lfunc_end
178}
179
180; verify calling through a function pointer.
181@a = dso_local local_unnamed_addr global ptr null, align 8
182@b = dso_local local_unnamed_addr global i32 0, align 4
183define dso_local void @indirect_call_global() local_unnamed_addr {
184; CHECK-LABEL: indirect_call_global:
185entry:
186  %0 = load ptr, ptr @a, align 8
187  %call = tail call i32 %0()  nounwind
188; HARDENARM: bl {{__llvm_slsblr_thunk_arm_r[0-9]+$}}
189; HARDENTHUMB: bl {{__llvm_slsblr_thunk_thumb_r[0-9]+$}}
190  store i32 %call, ptr @b, align 4
191  ret void
192; CHECK: .Lfunc_end
193}
194
195; Verify that neither r12 nor lr are used as registers in indirect call
196; instructions when the sls-hardening-blr mitigation is enabled, as
197; (a) a linker is allowed to clobber r12 on calls, and
198; (b) the hardening transformation isn't correct if lr is the register holding
199;     the address of the function called.
200define i32 @check_r12(ptr %fp) {
201entry:
202; CHECK-LABEL: check_r12:
203  %f = load ptr, ptr %fp, align 4
204  ; Force f to be moved into r12
205  %r12_f = tail call ptr asm "add $0, $1, #0", "={r12},{r12}"(ptr %f) nounwind
206  %call = call i32 %r12_f()
207; NOHARDENARM:     blx r12
208; NOHARDENTHUMB:   blx r12
209; HARDEN-NOT: bl {{__llvm_slsblr_thunk_(arm|thumb)_r12}}
210  ret i32 %call
211; CHECK: .Lfunc_end
212}
213
214define i32 @check_lr(ptr %fp) {
215entry:
216; CHECK-LABEL: check_lr:
217  %f = load ptr, ptr %fp, align 4
218  ; Force f to be moved into lr
219  %lr_f = tail call ptr asm "add $0, $1, #0", "={lr},{lr}"(ptr %f) nounwind
220  %call = call i32 %lr_f()
221; NOHARDENARM:     blx lr
222; NOHARDENTHUMB:   blx lr
223; HARDEN-NOT: bl {{__llvm_slsblr_thunk_(arm|thumb)_lr}}
224  ret i32 %call
225; CHECK: .Lfunc_end
226}
227
228; Verify that even when sls-harden-blr is enabled, "blx r12" is still an
229; instruction that is accepted by the inline assembler
230define void @verify_inline_asm_blx_r12(ptr %g) {
231entry:
232; CHECK-LABEL: verify_inline_asm_blx_r12:
233  tail call void asm sideeffect "blx $0", "{r12}"(ptr %g) nounwind
234; CHECK: blx r12
235  ret void
236; CHECK:       {{bx lr$}}
237; ISBDSB-NEXT: dsb sy
238; ISBDSB-NEXT: isb
239; SB-NEXT:     {{ sb$}}
240; CHECK: .Lfunc_end
241}
242
243; HARDEN-COMDAT:  .section {{.text.__llvm_slsblr_thunk_(arm|thumb)_r5}}
244; HARDEN-COMDAT:  .hidden {{__llvm_slsblr_thunk_(arm|thumb)_r5}}
245; HARDEN-COMDAT:  .weak {{__llvm_slsblr_thunk_(arm|thumb)_r5}}
246; HARDEN-COMDAT:  .type {{__llvm_slsblr_thunk_(arm|thumb)_r5}},%function
247; HARDEN-COMDAT-OFF-NOT:  .section {{.text.__llvm_slsblr_thunk_(arm|thumb)_r5}}
248; HARDEN-COMDAT-OFF-NOT:  .hidden {{__llvm_slsblr_thunk_(arm|thumb)_r5}}
249; HARDEN-COMDAT-OFF-NOT:  .weak {{__llvm_slsblr_thunk_(arm|thumb)_r5}}
250; HARDEN-COMDAT-OFF:      .type {{__llvm_slsblr_thunk_(arm|thumb)_r5}},%function
251; HARDEN-label: {{__llvm_slsblr_thunk_(arm|thumb)_r5}}:
252; HARDEN:    bx r5
253; ISBDSB-NEXT: dsb sy
254; ISBDSB-NEXT: isb
255; SB-NEXT:     dsb sy
256; SB-NEXT:     isb
257; HARDEN-NEXT: .Lfunc_end
258
259; THUMB-NOT: __llvm_slsblr_thunk_arm
260; ARM-NOT: __llvm_slsblr_thunk_thumb
261