1 2/*---------------------------------------------------------------*/ 3/*--- begin guest_arm_helpers.c ---*/ 4/*---------------------------------------------------------------*/ 5 6/* 7 This file is part of Valgrind, a dynamic binary instrumentation 8 framework. 9 10 Copyright (C) 2004-2011 OpenWorks LLP 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_emwarn.h" 33#include "libvex_guest_arm.h" 34#include "libvex_ir.h" 35#include "libvex.h" 36 37#include "main_util.h" 38#include "guest_generic_bb_to_IR.h" 39#include "guest_arm_defs.h" 40 41 42/* This file contains helper functions for arm guest code. Calls to 43 these functions are generated by the back end. These calls are of 44 course in the host machine code and this file will be compiled to 45 host machine code, so that all makes sense. 46 47 Only change the signatures of these helper functions very 48 carefully. If you change the signature here, you'll have to change 49 the parameters passed to it in the IR calls constructed by 50 guest-arm/toIR.c. 51*/ 52 53 54/* Set to 1 to get detailed profiling info about individual N, Z, C 55 and V flag evaluation. */ 56#define PROFILE_NZCV_FLAGS 0 57 58#if PROFILE_NZCV_FLAGS 59 60static UInt tab_n_eval[ARMG_CC_OP_NUMBER]; 61static UInt tab_z_eval[ARMG_CC_OP_NUMBER]; 62static UInt tab_c_eval[ARMG_CC_OP_NUMBER]; 63static UInt tab_v_eval[ARMG_CC_OP_NUMBER]; 64static UInt initted = 0; 65static UInt tot_evals = 0; 66 67static void initCounts ( void ) 68{ 69 UInt i; 70 for (i = 0; i < ARMG_CC_OP_NUMBER; i++) { 71 tab_n_eval[i] = tab_z_eval[i] = tab_c_eval[i] = tab_v_eval[i] = 0; 72 } 73 initted = 1; 74} 75 76static void showCounts ( void ) 77{ 78 UInt i; 79 vex_printf("\n N Z C V\n"); 80 vex_printf( "---------------------------------------------------\n"); 81 for (i = 0; i < ARMG_CC_OP_NUMBER; i++) { 82 vex_printf("CC_OP=%d %9d %9d %9d %9d\n", 83 i, 84 tab_n_eval[i], tab_z_eval[i], 85 tab_c_eval[i], tab_v_eval[i] ); 86 } 87} 88 89#define NOTE_N_EVAL(_cc_op) NOTE_EVAL(_cc_op, tab_n_eval) 90#define NOTE_Z_EVAL(_cc_op) NOTE_EVAL(_cc_op, tab_z_eval) 91#define NOTE_C_EVAL(_cc_op) NOTE_EVAL(_cc_op, tab_c_eval) 92#define NOTE_V_EVAL(_cc_op) NOTE_EVAL(_cc_op, tab_v_eval) 93 94#define NOTE_EVAL(_cc_op, _tab) \ 95 do { \ 96 if (!initted) initCounts(); \ 97 vassert( ((UInt)(_cc_op)) < ARMG_CC_OP_NUMBER); \ 98 _tab[(UInt)(_cc_op)]++; \ 99 tot_evals++; \ 100 if (0 == (tot_evals & 0xFFFFF)) \ 101 showCounts(); \ 102 } while (0) 103 104#endif /* PROFILE_NZCV_FLAGS */ 105 106 107/* Calculate the N flag from the supplied thunk components, in the 108 least significant bit of the word. Returned bits 31:1 are zero. */ 109static 110UInt armg_calculate_flag_n ( UInt cc_op, UInt cc_dep1, 111 UInt cc_dep2, UInt cc_dep3 ) 112{ 113# if PROFILE_NZCV_FLAGS 114 NOTE_N_EVAL(cc_op); 115# endif 116 117 switch (cc_op) { 118 case ARMG_CC_OP_COPY: { 119 /* (nzcv:28x0, unused, unused) */ 120 UInt nf = (cc_dep1 >> ARMG_CC_SHIFT_N) & 1; 121 return nf; 122 } 123 case ARMG_CC_OP_ADD: { 124 /* (argL, argR, unused) */ 125 UInt argL = cc_dep1; 126 UInt argR = cc_dep2; 127 UInt res = argL + argR; 128 UInt nf = res >> 31; 129 return nf; 130 } 131 case ARMG_CC_OP_SUB: { 132 /* (argL, argR, unused) */ 133 UInt argL = cc_dep1; 134 UInt argR = cc_dep2; 135 UInt res = argL - argR; 136 UInt nf = res >> 31; 137 return nf; 138 } 139 case ARMG_CC_OP_ADC: { 140 /* (argL, argR, oldC) */ 141 UInt argL = cc_dep1; 142 UInt argR = cc_dep2; 143 UInt oldC = cc_dep3; 144 vassert((oldC & ~1) == 0); 145 UInt res = argL + argR + oldC; 146 UInt nf = res >> 31; 147 return nf; 148 } 149 case ARMG_CC_OP_SBB: { 150 /* (argL, argR, oldC) */ 151 UInt argL = cc_dep1; 152 UInt argR = cc_dep2; 153 UInt oldC = cc_dep3; 154 vassert((oldC & ~1) == 0); 155 UInt res = argL - argR - (oldC ^ 1); 156 UInt nf = res >> 31; 157 return nf; 158 } 159 case ARMG_CC_OP_LOGIC: { 160 /* (res, shco, oldV) */ 161 UInt res = cc_dep1; 162 UInt nf = res >> 31; 163 return nf; 164 } 165 case ARMG_CC_OP_MUL: { 166 /* (res, unused, oldC:oldV) */ 167 UInt res = cc_dep1; 168 UInt nf = res >> 31; 169 return nf; 170 } 171 case ARMG_CC_OP_MULL: { 172 /* (resLo32, resHi32, oldC:oldV) */ 173 UInt resHi32 = cc_dep2; 174 UInt nf = resHi32 >> 31; 175 return nf; 176 } 177 default: 178 /* shouldn't really make these calls from generated code */ 179 vex_printf("armg_calculate_flag_n" 180 "( op=%u, dep1=0x%x, dep2=0x%x, dep3=0x%x )\n", 181 cc_op, cc_dep1, cc_dep2, cc_dep3 ); 182 vpanic("armg_calculate_flags_n"); 183 } 184} 185 186 187/* Calculate the Z flag from the supplied thunk components, in the 188 least significant bit of the word. Returned bits 31:1 are zero. */ 189static 190UInt armg_calculate_flag_z ( UInt cc_op, UInt cc_dep1, 191 UInt cc_dep2, UInt cc_dep3 ) 192{ 193# if PROFILE_NZCV_FLAGS 194 NOTE_Z_EVAL(cc_op); 195# endif 196 197 switch (cc_op) { 198 case ARMG_CC_OP_COPY: { 199 /* (nzcv:28x0, unused, unused) */ 200 UInt zf = (cc_dep1 >> ARMG_CC_SHIFT_Z) & 1; 201 return zf; 202 } 203 case ARMG_CC_OP_ADD: { 204 /* (argL, argR, unused) */ 205 UInt argL = cc_dep1; 206 UInt argR = cc_dep2; 207 UInt res = argL + argR; 208 UInt zf = res == 0; 209 return zf; 210 } 211 case ARMG_CC_OP_SUB: { 212 /* (argL, argR, unused) */ 213 UInt argL = cc_dep1; 214 UInt argR = cc_dep2; 215 UInt res = argL - argR; 216 UInt zf = res == 0; 217 return zf; 218 } 219 case ARMG_CC_OP_ADC: { 220 /* (argL, argR, oldC) */ 221 UInt argL = cc_dep1; 222 UInt argR = cc_dep2; 223 UInt oldC = cc_dep3; 224 vassert((oldC & ~1) == 0); 225 UInt res = argL + argR + oldC; 226 UInt zf = res == 0; 227 return zf; 228 } 229 case ARMG_CC_OP_SBB: { 230 /* (argL, argR, oldC) */ 231 UInt argL = cc_dep1; 232 UInt argR = cc_dep2; 233 UInt oldC = cc_dep3; 234 vassert((oldC & ~1) == 0); 235 UInt res = argL - argR - (oldC ^ 1); 236 UInt zf = res == 0; 237 return zf; 238 } 239 case ARMG_CC_OP_LOGIC: { 240 /* (res, shco, oldV) */ 241 UInt res = cc_dep1; 242 UInt zf = res == 0; 243 return zf; 244 } 245 case ARMG_CC_OP_MUL: { 246 /* (res, unused, oldC:oldV) */ 247 UInt res = cc_dep1; 248 UInt zf = res == 0; 249 return zf; 250 } 251 case ARMG_CC_OP_MULL: { 252 /* (resLo32, resHi32, oldC:oldV) */ 253 UInt resLo32 = cc_dep1; 254 UInt resHi32 = cc_dep2; 255 UInt zf = (resHi32|resLo32) == 0; 256 return zf; 257 } 258 default: 259 /* shouldn't really make these calls from generated code */ 260 vex_printf("armg_calculate_flags_z" 261 "( op=%u, dep1=0x%x, dep2=0x%x, dep3=0x%x )\n", 262 cc_op, cc_dep1, cc_dep2, cc_dep3 ); 263 vpanic("armg_calculate_flags_z"); 264 } 265} 266 267 268/* CALLED FROM GENERATED CODE: CLEAN HELPER */ 269/* Calculate the C flag from the supplied thunk components, in the 270 least significant bit of the word. Returned bits 31:1 are zero. */ 271UInt armg_calculate_flag_c ( UInt cc_op, UInt cc_dep1, 272 UInt cc_dep2, UInt cc_dep3 ) 273{ 274# if PROFILE_NZCV_FLAGS 275 NOTE_C_EVAL(cc_op); 276# endif 277 278 switch (cc_op) { 279 case ARMG_CC_OP_COPY: { 280 /* (nzcv:28x0, unused, unused) */ 281 UInt cf = (cc_dep1 >> ARMG_CC_SHIFT_C) & 1; 282 return cf; 283 } 284 case ARMG_CC_OP_ADD: { 285 /* (argL, argR, unused) */ 286 UInt argL = cc_dep1; 287 UInt argR = cc_dep2; 288 UInt res = argL + argR; 289 UInt cf = res < argL; 290 return cf; 291 } 292 case ARMG_CC_OP_SUB: { 293 /* (argL, argR, unused) */ 294 UInt argL = cc_dep1; 295 UInt argR = cc_dep2; 296 UInt cf = argL >= argR; 297 return cf; 298 } 299 case ARMG_CC_OP_ADC: { 300 /* (argL, argR, oldC) */ 301 UInt argL = cc_dep1; 302 UInt argR = cc_dep2; 303 UInt oldC = cc_dep3; 304 vassert((oldC & ~1) == 0); 305 UInt res = argL + argR + oldC; 306 UInt cf = oldC ? (res <= argL) : (res < argL); 307 return cf; 308 } 309 case ARMG_CC_OP_SBB: { 310 /* (argL, argR, oldC) */ 311 UInt argL = cc_dep1; 312 UInt argR = cc_dep2; 313 UInt oldC = cc_dep3; 314 vassert((oldC & ~1) == 0); 315 UInt cf = oldC ? (argL >= argR) : (argL > argR); 316 return cf; 317 } 318 case ARMG_CC_OP_LOGIC: { 319 /* (res, shco, oldV) */ 320 UInt shco = cc_dep2; 321 vassert((shco & ~1) == 0); 322 UInt cf = shco; 323 return cf; 324 } 325 case ARMG_CC_OP_MUL: { 326 /* (res, unused, oldC:oldV) */ 327 UInt oldC = (cc_dep3 >> 1) & 1; 328 vassert((cc_dep3 & ~3) == 0); 329 UInt cf = oldC; 330 return cf; 331 } 332 case ARMG_CC_OP_MULL: { 333 /* (resLo32, resHi32, oldC:oldV) */ 334 UInt oldC = (cc_dep3 >> 1) & 1; 335 vassert((cc_dep3 & ~3) == 0); 336 UInt cf = oldC; 337 return cf; 338 } 339 default: 340 /* shouldn't really make these calls from generated code */ 341 vex_printf("armg_calculate_flag_c" 342 "( op=%u, dep1=0x%x, dep2=0x%x, dep3=0x%x )\n", 343 cc_op, cc_dep1, cc_dep2, cc_dep3 ); 344 vpanic("armg_calculate_flag_c"); 345 } 346} 347 348 349/* CALLED FROM GENERATED CODE: CLEAN HELPER */ 350/* Calculate the V flag from the supplied thunk components, in the 351 least significant bit of the word. Returned bits 31:1 are zero. */ 352UInt armg_calculate_flag_v ( UInt cc_op, UInt cc_dep1, 353 UInt cc_dep2, UInt cc_dep3 ) 354{ 355# if PROFILE_NZCV_FLAGS 356 NOTE_V_EVAL(cc_op); 357# endif 358 359 switch (cc_op) { 360 case ARMG_CC_OP_COPY: { 361 /* (nzcv:28x0, unused, unused) */ 362 UInt vf = (cc_dep1 >> ARMG_CC_SHIFT_V) & 1; 363 return vf; 364 } 365 case ARMG_CC_OP_ADD: { 366 /* (argL, argR, unused) */ 367 UInt argL = cc_dep1; 368 UInt argR = cc_dep2; 369 UInt res = argL + argR; 370 UInt vf = ((res ^ argL) & (res ^ argR)) >> 31; 371 return vf; 372 } 373 case ARMG_CC_OP_SUB: { 374 /* (argL, argR, unused) */ 375 UInt argL = cc_dep1; 376 UInt argR = cc_dep2; 377 UInt res = argL - argR; 378 UInt vf = ((argL ^ argR) & (argL ^ res)) >> 31; 379 return vf; 380 } 381 case ARMG_CC_OP_ADC: { 382 /* (argL, argR, oldC) */ 383 UInt argL = cc_dep1; 384 UInt argR = cc_dep2; 385 UInt oldC = cc_dep3; 386 vassert((oldC & ~1) == 0); 387 UInt res = argL + argR + oldC; 388 UInt vf = ((res ^ argL) & (res ^ argR)) >> 31; 389 return vf; 390 } 391 case ARMG_CC_OP_SBB: { 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 ^ 1); 398 UInt vf = ((argL ^ argR) & (argL ^ res)) >> 31; 399 return vf; 400 } 401 case ARMG_CC_OP_LOGIC: { 402 /* (res, shco, oldV) */ 403 UInt oldV = cc_dep3; 404 vassert((oldV & ~1) == 0); 405 UInt vf = oldV; 406 return vf; 407 } 408 case ARMG_CC_OP_MUL: { 409 /* (res, unused, oldC:oldV) */ 410 UInt oldV = (cc_dep3 >> 0) & 1; 411 vassert((cc_dep3 & ~3) == 0); 412 UInt vf = oldV; 413 return vf; 414 } 415 case ARMG_CC_OP_MULL: { 416 /* (resLo32, resHi32, oldC:oldV) */ 417 UInt oldV = (cc_dep3 >> 0) & 1; 418 vassert((cc_dep3 & ~3) == 0); 419 UInt vf = oldV; 420 return vf; 421 } 422 default: 423 /* shouldn't really make these calls from generated code */ 424 vex_printf("armg_calculate_flag_v" 425 "( op=%u, dep1=0x%x, dep2=0x%x, dep3=0x%x )\n", 426 cc_op, cc_dep1, cc_dep2, cc_dep3 ); 427 vpanic("armg_calculate_flag_v"); 428 } 429} 430 431 432/* CALLED FROM GENERATED CODE: CLEAN HELPER */ 433/* Calculate NZCV from the supplied thunk components, in the positions 434 they appear in the CPSR, viz bits 31:28 for N Z C V respectively. 435 Returned bits 27:0 are zero. */ 436UInt armg_calculate_flags_nzcv ( UInt cc_op, UInt cc_dep1, 437 UInt cc_dep2, UInt cc_dep3 ) 438{ 439 UInt f; 440 UInt res = 0; 441 f = armg_calculate_flag_n(cc_op, cc_dep1, cc_dep2, cc_dep3); 442 res |= (f << ARMG_CC_SHIFT_N); 443 f = armg_calculate_flag_z(cc_op, cc_dep1, cc_dep2, cc_dep3); 444 res |= (f << ARMG_CC_SHIFT_Z); 445 f = armg_calculate_flag_c(cc_op, cc_dep1, cc_dep2, cc_dep3); 446 res |= (f << ARMG_CC_SHIFT_C); 447 f = armg_calculate_flag_v(cc_op, cc_dep1, cc_dep2, cc_dep3); 448 res |= (f << ARMG_CC_SHIFT_V); 449 return res; 450} 451 452 453/* CALLED FROM GENERATED CODE: CLEAN HELPER */ 454/* Calculate the QC flag from the arguments, in the lowest bit 455 of the word (bit 0). Urr, having this out of line is bizarre. 456 Push back inline. */ 457UInt armg_calculate_flag_qc ( UInt resL1, UInt resL2, 458 UInt resR1, UInt resR2 ) 459{ 460 if (resL1 != resR1 || resL2 != resR2) 461 return 1; 462 else 463 return 0; 464} 465 466/* CALLED FROM GENERATED CODE: CLEAN HELPER */ 467/* Calculate the specified condition from the thunk components, in the 468 lowest bit of the word (bit 0). Returned bits 31:1 are zero. */ 469UInt armg_calculate_condition ( UInt cond_n_op /* (ARMCondcode << 4) | cc_op */, 470 UInt cc_dep1, 471 UInt cc_dep2, UInt cc_dep3 ) 472{ 473 UInt cond = cond_n_op >> 4; 474 UInt cc_op = cond_n_op & 0xF; 475 UInt nf, zf, vf, cf, inv; 476 // vex_printf("XXXXXXXX %x %x %x %x\n", 477 // cond_n_op, cc_dep1, cc_dep2, cc_dep3); 478 479 // skip flags computation in this case 480 if (cond == ARMCondAL) return 1; 481 482 inv = cond & 1; 483 484 switch (cond) { 485 case ARMCondEQ: // Z=1 => z 486 case ARMCondNE: // Z=0 487 zf = armg_calculate_flag_z(cc_op, cc_dep1, cc_dep2, cc_dep3); 488 return inv ^ zf; 489 490 case ARMCondHS: // C=1 => c 491 case ARMCondLO: // C=0 492 cf = armg_calculate_flag_c(cc_op, cc_dep1, cc_dep2, cc_dep3); 493 return inv ^ cf; 494 495 case ARMCondMI: // N=1 => n 496 case ARMCondPL: // N=0 497 nf = armg_calculate_flag_n(cc_op, cc_dep1, cc_dep2, cc_dep3); 498 return inv ^ nf; 499 500 case ARMCondVS: // V=1 => v 501 case ARMCondVC: // V=0 502 vf = armg_calculate_flag_v(cc_op, cc_dep1, cc_dep2, cc_dep3); 503 return inv ^ vf; 504 505 case ARMCondHI: // C=1 && Z=0 => c & ~z 506 case ARMCondLS: // C=0 || Z=1 507 cf = armg_calculate_flag_c(cc_op, cc_dep1, cc_dep2, cc_dep3); 508 zf = armg_calculate_flag_z(cc_op, cc_dep1, cc_dep2, cc_dep3); 509 return inv ^ (cf & ~zf); 510 511 case ARMCondGE: // N=V => ~(n^v) 512 case ARMCondLT: // N!=V 513 nf = armg_calculate_flag_n(cc_op, cc_dep1, cc_dep2, cc_dep3); 514 vf = armg_calculate_flag_v(cc_op, cc_dep1, cc_dep2, cc_dep3); 515 return inv ^ (1 & ~(nf ^ vf)); 516 517 case ARMCondGT: // Z=0 && N=V => ~z & ~(n^v) => ~(z | (n^v)) 518 case ARMCondLE: // Z=1 || N!=V 519 nf = armg_calculate_flag_n(cc_op, cc_dep1, cc_dep2, cc_dep3); 520 vf = armg_calculate_flag_v(cc_op, cc_dep1, cc_dep2, cc_dep3); 521 zf = armg_calculate_flag_z(cc_op, cc_dep1, cc_dep2, cc_dep3); 522 return inv ^ (1 & ~(zf | (nf ^ vf))); 523 524 case ARMCondAL: // handled above 525 case ARMCondNV: // should never get here: Illegal instr 526 default: 527 /* shouldn't really make these calls from generated code */ 528 vex_printf("armg_calculate_condition(ARM)" 529 "( %u, %u, 0x%x, 0x%x, 0x%x )\n", 530 cond, cc_op, cc_dep1, cc_dep2, cc_dep3 ); 531 vpanic("armg_calculate_condition(ARM)"); 532 } 533} 534 535 536/*---------------------------------------------------------------*/ 537/*--- Flag-helpers translation-time function specialisers. ---*/ 538/*--- These help iropt specialise calls the above run-time ---*/ 539/*--- flags functions. ---*/ 540/*---------------------------------------------------------------*/ 541 542/* Used by the optimiser to try specialisations. Returns an 543 equivalent expression, or NULL if none. */ 544 545static Bool isU32 ( IRExpr* e, UInt n ) 546{ 547 return 548 toBool( e->tag == Iex_Const 549 && e->Iex.Const.con->tag == Ico_U32 550 && e->Iex.Const.con->Ico.U32 == n ); 551} 552 553IRExpr* guest_arm_spechelper ( HChar* function_name, 554 IRExpr** args, 555 IRStmt** precedingStmts, 556 Int n_precedingStmts ) 557{ 558# define unop(_op,_a1) IRExpr_Unop((_op),(_a1)) 559# define binop(_op,_a1,_a2) IRExpr_Binop((_op),(_a1),(_a2)) 560# define mkU32(_n) IRExpr_Const(IRConst_U32(_n)) 561# define mkU8(_n) IRExpr_Const(IRConst_U8(_n)) 562 563 Int i, arity = 0; 564 for (i = 0; args[i]; i++) 565 arity++; 566# if 0 567 vex_printf("spec request:\n"); 568 vex_printf(" %s ", function_name); 569 for (i = 0; i < arity; i++) { 570 vex_printf(" "); 571 ppIRExpr(args[i]); 572 } 573 vex_printf("\n"); 574# endif 575 576 /* --------- specialising "armg_calculate_condition" --------- */ 577 578 if (vex_streq(function_name, "armg_calculate_condition")) { 579 580 /* specialise calls to the "armg_calculate_condition" function. 581 Not sure whether this is strictly necessary, but: the 582 replacement IR must produce only the values 0 or 1. Bits 583 31:1 are required to be zero. */ 584 IRExpr *cond_n_op, *cc_dep1, *cc_dep2, *cc_ndep; 585 vassert(arity == 4); 586 cond_n_op = args[0]; /* (ARMCondcode << 4) | ARMG_CC_OP_* */ 587 cc_dep1 = args[1]; 588 cc_dep2 = args[2]; 589 cc_ndep = args[3]; 590 591 /*---------------- SUB ----------------*/ 592 593 if (isU32(cond_n_op, (ARMCondEQ << 4) | ARMG_CC_OP_SUB)) { 594 /* EQ after SUB --> test argL == argR */ 595 return unop(Iop_1Uto32, 596 binop(Iop_CmpEQ32, cc_dep1, cc_dep2)); 597 } 598 if (isU32(cond_n_op, (ARMCondNE << 4) | ARMG_CC_OP_SUB)) { 599 /* NE after SUB --> test argL != argR */ 600 return unop(Iop_1Uto32, 601 binop(Iop_CmpNE32, cc_dep1, cc_dep2)); 602 } 603 604 if (isU32(cond_n_op, (ARMCondGT << 4) | ARMG_CC_OP_SUB)) { 605 /* GT after SUB --> test argL >s argR 606 --> test argR <s argL */ 607 return unop(Iop_1Uto32, 608 binop(Iop_CmpLT32S, cc_dep2, cc_dep1)); 609 } 610 if (isU32(cond_n_op, (ARMCondLE << 4) | ARMG_CC_OP_SUB)) { 611 /* LE after SUB --> test argL <=s argR */ 612 return unop(Iop_1Uto32, 613 binop(Iop_CmpLE32S, cc_dep1, cc_dep2)); 614 } 615 616 if (isU32(cond_n_op, (ARMCondLT << 4) | ARMG_CC_OP_SUB)) { 617 /* LT after SUB --> test argL <s argR */ 618 return unop(Iop_1Uto32, 619 binop(Iop_CmpLT32S, cc_dep1, cc_dep2)); 620 } 621 622 if (isU32(cond_n_op, (ARMCondGE << 4) | ARMG_CC_OP_SUB)) { 623 /* GE after SUB --> test argL >=s argR 624 --> test argR <=s argL */ 625 return unop(Iop_1Uto32, 626 binop(Iop_CmpLE32S, cc_dep2, cc_dep1)); 627 } 628 629 if (isU32(cond_n_op, (ARMCondHS << 4) | ARMG_CC_OP_SUB)) { 630 /* HS after SUB --> test argL >=u argR 631 --> test argR <=u argL */ 632 return unop(Iop_1Uto32, 633 binop(Iop_CmpLE32U, cc_dep2, cc_dep1)); 634 } 635 if (isU32(cond_n_op, (ARMCondLO << 4) | ARMG_CC_OP_SUB)) { 636 /* LO after SUB --> test argL <u argR */ 637 return unop(Iop_1Uto32, 638 binop(Iop_CmpLT32U, cc_dep1, cc_dep2)); 639 } 640 641 if (isU32(cond_n_op, (ARMCondLS << 4) | ARMG_CC_OP_SUB)) { 642 /* LS after SUB --> test argL <=u argR */ 643 return unop(Iop_1Uto32, 644 binop(Iop_CmpLE32U, cc_dep1, cc_dep2)); 645 } 646 647 /*---------------- SBB ----------------*/ 648 649 if (isU32(cond_n_op, (ARMCondHS << 4) | ARMG_CC_OP_SBB)) { 650 /* This seems to happen a lot in softfloat code, eg __divdf3+140 */ 651 /* thunk is: (dep1=argL, dep2=argR, ndep=oldC) */ 652 /* HS after SBB (same as C after SBB below) 653 --> oldC ? (argL >=u argR) : (argL >u argR) 654 --> oldC ? (argR <=u argL) : (argR <u argL) 655 */ 656 return 657 IRExpr_Mux0X( 658 unop(Iop_32to8, cc_ndep), 659 /* case oldC == 0 */ 660 unop(Iop_1Uto32, binop(Iop_CmpLT32U, cc_dep2, cc_dep1)), 661 /* case oldC != 0 */ 662 unop(Iop_1Uto32, binop(Iop_CmpLE32U, cc_dep2, cc_dep1)) 663 ); 664 } 665 666 /*---------------- LOGIC ----------------*/ 667 668 if (isU32(cond_n_op, (ARMCondEQ << 4) | ARMG_CC_OP_LOGIC)) { 669 /* EQ after LOGIC --> test res == 0 */ 670 return unop(Iop_1Uto32, 671 binop(Iop_CmpEQ32, cc_dep1, mkU32(0))); 672 } 673 if (isU32(cond_n_op, (ARMCondNE << 4) | ARMG_CC_OP_LOGIC)) { 674 /* NE after LOGIC --> test res != 0 */ 675 return unop(Iop_1Uto32, 676 binop(Iop_CmpNE32, cc_dep1, mkU32(0))); 677 } 678 679 if (isU32(cond_n_op, (ARMCondPL << 4) | ARMG_CC_OP_LOGIC)) { 680 /* PL after LOGIC --> test (res >> 31) == 0 */ 681 return unop(Iop_1Uto32, 682 binop(Iop_CmpEQ32, 683 binop(Iop_Shr32, cc_dep1, mkU8(31)), 684 mkU32(0))); 685 } 686 if (isU32(cond_n_op, (ARMCondMI << 4) | ARMG_CC_OP_LOGIC)) { 687 /* MI after LOGIC --> test (res >> 31) == 1 */ 688 return unop(Iop_1Uto32, 689 binop(Iop_CmpEQ32, 690 binop(Iop_Shr32, cc_dep1, mkU8(31)), 691 mkU32(1))); 692 } 693 694 /*----------------- AL -----------------*/ 695 696 /* A critically important case for Thumb code. 697 698 What we're trying to spot is the case where cond_n_op is an 699 expression of the form Or32(..., 0xE0) since that means the 700 caller is asking for CondAL and we can simply return 1 701 without caring what the ... part is. This is a potentially 702 dodgy kludge in that it assumes that the ... part has zeroes 703 in bits 7:4, so that the result of the Or32 is guaranteed to 704 be 0xE in bits 7:4. Given that the places where this first 705 arg are constructed (in guest_arm_toIR.c) are very 706 constrained, we can get away with this. To make this 707 guaranteed safe would require to have a new primop, Slice44 708 or some such, thusly 709 710 Slice44(arg1, arg2) = 0--(24)--0 arg1[7:4] arg2[3:0] 711 712 and we would then look for Slice44(0xE0, ...) 713 which would give the required safety property. 714 715 It would be infeasibly expensive to scan backwards through 716 the entire block looking for an assignment to the temp, so 717 just look at the previous 16 statements. That should find it 718 if it is an interesting case, as a result of how the 719 boilerplate guff at the start of each Thumb insn translation 720 is made. 721 */ 722 if (cond_n_op->tag == Iex_RdTmp) { 723 Int j; 724 IRTemp look_for = cond_n_op->Iex.RdTmp.tmp; 725 Int limit = n_precedingStmts - 16; 726 if (limit < 0) limit = 0; 727 if (0) vex_printf("scanning %d .. %d\n", n_precedingStmts-1, limit); 728 for (j = n_precedingStmts - 1; j >= limit; j--) { 729 IRStmt* st = precedingStmts[j]; 730 if (st->tag == Ist_WrTmp 731 && st->Ist.WrTmp.tmp == look_for 732 && st->Ist.WrTmp.data->tag == Iex_Binop 733 && st->Ist.WrTmp.data->Iex.Binop.op == Iop_Or32 734 && isU32(st->Ist.WrTmp.data->Iex.Binop.arg2, (ARMCondAL << 4))) 735 return mkU32(1); 736 } 737 /* Didn't find any useful binding to the first arg 738 in the previous 16 stmts. */ 739 } 740 } 741 742 /* --------- specialising "armg_calculate_flag_c" --------- */ 743 744 else 745 if (vex_streq(function_name, "armg_calculate_flag_c")) { 746 747 /* specialise calls to the "armg_calculate_flag_c" function. 748 Note that the returned value must be either 0 or 1; nonzero 749 bits 31:1 are not allowed. In turn, incoming oldV and oldC 750 values (from the thunk) are assumed to have bits 31:1 751 clear. */ 752 IRExpr *cc_op, *cc_dep1, *cc_dep2, *cc_ndep; 753 vassert(arity == 4); 754 cc_op = args[0]; /* ARMG_CC_OP_* */ 755 cc_dep1 = args[1]; 756 cc_dep2 = args[2]; 757 cc_ndep = args[3]; 758 759 if (isU32(cc_op, ARMG_CC_OP_LOGIC)) { 760 /* Thunk args are (result, shco, oldV) */ 761 /* C after LOGIC --> shco */ 762 return cc_dep2; 763 } 764 765 if (isU32(cc_op, ARMG_CC_OP_SUB)) { 766 /* Thunk args are (argL, argR, unused) */ 767 /* C after SUB --> argL >=u argR 768 --> argR <=u argL */ 769 return unop(Iop_1Uto32, 770 binop(Iop_CmpLE32U, cc_dep2, cc_dep1)); 771 } 772 773 if (isU32(cc_op, ARMG_CC_OP_SBB)) { 774 /* This happens occasionally in softfloat code, eg __divdf3+140 */ 775 /* thunk is: (dep1=argL, dep2=argR, ndep=oldC) */ 776 /* C after SBB (same as HS after SBB above) 777 --> oldC ? (argL >=u argR) : (argL >u argR) 778 --> oldC ? (argR <=u argL) : (argR <u argL) 779 */ 780 return 781 IRExpr_Mux0X( 782 unop(Iop_32to8, cc_ndep), 783 /* case oldC == 0 */ 784 unop(Iop_1Uto32, binop(Iop_CmpLT32U, cc_dep2, cc_dep1)), 785 /* case oldC != 0 */ 786 unop(Iop_1Uto32, binop(Iop_CmpLE32U, cc_dep2, cc_dep1)) 787 ); 788 } 789 790 } 791 792 /* --------- specialising "armg_calculate_flag_v" --------- */ 793 794 else 795 if (vex_streq(function_name, "armg_calculate_flag_v")) { 796 797 /* specialise calls to the "armg_calculate_flag_v" function. 798 Note that the returned value must be either 0 or 1; nonzero 799 bits 31:1 are not allowed. In turn, incoming oldV and oldC 800 values (from the thunk) are assumed to have bits 31:1 801 clear. */ 802 IRExpr *cc_op, *cc_dep1, *cc_dep2, *cc_ndep; 803 vassert(arity == 4); 804 cc_op = args[0]; /* ARMG_CC_OP_* */ 805 cc_dep1 = args[1]; 806 cc_dep2 = args[2]; 807 cc_ndep = args[3]; 808 809 if (isU32(cc_op, ARMG_CC_OP_LOGIC)) { 810 /* Thunk args are (result, shco, oldV) */ 811 /* V after LOGIC --> oldV */ 812 return cc_ndep; 813 } 814 815 if (isU32(cc_op, ARMG_CC_OP_SUB)) { 816 /* Thunk args are (argL, argR, unused) */ 817 /* V after SUB 818 --> let res = argL - argR 819 in ((argL ^ argR) & (argL ^ res)) >> 31 820 --> ((argL ^ argR) & (argL ^ (argL - argR))) >> 31 821 */ 822 IRExpr* argL = cc_dep1; 823 IRExpr* argR = cc_dep2; 824 return 825 binop(Iop_Shr32, 826 binop(Iop_And32, 827 binop(Iop_Xor32, argL, argR), 828 binop(Iop_Xor32, argL, binop(Iop_Sub32, argL, argR)) 829 ), 830 mkU8(31) 831 ); 832 } 833 834 if (isU32(cc_op, ARMG_CC_OP_SBB)) { 835 /* This happens occasionally in softfloat code, eg __divdf3+140 */ 836 /* thunk is: (dep1=argL, dep2=argR, ndep=oldC) */ 837 /* V after SBB 838 --> let res = argL - argR - (oldC ^ 1) 839 in (argL ^ argR) & (argL ^ res) & 1 840 */ 841 return 842 binop( 843 Iop_And32, 844 binop( 845 Iop_And32, 846 // argL ^ argR 847 binop(Iop_Xor32, cc_dep1, cc_dep2), 848 // argL ^ (argL - argR - (oldC ^ 1)) 849 binop(Iop_Xor32, 850 cc_dep1, 851 binop(Iop_Sub32, 852 binop(Iop_Sub32, cc_dep1, cc_dep2), 853 binop(Iop_Xor32, cc_ndep, mkU32(1))) 854 ) 855 ), 856 mkU32(1) 857 ); 858 } 859 860 } 861 862# undef unop 863# undef binop 864# undef mkU32 865# undef mkU8 866 867 return NULL; 868} 869 870 871/*----------------------------------------------*/ 872/*--- The exported fns .. ---*/ 873/*----------------------------------------------*/ 874 875/* VISIBLE TO LIBVEX CLIENT */ 876#if 0 877void LibVEX_GuestARM_put_flags ( UInt flags_native, 878 /*OUT*/VexGuestARMState* vex_state ) 879{ 880 vassert(0); // FIXME 881 882 /* Mask out everything except N Z V C. */ 883 flags_native 884 &= (ARMG_CC_MASK_N | ARMG_CC_MASK_Z | ARMG_CC_MASK_V | ARMG_CC_MASK_C); 885 886 vex_state->guest_CC_OP = ARMG_CC_OP_COPY; 887 vex_state->guest_CC_DEP1 = flags_native; 888 vex_state->guest_CC_DEP2 = 0; 889 vex_state->guest_CC_NDEP = 0; 890} 891#endif 892 893/* VISIBLE TO LIBVEX CLIENT */ 894UInt LibVEX_GuestARM_get_cpsr ( /*IN*/VexGuestARMState* vex_state ) 895{ 896 UInt cpsr = 0; 897 // NZCV 898 cpsr |= armg_calculate_flags_nzcv( 899 vex_state->guest_CC_OP, 900 vex_state->guest_CC_DEP1, 901 vex_state->guest_CC_DEP2, 902 vex_state->guest_CC_NDEP 903 ); 904 vassert(0 == (cpsr & 0x0FFFFFFF)); 905 // Q 906 if (vex_state->guest_QFLAG32 > 0) 907 cpsr |= (1 << 27); 908 // GE 909 if (vex_state->guest_GEFLAG0 > 0) 910 cpsr |= (1 << 16); 911 if (vex_state->guest_GEFLAG1 > 0) 912 cpsr |= (1 << 17); 913 if (vex_state->guest_GEFLAG2 > 0) 914 cpsr |= (1 << 18); 915 if (vex_state->guest_GEFLAG3 > 0) 916 cpsr |= (1 << 19); 917 // M 918 cpsr |= (1 << 4); // 0b10000 means user-mode 919 // J,T J (bit 24) is zero by initialisation above 920 // T we copy from R15T[0] 921 if (vex_state->guest_R15T & 1) 922 cpsr |= (1 << 5); 923 // ITSTATE we punt on for the time being. Could compute it 924 // if needed though. 925 // E, endianness, 0 (littleendian) from initialisation above 926 // A,I,F disable some async exceptions. Not sure about these. 927 // Leave as zero for the time being. 928 return cpsr; 929} 930 931/* VISIBLE TO LIBVEX CLIENT */ 932void LibVEX_GuestARM_initialise ( /*OUT*/VexGuestARMState* vex_state ) 933{ 934 vex_state->guest_R0 = 0; 935 vex_state->guest_R1 = 0; 936 vex_state->guest_R2 = 0; 937 vex_state->guest_R3 = 0; 938 vex_state->guest_R4 = 0; 939 vex_state->guest_R5 = 0; 940 vex_state->guest_R6 = 0; 941 vex_state->guest_R7 = 0; 942 vex_state->guest_R8 = 0; 943 vex_state->guest_R9 = 0; 944 vex_state->guest_R10 = 0; 945 vex_state->guest_R11 = 0; 946 vex_state->guest_R12 = 0; 947 vex_state->guest_R13 = 0; 948 vex_state->guest_R14 = 0; 949 vex_state->guest_R15T = 0; /* NB: implies ARM mode */ 950 951 vex_state->guest_CC_OP = ARMG_CC_OP_COPY; 952 vex_state->guest_CC_DEP1 = 0; 953 vex_state->guest_CC_DEP2 = 0; 954 vex_state->guest_CC_NDEP = 0; 955 vex_state->guest_QFLAG32 = 0; 956 vex_state->guest_GEFLAG0 = 0; 957 vex_state->guest_GEFLAG1 = 0; 958 vex_state->guest_GEFLAG2 = 0; 959 vex_state->guest_GEFLAG3 = 0; 960 961 vex_state->guest_EMWARN = 0; 962 vex_state->guest_TISTART = 0; 963 vex_state->guest_TILEN = 0; 964 vex_state->guest_NRADDR = 0; 965 vex_state->guest_IP_AT_SYSCALL = 0; 966 967 vex_state->guest_D0 = 0; 968 vex_state->guest_D1 = 0; 969 vex_state->guest_D2 = 0; 970 vex_state->guest_D3 = 0; 971 vex_state->guest_D4 = 0; 972 vex_state->guest_D5 = 0; 973 vex_state->guest_D6 = 0; 974 vex_state->guest_D7 = 0; 975 vex_state->guest_D8 = 0; 976 vex_state->guest_D9 = 0; 977 vex_state->guest_D10 = 0; 978 vex_state->guest_D11 = 0; 979 vex_state->guest_D12 = 0; 980 vex_state->guest_D13 = 0; 981 vex_state->guest_D14 = 0; 982 vex_state->guest_D15 = 0; 983 vex_state->guest_D16 = 0; 984 vex_state->guest_D17 = 0; 985 vex_state->guest_D18 = 0; 986 vex_state->guest_D19 = 0; 987 vex_state->guest_D20 = 0; 988 vex_state->guest_D21 = 0; 989 vex_state->guest_D22 = 0; 990 vex_state->guest_D23 = 0; 991 vex_state->guest_D24 = 0; 992 vex_state->guest_D25 = 0; 993 vex_state->guest_D26 = 0; 994 vex_state->guest_D27 = 0; 995 vex_state->guest_D28 = 0; 996 vex_state->guest_D29 = 0; 997 vex_state->guest_D30 = 0; 998 vex_state->guest_D31 = 0; 999 1000 /* ARM encoded; zero is the default as it happens (result flags 1001 (NZCV) cleared, FZ disabled, round to nearest, non-vector mode, 1002 all exns masked, all exn sticky bits cleared). */ 1003 vex_state->guest_FPSCR = 0; 1004 1005 vex_state->guest_TPIDRURO = 0; 1006 1007 /* Not in a Thumb IT block. */ 1008 vex_state->guest_ITSTATE = 0; 1009 1010 vex_state->padding1 = 0; 1011 vex_state->padding2 = 0; 1012 vex_state->padding3 = 0; 1013} 1014 1015 1016/*-----------------------------------------------------------*/ 1017/*--- Describing the arm guest state, for the benefit ---*/ 1018/*--- of iropt and instrumenters. ---*/ 1019/*-----------------------------------------------------------*/ 1020 1021/* Figure out if any part of the guest state contained in minoff 1022 .. maxoff requires precise memory exceptions. If in doubt return 1023 True (but this is generates significantly slower code). 1024 1025 We enforce precise exns for guest R13(sp), R15T(pc). 1026*/ 1027Bool guest_arm_state_requires_precise_mem_exns ( Int minoff, 1028 Int maxoff) 1029{ 1030 Int sp_min = offsetof(VexGuestARMState, guest_R13); 1031 Int sp_max = sp_min + 4 - 1; 1032 Int pc_min = offsetof(VexGuestARMState, guest_R15T); 1033 Int pc_max = pc_min + 4 - 1; 1034 1035 if (maxoff < sp_min || minoff > sp_max) { 1036 /* no overlap with sp */ 1037 } else { 1038 return True; 1039 } 1040 1041 if (maxoff < pc_min || minoff > pc_max) { 1042 /* no overlap with pc */ 1043 } else { 1044 return True; 1045 } 1046 1047 /* We appear to need precise updates of R11 in order to get proper 1048 stacktraces from non-optimised code. */ 1049 Int r11_min = offsetof(VexGuestARMState, guest_R11); 1050 Int r11_max = r11_min + 4 - 1; 1051 1052 if (maxoff < r11_min || minoff > r11_max) { 1053 /* no overlap with r11 */ 1054 } else { 1055 return True; 1056 } 1057 1058 /* Ditto R7, particularly needed for proper stacktraces in Thumb 1059 code. */ 1060 Int r7_min = offsetof(VexGuestARMState, guest_R7); 1061 Int r7_max = r7_min + 4 - 1; 1062 1063 if (maxoff < r7_min || minoff > r7_max) { 1064 /* no overlap with r7 */ 1065 } else { 1066 return True; 1067 } 1068 1069 return False; 1070} 1071 1072 1073 1074#define ALWAYSDEFD(field) \ 1075 { offsetof(VexGuestARMState, field), \ 1076 (sizeof ((VexGuestARMState*)0)->field) } 1077 1078VexGuestLayout 1079 armGuest_layout 1080 = { 1081 /* Total size of the guest state, in bytes. */ 1082 .total_sizeB = sizeof(VexGuestARMState), 1083 1084 /* Describe the stack pointer. */ 1085 .offset_SP = offsetof(VexGuestARMState,guest_R13), 1086 .sizeof_SP = 4, 1087 1088 /* Describe the instruction pointer. */ 1089 .offset_IP = offsetof(VexGuestARMState,guest_R15T), 1090 .sizeof_IP = 4, 1091 1092 /* Describe any sections to be regarded by Memcheck as 1093 'always-defined'. */ 1094 .n_alwaysDefd = 10, 1095 1096 /* flags thunk: OP is always defd, whereas DEP1 and DEP2 1097 have to be tracked. See detailed comment in gdefs.h on 1098 meaning of thunk fields. */ 1099 .alwaysDefd 1100 = { /* 0 */ ALWAYSDEFD(guest_R15T), 1101 /* 1 */ ALWAYSDEFD(guest_CC_OP), 1102 /* 2 */ ALWAYSDEFD(guest_CC_NDEP), 1103 /* 3 */ ALWAYSDEFD(guest_EMWARN), 1104 /* 4 */ ALWAYSDEFD(guest_TISTART), 1105 /* 5 */ ALWAYSDEFD(guest_TILEN), 1106 /* 6 */ ALWAYSDEFD(guest_NRADDR), 1107 /* 7 */ ALWAYSDEFD(guest_IP_AT_SYSCALL), 1108 /* 8 */ ALWAYSDEFD(guest_TPIDRURO), 1109 /* 9 */ ALWAYSDEFD(guest_ITSTATE) 1110 } 1111 }; 1112 1113 1114/*---------------------------------------------------------------*/ 1115/*--- end guest_arm_helpers.c ---*/ 1116/*---------------------------------------------------------------*/ 1117