1
2 /*---------------------------------------------------------------*/
3 /*--- begin guest_arm64_helpers.c ---*/
4 /*---------------------------------------------------------------*/
5
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
10 Copyright (C) 2013-2013 OpenWorks
11 info@open-works.net
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 02110-1301, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29 */
30
31 #include "libvex_basictypes.h"
32 #include "libvex_emnote.h"
33 #include "libvex_guest_arm64.h"
34 #include "libvex_ir.h"
35 #include "libvex.h"
36
37 #include "main_util.h"
38 #include "main_globals.h"
39 #include "guest_generic_bb_to_IR.h"
40 #include "guest_arm64_defs.h"
41
42
43 /* This file contains helper functions for arm guest code. Calls to
44 these functions are generated by the back end. These calls are of
45 course in the host machine code and this file will be compiled to
46 host machine code, so that all makes sense.
47
48 Only change the signatures of these helper functions very
49 carefully. If you change the signature here, you'll have to change
50 the parameters passed to it in the IR calls constructed by
51 guest_arm64_toIR.c.
52 */
53
54
55 /* Set to 1 to get detailed profiling info about individual N, Z, C
56 and V flag evaluation. */
57 #define PROFILE_NZCV_FLAGS 0
58
59 #if PROFILE_NZCV_FLAGS
60
61 static UInt tab_eval[ARM64G_CC_OP_NUMBER][16];
62 static UInt initted = 0;
63 static UInt tot_evals = 0;
64
initCounts(void)65 static void initCounts ( void )
66 {
67 UInt i, j;
68 for (i = 0; i < ARM64G_CC_OP_NUMBER; i++) {
69 for (j = 0; j < 16; j++) {
70 tab_eval[i][j] = 0;
71 }
72 }
73 initted = 1;
74 }
75
showCounts(void)76 static void showCounts ( void )
77 {
78 const HChar* nameCC[16]
79 = { "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC",
80 "HI", "LS", "GE", "LT", "GT", "LE", "AL", "NV" };
81 UInt i, j;
82 ULong sum = 0;
83 vex_printf("\nCC_OP 0 1 2 3 "
84 " 4 5 6\n");
85 vex_printf( "--------------------------------------------------"
86 "--------------------------\n");
87 for (j = 0; j < 16; j++) {
88 vex_printf("%2d %s ", j, nameCC[j]);
89 for (i = 0; i < ARM64G_CC_OP_NUMBER; i++) {
90 vex_printf("%9d ", tab_eval[i][j]);
91 sum += tab_eval[i][j];
92 }
93 vex_printf("\n");
94 }
95 vex_printf("(In total %llu calls)\n", sum);
96 }
97
98 #define NOTE_EVAL(_cc_op, _cond) \
99 do { \
100 if (!initted) initCounts(); \
101 vassert( ((UInt)(_cc_op)) < ARM64G_CC_OP_NUMBER); \
102 vassert( ((UInt)(_cond)) < 16); \
103 tab_eval[(UInt)(_cc_op)][(UInt)(cond)]++; \
104 tot_evals++; \
105 if (0 == (tot_evals & 0x7FFF)) \
106 showCounts(); \
107 } while (0)
108
109 #endif /* PROFILE_NZCV_FLAGS */
110
111
112 /* Calculate the N flag from the supplied thunk components, in the
113 least significant bit of the word. Returned bits 63:1 are zero. */
114 static
arm64g_calculate_flag_n(ULong cc_op,ULong cc_dep1,ULong cc_dep2,ULong cc_dep3)115 ULong arm64g_calculate_flag_n ( ULong cc_op, ULong cc_dep1,
116 ULong cc_dep2, ULong cc_dep3 )
117 {
118 switch (cc_op) {
119 case ARM64G_CC_OP_COPY: {
120 /* (nzcv:28x0, unused, unused) */
121 ULong nf = (cc_dep1 >> ARM64G_CC_SHIFT_N) & 1;
122 return nf;
123 }
124 case ARM64G_CC_OP_ADD32: {
125 /* (argL, argR, unused) */
126 UInt argL = (UInt)cc_dep1;
127 UInt argR = (UInt)cc_dep2;
128 UInt res = argL + argR;
129 ULong nf = (ULong)(res >> 31);
130 return nf;
131 }
132 case ARM64G_CC_OP_ADD64: {
133 /* (argL, argR, unused) */
134 ULong argL = cc_dep1;
135 ULong argR = cc_dep2;
136 ULong res = argL + argR;
137 ULong nf = (ULong)(res >> 63);
138 return nf;
139 }
140 case ARM64G_CC_OP_SUB32: {
141 /* (argL, argR, unused) */
142 UInt argL = (UInt)cc_dep1;
143 UInt argR = (UInt)cc_dep2;
144 UInt res = argL - argR;
145 ULong nf = (ULong)(res >> 31);
146 return nf;
147 }
148 case ARM64G_CC_OP_SUB64: {
149 /* (argL, argR, unused) */
150 ULong argL = cc_dep1;
151 ULong argR = cc_dep2;
152 ULong res = argL - argR;
153 ULong nf = res >> 63;
154 return nf;
155 }
156 case ARM64G_CC_OP_ADC32: {
157 /* (argL, argR, oldC) */
158 UInt argL = cc_dep1;
159 UInt argR = cc_dep2;
160 UInt oldC = cc_dep3;
161 vassert((oldC & ~1) == 0);
162 UInt res = argL + argR + oldC;
163 ULong nf = (ULong)(res >> 31);
164 return nf;
165 }
166 case ARM64G_CC_OP_ADC64: {
167 /* (argL, argR, oldC) */
168 ULong argL = cc_dep1;
169 ULong argR = cc_dep2;
170 ULong oldC = cc_dep3;
171 vassert((oldC & ~1) == 0);
172 ULong res = argL + argR + oldC;
173 ULong nf = res >> 63;
174 return nf;
175 }
176 case ARM64G_CC_OP_SBC32: {
177 /* (argL, argR, oldC) */
178 UInt argL = cc_dep1;
179 UInt argR = cc_dep2;
180 UInt oldC = cc_dep3;
181 vassert((oldC & ~1) == 0);
182 UInt res = argL - argR - (oldC ^ 1);
183 ULong nf = (ULong)(res >> 31);
184 return nf;
185 }
186 case ARM64G_CC_OP_SBC64: {
187 /* (argL, argR, oldC) */
188 ULong argL = cc_dep1;
189 ULong argR = cc_dep2;
190 ULong oldC = cc_dep3;
191 vassert((oldC & ~1) == 0);
192 ULong res = argL - argR - (oldC ^ 1);
193 ULong nf = res >> 63;
194 return nf;
195 }
196 case ARM64G_CC_OP_LOGIC32: {
197 /* (res, unused, unused) */
198 UInt res = (UInt)cc_dep1;
199 ULong nf = res >> 31;
200 return nf;
201 }
202 case ARM64G_CC_OP_LOGIC64: {
203 /* (res, unused, unused) */
204 ULong res = cc_dep1;
205 ULong nf = res >> 63;
206 return nf;
207 }
208 //ZZ case ARMG_CC_OP_MUL: {
209 //ZZ /* (res, unused, oldC:oldV) */
210 //ZZ UInt res = cc_dep1;
211 //ZZ UInt nf = res >> 31;
212 //ZZ return nf;
213 //ZZ }
214 //ZZ case ARMG_CC_OP_MULL: {
215 //ZZ /* (resLo32, resHi32, oldC:oldV) */
216 //ZZ UInt resHi32 = cc_dep2;
217 //ZZ UInt nf = resHi32 >> 31;
218 //ZZ return nf;
219 //ZZ }
220 default:
221 /* shouldn't really make these calls from generated code */
222 vex_printf("arm64g_calculate_flag_n"
223 "( op=%llu, dep1=0x%llx, dep2=0x%llx, dep3=0x%llx )\n",
224 cc_op, cc_dep1, cc_dep2, cc_dep3 );
225 vpanic("arm64g_calculate_flag_n");
226 }
227 }
228
229
230 /* Calculate the Z flag from the supplied thunk components, in the
231 least significant bit of the word. Returned bits 63:1 are zero. */
232 static
arm64g_calculate_flag_z(ULong cc_op,ULong cc_dep1,ULong cc_dep2,ULong cc_dep3)233 ULong arm64g_calculate_flag_z ( ULong cc_op, ULong cc_dep1,
234 ULong cc_dep2, ULong cc_dep3 )
235 {
236 switch (cc_op) {
237 case ARM64G_CC_OP_COPY: {
238 /* (nzcv:28x0, unused, unused) */
239 ULong zf = (cc_dep1 >> ARM64G_CC_SHIFT_Z) & 1;
240 return zf;
241 }
242 case ARM64G_CC_OP_ADD32: {
243 /* (argL, argR, unused) */
244 UInt argL = (UInt)cc_dep1;
245 UInt argR = (UInt)cc_dep2;
246 UInt res = argL + argR;
247 ULong zf = res == 0;
248 return zf;
249 }
250 case ARM64G_CC_OP_ADD64: {
251 /* (argL, argR, unused) */
252 ULong argL = cc_dep1;
253 ULong argR = cc_dep2;
254 ULong res = argL + argR;
255 ULong zf = res == 0;
256 return zf;
257 }
258 case ARM64G_CC_OP_SUB32: {
259 /* (argL, argR, unused) */
260 UInt argL = (UInt)cc_dep1;
261 UInt argR = (UInt)cc_dep2;
262 UInt res = argL - argR;
263 ULong zf = res == 0;
264 return zf;
265 }
266 case ARM64G_CC_OP_SUB64: {
267 /* (argL, argR, unused) */
268 ULong argL = cc_dep1;
269 ULong argR = cc_dep2;
270 ULong res = argL - argR;
271 ULong zf = res == 0;
272 return zf;
273 }
274 case ARM64G_CC_OP_ADC32: {
275 /* (argL, argR, oldC) */
276 UInt argL = cc_dep1;
277 UInt argR = cc_dep2;
278 UInt oldC = cc_dep3;
279 vassert((oldC & ~1) == 0);
280 UInt res = argL + argR + oldC;
281 ULong zf = res == 0;
282 return zf;
283 }
284 case ARM64G_CC_OP_ADC64: {
285 /* (argL, argR, oldC) */
286 ULong argL = cc_dep1;
287 ULong argR = cc_dep2;
288 ULong oldC = cc_dep3;
289 vassert((oldC & ~1) == 0);
290 ULong res = argL + argR + oldC;
291 ULong zf = res == 0;
292 return zf;
293 }
294 case ARM64G_CC_OP_SBC32: {
295 /* (argL, argR, oldC) */
296 UInt argL = cc_dep1;
297 UInt argR = cc_dep2;
298 UInt oldC = cc_dep3;
299 vassert((oldC & ~1) == 0);
300 UInt res = argL - argR - (oldC ^ 1);
301 ULong zf = res == 0;
302 return zf;
303 }
304 case ARM64G_CC_OP_SBC64: {
305 /* (argL, argR, oldC) */
306 ULong argL = cc_dep1;
307 ULong argR = cc_dep2;
308 ULong oldC = cc_dep3;
309 vassert((oldC & ~1) == 0);
310 ULong res = argL - argR - (oldC ^ 1);
311 ULong zf = res == 0;
312 return zf;
313 }
314 case ARM64G_CC_OP_LOGIC32: {
315 /* (res, unused, unused) */
316 UInt res = (UInt)cc_dep1;
317 ULong zf = res == 0;
318 return zf;
319 }
320 case ARM64G_CC_OP_LOGIC64: {
321 /* (res, unused, unused) */
322 ULong res = cc_dep1;
323 ULong zf = res == 0;
324 return zf;
325 }
326 //ZZ case ARMG_CC_OP_MUL: {
327 //ZZ /* (res, unused, oldC:oldV) */
328 //ZZ UInt res = cc_dep1;
329 //ZZ UInt zf = res == 0;
330 //ZZ return zf;
331 //ZZ }
332 //ZZ case ARMG_CC_OP_MULL: {
333 //ZZ /* (resLo32, resHi32, oldC:oldV) */
334 //ZZ UInt resLo32 = cc_dep1;
335 //ZZ UInt resHi32 = cc_dep2;
336 //ZZ UInt zf = (resHi32|resLo32) == 0;
337 //ZZ return zf;
338 //ZZ }
339 default:
340 /* shouldn't really make these calls from generated code */
341 vex_printf("arm64g_calculate_flag_z"
342 "( op=%llu, dep1=0x%llx, dep2=0x%llx, dep3=0x%llx )\n",
343 cc_op, cc_dep1, cc_dep2, cc_dep3 );
344 vpanic("arm64g_calculate_flag_z");
345 }
346 }
347
348
349 /* CALLED FROM GENERATED CODE: CLEAN HELPER */
350 /* Calculate the C flag from the supplied thunk components, in the
351 least significant bit of the word. Returned bits 63:1 are zero. */
arm64g_calculate_flag_c(ULong cc_op,ULong cc_dep1,ULong cc_dep2,ULong cc_dep3)352 ULong arm64g_calculate_flag_c ( ULong cc_op, ULong cc_dep1,
353 ULong cc_dep2, ULong cc_dep3 )
354 {
355 switch (cc_op) {
356 case ARM64G_CC_OP_COPY: {
357 /* (nzcv:28x0, unused, unused) */
358 ULong cf = (cc_dep1 >> ARM64G_CC_SHIFT_C) & 1;
359 return cf;
360 }
361 case ARM64G_CC_OP_ADD32: {
362 /* (argL, argR, unused) */
363 UInt argL = (UInt)cc_dep1;
364 UInt argR = (UInt)cc_dep2;
365 UInt res = argL + argR;
366 ULong cf = res < argL;
367 return cf;
368 }
369 case ARM64G_CC_OP_ADD64: {
370 /* (argL, argR, unused) */
371 ULong argL = cc_dep1;
372 ULong argR = cc_dep2;
373 ULong res = argL + argR;
374 ULong cf = res < argL;
375 return cf;
376 }
377 case ARM64G_CC_OP_SUB32: {
378 /* (argL, argR, unused) */
379 UInt argL = (UInt)cc_dep1;
380 UInt argR = (UInt)cc_dep2;
381 ULong cf = argL >= argR;
382 return cf;
383 }
384 case ARM64G_CC_OP_SUB64: {
385 /* (argL, argR, unused) */
386 ULong argL = cc_dep1;
387 ULong argR = cc_dep2;
388 ULong cf = argL >= argR;
389 return cf;
390 }
391 case ARM64G_CC_OP_ADC32: {
392 /* (argL, argR, oldC) */
393 UInt argL = cc_dep1;
394 UInt argR = cc_dep2;
395 UInt oldC = cc_dep3;
396 vassert((oldC & ~1) == 0);
397 UInt res = argL + argR + oldC;
398 ULong cf = oldC ? (res <= argL) : (res < argL);
399 return cf;
400 }
401 case ARM64G_CC_OP_ADC64: {
402 /* (argL, argR, oldC) */
403 ULong argL = cc_dep1;
404 ULong argR = cc_dep2;
405 ULong oldC = cc_dep3;
406 vassert((oldC & ~1) == 0);
407 ULong res = argL + argR + oldC;
408 ULong cf = oldC ? (res <= argL) : (res < argL);
409 return cf;
410 }
411 case ARM64G_CC_OP_SBC32: {
412 /* (argL, argR, oldC) */
413 UInt argL = cc_dep1;
414 UInt argR = cc_dep2;
415 UInt oldC = cc_dep3;
416 vassert((oldC & ~1) == 0);
417 ULong cf = oldC ? (argL >= argR) : (argL > argR);
418 return cf;
419 }
420 case ARM64G_CC_OP_SBC64: {
421 /* (argL, argR, oldC) */
422 ULong argL = cc_dep1;
423 ULong argR = cc_dep2;
424 ULong oldC = cc_dep3;
425 vassert((oldC & ~1) == 0);
426 ULong cf = oldC ? (argL >= argR) : (argL > argR);
427 return cf;
428 }
429 case ARM64G_CC_OP_LOGIC32:
430 case ARM64G_CC_OP_LOGIC64: {
431 /* (res, unused, unused) */
432 return 0; // C after logic is zero on arm64
433 }
434 //ZZ case ARMG_CC_OP_MUL: {
435 //ZZ /* (res, unused, oldC:oldV) */
436 //ZZ UInt oldC = (cc_dep3 >> 1) & 1;
437 //ZZ vassert((cc_dep3 & ~3) == 0);
438 //ZZ UInt cf = oldC;
439 //ZZ return cf;
440 //ZZ }
441 //ZZ case ARMG_CC_OP_MULL: {
442 //ZZ /* (resLo32, resHi32, oldC:oldV) */
443 //ZZ UInt oldC = (cc_dep3 >> 1) & 1;
444 //ZZ vassert((cc_dep3 & ~3) == 0);
445 //ZZ UInt cf = oldC;
446 //ZZ return cf;
447 //ZZ }
448 default:
449 /* shouldn't really make these calls from generated code */
450 vex_printf("arm64g_calculate_flag_c"
451 "( op=%llu, dep1=0x%llx, dep2=0x%llx, dep3=0x%llx )\n",
452 cc_op, cc_dep1, cc_dep2, cc_dep3 );
453 vpanic("arm64g_calculate_flag_c");
454 }
455 }
456
457
458 /* CALLED FROM GENERATED CODE: CLEAN HELPER */
459 /* Calculate the V flag from the supplied thunk components, in the
460 least significant bit of the word. Returned bits 63:1 are zero. */
461 static
arm64g_calculate_flag_v(ULong cc_op,ULong cc_dep1,ULong cc_dep2,ULong cc_dep3)462 ULong arm64g_calculate_flag_v ( ULong cc_op, ULong cc_dep1,
463 ULong cc_dep2, ULong cc_dep3 )
464 {
465 switch (cc_op) {
466 case ARM64G_CC_OP_COPY: {
467 /* (nzcv:28x0, unused, unused) */
468 ULong vf = (cc_dep1 >> ARM64G_CC_SHIFT_V) & 1;
469 return vf;
470 }
471 case ARM64G_CC_OP_ADD32: {
472 /* (argL, argR, unused) */
473 UInt argL = (UInt)cc_dep1;
474 UInt argR = (UInt)cc_dep2;
475 UInt res = argL + argR;
476 ULong vf = (ULong)(((res ^ argL) & (res ^ argR)) >> 31);
477 return vf;
478 }
479 case ARM64G_CC_OP_ADD64: {
480 /* (argL, argR, unused) */
481 ULong argL = cc_dep1;
482 ULong argR = cc_dep2;
483 ULong res = argL + argR;
484 ULong vf = ((res ^ argL) & (res ^ argR)) >> 63;
485 return vf;
486 }
487 case ARM64G_CC_OP_SUB32: {
488 /* (argL, argR, unused) */
489 UInt argL = (UInt)cc_dep1;
490 UInt argR = (UInt)cc_dep2;
491 UInt res = argL - argR;
492 ULong vf = (ULong)(((argL ^ argR) & (argL ^ res)) >> 31);
493 return vf;
494 }
495 case ARM64G_CC_OP_SUB64: {
496 /* (argL, argR, unused) */
497 ULong argL = cc_dep1;
498 ULong argR = cc_dep2;
499 ULong res = argL - argR;
500 ULong vf = (((argL ^ argR) & (argL ^ res))) >> 63;
501 return vf;
502 }
503 case ARM64G_CC_OP_ADC32: {
504 /* (argL, argR, oldC) */
505 UInt argL = cc_dep1;
506 UInt argR = cc_dep2;
507 UInt oldC = cc_dep3;
508 vassert((oldC & ~1) == 0);
509 UInt res = argL + argR + oldC;
510 ULong vf = (ULong)(((res ^ argL) & (res ^ argR)) >> 31);
511 return vf;
512 }
513 case ARM64G_CC_OP_ADC64: {
514 /* (argL, argR, oldC) */
515 ULong argL = cc_dep1;
516 ULong argR = cc_dep2;
517 ULong oldC = cc_dep3;
518 vassert((oldC & ~1) == 0);
519 ULong res = argL + argR + oldC;
520 ULong vf = ((res ^ argL) & (res ^ argR)) >> 63;
521 return vf;
522 }
523 case ARM64G_CC_OP_SBC32: {
524 /* (argL, argR, oldC) */
525 UInt argL = cc_dep1;
526 UInt argR = cc_dep2;
527 UInt oldC = cc_dep3;
528 vassert((oldC & ~1) == 0);
529 UInt res = argL - argR - (oldC ^ 1);
530 ULong vf = (ULong)(((argL ^ argR) & (argL ^ res)) >> 31);
531 return vf;
532 }
533 case ARM64G_CC_OP_SBC64: {
534 /* (argL, argR, oldC) */
535 ULong argL = cc_dep1;
536 ULong argR = cc_dep2;
537 ULong oldC = cc_dep3;
538 vassert((oldC & ~1) == 0);
539 ULong res = argL - argR - (oldC ^ 1);
540 ULong vf = ((argL ^ argR) & (argL ^ res)) >> 63;
541 return vf;
542 }
543 case ARM64G_CC_OP_LOGIC32:
544 case ARM64G_CC_OP_LOGIC64: {
545 /* (res, unused, unused) */
546 return 0; // V after logic is zero on arm64
547 }
548 //ZZ case ARMG_CC_OP_MUL: {
549 //ZZ /* (res, unused, oldC:oldV) */
550 //ZZ UInt oldV = (cc_dep3 >> 0) & 1;
551 //ZZ vassert((cc_dep3 & ~3) == 0);
552 //ZZ UInt vf = oldV;
553 //ZZ return vf;
554 //ZZ }
555 //ZZ case ARMG_CC_OP_MULL: {
556 //ZZ /* (resLo32, resHi32, oldC:oldV) */
557 //ZZ UInt oldV = (cc_dep3 >> 0) & 1;
558 //ZZ vassert((cc_dep3 & ~3) == 0);
559 //ZZ UInt vf = oldV;
560 //ZZ return vf;
561 //ZZ }
562 default:
563 /* shouldn't really make these calls from generated code */
564 vex_printf("arm64g_calculate_flag_v"
565 "( op=%llu, dep1=0x%llx, dep2=0x%llx, dep3=0x%llx )\n",
566 cc_op, cc_dep1, cc_dep2, cc_dep3 );
567 vpanic("arm64g_calculate_flag_v");
568 }
569 }
570
571
572 /* CALLED FROM GENERATED CODE: CLEAN HELPER */
573 /* Calculate NZCV from the supplied thunk components, in the positions
574 they appear in the CPSR, viz bits 31:28 for N Z C V respectively.
575 Returned bits 27:0 are zero. */
arm64g_calculate_flags_nzcv(ULong cc_op,ULong cc_dep1,ULong cc_dep2,ULong cc_dep3)576 ULong arm64g_calculate_flags_nzcv ( ULong cc_op, ULong cc_dep1,
577 ULong cc_dep2, ULong cc_dep3 )
578 {
579 ULong f;
580 ULong res = 0;
581 f = 1 & arm64g_calculate_flag_n(cc_op, cc_dep1, cc_dep2, cc_dep3);
582 res |= (f << ARM64G_CC_SHIFT_N);
583 f = 1 & arm64g_calculate_flag_z(cc_op, cc_dep1, cc_dep2, cc_dep3);
584 res |= (f << ARM64G_CC_SHIFT_Z);
585 f = 1 & arm64g_calculate_flag_c(cc_op, cc_dep1, cc_dep2, cc_dep3);
586 res |= (f << ARM64G_CC_SHIFT_C);
587 f = 1 & arm64g_calculate_flag_v(cc_op, cc_dep1, cc_dep2, cc_dep3);
588 res |= (f << ARM64G_CC_SHIFT_V);
589 return res;
590 }
591
592 //ZZ
593 //ZZ /* CALLED FROM GENERATED CODE: CLEAN HELPER */
594 //ZZ /* Calculate the QC flag from the arguments, in the lowest bit
595 //ZZ of the word (bit 0). Urr, having this out of line is bizarre.
596 //ZZ Push back inline. */
597 //ZZ UInt armg_calculate_flag_qc ( UInt resL1, UInt resL2,
598 //ZZ UInt resR1, UInt resR2 )
599 //ZZ {
600 //ZZ if (resL1 != resR1 || resL2 != resR2)
601 //ZZ return 1;
602 //ZZ else
603 //ZZ return 0;
604 //ZZ }
605
606 /* CALLED FROM GENERATED CODE: CLEAN HELPER */
607 /* Calculate the specified condition from the thunk components, in the
608 lowest bit of the word (bit 0). Returned bits 63:1 are zero. */
arm64g_calculate_condition(ULong cond_n_op,ULong cc_dep1,ULong cc_dep2,ULong cc_dep3)609 ULong arm64g_calculate_condition ( /* ARM64Condcode << 4 | cc_op */
610 ULong cond_n_op ,
611 ULong cc_dep1,
612 ULong cc_dep2, ULong cc_dep3 )
613 {
614 ULong cond = cond_n_op >> 4;
615 ULong cc_op = cond_n_op & 0xF;
616 ULong inv = cond & 1;
617 ULong nf, zf, vf, cf;
618
619 # if PROFILE_NZCV_FLAGS
620 NOTE_EVAL(cc_op, cond);
621 # endif
622
623 // vex_printf("XXXXXXXX %llx %llx %llx %llx\n",
624 // cond_n_op, cc_dep1, cc_dep2, cc_dep3);
625
626 switch (cond) {
627 case ARM64CondEQ: // Z=1 => z
628 case ARM64CondNE: // Z=0
629 zf = arm64g_calculate_flag_z(cc_op, cc_dep1, cc_dep2, cc_dep3);
630 return inv ^ zf;
631
632 case ARM64CondCS: // C=1 => c
633 case ARM64CondCC: // C=0
634 cf = arm64g_calculate_flag_c(cc_op, cc_dep1, cc_dep2, cc_dep3);
635 return inv ^ cf;
636
637 case ARM64CondMI: // N=1 => n
638 case ARM64CondPL: // N=0
639 nf = arm64g_calculate_flag_n(cc_op, cc_dep1, cc_dep2, cc_dep3);
640 return inv ^ nf;
641
642 case ARM64CondVS: // V=1 => v
643 case ARM64CondVC: // V=0
644 vf = arm64g_calculate_flag_v(cc_op, cc_dep1, cc_dep2, cc_dep3);
645 return inv ^ vf;
646
647 case ARM64CondHI: // C=1 && Z=0 => c & ~z
648 case ARM64CondLS: // C=0 || Z=1
649 cf = arm64g_calculate_flag_c(cc_op, cc_dep1, cc_dep2, cc_dep3);
650 zf = arm64g_calculate_flag_z(cc_op, cc_dep1, cc_dep2, cc_dep3);
651 return inv ^ (1 & (cf & ~zf));
652
653 case ARM64CondGE: // N=V => ~(n^v)
654 case ARM64CondLT: // N!=V
655 nf = arm64g_calculate_flag_n(cc_op, cc_dep1, cc_dep2, cc_dep3);
656 vf = arm64g_calculate_flag_v(cc_op, cc_dep1, cc_dep2, cc_dep3);
657 return inv ^ (1 & ~(nf ^ vf));
658
659 case ARM64CondGT: // Z=0 && N=V => ~z & ~(n^v) => ~(z | (n^v))
660 case ARM64CondLE: // Z=1 || N!=V
661 nf = arm64g_calculate_flag_n(cc_op, cc_dep1, cc_dep2, cc_dep3);
662 vf = arm64g_calculate_flag_v(cc_op, cc_dep1, cc_dep2, cc_dep3);
663 zf = arm64g_calculate_flag_z(cc_op, cc_dep1, cc_dep2, cc_dep3);
664 return inv ^ (1 & ~(zf | (nf ^ vf)));
665
666 case ARM64CondAL: // 1
667 case ARM64CondNV: // 1
668 return 1;
669
670 default:
671 /* shouldn't really make these calls from generated code */
672 vex_printf("arm64g_calculate_condition(ARM64)"
673 "( %llu, %llu, 0x%llx, 0x%llx, 0x%llx )\n",
674 cond, cc_op, cc_dep1, cc_dep2, cc_dep3 );
675 vpanic("armg_calculate_condition(ARM64)");
676 }
677 }
678
679
680 /* CALLED FROM GENERATED CODE */
681 /* DIRTY HELPER (non-referentially-transparent) */
682 /* Horrible hack. On non-arm64 platforms, return 0. */
arm64g_dirtyhelper_MRS_CNTVCT_EL0(void)683 ULong arm64g_dirtyhelper_MRS_CNTVCT_EL0 ( void )
684 {
685 # if defined(__aarch64__) && !defined(__arm__)
686 ULong w = 0x5555555555555555ULL; /* overwritten */
687 __asm__ __volatile__("mrs %0, cntvct_el0" : "=r"(w));
688 return w;
689 # else
690 return 0ULL;
691 # endif
692 }
693
694
695 /*---------------------------------------------------------------*/
696 /*--- Flag-helpers translation-time function specialisers. ---*/
697 /*--- These help iropt specialise calls the above run-time ---*/
698 /*--- flags functions. ---*/
699 /*---------------------------------------------------------------*/
700
701 /* Used by the optimiser to try specialisations. Returns an
702 equivalent expression, or NULL if none. */
703
isU64(IRExpr * e,ULong n)704 static Bool isU64 ( IRExpr* e, ULong n )
705 {
706 return
707 toBool( e->tag == Iex_Const
708 && e->Iex.Const.con->tag == Ico_U64
709 && e->Iex.Const.con->Ico.U64 == n );
710 }
711
guest_arm64_spechelper(const HChar * function_name,IRExpr ** args,IRStmt ** precedingStmts,Int n_precedingStmts)712 IRExpr* guest_arm64_spechelper ( const HChar* function_name,
713 IRExpr** args,
714 IRStmt** precedingStmts,
715 Int n_precedingStmts )
716 {
717 # define unop(_op,_a1) IRExpr_Unop((_op),(_a1))
718 # define binop(_op,_a1,_a2) IRExpr_Binop((_op),(_a1),(_a2))
719 # define mkU64(_n) IRExpr_Const(IRConst_U64(_n))
720 # define mkU8(_n) IRExpr_Const(IRConst_U8(_n))
721
722 Int i, arity = 0;
723 for (i = 0; args[i]; i++)
724 arity++;
725 //ZZ # if 0
726 //ZZ vex_printf("spec request:\n");
727 //ZZ vex_printf(" %s ", function_name);
728 //ZZ for (i = 0; i < arity; i++) {
729 //ZZ vex_printf(" ");
730 //ZZ ppIRExpr(args[i]);
731 //ZZ }
732 //ZZ vex_printf("\n");
733 //ZZ # endif
734
735 /* --------- specialising "arm64g_calculate_condition" --------- */
736
737 if (vex_streq(function_name, "arm64g_calculate_condition")) {
738
739 /* specialise calls to the "arm64g_calculate_condition" function.
740 Not sure whether this is strictly necessary, but: the
741 replacement IR must produce only the values 0 or 1. Bits
742 63:1 are required to be zero. */
743 IRExpr *cond_n_op, *cc_dep1, *cc_dep2 ; //, *cc_ndep;
744 vassert(arity == 4);
745 cond_n_op = args[0]; /* (ARM64Condcode << 4) | ARM64G_CC_OP_* */
746 cc_dep1 = args[1];
747 cc_dep2 = args[2];
748 //cc_ndep = args[3];
749
750 /*---------------- SUB64 ----------------*/
751
752 /* 0, 1 */
753 if (isU64(cond_n_op, (ARM64CondEQ << 4) | ARM64G_CC_OP_SUB64)) {
754 /* EQ after SUB --> test argL == argR */
755 return unop(Iop_1Uto64,
756 binop(Iop_CmpEQ64, cc_dep1, cc_dep2));
757 }
758 if (isU64(cond_n_op, (ARM64CondNE << 4) | ARM64G_CC_OP_SUB64)) {
759 /* NE after SUB --> test argL != argR */
760 return unop(Iop_1Uto64,
761 binop(Iop_CmpNE64, cc_dep1, cc_dep2));
762 }
763
764 /* 2, 3 */
765 if (isU64(cond_n_op, (ARM64CondCS << 4) | ARM64G_CC_OP_SUB64)) {
766 /* CS after SUB --> test argL >=u argR
767 --> test argR <=u argL */
768 return unop(Iop_1Uto64,
769 binop(Iop_CmpLE64U, cc_dep2, cc_dep1));
770 }
771 if (isU64(cond_n_op, (ARM64CondCC << 4) | ARM64G_CC_OP_SUB64)) {
772 /* CC after SUB --> test argL <u argR */
773 return unop(Iop_1Uto64,
774 binop(Iop_CmpLT64U, cc_dep1, cc_dep2));
775 }
776
777 /* 8, 9 */
778 if (isU64(cond_n_op, (ARM64CondLS << 4) | ARM64G_CC_OP_SUB64)) {
779 /* LS after SUB --> test argL <=u argR */
780 return unop(Iop_1Uto64,
781 binop(Iop_CmpLE64U, cc_dep1, cc_dep2));
782 }
783 if (isU64(cond_n_op, (ARM64CondHI << 4) | ARM64G_CC_OP_SUB64)) {
784 /* HI after SUB --> test argL >u argR
785 --> test argR <u argL */
786 return unop(Iop_1Uto64,
787 binop(Iop_CmpLT64U, cc_dep2, cc_dep1));
788 }
789
790 /* 10, 11 */
791 if (isU64(cond_n_op, (ARM64CondLT << 4) | ARM64G_CC_OP_SUB64)) {
792 /* LT after SUB --> test argL <s argR */
793 return unop(Iop_1Uto64,
794 binop(Iop_CmpLT64S, cc_dep1, cc_dep2));
795 }
796 if (isU64(cond_n_op, (ARM64CondGE << 4) | ARM64G_CC_OP_SUB64)) {
797 /* GE after SUB --> test argL >=s argR
798 --> test argR <=s argL */
799 return unop(Iop_1Uto64,
800 binop(Iop_CmpLE64S, cc_dep2, cc_dep1));
801 }
802
803 /* 12, 13 */
804 if (isU64(cond_n_op, (ARM64CondGT << 4) | ARM64G_CC_OP_SUB64)) {
805 /* GT after SUB --> test argL >s argR
806 --> test argR <s argL */
807 return unop(Iop_1Uto64,
808 binop(Iop_CmpLT64S, cc_dep2, cc_dep1));
809 }
810 if (isU64(cond_n_op, (ARM64CondLE << 4) | ARM64G_CC_OP_SUB64)) {
811 /* LE after SUB --> test argL <=s argR */
812 return unop(Iop_1Uto64,
813 binop(Iop_CmpLE64S, cc_dep1, cc_dep2));
814 }
815
816 /*---------------- SUB32 ----------------*/
817
818 /* 0, 1 */
819 if (isU64(cond_n_op, (ARM64CondEQ << 4) | ARM64G_CC_OP_SUB32)) {
820 /* EQ after SUB --> test argL == argR */
821 return unop(Iop_1Uto64,
822 binop(Iop_CmpEQ32, unop(Iop_64to32, cc_dep1),
823 unop(Iop_64to32, cc_dep2)));
824 }
825 if (isU64(cond_n_op, (ARM64CondNE << 4) | ARM64G_CC_OP_SUB32)) {
826 /* NE after SUB --> test argL != argR */
827 return unop(Iop_1Uto64,
828 binop(Iop_CmpNE32, unop(Iop_64to32, cc_dep1),
829 unop(Iop_64to32, cc_dep2)));
830 }
831
832 /* 2, 3 */
833 if (isU64(cond_n_op, (ARM64CondCS << 4) | ARM64G_CC_OP_SUB32)) {
834 /* CS after SUB --> test argL >=u argR
835 --> test argR <=u argL */
836 return unop(Iop_1Uto64,
837 binop(Iop_CmpLE32U, unop(Iop_64to32, cc_dep2),
838 unop(Iop_64to32, cc_dep1)));
839 }
840 if (isU64(cond_n_op, (ARM64CondCC << 4) | ARM64G_CC_OP_SUB32)) {
841 /* CC after SUB --> test argL <u argR */
842 return unop(Iop_1Uto64,
843 binop(Iop_CmpLT32U, unop(Iop_64to32, cc_dep1),
844 unop(Iop_64to32, cc_dep2)));
845 }
846
847 /* 8, 9 */
848 if (isU64(cond_n_op, (ARM64CondLS << 4) | ARM64G_CC_OP_SUB32)) {
849 /* LS after SUB --> test argL <=u argR */
850 return unop(Iop_1Uto64,
851 binop(Iop_CmpLE32U, unop(Iop_64to32, cc_dep1),
852 unop(Iop_64to32, cc_dep2)));
853 }
854 if (isU64(cond_n_op, (ARM64CondHI << 4) | ARM64G_CC_OP_SUB32)) {
855 /* HI after SUB --> test argL >u argR
856 --> test argR <u argL */
857 return unop(Iop_1Uto64,
858 binop(Iop_CmpLT32U, unop(Iop_64to32, cc_dep2),
859 unop(Iop_64to32, cc_dep1)));
860 }
861
862 /* 10, 11 */
863 if (isU64(cond_n_op, (ARM64CondLT << 4) | ARM64G_CC_OP_SUB32)) {
864 /* LT after SUB --> test argL <s argR */
865 return unop(Iop_1Uto64,
866 binop(Iop_CmpLT32S, unop(Iop_64to32, cc_dep1),
867 unop(Iop_64to32, cc_dep2)));
868 }
869 if (isU64(cond_n_op, (ARM64CondGE << 4) | ARM64G_CC_OP_SUB32)) {
870 /* GE after SUB --> test argL >=s argR
871 --> test argR <=s argL */
872 return unop(Iop_1Uto64,
873 binop(Iop_CmpLE32S, unop(Iop_64to32, cc_dep2),
874 unop(Iop_64to32, cc_dep1)));
875 }
876
877 /* 12, 13 */
878 if (isU64(cond_n_op, (ARM64CondGT << 4) | ARM64G_CC_OP_SUB32)) {
879 /* GT after SUB --> test argL >s argR
880 --> test argR <s argL */
881 return unop(Iop_1Uto64,
882 binop(Iop_CmpLT32S, unop(Iop_64to32, cc_dep2),
883 unop(Iop_64to32, cc_dep1)));
884 }
885 if (isU64(cond_n_op, (ARM64CondLE << 4) | ARM64G_CC_OP_SUB32)) {
886 /* LE after SUB --> test argL <=s argR */
887 return unop(Iop_1Uto64,
888 binop(Iop_CmpLE32S, unop(Iop_64to32, cc_dep1),
889 unop(Iop_64to32, cc_dep2)));
890 }
891
892 //ZZ /*---------------- SBB ----------------*/
893 //ZZ
894 //ZZ if (isU32(cond_n_op, (ARMCondHS << 4) | ARMG_CC_OP_SBB)) {
895 //ZZ /* This seems to happen a lot in softfloat code, eg __divdf3+140 */
896 //ZZ /* thunk is: (dep1=argL, dep2=argR, ndep=oldC) */
897 //ZZ /* HS after SBB (same as C after SBB below)
898 //ZZ --> oldC ? (argL >=u argR) : (argL >u argR)
899 //ZZ --> oldC ? (argR <=u argL) : (argR <u argL)
900 //ZZ */
901 //ZZ return
902 //ZZ IRExpr_ITE(
903 //ZZ binop(Iop_CmpNE32, cc_ndep, mkU32(0)),
904 //ZZ /* case oldC != 0 */
905 //ZZ unop(Iop_1Uto32, binop(Iop_CmpLE32U, cc_dep2, cc_dep1)),
906 //ZZ /* case oldC == 0 */
907 //ZZ unop(Iop_1Uto32, binop(Iop_CmpLT32U, cc_dep2, cc_dep1))
908 //ZZ );
909 //ZZ }
910 //ZZ
911 //ZZ /*---------------- LOGIC ----------------*/
912 //ZZ
913 //ZZ if (isU32(cond_n_op, (ARMCondEQ << 4) | ARMG_CC_OP_LOGIC)) {
914 //ZZ /* EQ after LOGIC --> test res == 0 */
915 //ZZ return unop(Iop_1Uto32,
916 //ZZ binop(Iop_CmpEQ32, cc_dep1, mkU32(0)));
917 //ZZ }
918 //ZZ if (isU32(cond_n_op, (ARMCondNE << 4) | ARMG_CC_OP_LOGIC)) {
919 //ZZ /* NE after LOGIC --> test res != 0 */
920 //ZZ return unop(Iop_1Uto32,
921 //ZZ binop(Iop_CmpNE32, cc_dep1, mkU32(0)));
922 //ZZ }
923 //ZZ
924 //ZZ if (isU32(cond_n_op, (ARMCondPL << 4) | ARMG_CC_OP_LOGIC)) {
925 //ZZ /* PL after LOGIC --> test (res >> 31) == 0 */
926 //ZZ return unop(Iop_1Uto32,
927 //ZZ binop(Iop_CmpEQ32,
928 //ZZ binop(Iop_Shr32, cc_dep1, mkU8(31)),
929 //ZZ mkU32(0)));
930 //ZZ }
931 //ZZ if (isU32(cond_n_op, (ARMCondMI << 4) | ARMG_CC_OP_LOGIC)) {
932 //ZZ /* MI after LOGIC --> test (res >> 31) == 1 */
933 //ZZ return unop(Iop_1Uto32,
934 //ZZ binop(Iop_CmpEQ32,
935 //ZZ binop(Iop_Shr32, cc_dep1, mkU8(31)),
936 //ZZ mkU32(1)));
937 //ZZ }
938
939 /*---------------- COPY ----------------*/
940
941 if (isU64(cond_n_op, (ARM64CondEQ << 4) | ARM64G_CC_OP_COPY)) {
942 /* EQ after COPY --> (cc_dep1 >> ARM64G_CC_SHIFT_Z) & 1 */
943 return binop(Iop_And64,
944 binop(Iop_Shr64, cc_dep1,
945 mkU8(ARM64G_CC_SHIFT_Z)),
946 mkU64(1));
947 }
948 if (isU64(cond_n_op, (ARM64CondNE << 4) | ARM64G_CC_OP_COPY)) {
949 /* NE after COPY --> ((cc_dep1 >> ARM64G_CC_SHIFT_Z) ^ 1) & 1 */
950 return binop(Iop_And64,
951 binop(Iop_Xor64,
952 binop(Iop_Shr64, cc_dep1,
953 mkU8(ARM64G_CC_SHIFT_Z)),
954 mkU64(1)),
955 mkU64(1));
956 }
957
958 //ZZ /*----------------- AL -----------------*/
959 //ZZ
960 //ZZ /* A critically important case for Thumb code.
961 //ZZ
962 //ZZ What we're trying to spot is the case where cond_n_op is an
963 //ZZ expression of the form Or32(..., 0xE0) since that means the
964 //ZZ caller is asking for CondAL and we can simply return 1
965 //ZZ without caring what the ... part is. This is a potentially
966 //ZZ dodgy kludge in that it assumes that the ... part has zeroes
967 //ZZ in bits 7:4, so that the result of the Or32 is guaranteed to
968 //ZZ be 0xE in bits 7:4. Given that the places where this first
969 //ZZ arg are constructed (in guest_arm_toIR.c) are very
970 //ZZ constrained, we can get away with this. To make this
971 //ZZ guaranteed safe would require to have a new primop, Slice44
972 //ZZ or some such, thusly
973 //ZZ
974 //ZZ Slice44(arg1, arg2) = 0--(24)--0 arg1[7:4] arg2[3:0]
975 //ZZ
976 //ZZ and we would then look for Slice44(0xE0, ...)
977 //ZZ which would give the required safety property.
978 //ZZ
979 //ZZ It would be infeasibly expensive to scan backwards through
980 //ZZ the entire block looking for an assignment to the temp, so
981 //ZZ just look at the previous 16 statements. That should find it
982 //ZZ if it is an interesting case, as a result of how the
983 //ZZ boilerplate guff at the start of each Thumb insn translation
984 //ZZ is made.
985 //ZZ */
986 //ZZ if (cond_n_op->tag == Iex_RdTmp) {
987 //ZZ Int j;
988 //ZZ IRTemp look_for = cond_n_op->Iex.RdTmp.tmp;
989 //ZZ Int limit = n_precedingStmts - 16;
990 //ZZ if (limit < 0) limit = 0;
991 //ZZ if (0) vex_printf("scanning %d .. %d\n", n_precedingStmts-1, limit);
992 //ZZ for (j = n_precedingStmts - 1; j >= limit; j--) {
993 //ZZ IRStmt* st = precedingStmts[j];
994 //ZZ if (st->tag == Ist_WrTmp
995 //ZZ && st->Ist.WrTmp.tmp == look_for
996 //ZZ && st->Ist.WrTmp.data->tag == Iex_Binop
997 //ZZ && st->Ist.WrTmp.data->Iex.Binop.op == Iop_Or32
998 //ZZ && isU32(st->Ist.WrTmp.data->Iex.Binop.arg2, (ARMCondAL << 4)))
999 //ZZ return mkU32(1);
1000 //ZZ }
1001 //ZZ /* Didn't find any useful binding to the first arg
1002 //ZZ in the previous 16 stmts. */
1003 //ZZ }
1004 }
1005
1006 //ZZ /* --------- specialising "armg_calculate_flag_c" --------- */
1007 //ZZ
1008 //ZZ else
1009 //ZZ if (vex_streq(function_name, "armg_calculate_flag_c")) {
1010 //ZZ
1011 //ZZ /* specialise calls to the "armg_calculate_flag_c" function.
1012 //ZZ Note that the returned value must be either 0 or 1; nonzero
1013 //ZZ bits 31:1 are not allowed. In turn, incoming oldV and oldC
1014 //ZZ values (from the thunk) are assumed to have bits 31:1
1015 //ZZ clear. */
1016 //ZZ IRExpr *cc_op, *cc_dep1, *cc_dep2, *cc_ndep;
1017 //ZZ vassert(arity == 4);
1018 //ZZ cc_op = args[0]; /* ARMG_CC_OP_* */
1019 //ZZ cc_dep1 = args[1];
1020 //ZZ cc_dep2 = args[2];
1021 //ZZ cc_ndep = args[3];
1022 //ZZ
1023 //ZZ if (isU32(cc_op, ARMG_CC_OP_LOGIC)) {
1024 //ZZ /* Thunk args are (result, shco, oldV) */
1025 //ZZ /* C after LOGIC --> shco */
1026 //ZZ return cc_dep2;
1027 //ZZ }
1028 //ZZ
1029 //ZZ if (isU32(cc_op, ARMG_CC_OP_SUB)) {
1030 //ZZ /* Thunk args are (argL, argR, unused) */
1031 //ZZ /* C after SUB --> argL >=u argR
1032 //ZZ --> argR <=u argL */
1033 //ZZ return unop(Iop_1Uto32,
1034 //ZZ binop(Iop_CmpLE32U, cc_dep2, cc_dep1));
1035 //ZZ }
1036 //ZZ
1037 //ZZ if (isU32(cc_op, ARMG_CC_OP_SBB)) {
1038 //ZZ /* This happens occasionally in softfloat code, eg __divdf3+140 */
1039 //ZZ /* thunk is: (dep1=argL, dep2=argR, ndep=oldC) */
1040 //ZZ /* C after SBB (same as HS after SBB above)
1041 //ZZ --> oldC ? (argL >=u argR) : (argL >u argR)
1042 //ZZ --> oldC ? (argR <=u argL) : (argR <u argL)
1043 //ZZ */
1044 //ZZ return
1045 //ZZ IRExpr_ITE(
1046 //ZZ binop(Iop_CmpNE32, cc_ndep, mkU32(0)),
1047 //ZZ /* case oldC != 0 */
1048 //ZZ unop(Iop_1Uto32, binop(Iop_CmpLE32U, cc_dep2, cc_dep1)),
1049 //ZZ /* case oldC == 0 */
1050 //ZZ unop(Iop_1Uto32, binop(Iop_CmpLT32U, cc_dep2, cc_dep1))
1051 //ZZ );
1052 //ZZ }
1053 //ZZ
1054 //ZZ }
1055 //ZZ
1056 //ZZ /* --------- specialising "armg_calculate_flag_v" --------- */
1057 //ZZ
1058 //ZZ else
1059 //ZZ if (vex_streq(function_name, "armg_calculate_flag_v")) {
1060 //ZZ
1061 //ZZ /* specialise calls to the "armg_calculate_flag_v" function.
1062 //ZZ Note that the returned value must be either 0 or 1; nonzero
1063 //ZZ bits 31:1 are not allowed. In turn, incoming oldV and oldC
1064 //ZZ values (from the thunk) are assumed to have bits 31:1
1065 //ZZ clear. */
1066 //ZZ IRExpr *cc_op, *cc_dep1, *cc_dep2, *cc_ndep;
1067 //ZZ vassert(arity == 4);
1068 //ZZ cc_op = args[0]; /* ARMG_CC_OP_* */
1069 //ZZ cc_dep1 = args[1];
1070 //ZZ cc_dep2 = args[2];
1071 //ZZ cc_ndep = args[3];
1072 //ZZ
1073 //ZZ if (isU32(cc_op, ARMG_CC_OP_LOGIC)) {
1074 //ZZ /* Thunk args are (result, shco, oldV) */
1075 //ZZ /* V after LOGIC --> oldV */
1076 //ZZ return cc_ndep;
1077 //ZZ }
1078 //ZZ
1079 //ZZ if (isU32(cc_op, ARMG_CC_OP_SUB)) {
1080 //ZZ /* Thunk args are (argL, argR, unused) */
1081 //ZZ /* V after SUB
1082 //ZZ --> let res = argL - argR
1083 //ZZ in ((argL ^ argR) & (argL ^ res)) >> 31
1084 //ZZ --> ((argL ^ argR) & (argL ^ (argL - argR))) >> 31
1085 //ZZ */
1086 //ZZ IRExpr* argL = cc_dep1;
1087 //ZZ IRExpr* argR = cc_dep2;
1088 //ZZ return
1089 //ZZ binop(Iop_Shr32,
1090 //ZZ binop(Iop_And32,
1091 //ZZ binop(Iop_Xor32, argL, argR),
1092 //ZZ binop(Iop_Xor32, argL, binop(Iop_Sub32, argL, argR))
1093 //ZZ ),
1094 //ZZ mkU8(31)
1095 //ZZ );
1096 //ZZ }
1097 //ZZ
1098 //ZZ if (isU32(cc_op, ARMG_CC_OP_SBB)) {
1099 //ZZ /* This happens occasionally in softfloat code, eg __divdf3+140 */
1100 //ZZ /* thunk is: (dep1=argL, dep2=argR, ndep=oldC) */
1101 //ZZ /* V after SBB
1102 //ZZ --> let res = argL - argR - (oldC ^ 1)
1103 //ZZ in (argL ^ argR) & (argL ^ res) & 1
1104 //ZZ */
1105 //ZZ return
1106 //ZZ binop(
1107 //ZZ Iop_And32,
1108 //ZZ binop(
1109 //ZZ Iop_And32,
1110 //ZZ // argL ^ argR
1111 //ZZ binop(Iop_Xor32, cc_dep1, cc_dep2),
1112 //ZZ // argL ^ (argL - argR - (oldC ^ 1))
1113 //ZZ binop(Iop_Xor32,
1114 //ZZ cc_dep1,
1115 //ZZ binop(Iop_Sub32,
1116 //ZZ binop(Iop_Sub32, cc_dep1, cc_dep2),
1117 //ZZ binop(Iop_Xor32, cc_ndep, mkU32(1)))
1118 //ZZ )
1119 //ZZ ),
1120 //ZZ mkU32(1)
1121 //ZZ );
1122 //ZZ }
1123 //ZZ
1124 //ZZ }
1125
1126 # undef unop
1127 # undef binop
1128 # undef mkU64
1129 # undef mkU8
1130
1131 return NULL;
1132 }
1133
1134
1135 /*----------------------------------------------*/
1136 /*--- The exported fns .. ---*/
1137 /*----------------------------------------------*/
1138
1139 //ZZ /* VISIBLE TO LIBVEX CLIENT */
1140 //ZZ #if 0
1141 //ZZ void LibVEX_GuestARM_put_flags ( UInt flags_native,
1142 //ZZ /*OUT*/VexGuestARMState* vex_state )
1143 //ZZ {
1144 //ZZ vassert(0); // FIXME
1145 //ZZ
1146 //ZZ /* Mask out everything except N Z V C. */
1147 //ZZ flags_native
1148 //ZZ &= (ARMG_CC_MASK_N | ARMG_CC_MASK_Z | ARMG_CC_MASK_V | ARMG_CC_MASK_C);
1149 //ZZ
1150 //ZZ vex_state->guest_CC_OP = ARMG_CC_OP_COPY;
1151 //ZZ vex_state->guest_CC_DEP1 = flags_native;
1152 //ZZ vex_state->guest_CC_DEP2 = 0;
1153 //ZZ vex_state->guest_CC_NDEP = 0;
1154 //ZZ }
1155 //ZZ #endif
1156
1157 /* VISIBLE TO LIBVEX CLIENT */
LibVEX_GuestARM64_get_nzcv(const VexGuestARM64State * vex_state)1158 ULong LibVEX_GuestARM64_get_nzcv ( /*IN*/const VexGuestARM64State* vex_state )
1159 {
1160 ULong nzcv = 0;
1161 // NZCV
1162 nzcv |= arm64g_calculate_flags_nzcv(
1163 vex_state->guest_CC_OP,
1164 vex_state->guest_CC_DEP1,
1165 vex_state->guest_CC_DEP2,
1166 vex_state->guest_CC_NDEP
1167 );
1168 vassert(0 == (nzcv & 0xFFFFFFFF0FFFFFFFULL));
1169 //ZZ // Q
1170 //ZZ if (vex_state->guest_QFLAG32 > 0)
1171 //ZZ cpsr |= (1 << 27);
1172 //ZZ // GE
1173 //ZZ if (vex_state->guest_GEFLAG0 > 0)
1174 //ZZ cpsr |= (1 << 16);
1175 //ZZ if (vex_state->guest_GEFLAG1 > 0)
1176 //ZZ cpsr |= (1 << 17);
1177 //ZZ if (vex_state->guest_GEFLAG2 > 0)
1178 //ZZ cpsr |= (1 << 18);
1179 //ZZ if (vex_state->guest_GEFLAG3 > 0)
1180 //ZZ cpsr |= (1 << 19);
1181 //ZZ // M
1182 //ZZ cpsr |= (1 << 4); // 0b10000 means user-mode
1183 //ZZ // J,T J (bit 24) is zero by initialisation above
1184 //ZZ // T we copy from R15T[0]
1185 //ZZ if (vex_state->guest_R15T & 1)
1186 //ZZ cpsr |= (1 << 5);
1187 //ZZ // ITSTATE we punt on for the time being. Could compute it
1188 //ZZ // if needed though.
1189 //ZZ // E, endianness, 0 (littleendian) from initialisation above
1190 //ZZ // A,I,F disable some async exceptions. Not sure about these.
1191 //ZZ // Leave as zero for the time being.
1192 return nzcv;
1193 }
1194
1195 /* VISIBLE TO LIBVEX CLIENT */
LibVEX_GuestARM64_get_fpsr(const VexGuestARM64State * vex_state)1196 ULong LibVEX_GuestARM64_get_fpsr ( const VexGuestARM64State* vex_state )
1197 {
1198 UInt w32 = vex_state->guest_QCFLAG[0] | vex_state->guest_QCFLAG[1]
1199 | vex_state->guest_QCFLAG[2] | vex_state->guest_QCFLAG[3];
1200 ULong fpsr = 0;
1201 // QC
1202 if (w32 != 0)
1203 fpsr |= (1 << 27);
1204 return fpsr;
1205 }
1206
LibVEX_GuestARM64_set_fpsr(VexGuestARM64State * vex_state,ULong fpsr)1207 void LibVEX_GuestARM64_set_fpsr ( /*MOD*/VexGuestARM64State* vex_state,
1208 ULong fpsr )
1209 {
1210 // QC
1211 vex_state->guest_QCFLAG[0] = (UInt)((fpsr >> 27) & 1);
1212 vex_state->guest_QCFLAG[1] = 0;
1213 vex_state->guest_QCFLAG[2] = 0;
1214 vex_state->guest_QCFLAG[3] = 0;
1215 }
1216
1217 /* VISIBLE TO LIBVEX CLIENT */
LibVEX_GuestARM64_initialise(VexGuestARM64State * vex_state)1218 void LibVEX_GuestARM64_initialise ( /*OUT*/VexGuestARM64State* vex_state )
1219 {
1220 vex_bzero(vex_state, sizeof(*vex_state));
1221 //ZZ vex_state->host_EvC_FAILADDR = 0;
1222 //ZZ vex_state->host_EvC_COUNTER = 0;
1223 //ZZ
1224 //ZZ vex_state->guest_R0 = 0;
1225 //ZZ vex_state->guest_R1 = 0;
1226 //ZZ vex_state->guest_R2 = 0;
1227 //ZZ vex_state->guest_R3 = 0;
1228 //ZZ vex_state->guest_R4 = 0;
1229 //ZZ vex_state->guest_R5 = 0;
1230 //ZZ vex_state->guest_R6 = 0;
1231 //ZZ vex_state->guest_R7 = 0;
1232 //ZZ vex_state->guest_R8 = 0;
1233 //ZZ vex_state->guest_R9 = 0;
1234 //ZZ vex_state->guest_R10 = 0;
1235 //ZZ vex_state->guest_R11 = 0;
1236 //ZZ vex_state->guest_R12 = 0;
1237 //ZZ vex_state->guest_R13 = 0;
1238 //ZZ vex_state->guest_R14 = 0;
1239 //ZZ vex_state->guest_R15T = 0; /* NB: implies ARM mode */
1240 //ZZ
1241 vex_state->guest_CC_OP = ARM64G_CC_OP_COPY;
1242 //ZZ vex_state->guest_CC_DEP1 = 0;
1243 //ZZ vex_state->guest_CC_DEP2 = 0;
1244 //ZZ vex_state->guest_CC_NDEP = 0;
1245 //ZZ vex_state->guest_QFLAG32 = 0;
1246 //ZZ vex_state->guest_GEFLAG0 = 0;
1247 //ZZ vex_state->guest_GEFLAG1 = 0;
1248 //ZZ vex_state->guest_GEFLAG2 = 0;
1249 //ZZ vex_state->guest_GEFLAG3 = 0;
1250 //ZZ
1251 //ZZ vex_state->guest_EMNOTE = EmNote_NONE;
1252 //ZZ vex_state->guest_CMSTART = 0;
1253 //ZZ vex_state->guest_CMLEN = 0;
1254 //ZZ vex_state->guest_NRADDR = 0;
1255 //ZZ vex_state->guest_IP_AT_SYSCALL = 0;
1256 //ZZ
1257 //ZZ vex_state->guest_D0 = 0;
1258 //ZZ vex_state->guest_D1 = 0;
1259 //ZZ vex_state->guest_D2 = 0;
1260 //ZZ vex_state->guest_D3 = 0;
1261 //ZZ vex_state->guest_D4 = 0;
1262 //ZZ vex_state->guest_D5 = 0;
1263 //ZZ vex_state->guest_D6 = 0;
1264 //ZZ vex_state->guest_D7 = 0;
1265 //ZZ vex_state->guest_D8 = 0;
1266 //ZZ vex_state->guest_D9 = 0;
1267 //ZZ vex_state->guest_D10 = 0;
1268 //ZZ vex_state->guest_D11 = 0;
1269 //ZZ vex_state->guest_D12 = 0;
1270 //ZZ vex_state->guest_D13 = 0;
1271 //ZZ vex_state->guest_D14 = 0;
1272 //ZZ vex_state->guest_D15 = 0;
1273 //ZZ vex_state->guest_D16 = 0;
1274 //ZZ vex_state->guest_D17 = 0;
1275 //ZZ vex_state->guest_D18 = 0;
1276 //ZZ vex_state->guest_D19 = 0;
1277 //ZZ vex_state->guest_D20 = 0;
1278 //ZZ vex_state->guest_D21 = 0;
1279 //ZZ vex_state->guest_D22 = 0;
1280 //ZZ vex_state->guest_D23 = 0;
1281 //ZZ vex_state->guest_D24 = 0;
1282 //ZZ vex_state->guest_D25 = 0;
1283 //ZZ vex_state->guest_D26 = 0;
1284 //ZZ vex_state->guest_D27 = 0;
1285 //ZZ vex_state->guest_D28 = 0;
1286 //ZZ vex_state->guest_D29 = 0;
1287 //ZZ vex_state->guest_D30 = 0;
1288 //ZZ vex_state->guest_D31 = 0;
1289 //ZZ
1290 //ZZ /* ARM encoded; zero is the default as it happens (result flags
1291 //ZZ (NZCV) cleared, FZ disabled, round to nearest, non-vector mode,
1292 //ZZ all exns masked, all exn sticky bits cleared). */
1293 //ZZ vex_state->guest_FPSCR = 0;
1294 //ZZ
1295 //ZZ vex_state->guest_TPIDRURO = 0;
1296 //ZZ
1297 //ZZ /* Not in a Thumb IT block. */
1298 //ZZ vex_state->guest_ITSTATE = 0;
1299 //ZZ
1300 //ZZ vex_state->padding1 = 0;
1301 //ZZ vex_state->padding2 = 0;
1302 //ZZ vex_state->padding3 = 0;
1303 //ZZ vex_state->padding4 = 0;
1304 //ZZ vex_state->padding5 = 0;
1305 }
1306
1307
1308 /*-----------------------------------------------------------*/
1309 /*--- Describing the arm guest state, for the benefit ---*/
1310 /*--- of iropt and instrumenters. ---*/
1311 /*-----------------------------------------------------------*/
1312
1313 /* Figure out if any part of the guest state contained in minoff
1314 .. maxoff requires precise memory exceptions. If in doubt return
1315 True (but this generates significantly slower code).
1316
1317 We enforce precise exns for guest SP, PC, 29(FP), 30(LR).
1318 That might be overkill (for 29 and 30); I don't know.
1319 */
guest_arm64_state_requires_precise_mem_exns(Int minoff,Int maxoff,VexRegisterUpdates pxControl)1320 Bool guest_arm64_state_requires_precise_mem_exns (
1321 Int minoff, Int maxoff, VexRegisterUpdates pxControl
1322 )
1323 {
1324 Int xsp_min = offsetof(VexGuestARM64State, guest_XSP);
1325 Int xsp_max = xsp_min + 8 - 1;
1326 Int pc_min = offsetof(VexGuestARM64State, guest_PC);
1327 Int pc_max = pc_min + 8 - 1;
1328
1329 if (maxoff < xsp_min || minoff > xsp_max) {
1330 /* no overlap with xsp */
1331 if (pxControl == VexRegUpdSpAtMemAccess)
1332 return False; // We only need to check stack pointer.
1333 } else {
1334 return True;
1335 }
1336
1337 if (maxoff < pc_min || minoff > pc_max) {
1338 /* no overlap with pc */
1339 } else {
1340 return True;
1341 }
1342
1343 /* Guessing that we need PX for FP, but I don't really know. */
1344 Int x29_min = offsetof(VexGuestARM64State, guest_X29);
1345 Int x29_max = x29_min + 8 - 1;
1346
1347 if (maxoff < x29_min || minoff > x29_max) {
1348 /* no overlap with x29 */
1349 } else {
1350 return True;
1351 }
1352
1353 /* Guessing that we need PX for LR, but I don't really know. */
1354 Int x30_min = offsetof(VexGuestARM64State, guest_X30);
1355 Int x30_max = x30_min + 8 - 1;
1356
1357 if (maxoff < x30_min || minoff > x30_max) {
1358 /* no overlap with r30 */
1359 } else {
1360 return True;
1361 }
1362
1363 return False;
1364 }
1365
1366
1367 #define ALWAYSDEFD(field) \
1368 { offsetof(VexGuestARM64State, field), \
1369 (sizeof ((VexGuestARM64State*)0)->field) }
1370 VexGuestLayout
1371 arm64Guest_layout
1372 = {
1373 /* Total size of the guest state, in bytes. */
1374 .total_sizeB = sizeof(VexGuestARM64State),
1375
1376 /* Describe the stack pointer. */
1377 .offset_SP = offsetof(VexGuestARM64State,guest_XSP),
1378 .sizeof_SP = 8,
1379
1380 /* Describe the instruction pointer. */
1381 .offset_IP = offsetof(VexGuestARM64State,guest_PC),
1382 .sizeof_IP = 8,
1383
1384 /* Describe any sections to be regarded by Memcheck as
1385 'always-defined'. */
1386 .n_alwaysDefd = 9,
1387
1388 /* flags thunk: OP is always defd, whereas DEP1 and DEP2
1389 have to be tracked. See detailed comment in gdefs.h on
1390 meaning of thunk fields. */
1391 .alwaysDefd
1392 = { /* 0 */ ALWAYSDEFD(guest_PC),
1393 /* 1 */ ALWAYSDEFD(guest_CC_OP),
1394 /* 2 */ ALWAYSDEFD(guest_CC_NDEP),
1395 /* 3 */ ALWAYSDEFD(guest_EMNOTE),
1396 /* 4 */ ALWAYSDEFD(guest_CMSTART),
1397 /* 5 */ ALWAYSDEFD(guest_CMLEN),
1398 /* 6 */ ALWAYSDEFD(guest_NRADDR),
1399 /* 7 */ ALWAYSDEFD(guest_IP_AT_SYSCALL),
1400 /* 8 */ ALWAYSDEFD(guest_TPIDR_EL0)
1401 }
1402 };
1403
1404
1405 /*---------------------------------------------------------------*/
1406 /*--- end guest_arm64_helpers.c ---*/
1407 /*---------------------------------------------------------------*/
1408