xref: /llvm-project/llvm/test/CodeGen/AArch64/cfguard-checks.ll (revision 5ddce70ef0e5a641d7fea95e31fc5e2439cb98cb)
1; RUN: llc < %s -mtriple=aarch64-pc-windows-msvc | FileCheck %s
2; RUN: llc < %s -mtriple=aarch64-w64-windows-gnu | FileCheck %s
3; Control Flow Guard is currently only available on Windows
4
5; Test that Control Flow Guard checks are correctly added when required.
6
7
8declare i32 @target_func()
9
10
11; Test that Control Flow Guard checks are not added on calls with the "guard_nocf" attribute.
12define i32 @func_guard_nocf() {
13entry:
14  %func_ptr = alloca ptr, align 8
15  store ptr @target_func, ptr %func_ptr, align 8
16  %0 = load ptr, ptr %func_ptr, align 8
17  %1 = call i32 %0() #0
18  ret i32 %1
19
20  ; CHECK-LABEL: func_guard_nocf
21  ; CHECK:       adrp x8, target_func
22	; CHECK:       add x8, x8, :lo12:target_func
23  ; CHECK-NOT:   __guard_check_icall_fptr
24	; CHECK:       blr x8
25}
26attributes #0 = { "guard_nocf" }
27
28
29; Test that Control Flow Guard checks are added even at -O0.
30define i32 @func_optnone_cf() #1 {
31entry:
32  %func_ptr = alloca ptr, align 8
33  store ptr @target_func, ptr %func_ptr, align 8
34  %0 = load ptr, ptr %func_ptr, align 8
35  %1 = call i32 %0()
36  ret i32 %1
37
38  ; The call to __guard_check_icall_fptr should come immediately before the call to the target function.
39  ; CHECK-LABEL: func_optnone_cf
40	; CHECK:        adrp x8, target_func
41	; CHECK:        add x8, x8, :lo12:target_func
42	; CHECK:        adrp x9, __guard_check_icall_fptr
43	; CHECK:        add x9, x9, :lo12:__guard_check_icall_fptr
44	; CHECK:        ldr x9, [x9]
45	; CHECK:        mov x15, x8
46	; CHECK:        blr x9
47	; CHECK-NEXT:   blr x8
48}
49attributes #1 = { noinline optnone }
50
51
52; Test that Control Flow Guard checks are correctly added in optimized code (common case).
53define i32 @func_cf() {
54entry:
55  %func_ptr = alloca ptr, align 8
56  store ptr @target_func, ptr %func_ptr, align 8
57  %0 = load ptr, ptr %func_ptr, align 8
58  %1 = call i32 %0()
59  ret i32 %1
60
61  ; The call to __guard_check_icall_fptr should come immediately before the call to the target function.
62  ; CHECK-LABEL: func_cf
63  ; CHECK:        adrp x8, __guard_check_icall_fptr
64	; CHECK:        ldr x9, [x8, :lo12:__guard_check_icall_fptr]
65	; CHECK:        adrp x8, target_func
66	; CHECK:        add x8, x8, :lo12:target_func
67	; CHECK:        mov x15, x8
68	; CHECK: 	     	blr x9
69	; CHECK-NEXT:   blr x8
70}
71
72
73; Test that Control Flow Guard checks are correctly added on invoke instructions.
74define i32 @func_cf_invoke() personality ptr @h {
75entry:
76  %0 = alloca i32, align 4
77  %func_ptr = alloca ptr, align 8
78  store ptr @target_func, ptr %func_ptr, align 8
79  %1 = load ptr, ptr %func_ptr, align 8
80  %2 = invoke i32 %1()
81          to label %invoke.cont unwind label %lpad
82invoke.cont:                                      ; preds = %entry
83  ret i32 %2
84
85lpad:                                             ; preds = %entry
86  %tmp = landingpad { ptr, i32 }
87          catch ptr null
88  ret i32 -1
89
90  ; The call to __guard_check_icall_fptr should come immediately before the call to the target function.
91  ; CHECK-LABEL: func_cf_invoke
92  ; CHECK:        adrp x8, __guard_check_icall_fptr
93	; CHECK:        ldr x9, [x8, :lo12:__guard_check_icall_fptr]
94	; CHECK:        adrp x8, target_func
95	; CHECK:        add x8, x8, :lo12:target_func
96	; CHECK:        mov x15, x8
97	; CHECK:        blr x9
98  ; CHECK-NEXT:   .Ltmp0:
99	; CHECK-NEXT:   blr x8
100  ; CHECK:       // %common.ret
101  ; CHECK:       // %lpad
102}
103
104declare void @h()
105
106
107; Test that longjmp targets have public labels and are included in the .gljmp section.
108%struct._SETJMP_FLOAT128 = type { [2 x i64] }
109@buf1 = internal global [16 x %struct._SETJMP_FLOAT128] zeroinitializer, align 16
110
111define i32 @func_cf_setjmp() {
112  %1 = alloca i32, align 4
113  %2 = alloca i32, align 4
114  store i32 0, ptr %1, align 4
115  store i32 -1, ptr %2, align 4
116  %3 = call ptr @llvm.frameaddress(i32 0)
117  %4 = call i32 @_setjmp(ptr @buf1, ptr %3) #2
118
119  ; CHECK-LABEL: func_cf_setjmp
120  ; CHECK:       bl _setjmp
121  ; CHECK-NEXT:  $cfgsj_func_cf_setjmp0:
122
123  %5 = call ptr @llvm.frameaddress(i32 0)
124  %6 = call i32 @_setjmp(ptr @buf1, ptr %5) #3
125
126  ; CHECK:       bl _setjmp
127  ; CHECK-NEXT:  $cfgsj_func_cf_setjmp1:
128
129  store i32 1, ptr %2, align 4
130  %7 = load i32, ptr %2, align 4
131  ret i32 %7
132
133  ; CHECK:       .section .gljmp$y,"dr"
134  ; CHECK-NEXT:  .symidx $cfgsj_func_cf_setjmp0
135  ; CHECK-NEXT:  .symidx $cfgsj_func_cf_setjmp1
136}
137
138declare ptr @llvm.frameaddress(i32)
139
140; Function Attrs: returns_twice
141declare dso_local i32 @_setjmp(ptr, ptr) #2
142
143attributes #2 = { returns_twice }
144attributes #3 = { returns_twice }
145
146
147!llvm.module.flags = !{!0}
148!0 = !{i32 2, !"cfguard", i32 2}
149