OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
211 } | 211 } |
212 | 212 |
213 | 213 |
214 void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) { | 214 void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) { |
215 for (int i = 0; bm[i].b >= 0; i++) { | 215 for (int i = 0; bm[i].b >= 0; i++) { |
216 InstructionDesc* id = &instructions_[bm[i].b]; | 216 InstructionDesc* id = &instructions_[bm[i].b]; |
217 id->mnem = bm[i].mnem; | 217 id->mnem = bm[i].mnem; |
218 OperandType op_order = bm[i].op_order_; | 218 OperandType op_order = bm[i].op_order_; |
219 id->op_order_ = | 219 id->op_order_ = |
220 static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG); | 220 static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG); |
221 assert(id->type == NO_INSTR); // Information not already entered | 221 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered |
222 id->type = type; | 222 id->type = type; |
223 id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0); | 223 id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0); |
224 } | 224 } |
225 } | 225 } |
226 | 226 |
227 | 227 |
228 void InstructionTable::SetTableRange(InstructionType type, | 228 void InstructionTable::SetTableRange(InstructionType type, |
229 byte start, | 229 byte start, |
230 byte end, | 230 byte end, |
231 bool byte_size, | 231 bool byte_size, |
232 const char* mnem) { | 232 const char* mnem) { |
233 for (byte b = start; b <= end; b++) { | 233 for (byte b = start; b <= end; b++) { |
234 InstructionDesc* id = &instructions_[b]; | 234 InstructionDesc* id = &instructions_[b]; |
235 assert(id->type == NO_INSTR); // Information already entered | 235 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered |
236 id->mnem = mnem; | 236 id->mnem = mnem; |
237 id->type = type; | 237 id->type = type; |
238 id->byte_size_operation = byte_size; | 238 id->byte_size_operation = byte_size; |
239 } | 239 } |
240 } | 240 } |
241 | 241 |
242 | 242 |
243 void InstructionTable::AddJumpConditionalShort() { | 243 void InstructionTable::AddJumpConditionalShort() { |
244 for (byte b = 0x70; b <= 0x7F; b++) { | 244 for (byte b = 0x70; b <= 0x7F; b++) { |
245 InstructionDesc* id = &instructions_[b]; | 245 InstructionDesc* id = &instructions_[b]; |
246 assert(id->type == NO_INSTR); // Information already entered | 246 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered |
247 id->mnem = NULL; // Computed depending on condition code. | 247 id->mnem = NULL; // Computed depending on condition code. |
248 id->type = JUMP_CONDITIONAL_SHORT_INSTR; | 248 id->type = JUMP_CONDITIONAL_SHORT_INSTR; |
249 } | 249 } |
250 } | 250 } |
251 | 251 |
252 | 252 |
253 static InstructionTable instruction_table; | 253 static InstructionTable instruction_table; |
254 | 254 |
255 static InstructionDesc cmov_instructions[16] = { | 255 static InstructionDesc cmov_instructions[16] = { |
256 {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 256 {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
386 *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0); | 386 *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0); |
387 *base = (data & 7) | (rex_b() ? 8 : 0); | 387 *base = (data & 7) | (rex_b() ? 8 : 0); |
388 } | 388 } |
389 | 389 |
390 typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const; | 390 typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const; |
391 | 391 |
392 int PrintRightOperandHelper(byte* modrmp, | 392 int PrintRightOperandHelper(byte* modrmp, |
393 RegisterNameMapping register_name); | 393 RegisterNameMapping register_name); |
394 int PrintRightOperand(byte* modrmp); | 394 int PrintRightOperand(byte* modrmp); |
395 int PrintRightByteOperand(byte* modrmp); | 395 int PrintRightByteOperand(byte* modrmp); |
| 396 int PrintRightXMMOperand(byte* modrmp); |
396 int PrintOperands(const char* mnem, | 397 int PrintOperands(const char* mnem, |
397 OperandType op_order, | 398 OperandType op_order, |
398 byte* data); | 399 byte* data); |
399 int PrintImmediate(byte* data, OperandSize size); | 400 int PrintImmediate(byte* data, OperandSize size); |
400 int PrintImmediateOp(byte* data); | 401 int PrintImmediateOp(byte* data); |
401 const char* TwoByteMnemonic(byte opcode); | 402 const char* TwoByteMnemonic(byte opcode); |
402 int TwoByteOpcodeInstruction(byte* data); | 403 int TwoByteOpcodeInstruction(byte* data); |
403 int F7Instruction(byte* data); | 404 int F6F7Instruction(byte* data); |
404 int ShiftInstruction(byte* data); | 405 int ShiftInstruction(byte* data); |
405 int JumpShort(byte* data); | 406 int JumpShort(byte* data); |
406 int JumpConditional(byte* data); | 407 int JumpConditional(byte* data); |
407 int JumpConditionalShort(byte* data); | 408 int JumpConditionalShort(byte* data); |
408 int SetCC(byte* data); | 409 int SetCC(byte* data); |
409 int FPUInstruction(byte* data); | 410 int FPUInstruction(byte* data); |
| 411 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start); |
| 412 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte); |
410 void AppendToBuffer(const char* format, ...); | 413 void AppendToBuffer(const char* format, ...); |
411 | 414 |
412 void UnimplementedInstruction() { | 415 void UnimplementedInstruction() { |
413 if (abort_on_unimplemented_) { | 416 if (abort_on_unimplemented_) { |
414 CHECK(false); | 417 CHECK(false); |
415 } else { | 418 } else { |
416 AppendToBuffer("'Unimplemented Instruction'"); | 419 AppendToBuffer("'Unimplemented Instruction'"); |
417 } | 420 } |
418 } | 421 } |
419 }; | 422 }; |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
561 &DisassemblerX64::NameOfCPURegister); | 564 &DisassemblerX64::NameOfCPURegister); |
562 } | 565 } |
563 | 566 |
564 | 567 |
565 int DisassemblerX64::PrintRightByteOperand(byte* modrmp) { | 568 int DisassemblerX64::PrintRightByteOperand(byte* modrmp) { |
566 return PrintRightOperandHelper(modrmp, | 569 return PrintRightOperandHelper(modrmp, |
567 &DisassemblerX64::NameOfByteCPURegister); | 570 &DisassemblerX64::NameOfByteCPURegister); |
568 } | 571 } |
569 | 572 |
570 | 573 |
| 574 int DisassemblerX64::PrintRightXMMOperand(byte* modrmp) { |
| 575 return PrintRightOperandHelper(modrmp, |
| 576 &DisassemblerX64::NameOfXMMRegister); |
| 577 } |
| 578 |
| 579 |
571 // Returns number of bytes used including the current *data. | 580 // Returns number of bytes used including the current *data. |
572 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'. | 581 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'. |
573 int DisassemblerX64::PrintOperands(const char* mnem, | 582 int DisassemblerX64::PrintOperands(const char* mnem, |
574 OperandType op_order, | 583 OperandType op_order, |
575 byte* data) { | 584 byte* data) { |
576 byte modrm = *data; | 585 byte modrm = *data; |
577 int mod, regop, rm; | 586 int mod, regop, rm; |
578 get_modrm(modrm, &mod, ®op, &rm); | 587 get_modrm(modrm, &mod, ®op, &rm); |
579 int advance = 0; | 588 int advance = 0; |
580 const char* register_name = | 589 const char* register_name = |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
641 AppendToBuffer("%s%c ", mnem, operand_size_code()); | 650 AppendToBuffer("%s%c ", mnem, operand_size_code()); |
642 int count = PrintRightOperand(data + 1); | 651 int count = PrintRightOperand(data + 1); |
643 AppendToBuffer(",0x"); | 652 AppendToBuffer(",0x"); |
644 OperandSize immediate_size = byte_size_immediate ? BYTE_SIZE : operand_size(); | 653 OperandSize immediate_size = byte_size_immediate ? BYTE_SIZE : operand_size(); |
645 count += PrintImmediate(data + 1 + count, immediate_size); | 654 count += PrintImmediate(data + 1 + count, immediate_size); |
646 return 1 + count; | 655 return 1 + count; |
647 } | 656 } |
648 | 657 |
649 | 658 |
650 // Returns number of bytes used, including *data. | 659 // Returns number of bytes used, including *data. |
651 int DisassemblerX64::F7Instruction(byte* data) { | 660 int DisassemblerX64::F6F7Instruction(byte* data) { |
652 assert(*data == 0xF7); | 661 ASSERT(*data == 0xF7 || *data == 0xF6); |
653 byte modrm = *(data + 1); | 662 byte modrm = *(data + 1); |
654 int mod, regop, rm; | 663 int mod, regop, rm; |
655 get_modrm(modrm, &mod, ®op, &rm); | 664 get_modrm(modrm, &mod, ®op, &rm); |
656 if (mod == 3 && regop != 0) { | 665 if (mod == 3 && regop != 0) { |
657 const char* mnem = NULL; | 666 const char* mnem = NULL; |
658 switch (regop) { | 667 switch (regop) { |
659 case 2: | 668 case 2: |
660 mnem = "not"; | 669 mnem = "not"; |
661 break; | 670 break; |
662 case 3: | 671 case 3: |
663 mnem = "neg"; | 672 mnem = "neg"; |
664 break; | 673 break; |
665 case 4: | 674 case 4: |
666 mnem = "mul"; | 675 mnem = "mul"; |
667 break; | 676 break; |
668 case 7: | 677 case 7: |
669 mnem = "idiv"; | 678 mnem = "idiv"; |
670 break; | 679 break; |
671 default: | 680 default: |
672 UnimplementedInstruction(); | 681 UnimplementedInstruction(); |
673 } | 682 } |
674 AppendToBuffer("%s%c %s", | 683 AppendToBuffer("%s%c %s", |
675 mnem, | 684 mnem, |
676 operand_size_code(), | 685 operand_size_code(), |
677 NameOfCPURegister(rm)); | 686 NameOfCPURegister(rm)); |
678 return 2; | 687 return 2; |
679 } else if (mod == 3 && regop == 0) { | |
680 int32_t imm = *reinterpret_cast<int32_t*>(data + 2); | |
681 AppendToBuffer("test%c %s,0x%x", | |
682 operand_size_code(), | |
683 NameOfCPURegister(rm), | |
684 imm); | |
685 return 6; | |
686 } else if (regop == 0) { | 688 } else if (regop == 0) { |
687 AppendToBuffer("test%c ", operand_size_code()); | 689 AppendToBuffer("test%c ", operand_size_code()); |
688 int count = PrintRightOperand(data + 1); | 690 int count = PrintRightOperand(data + 1); // Use name of 64-bit register. |
689 int32_t imm = *reinterpret_cast<int32_t*>(data + 1 + count); | 691 AppendToBuffer(",0x"); |
690 AppendToBuffer(",0x%x", imm); | 692 count += PrintImmediate(data + 1 + count, operand_size()); |
691 return 1 + count + 4 /*int32_t*/; | 693 return 1 + count; |
692 } else { | 694 } else { |
693 UnimplementedInstruction(); | 695 UnimplementedInstruction(); |
694 return 2; | 696 return 2; |
695 } | 697 } |
696 } | 698 } |
697 | 699 |
698 | 700 |
699 int DisassemblerX64::ShiftInstruction(byte* data) { | 701 int DisassemblerX64::ShiftInstruction(byte* data) { |
700 byte op = *data & (~1); | 702 byte op = *data & (~1); |
701 if (op != 0xD0 && op != 0xD2 && op != 0xC0) { | 703 if (op != 0xD0 && op != 0xD2 && op != 0xC0) { |
(...skipping 30 matching lines...) Expand all Loading... |
732 case 5: | 734 case 5: |
733 mnem = "shr"; | 735 mnem = "shr"; |
734 break; | 736 break; |
735 case 7: | 737 case 7: |
736 mnem = "sar"; | 738 mnem = "sar"; |
737 break; | 739 break; |
738 default: | 740 default: |
739 UnimplementedInstruction(); | 741 UnimplementedInstruction(); |
740 return num_bytes; | 742 return num_bytes; |
741 } | 743 } |
742 assert(mnem != NULL); | 744 ASSERT_NE(NULL, mnem); |
743 if (op == 0xD0) { | 745 if (op == 0xD0) { |
744 imm8 = 1; | 746 imm8 = 1; |
745 } else if (op == 0xC0) { | 747 } else if (op == 0xC0) { |
746 imm8 = *(data + 2); | 748 imm8 = *(data + 2); |
747 num_bytes = 3; | 749 num_bytes = 3; |
748 } | 750 } |
749 AppendToBuffer("%s%c %s,", | 751 AppendToBuffer("%s%c %s,", |
750 mnem, | 752 mnem, |
751 operand_size_code(), | 753 operand_size_code(), |
752 byte_size_operand_ ? NameOfByteCPURegister(rm) | 754 byte_size_operand_ ? NameOfByteCPURegister(rm) |
753 : NameOfCPURegister(rm)); | 755 : NameOfCPURegister(rm)); |
754 if (op == 0xD2) { | 756 if (op == 0xD2) { |
755 AppendToBuffer("cl"); | 757 AppendToBuffer("cl"); |
756 } else { | 758 } else { |
757 AppendToBuffer("%d", imm8); | 759 AppendToBuffer("%d", imm8); |
758 } | 760 } |
759 return num_bytes; | 761 return num_bytes; |
760 } | 762 } |
761 | 763 |
762 | 764 |
763 // Returns number of bytes used, including *data. | 765 // Returns number of bytes used, including *data. |
764 int DisassemblerX64::JumpShort(byte* data) { | 766 int DisassemblerX64::JumpShort(byte* data) { |
765 assert(*data == 0xEB); | 767 ASSERT_EQ(0xEB, *data); |
766 byte b = *(data + 1); | 768 byte b = *(data + 1); |
767 byte* dest = data + static_cast<int8_t>(b) + 2; | 769 byte* dest = data + static_cast<int8_t>(b) + 2; |
768 AppendToBuffer("jmp %s", NameOfAddress(dest)); | 770 AppendToBuffer("jmp %s", NameOfAddress(dest)); |
769 return 2; | 771 return 2; |
770 } | 772 } |
771 | 773 |
772 | 774 |
773 // Returns number of bytes used, including *data. | 775 // Returns number of bytes used, including *data. |
774 int DisassemblerX64::JumpConditional(byte* data) { | 776 int DisassemblerX64::JumpConditional(byte* data) { |
775 assert(*data == 0x0F); | 777 ASSERT_EQ(0x0F, *data); |
776 byte cond = *(data + 1) & 0x0F; | 778 byte cond = *(data + 1) & 0x0F; |
777 byte* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6; | 779 byte* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6; |
778 const char* mnem = conditional_code_suffix[cond]; | 780 const char* mnem = conditional_code_suffix[cond]; |
779 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest)); | 781 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest)); |
780 return 6; // includes 0x0F | 782 return 6; // includes 0x0F |
781 } | 783 } |
782 | 784 |
783 | 785 |
784 // Returns number of bytes used, including *data. | 786 // Returns number of bytes used, including *data. |
785 int DisassemblerX64::JumpConditionalShort(byte* data) { | 787 int DisassemblerX64::JumpConditionalShort(byte* data) { |
786 byte cond = *data & 0x0F; | 788 byte cond = *data & 0x0F; |
787 byte b = *(data + 1); | 789 byte b = *(data + 1); |
788 byte* dest = data + static_cast<int8_t>(b) + 2; | 790 byte* dest = data + static_cast<int8_t>(b) + 2; |
789 const char* mnem = conditional_code_suffix[cond]; | 791 const char* mnem = conditional_code_suffix[cond]; |
790 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest)); | 792 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest)); |
791 return 2; | 793 return 2; |
792 } | 794 } |
793 | 795 |
794 | 796 |
795 // Returns number of bytes used, including *data. | 797 // Returns number of bytes used, including *data. |
796 int DisassemblerX64::SetCC(byte* data) { | 798 int DisassemblerX64::SetCC(byte* data) { |
797 assert(*data == 0x0F); | 799 ASSERT_EQ(0x0F, *data); |
798 byte cond = *(data + 1) & 0x0F; | 800 byte cond = *(data + 1) & 0x0F; |
799 const char* mnem = conditional_code_suffix[cond]; | 801 const char* mnem = conditional_code_suffix[cond]; |
800 AppendToBuffer("set%s%c ", mnem, operand_size_code()); | 802 AppendToBuffer("set%s%c ", mnem, operand_size_code()); |
801 PrintRightByteOperand(data + 2); | 803 PrintRightByteOperand(data + 2); |
802 return 3; // includes 0x0F | 804 return 3; // includes 0x0F |
803 } | 805 } |
804 | 806 |
805 | 807 |
806 // Returns number of bytes used, including *data. | 808 // Returns number of bytes used, including *data. |
807 int DisassemblerX64::FPUInstruction(byte* data) { | 809 int DisassemblerX64::FPUInstruction(byte* data) { |
808 byte b1 = *data; | 810 byte escape_opcode = *data; |
809 byte b2 = *(data + 1); | 811 ASSERT_EQ(0xD8, escape_opcode & 0xF8); |
810 if (b1 == 0xD9) { | 812 byte modrm_byte = *(data+1); |
811 const char* mnem = NULL; | 813 |
812 switch (b2) { | 814 if (modrm_byte >= 0xC0) { |
813 case 0xE0: | 815 return RegisterFPUInstruction(escape_opcode, modrm_byte); |
814 mnem = "fchs"; | 816 } else { |
815 break; | 817 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1); |
816 case 0xE1: | 818 } |
817 mnem = "fabs"; | 819 } |
818 break; | 820 |
819 case 0xE4: | 821 int DisassemblerX64::MemoryFPUInstruction(int escape_opcode, |
820 mnem = "ftst"; | 822 int modrm_byte, |
821 break; | 823 byte* modrm_start) { |
822 case 0xF5: | 824 const char* mnem = "?"; |
823 mnem = "fprem1"; | 825 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte. |
824 break; | 826 switch (escape_opcode) { |
825 case 0xF7: | 827 case 0xD9: switch (regop) { |
826 mnem = "fincstp"; | 828 case 0: mnem = "fld_s"; break; |
827 break; | 829 case 3: mnem = "fstp_s"; break; |
828 case 0xE8: | 830 case 7: mnem = "fstcw"; break; |
829 mnem = "fld1"; | 831 default: UnimplementedInstruction(); |
830 break; | 832 } |
831 case 0xEE: | 833 break; |
832 mnem = "fldz"; | 834 |
833 break; | 835 case 0xDB: switch (regop) { |
834 case 0xF8: | 836 case 0: mnem = "fild_s"; break; |
835 mnem = "fprem"; | 837 case 1: mnem = "fisttp_s"; break; |
836 break; | 838 case 2: mnem = "fist_s"; break; |
837 } | 839 case 3: mnem = "fistp_s"; break; |
838 if (mnem != NULL) { | 840 default: UnimplementedInstruction(); |
839 AppendToBuffer("%s", mnem); | 841 } |
840 return 2; | 842 break; |
841 } else if ((b2 & 0xF8) == 0xC8) { | 843 |
842 AppendToBuffer("fxch st%d", b2 & 0x7); | 844 case 0xDD: switch (regop) { |
843 return 2; | 845 case 0: mnem = "fld_d"; break; |
844 } else { | 846 case 3: mnem = "fstp_d"; break; |
845 int mod, regop, rm; | 847 default: UnimplementedInstruction(); |
846 get_modrm(*(data + 1), &mod, ®op, &rm); | 848 } |
847 const char* mnem = "?"; | 849 break; |
848 switch (regop) { | 850 |
849 case 0: | 851 case 0xDF: switch (regop) { |
850 mnem = "fld_s"; | 852 case 5: mnem = "fild_d"; break; |
851 break; | 853 case 7: mnem = "fistp_d"; break; |
852 case 3: | 854 default: UnimplementedInstruction(); |
853 mnem = "fstp_s"; | 855 } |
| 856 break; |
| 857 |
| 858 default: UnimplementedInstruction(); |
| 859 } |
| 860 AppendToBuffer("%s ", mnem); |
| 861 int count = PrintRightOperand(modrm_start); |
| 862 return count + 1; |
| 863 } |
| 864 |
| 865 int DisassemblerX64::RegisterFPUInstruction(int escape_opcode, |
| 866 byte modrm_byte) { |
| 867 bool has_register = false; // Is the FPU register encoded in modrm_byte? |
| 868 const char* mnem = "?"; |
| 869 |
| 870 switch (escape_opcode) { |
| 871 case 0xD8: |
| 872 UnimplementedInstruction(); |
| 873 break; |
| 874 |
| 875 case 0xD9: |
| 876 switch (modrm_byte & 0xF8) { |
| 877 case 0xC8: |
| 878 mnem = "fxch"; |
| 879 has_register = true; |
854 break; | 880 break; |
855 default: | 881 default: |
856 UnimplementedInstruction(); | 882 switch (modrm_byte) { |
| 883 case 0xE0: mnem = "fchs"; break; |
| 884 case 0xE1: mnem = "fabs"; break; |
| 885 case 0xE4: mnem = "ftst"; break; |
| 886 case 0xE8: mnem = "fld1"; break; |
| 887 case 0xEE: mnem = "fldz"; break; |
| 888 case 0xF5: mnem = "fprem1"; break; |
| 889 case 0xF7: mnem = "fincstp"; break; |
| 890 case 0xF8: mnem = "fprem"; break; |
| 891 case 0xFE: mnem = "fsin"; break; |
| 892 case 0xFF: mnem = "fcos"; break; |
| 893 default: UnimplementedInstruction(); |
| 894 } |
857 } | 895 } |
858 AppendToBuffer("%s ", mnem); | 896 break; |
859 int count = PrintRightOperand(data + 1); | 897 |
860 return count + 1; | 898 case 0xDA: |
861 } | 899 if (modrm_byte == 0xE9) { |
862 } else if (b1 == 0xDD) { | 900 mnem = "fucompp"; |
863 int mod, regop, rm; | 901 } else { |
864 get_modrm(*(data + 1), &mod, ®op, &rm); | 902 UnimplementedInstruction(); |
865 if (mod == 3) { | |
866 switch (regop) { | |
867 case 0: | |
868 AppendToBuffer("ffree st%d", rm & 7); | |
869 break; | |
870 case 2: | |
871 AppendToBuffer("fstp st%d", rm & 7); | |
872 break; | |
873 default: | |
874 UnimplementedInstruction(); | |
875 break; | |
876 } | 903 } |
877 return 2; | 904 break; |
878 } else { | 905 |
879 const char* mnem = "?"; | 906 case 0xDB: |
880 switch (regop) { | 907 if ((modrm_byte & 0xF8) == 0xE8) { |
881 case 0: | 908 mnem = "fucomi"; |
882 mnem = "fld_d"; | 909 has_register = true; |
883 break; | 910 } else if (modrm_byte == 0xE2) { |
884 case 3: | 911 mnem = "fclex"; |
885 mnem = "fstp_d"; | 912 } else { |
886 break; | 913 UnimplementedInstruction(); |
887 default: | |
888 UnimplementedInstruction(); | |
889 } | 914 } |
890 AppendToBuffer("%s ", mnem); | 915 break; |
891 int count = PrintRightOperand(data + 1); | 916 |
892 return count + 1; | 917 case 0xDC: |
893 } | 918 has_register = true; |
894 } else if (b1 == 0xDB) { | 919 switch (modrm_byte & 0xF8) { |
895 int mod, regop, rm; | 920 case 0xC0: mnem = "fadd"; break; |
896 get_modrm(*(data + 1), &mod, ®op, &rm); | 921 case 0xE8: mnem = "fsub"; break; |
897 const char* mnem = "?"; | 922 case 0xC8: mnem = "fmul"; break; |
898 switch (regop) { | 923 case 0xF8: mnem = "fdiv"; break; |
899 case 0: | 924 default: UnimplementedInstruction(); |
900 mnem = "fild_s"; | 925 } |
901 break; | 926 break; |
902 case 2: | 927 |
903 mnem = "fist_s"; | 928 case 0xDD: |
904 break; | 929 has_register = true; |
905 case 3: | 930 switch (modrm_byte & 0xF8) { |
906 mnem = "fistp_s"; | 931 case 0xC0: mnem = "ffree"; break; |
907 break; | 932 case 0xD8: mnem = "fstp"; break; |
908 default: | 933 default: UnimplementedInstruction(); |
909 UnimplementedInstruction(); | 934 } |
910 } | 935 break; |
911 AppendToBuffer("%s ", mnem); | 936 |
912 int count = PrintRightOperand(data + 1); | 937 case 0xDE: |
913 return count + 1; | 938 if (modrm_byte == 0xD9) { |
914 } else if (b1 == 0xDF) { | 939 mnem = "fcompp"; |
915 if (b2 == 0xE0) { | 940 } else { |
916 AppendToBuffer("fnstsw_ax"); | 941 has_register = true; |
917 return 2; | 942 switch (modrm_byte & 0xF8) { |
918 } | 943 case 0xC0: mnem = "faddp"; break; |
919 int mod, regop, rm; | 944 case 0xE8: mnem = "fsubp"; break; |
920 get_modrm(*(data + 1), &mod, ®op, &rm); | 945 case 0xC8: mnem = "fmulp"; break; |
921 const char* mnem = "?"; | 946 case 0xF8: mnem = "fdivp"; break; |
922 switch (regop) { | 947 default: UnimplementedInstruction(); |
923 case 5: | 948 } |
924 mnem = "fild_d"; | 949 } |
925 break; | 950 break; |
926 case 7: | 951 |
927 mnem = "fistp_d"; | 952 case 0xDF: |
928 break; | 953 if (modrm_byte == 0xE0) { |
929 default: | 954 mnem = "fnstsw_ax"; |
930 UnimplementedInstruction(); | 955 } else if ((modrm_byte & 0xF8) == 0xE8) { |
931 } | 956 mnem = "fucomip"; |
932 AppendToBuffer("%s ", mnem); | 957 has_register = true; |
933 int count = PrintRightOperand(data + 1); | 958 } |
934 return count + 1; | 959 break; |
935 } else if (b1 == 0xDC || b1 == 0xDE) { | 960 |
936 bool is_pop = (b1 == 0xDE); | 961 default: UnimplementedInstruction(); |
937 if (is_pop && b2 == 0xD9) { | 962 } |
938 AppendToBuffer("fcompp"); | 963 |
939 return 2; | 964 if (has_register) { |
940 } | 965 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7); |
941 const char* mnem = "FP0xDC"; | 966 } else { |
942 switch (b2 & 0xF8) { | |
943 case 0xC0: | |
944 mnem = "fadd"; | |
945 break; | |
946 case 0xE8: | |
947 mnem = "fsub"; | |
948 break; | |
949 case 0xC8: | |
950 mnem = "fmul"; | |
951 break; | |
952 case 0xF8: | |
953 mnem = "fdiv"; | |
954 break; | |
955 default: | |
956 UnimplementedInstruction(); | |
957 } | |
958 AppendToBuffer("%s%s st%d", mnem, is_pop ? "p" : "", b2 & 0x7); | |
959 return 2; | |
960 } else if (b1 == 0xDA && b2 == 0xE9) { | |
961 const char* mnem = "fucompp"; | |
962 AppendToBuffer("%s", mnem); | 967 AppendToBuffer("%s", mnem); |
963 return 2; | |
964 } | 968 } |
965 AppendToBuffer("Unknown FP instruction"); | |
966 return 2; | 969 return 2; |
967 } | 970 } |
968 | 971 |
969 | 972 |
| 973 |
970 // Handle all two-byte opcodes, which start with 0x0F. | 974 // Handle all two-byte opcodes, which start with 0x0F. |
971 // These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix. | 975 // These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix. |
972 // We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A. | 976 // We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A. |
973 int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { | 977 int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { |
974 byte opcode = *(data + 1); | 978 byte opcode = *(data + 1); |
975 byte* current = data + 2; | 979 byte* current = data + 2; |
976 // At return, "current" points to the start of the next instruction. | 980 // At return, "current" points to the start of the next instruction. |
977 const char* mnemonic = TwoByteMnemonic(opcode); | 981 const char* mnemonic = TwoByteMnemonic(opcode); |
978 if (opcode == 0x1F) { | 982 if (opcode == 0x1F) { |
979 // NOP | 983 // NOP |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1038 AppendToBuffer(",%s", NameOfXMMRegister(regop)); | 1042 AppendToBuffer(",%s", NameOfXMMRegister(regop)); |
1039 } else { | 1043 } else { |
1040 AppendToBuffer("%s,", NameOfXMMRegister(regop)); | 1044 AppendToBuffer("%s,", NameOfXMMRegister(regop)); |
1041 current += PrintRightOperand(current); | 1045 current += PrintRightOperand(current); |
1042 } | 1046 } |
1043 } else if (opcode == 0x2A) { | 1047 } else if (opcode == 0x2A) { |
1044 // CVTSI2SD: integer to XMM double conversion. | 1048 // CVTSI2SD: integer to XMM double conversion. |
1045 int mod, regop, rm; | 1049 int mod, regop, rm; |
1046 get_modrm(*current, &mod, ®op, &rm); | 1050 get_modrm(*current, &mod, ®op, &rm); |
1047 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop)); | 1051 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop)); |
1048 data += PrintRightOperand(data); | 1052 current += PrintRightOperand(current); |
1049 } else if ((opcode & 0xF8) == 0x58) { | 1053 } else if ((opcode & 0xF8) == 0x58) { |
1050 // XMM arithmetic. Mnemonic was retrieved at the start of this function. | 1054 // XMM arithmetic. Mnemonic was retrieved at the start of this function. |
1051 int mod, regop, rm; | 1055 int mod, regop, rm; |
1052 get_modrm(*current, &mod, ®op, &rm); | 1056 get_modrm(*current, &mod, ®op, &rm); |
1053 AppendToBuffer("%s %s,%s", mnemonic, NameOfXMMRegister(regop), | 1057 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop)); |
1054 NameOfXMMRegister(rm)); | 1058 current += PrintRightXMMOperand(current); |
1055 } else { | 1059 } else { |
1056 UnimplementedInstruction(); | 1060 UnimplementedInstruction(); |
1057 } | 1061 } |
1058 } else if (opcode == 0x2C && group_1_prefix_ == 0xF3) { | 1062 } else if (opcode == 0x2C && group_1_prefix_ == 0xF3) { |
1059 // Instruction with prefix 0xF3. | 1063 // Instruction with prefix 0xF3. |
1060 | 1064 |
1061 // CVTTSS2SI: Convert scalar single-precision FP to dword integer. | 1065 // CVTTSS2SI: Convert scalar single-precision FP to dword integer. |
1062 // Assert that mod is not 3, so source is memory, not an XMM register. | 1066 // Assert that mod is not 3, so source is memory, not an XMM register. |
1063 ASSERT((*current & 0xC0) != 0xC0); | 1067 ASSERT_NE(0xC0, *current & 0xC0); |
1064 current += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, current); | 1068 current += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, current); |
1065 } else { | 1069 } else { |
1066 UnimplementedInstruction(); | 1070 UnimplementedInstruction(); |
1067 } | 1071 } |
1068 return current - data; | 1072 return current - data; |
1069 } | 1073 } |
1070 | 1074 |
1071 | 1075 |
1072 // Mnemonics for two-byte opcode instructions starting with 0x0F. | 1076 // Mnemonics for two-byte opcode instructions starting with 0x0F. |
1073 // The argument is the second byte of the two-byte opcode. | 1077 // The argument is the second byte of the two-byte opcode. |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1229 int mod, regop, rm; | 1233 int mod, regop, rm; |
1230 get_modrm(*(data + 1), &mod, ®op, &rm); | 1234 get_modrm(*(data + 1), &mod, ®op, &rm); |
1231 int32_t imm = *data == 0x6B ? *(data + 2) | 1235 int32_t imm = *data == 0x6B ? *(data + 2) |
1232 : *reinterpret_cast<int32_t*>(data + 2); | 1236 : *reinterpret_cast<int32_t*>(data + 2); |
1233 AppendToBuffer("imul %s,%s,0x%x", NameOfCPURegister(regop), | 1237 AppendToBuffer("imul %s,%s,0x%x", NameOfCPURegister(regop), |
1234 NameOfCPURegister(rm), imm); | 1238 NameOfCPURegister(rm), imm); |
1235 data += 2 + (*data == 0x6B ? 1 : 4); | 1239 data += 2 + (*data == 0x6B ? 1 : 4); |
1236 break; | 1240 break; |
1237 } | 1241 } |
1238 | 1242 |
1239 case 0xF6: { | |
1240 int mod, regop, rm; | |
1241 get_modrm(*(data + 1), &mod, ®op, &rm); | |
1242 if (mod == 3 && regop == 0) { | |
1243 AppendToBuffer("testb %s,%d", NameOfCPURegister(rm), *(data + 2)); | |
1244 } else { | |
1245 UnimplementedInstruction(); | |
1246 } | |
1247 data += 3; | |
1248 break; | |
1249 } | |
1250 | |
1251 case 0x81: // fall through | 1243 case 0x81: // fall through |
1252 case 0x83: // 0x81 with sign extension bit set | 1244 case 0x83: // 0x81 with sign extension bit set |
1253 data += PrintImmediateOp(data); | 1245 data += PrintImmediateOp(data); |
1254 break; | 1246 break; |
1255 | 1247 |
1256 case 0x0F: | 1248 case 0x0F: |
1257 data += TwoByteOpcodeInstruction(data); | 1249 data += TwoByteOpcodeInstruction(data); |
1258 break; | 1250 break; |
1259 | 1251 |
1260 case 0x8F: { | 1252 case 0x8F: { |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1337 break; | 1329 break; |
1338 | 1330 |
1339 case 0x90: | 1331 case 0x90: |
1340 case 0x91: | 1332 case 0x91: |
1341 case 0x92: | 1333 case 0x92: |
1342 case 0x93: | 1334 case 0x93: |
1343 case 0x94: | 1335 case 0x94: |
1344 case 0x95: | 1336 case 0x95: |
1345 case 0x96: | 1337 case 0x96: |
1346 case 0x97: { | 1338 case 0x97: { |
1347 int reg = (current & 0x7) | (rex_b() ? 8 : 0); | 1339 int reg = (*data & 0x7) | (rex_b() ? 8 : 0); |
1348 if (reg == 0) { | 1340 if (reg == 0) { |
1349 AppendToBuffer("nop"); // Common name for xchg rax,rax. | 1341 AppendToBuffer("nop"); // Common name for xchg rax,rax. |
1350 } else { | 1342 } else { |
1351 AppendToBuffer("xchg%c rax, %s", | 1343 AppendToBuffer("xchg%c rax, %s", |
1352 operand_size_code(), | 1344 operand_size_code(), |
1353 NameOfCPURegister(reg)); | 1345 NameOfCPURegister(reg)); |
1354 } | 1346 } |
| 1347 data++; |
1355 } | 1348 } |
1356 | 1349 break; |
1357 | 1350 |
1358 case 0xFE: { | 1351 case 0xFE: { |
1359 data++; | 1352 data++; |
1360 int mod, regop, rm; | 1353 int mod, regop, rm; |
1361 get_modrm(*data, &mod, ®op, &rm); | 1354 get_modrm(*data, &mod, ®op, &rm); |
1362 if (mod == 3 && regop == 1) { | 1355 if (mod == 3 && regop == 1) { |
1363 AppendToBuffer("decb %s", NameOfCPURegister(rm)); | 1356 AppendToBuffer("decb %s", NameOfCPURegister(rm)); |
1364 } else { | 1357 } else { |
1365 UnimplementedInstruction(); | 1358 UnimplementedInstruction(); |
1366 } | 1359 } |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1458 case 0xDD: // fall through | 1451 case 0xDD: // fall through |
1459 case 0xDE: // fall through | 1452 case 0xDE: // fall through |
1460 case 0xDF: | 1453 case 0xDF: |
1461 data += FPUInstruction(data); | 1454 data += FPUInstruction(data); |
1462 break; | 1455 break; |
1463 | 1456 |
1464 case 0xEB: | 1457 case 0xEB: |
1465 data += JumpShort(data); | 1458 data += JumpShort(data); |
1466 break; | 1459 break; |
1467 | 1460 |
| 1461 case 0xF6: |
| 1462 byte_size_operand_ = true; // fall through |
1468 case 0xF7: | 1463 case 0xF7: |
1469 data += F7Instruction(data); | 1464 data += F6F7Instruction(data); |
1470 break; | 1465 break; |
1471 | 1466 |
1472 default: | 1467 default: |
1473 UnimplementedInstruction(); | 1468 UnimplementedInstruction(); |
1474 data += 1; | 1469 data += 1; |
1475 } | 1470 } |
1476 } // !processed | 1471 } // !processed |
1477 | 1472 |
1478 if (tmp_buffer_pos_ < sizeof tmp_buffer_) { | 1473 if (tmp_buffer_pos_ < sizeof tmp_buffer_) { |
1479 tmp_buffer_[tmp_buffer_pos_] = '\0'; | 1474 tmp_buffer_[tmp_buffer_pos_] = '\0'; |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1592 fprintf(f, "%02x", *bp); | 1587 fprintf(f, "%02x", *bp); |
1593 } | 1588 } |
1594 for (int i = 6 - (pc - prev_pc); i >= 0; i--) { | 1589 for (int i = 6 - (pc - prev_pc); i >= 0; i--) { |
1595 fprintf(f, " "); | 1590 fprintf(f, " "); |
1596 } | 1591 } |
1597 fprintf(f, " %s\n", buffer.start()); | 1592 fprintf(f, " %s\n", buffer.start()); |
1598 } | 1593 } |
1599 } | 1594 } |
1600 | 1595 |
1601 } // namespace disasm | 1596 } // namespace disasm |
OLD | NEW |