Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(110)

Side by Side Diff: src/x64/disasm-x64.cc

Issue 316010: Add fucomip instruction to disassembler. (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 11 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ia32/disasm-ia32.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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, &regop, &rm); 587 get_modrm(modrm, &mod, &regop, &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
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, &regop, &rm); 664 get_modrm(modrm, &mod, &regop, &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
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, &regop, &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, &regop, &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, &regop, &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, &regop, &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
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, &regop, &rm); 1050 get_modrm(*current, &mod, &regop, &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, &regop, &rm); 1056 get_modrm(*current, &mod, &regop, &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
1229 int mod, regop, rm; 1233 int mod, regop, rm;
1230 get_modrm(*(data + 1), &mod, &regop, &rm); 1234 get_modrm(*(data + 1), &mod, &regop, &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, &regop, &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
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, &regop, &rm); 1354 get_modrm(*data, &mod, &regop, &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
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
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
OLDNEW
« no previous file with comments | « src/ia32/disasm-ia32.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698