OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2011 The Native Client Authors. All rights reserved. | 2 * Copyright (c) 2011 The Native Client Authors. All rights reserved. |
3 * Use of this source code is governed by a BSD-style license that can be | 3 * Use of this source code is governed by a BSD-style license that can be |
4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
5 */ | 5 */ |
6 | 6 |
7 #include "native_client/src/trusted/validator_arm/inst_classes.h" | 7 #include "native_client/src/trusted/validator_arm/inst_classes.h" |
8 | 8 // TODO(jasonwkim) remove when debug is gone |
| 9 #include <stdio.h> |
9 /* | 10 /* |
10 * Implementations of instruction classes, for those not completely defined in | 11 * Implementations of instruction classes, for those not completely defined in |
11 * the header. | 12 * the header. |
12 */ | 13 */ |
13 | 14 |
14 namespace nacl_arm_dec { | 15 namespace nacl_arm_dec { |
15 | 16 |
16 /* | 17 /* |
17 * A utility function: given a modified-immediate-form instruction, extracts | 18 * A utility function: given a modified-immediate-form instruction, extracts |
18 * the immediate value. This is used to analyze BIC and TST. | 19 * the immediate value. This is used to analyze BIC and TST. |
(...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
412 RegisterList Branch::defs(const Instruction i) const { | 413 RegisterList Branch::defs(const Instruction i) const { |
413 return kRegisterPc + (i.bit(24)? kRegisterLink : kRegisterNone); | 414 return kRegisterPc + (i.bit(24)? kRegisterLink : kRegisterNone); |
414 } | 415 } |
415 | 416 |
416 int32_t Branch::branch_target_offset(const Instruction i) const { | 417 int32_t Branch::branch_target_offset(const Instruction i) const { |
417 // Sign extend and shift left 2: | 418 // Sign extend and shift left 2: |
418 int32_t offset = (int32_t)(i.bits(23, 0) << 8) >> 6; | 419 int32_t offset = (int32_t)(i.bits(23, 0) << 8) >> 6; |
419 return offset + 8; // because r15 reads as 8 bytes ahead | 420 return offset + 8; // because r15 reads as 8 bytes ahead |
420 } | 421 } |
421 | 422 |
| 423 /* Thumb Functions */ |
| 424 SafetyLevel Def3::safety(Instruction i) const { |
| 425 /* If it tries to write to PC, unsafe */ |
| 426 if (defs(i)[kRegisterPc]) { |
| 427 return FORBIDDEN_OPERANDS; |
| 428 } |
| 429 return MAY_BE_SAFE; |
| 430 } |
| 431 |
| 432 RegisterList Def3::defs(Instruction i) const { |
| 433 return i.reg(3, 0); |
| 434 } |
| 435 |
| 436 SafetyLevel Def8_10::safety(Instruction i) const { |
| 437 // TODO(jasonwkim) should be encoding impossible, check |
| 438 if (defs(i)[kRegisterPc]) { |
| 439 return FORBIDDEN_OPERANDS; |
| 440 } |
| 441 return MAY_BE_SAFE; |
| 442 } |
| 443 |
| 444 RegisterList Def8_10::defs(Instruction i) const { |
| 445 return i.reg(10, 8); |
| 446 } |
| 447 |
| 448 SafetyLevel MemOpThumb::safety(Instruction i) const { |
| 449 // Don't let addressing writeback alter PC. |
| 450 // TODO(jasonwkim): Check if this is possible, we may be able to remove this. |
| 451 if (defs(i)[kRegisterPc]) return FORBIDDEN_OPERANDS; |
| 452 |
| 453 return MAY_BE_SAFE; |
| 454 } |
| 455 |
| 456 Register MemOpThumb::base_address_register(Instruction i) const { |
| 457 return i.reg(5, 3); |
| 458 } |
| 459 |
| 460 RegisterList MemOpThumbLoad::defs(Instruction i) const { |
| 461 return i.reg(2, 0); |
| 462 } |
| 463 |
| 464 // TODO(jasonwkim) double check, this is suspect |
| 465 // Specifically, double check if I need to +4 things? |
| 466 int32_t CmpBrZ::branch_target_offset(Instruction i) const { |
| 467 return int32_t ((i.bits(9, 9) << 6) & (i.bits(7, 3) << 1)); |
| 468 } |
| 469 |
| 470 RegisterList PopMult::defs(Instruction i) const { |
| 471 return RegisterList(i.bits(7, 0)) + kRegisterStack; |
| 472 } |
| 473 |
| 474 SafetyLevel BranchTCond::safety(Instruction i) const { |
| 475 if ((condition(i) & 14) != 14) |
| 476 return MAY_BE_SAFE; |
| 477 return FORBIDDEN_OPERANDS; |
| 478 } |
| 479 |
| 480 // TODO(jasonwkim) Check if I need to +4 |
| 481 int32_t BranchT1::branch_target_offset(Instruction i) const { |
| 482 // Sign extend and left shift by one |
| 483 return ((int32_t)(i.bits(7, 0) << 24)) >> 23; |
| 484 } |
| 485 |
| 486 // TODO(jasonwkim) write test |
| 487 Instruction::Condition BranchT1::condition(Instruction i) const { |
| 488 return (Instruction::Condition)i.bits(11, 8); |
| 489 } |
| 490 |
| 491 // TODO(jasonwkim) Check if I need to +4 |
| 492 int32_t BranchT2::branch_target_offset(Instruction i) const { |
| 493 // Sign extend and left shift by one. |
| 494 return ((int32_t)(i.bits(10, 0) << 21)) >> 20; |
| 495 } |
| 496 |
| 497 // TODO(jasonwkim) Check if I need to +4 |
| 498 int32_t BranchT3::branch_target_offset(Instruction i) const { |
| 499 // Construct the value |
| 500 uint32_t val = ((((((((i.bit(10) << 1) | i.bit(27)) << 1) | i.bit(29)) << 6) |
| 501 | i.bits(5, 0)) << 11) | i.bits(26, 16)) << 1; |
| 502 // Sign extend it. |
| 503 return ((int32_t)(val << 9)) >> 9; |
| 504 } |
| 505 |
| 506 Instruction::Condition BranchT3::condition(Instruction i) const { |
| 507 return (Instruction::Condition)i.bits(9, 6); |
| 508 } |
| 509 |
| 510 int32_t get_stretched_immediate(Instruction i) { |
| 511 uint32_t s = i.bit(10); |
| 512 uint32_t i1 = (~(i.bit(27) ^ s)) & 1; |
| 513 uint32_t i2 = (~(i.bit(29) ^ s)) & 1; |
| 514 // Construct the value |
| 515 uint32_t val = ((((((((i.bit(10) << 1) | i1) << 1) | i2) << 10) |
| 516 | i.bits(9, 0)) << 11) | i.bits(26, 16)) << 1; |
| 517 // Sign extend it, adjust for pc shift |
| 518 return (((int32_t)(val << 9)) >> 9); |
| 519 } |
| 520 |
| 521 int32_t BranchT4::branch_target_offset(Instruction i) const { |
| 522 return get_stretched_immediate(i) + 4; |
| 523 } |
| 524 |
| 525 // TODO(jasonwkim) LDMT1/STMT1 could be cleaned up |
| 526 RegisterList LDMT1::defs(Instruction i) const { |
| 527 return RegisterList(i.bits(7, 0)); |
| 528 } |
| 529 |
| 530 RegisterList STMT1::defs(Instruction i) const { |
| 531 return RegisterList(i.bits(7, 0)) + i.reg(10, 8); |
| 532 } |
| 533 |
| 534 RegisterList STMT1::immediate_addressing_defs(Instruction i) const { |
| 535 return i.reg(10, 8); |
| 536 } |
| 537 |
| 538 Register STMT1::base_address_register(Instruction i) const { |
| 539 return i.reg(10, 8); |
| 540 } |
| 541 |
| 542 RegisterList LDRLitT1::defs(Instruction i) const { |
| 543 return i.reg(10, 8); |
| 544 } |
| 545 |
| 546 RegisterList ADRT1::defs(Instruction i) const { |
| 547 return i.reg(10, 8); |
| 548 } |
| 549 |
| 550 RegisterList MemOpSPThumbLoad::defs(Instruction i) const { |
| 551 return i.reg(10, 8); |
| 552 } |
| 553 |
| 554 RegisterList DPMImm::defs(Instruction i) const { |
| 555 return i.reg(27, 24); |
| 556 } |
| 557 |
| 558 uint32_t get_thumb_modified_immediate(Instruction i) { |
| 559 uint32_t raw = i.bits(23, 16); |
| 560 uint8_t shift_mode = (((i.bits(10, 10) << 3) | i.bits(30, 28)) << 1) |
| 561 | i.bits(23, 23); |
| 562 switch (shift_mode >> 1) { |
| 563 case 0: return raw; |
| 564 case 1: return (raw << 16) | raw; |
| 565 case 2: return ((raw << 16) | raw) << 8; |
| 566 case 3: return (((((raw << 8) | raw) << 8) | raw) << 8) | raw; |
| 567 default: return (raw | (1 << 7)) << (31 - 7 - (shift_mode - 8)); |
| 568 }; |
| 569 } |
| 570 |
| 571 bool BicModImmT::clears_bits(Instruction i, uint32_t mask) const { |
| 572 return (get_thumb_modified_immediate(i) & mask) == mask; |
| 573 } |
| 574 |
| 575 bool OrrModImmT::sets_bits(Instruction i, uint32_t mask) const { |
| 576 return get_thumb_modified_immediate(i) == mask; |
| 577 } |
| 578 |
| 579 RegisterList MovT::defs(Instruction i) const { |
| 580 return Register((i.bits(7, 7) << 3) | i.bits(2, 0)); |
| 581 } |
| 582 |
| 583 Register BXT::branch_target_register(Instruction i) const { |
| 584 return i.reg(6, 3); |
| 585 } |
| 586 |
| 587 int32_t BLT::branch_target_offset(Instruction i) const { |
| 588 return get_stretched_immediate(i); |
| 589 } |
| 590 |
| 591 ITCond IT::it_sequence(Instruction i) const { |
| 592 uint32_t firstmask = i.bit(4); |
| 593 ITCond base = it_set(0, THEN, 0); |
| 594 uint32_t maskdex = 0; |
| 595 while (i.bit(maskdex) == 0) |
| 596 maskdex++; |
| 597 // TODO(jasonwkim) Add a guard to the parse table to make sure |
| 598 // the mask is never 0 |
| 599 maskdex++; |
| 600 for (uint32_t conddex = 1; maskdex < 4; maskdex++, conddex++) { |
| 601 base = it_set(conddex, i.bit(maskdex) == firstmask ? THEN : ELSE, base); |
| 602 } |
| 603 return base; |
| 604 } |
| 605 |
| 606 Instruction::Condition IT::condition(Instruction i) const { |
| 607 return (Instruction::Condition)i.bits(7, 4); |
| 608 } |
| 609 |
| 610 RegisterList STMTD::defs(Instruction i) const { |
| 611 return i.reg(3, 0); |
| 612 } |
| 613 |
| 614 Register STMTD::base_address_register(Instruction i) const { |
| 615 return i.reg(3, 0); |
| 616 } |
| 617 |
| 618 RegisterList STMTD::immediate_addressing_defs(Instruction i) const { |
| 619 return base_address_register(i); |
| 620 } |
| 621 |
| 622 RegisterList LDMTD::defs(Instruction i) const { |
| 623 return i.reg(3, 0) + RegisterList(i.bits(12, 0)); |
| 624 } |
| 625 |
| 626 Register StrS::base_address_register(Instruction i) const { |
| 627 return i.reg(3, 0); |
| 628 } |
| 629 |
| 630 // Note that while this doesn't always write something to i.reg(3, 0), it is |
| 631 // safe to pretend that it does. |
| 632 RegisterList StrS::defs(Instruction i) const { |
| 633 return i.reg(3, 0); |
| 634 } |
| 635 |
| 636 Register LDRImmT3::base_address_register(Instruction i) const { |
| 637 return i.reg(3, 0); |
| 638 } |
| 639 |
| 640 RegisterList LDRImmT4::defs(Instruction i) const { |
| 641 if (i.bit(8 + 16)) { |
| 642 return base_address_register(i); // Writeback |
| 643 } else { |
| 644 return kRegisterNone; |
| 645 } |
| 646 } |
| 647 |
| 648 RegisterList LDRImmT4::immediate_addressing_defs(Instruction i) const { |
| 649 return defs(i); |
| 650 } |
| 651 |
| 652 RegisterList Def31_18::defs(Instruction i) const { |
| 653 return i.reg(31, 18); |
| 654 } |
| 655 |
| 656 RegisterList StrEx::defs(Instruction i) const { |
| 657 return immediate_addressing_defs(i) + i.reg(11 + 16, 8 + 16); |
| 658 } |
| 659 |
| 660 RegisterList StrEx::immediate_addressing_defs(Instruction i) const { |
| 661 if (i.bit(5)) |
| 662 return base_address_register(i); |
| 663 return kRegisterNone; |
| 664 } |
| 665 |
| 666 Register StrEx::base_address_register(Instruction i) const { |
| 667 return i.reg(3, 0); |
| 668 } |
| 669 |
| 670 RegisterList LdrEx::defs(Instruction i) const { |
| 671 return immediate_addressing_defs(i) + i.reg(15 + 16, 12 + 16); |
| 672 } |
| 673 |
| 674 RegisterList StrD::defs(Instruction i) const { |
| 675 return immediate_addressing_defs(i); |
| 676 } |
| 677 |
| 678 RegisterList LdrD::defs(Instruction i) const { |
| 679 return immediate_addressing_defs(i) + i.reg(11 + 16, 8 + 16) |
| 680 + i.reg(15 + 16, 12 + 16); |
| 681 } |
| 682 |
| 683 RegisterList Def27_24::defs(Instruction i) const { |
| 684 return i.reg(27, 24); |
| 685 } |
| 686 |
| 687 bool ThumbBreakpoint::is_literal_pool_head(Instruction i) const { |
| 688 UNREFERENCED_PARAMETER(i); |
| 689 // TODO(jasonwkim) We ideally want to think about conditions, but due to the |
| 690 // rule that IT cannot straddle a boundary, and this has to start |
| 691 // a bundle, we're fine. |
| 692 return true; |
| 693 } |
| 694 |
422 } // namespace | 695 } // namespace |
OLD | NEW |