xref: /llvm-project/clang/test/CodeGen/memtag-globals-asm.cpp (revision c9f5b5c935bd12d76d4bafff61d8116cb3229972)
1 // REQUIRES: aarch64-registered-target
2 
3 // RUN: %clang_cc1 -S -x c++ -std=c++11 -triple aarch64-linux-android31 \
4 // RUN:   -fsanitize=memtag-globals -o %t.out %s
5 // RUN: FileCheck %s --input-file=%t.out
6 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-A
7 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-B
8 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-C
9 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-D
10 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-E
11 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-F
12 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-G
13 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-H
14 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-I
15 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-J
16 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-K
17 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-L
18 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-M
19 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-N
20 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-O
21 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-P
22 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-Q
23 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-R
24 
25 // RUN: %clang_cc1 -O3 -S -x c++ -std=c++11 -triple aarch64-linux-android31 \
26 // RUN:   -fsanitize=memtag-globals -o %t.out %s
27 // RUN: FileCheck %s --input-file=%t.out
28 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-A
29 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-B
30 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-C
31 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-D
32 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-E
33 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-F
34 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-G
35 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-H
36 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-I
37 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-J
38 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-K
39 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-L
40 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-M
41 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-N
42 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-O
43 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-P
44 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-Q
45 // RUN: FileCheck %s --input-file=%t.out --check-prefix=CHECK-R
46 
47 /// Ensure that emulated TLS also doesn't get sanitized.
48 // RUN: %clang_cc1 -S -x c++ -std=c++11 -triple aarch64-linux-android31 \
49 // RUN:   -fsanitize=memtag-globals -o - %s | FileCheck %s
50 
51 // CHECK-A: .memtag global_int
52 // CHECK-A: .globl global_int
53 // CHECK-A: .p2align 4, 0x0
54 // CHECK-A: .size global_int, 16
55 int global_int;
56 // CHECK-B: .memtag _ZL9local_int
57 // CHECK-B: .local _ZL9local_int
58 // CHECK-B: .comm _ZL9local_int,16,16
59 static int local_int;
60 
61 // CHECK-C: .memtag _ZL12local_buffer
62 // CHECK-C: .local _ZL12local_buffer
63 // CHECK-C: .comm _ZL12local_buffer,16,16
64 static char local_buffer[16];
65 // CHECK-D: .memtag _ZL22local_buffer_local_end
66 // CHECK-D: .p2align 4, 0x0
67 // CHECK-D: _ZL22local_buffer_local_end:
68 // CHECK-D: .xword _ZL12local_buffer+16
69 // CHECK-D: .size _ZL22local_buffer_local_end, 16
70 static char* local_buffer_local_end = &local_buffer[16];
71 // CHECK-E: .memtag local_buffer_global_end
72 // CHECK-E: .globl local_buffer_global_end
73 // CHECK-E  .p2align 4, 0x0
74 // CHECK-E: local_buffer_global_end:
75 // CHECK-E: .xword _ZL12local_buffer+16
76 // CHECK-E: .size local_buffer_global_end, 16
77 char* local_buffer_global_end = &local_buffer[16];
78 
79 // CHECK-F: .memtag global_buffer
80 // CHECK-F: .globl global_buffer
81 // CHECK-F: .p2align 4, 0x0
82 // CHECK-F: .size global_buffer, 16
83 char global_buffer[16];
84 // CHECK-G: .memtag _ZL23global_buffer_local_end
85 // CHECK-G: .p2align 4, 0x0
86 // CHECK-G: _ZL23global_buffer_local_end:
87 // CHECK-G: .xword global_buffer+16
88 // CHECK-G: .size _ZL23global_buffer_local_end, 16
89 static char* global_buffer_local_end = &global_buffer[16];
90 // CHECK-H: .memtag global_buffer_global_end
91 // CHECK-H: .p2align 4, 0x0
92 // CHECK-H: global_buffer_global_end:
93 // CHECK-H: .xword global_buffer+16
94 // CHECK-H: .size global_buffer_global_end, 16
95 char* global_buffer_global_end = &global_buffer[16];
96 
97 class MyClass {
98  public:
~MyClass()99   virtual ~MyClass() {}
100   static int my_class_int;
101   static const int my_class_const_int;
virtual_func()102   virtual int virtual_func() { return 1; }
103 };
104 // CHECK-I: .memtag _ZN7MyClass12my_class_intE
105 // CHECK-I: .globl _ZN7MyClass12my_class_intE
106 // CHECK-I: .p2align 4, 0x0
107 // CHECK-I: .size _ZN7MyClass12my_class_intE, 16
108 int MyClass::my_class_int;
109 // CHECK-NOT: .memtag _ZN7MyClass18my_class_const_intE
110 const int MyClass::my_class_const_int = 1;
111 
112 // CHECK-J: .memtag global_my_class
113 // CHECK-J: .globl global_my_class
114 // CHECK-J: .p2align 4, 0x0
115 // CHECK-J: .size global_my_class, 16
116 MyClass global_my_class;
117 // CHECK-K: .memtag _ZL14local_my_class
118 // CHECK-K: .p2align 4, 0x0
119 // CHECK-K: .size _ZL14local_my_class, 16
120 static MyClass local_my_class;
121 
122 // CHECK-NOT: .memtag _ZL18local_const_string
123 static const char local_const_string[] = "this is a local string";
124 // CHECK-L: .memtag _ZL12local_string
125 // CHECK-L: .p2align 4, 0x0
126 // CHECK-L: .size _ZL12local_string, 32
127 static char local_string[] = "this is a local string";
128 
129 // CHECK-M: .memtag global_atomic_int
130 // CHECK-M: .globl global_atomic_int
131 // CHECK-M: .p2align 4, 0x0
132 // CHECK-M: .size global_atomic_int, 16
133 _Atomic(int) global_atomic_int;
134 // CHECK-N: .memtag _ZL16local_atomic_int
135 // CHECK-N: .local _ZL16local_atomic_int
136 // CHECK-N: .comm _ZL16local_atomic_int,16,16
137 static _Atomic(int) local_atomic_int;
138 
139 union MyUnion {
140   int i;
141   char c;
142 };
143 
144 // CHECK-O: .memtag global_union
145 // CHECK-O: .globl global_union
146 // CHECK-O: .p2align 4, 0x0
147 // CHECK-O: .size global_union, 16
148 MyUnion global_union;
149 // CHECK-P: .memtag _ZL11local_union
150 // CHECK-P: .local _ZL11local_union
151 // CHECK-P: .comm _ZL11local_union,16,16
152 static MyUnion local_union;
153 
154 // CHECK-NOT: .memtag {{.*}}global_tls
155 thread_local int global_tls;
156 // CHECK-NOT: .memtag {{.*}}local_tls
157 static thread_local int local_tls;
158 
159 /// Prevent the compiler from realising that non-const local variables are not
160 /// modified, and constant inlining into f().
export_pointers(int c)161 const void* export_pointers(int c) {
162   switch (c) {
163     case 0:  return &local_int;
164     case 1:  return &local_buffer;
165     case 2:  return &local_buffer_local_end;
166     case 3:  return &global_buffer_local_end;
167     case 4:  return &MyClass::my_class_int;
168     case 6:  return &local_my_class;
169     case 8:  return &local_string;
170     case 9:  return &local_atomic_int;
171     case 10: return &local_union;
172     case 11: return &local_tls;
173   }
174   return nullptr;
175 }
176 
177 /// Ensure that all tagged globals are loaded/referenced via. the GOT.
178 // CHECK-NOT:      .memtag _Z1fi
179 // CHECK-Q:        _Z1fi:
f(int x)180 int f(int x) {
181   // CHECK-R: .memtag _ZZ1fiE12function_int
182   // CHECK-R: .local _ZZ1fiE12function_int
183   // CHECK-R: .comm _ZZ1fiE12function_int,16,16
184   static int function_int = 0;
185   /// Prevent non-const `f` from being promoted to a constant and inlined.
186   function_int += x;
187 
188   return
189   // CHECK-Q-DAG: adrp [[REG_A:x[0-9]+]], :got:global_int
190   // CHECK-Q-DAG: ldr  [[REG_A2:x[0-9]+]], [[[REG_A]], :got_lo12:global_int]
191   // CHECK-Q-DAG: ldr  {{.*}}, [[[REG_A2]]]
192       global_int +
193   // CHECK-Q-DAG: adrp [[REG_B:x[0-9]+]], :got:_ZL9local_int
194   // CHECK-Q-DAG: ldr  [[REG_B2:x[0-9]+]], [[[REG_B]], :got_lo12:_ZL9local_int]
195   // CHECK-Q-DAG: ldr  {{.*}}, [[[REG_B2]]]
196       local_int +
197   // CHECK-Q-DAG: adrp  [[REG_C:x[0-9]+]], :got:_ZL12local_buffer
198   // CHECK-Q-DAG: ldr   [[REG_C2:x[0-9]+]], [[[REG_C]], :got_lo12:_ZL12local_buffer]
199   // CHECK-Q-DAG: ldrsb {{.*}}, [[[REG_C2]]]
200       local_buffer[0] +
201   // CHECK-Q-DAG: adrp   [[REG_D:x[0-9]+]], :got:_ZL22local_buffer_local_end
202   // CHECK-Q-DAG: ldr    [[REG_D2:x[0-9]+]], [[[REG_D]], :got_lo12:_ZL22local_buffer_local_end]
203   // CHECK-Q-DAG: ldr    [[REG_D3:x[0-9]+]], [[[REG_D2]]]
204   // CHECK-Q-DAG: ldursb {{.*}}, [[[REG_D3]], #-16]
205       local_buffer_local_end[-16] +
206   // CHECK-Q-DAG: adrp   [[REG_E:x[0-9]+]], :got:local_buffer_global_end
207   // CHECK-Q-DAG: ldr    [[REG_E2:x[0-9]+]], [[[REG_E]], :got_lo12:local_buffer_global_end]
208   // CHECK-Q-DAG: ldr    [[REG_E3:x[0-9]+]], [[[REG_E2]]]
209   // CHECK-Q-DAG: ldursb {{.*}}, [[[REG_E3]], #-16]
210       local_buffer_global_end[-16] +
211   // CHECK-Q-DAG: adrp  [[REG_F:x[0-9]+]], :got:global_buffer{{$}}
212   // CHECK-Q-DAG: ldr   [[REG_F2:x[0-9]+]], [[[REG_F]], :got_lo12:global_buffer]
213   // CHECK-Q-DAG: ldrsb {{.*}}, [[[REG_F2]]]
214       global_buffer[0] +
215   // CHECK-Q-DAG: adrp   [[REG_G:x[0-9]+]], :got:_ZL23global_buffer_local_end
216   // CHECK-Q-DAG: ldr    [[REG_G2:x[0-9]+]], [[[REG_G]], :got_lo12:_ZL23global_buffer_local_end]
217   // CHECK-Q-DAG: ldr    [[REG_G3:x[0-9]+]], [[[REG_G2]]]
218   // CHECK-Q-DAG: ldursb {{.*}}, [[[REG_G3]], #-16]
219       global_buffer_local_end[-16] +
220   // CHECK-Q-DAG: adrp   [[REG_H:x[0-9]+]], :got:global_buffer_global_end
221   // CHECK-Q-DAG: ldr    [[REG_H2:x[0-9]+]], [[[REG_H]], :got_lo12:global_buffer_global_end]
222   // CHECK-Q-DAG: ldr    [[REG_H3:x[0-9]+]], [[[REG_H2]]]
223   // CHECK-Q-DAG: ldursb {{.*}}, [[[REG_H3]], #-16]
224       global_buffer_global_end[-16] +
225   // CHECK-Q-DAG: adrp [[REG_I:x[0-9]+]], :got:_ZN7MyClass12my_class_intE
226   // CHECK-Q-DAG: ldr  [[REG_I2:x[0-9]+]], [[[REG_I]], :got_lo12:_ZN7MyClass12my_class_intE]
227   // CHECK-Q-DAG: ldr  {{.*}}, [[[REG_I2]]]
228       MyClass::my_class_int +
229   /// Constant values - ignore.
230       MyClass::my_class_const_int +
231       global_my_class.virtual_func() +
232       local_my_class.virtual_func() +
233       local_const_string[0] +
234   // CHECK-Q-DAG: adrp  [[REG_J:x[0-9]+]], :got:_ZL12local_string
235   // CHECK-Q-DAG: ldr   [[REG_J2:x[0-9]+]], [[[REG_J]], :got_lo12:_ZL12local_string]
236   // CHECK-Q-DAG: ldrsb {{.*}}, [[[REG_J2]]]
237       local_string[0] +
238   // CHECK-Q-DAG: adrp  [[REG_K:x[0-9]+]], :got:_ZL16local_atomic_int
239   // CHECK-Q-DAG: ldr   [[REG_K2:x[0-9]+]], [[[REG_K]], :got_lo12:_ZL16local_atomic_int]
240   // CHECK-Q-DAG: ldar {{.*}}, [[[REG_K2]]]
241       local_atomic_int +
242   // CHECK-Q-DAG: adrp [[REG_L:x[0-9]+]], :got:global_atomic_int
243   // CHECK-Q-DAG: ldr  [[REG_L2:x[0-9]+]], [[[REG_L]], :got_lo12:global_atomic_int]
244   // CHECK-Q-DAG: ldar {{.*}}, [[[REG_L2]]]
245       global_atomic_int +
246   // CHECK-Q-DAG: adrp [[REG_M:x[0-9]+]], :got:global_union
247   // CHECK-Q-DAG: ldr  [[REG_M2:x[0-9]+]], [[[REG_M]], :got_lo12:global_union]
248   // CHECK-Q-DAG: ldr  {{.*}}, [[[REG_M2]]]
249       global_union.i +
250   // CHECK-Q-DAG: adrp  [[REG_N:x[0-9]+]], :got:_ZL11local_union
251   // CHECK-Q-DAG: ldr   [[REG_N2:x[0-9]+]], [[[REG_N]], :got_lo12:_ZL11local_union]
252   // CHECK-Q-DAG: ldrsb {{.*}}, [[[REG_N2]]]
253       local_union.c +
254   /// Global variables - ignore.
255       global_tls +
256       local_tls +
257   // CHECK-Q-DAG: adrp  [[REG_O:x[0-9]+]], :got:_ZZ1fiE12function_int
258   // CHECK-Q-DAG: ldr   [[REG_O2:x[0-9]+]], [[[REG_O]], :got_lo12:_ZZ1fiE12function_int]
259   // CHECK-Q-DAG: ldr   {{.*}}, [[[REG_O2]]]
260       function_int;
261 }
262 
263 typedef void (*func_t)(void);
264 #define CONSTRUCTOR(section_name) \
265   __attribute__((used)) __attribute__((section(section_name)))
266 
func_constructor()267 __attribute__((constructor(0))) void func_constructor() {}
268 CONSTRUCTOR(".init") func_t func_init = func_constructor;
269 CONSTRUCTOR(".fini") func_t func_fini = func_constructor;
270 CONSTRUCTOR(".ctors") func_t func_ctors = func_constructor;
271 CONSTRUCTOR(".dtors") func_t func_dtors = func_constructor;
272 CONSTRUCTOR(".init_array") func_t func_init_array = func_constructor;
273 CONSTRUCTOR(".fini_array") func_t func_fini_array = func_constructor;
274 CONSTRUCTOR(".preinit_array") func_t preinit_array = func_constructor;
275 CONSTRUCTOR("array_of_globals") int global1;
276 CONSTRUCTOR("array_of_globals") int global2;
277 CONSTRUCTOR("array_of_globals") int global_string;
278 
279 // CHECK-NOT: .memtag func_constructor
280 // CHECK-NOT: .memtag func_init
281 // CHECK-NOT: .memtag func_fini
282 // CHECK-NOT: .memtag func_ctors
283 // CHECK-NOT: .memtag func_dtors
284 // CHECK-NOT: .memtag func_init_array
285 // CHECK-NOT: .memtag func_fini_array
286 // CHECK-NOT: .memtag preinit_array
287 // CHECK-NOT: .memtag global1
288 // CHECK-NOT: .memtag global2
289 // CHECK-NOT: .memtag global_string
290