OLD | NEW |
1 // Copyright 2007-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2007-2008 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 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
197 SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop. | 197 SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop. |
198 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov"); | 198 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov"); |
199 } | 199 } |
200 | 200 |
201 | 201 |
202 void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) { | 202 void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) { |
203 for (int i = 0; bm[i].b >= 0; i++) { | 203 for (int i = 0; bm[i].b >= 0; i++) { |
204 InstructionDesc* id = &instructions_[bm[i].b]; | 204 InstructionDesc* id = &instructions_[bm[i].b]; |
205 id->mnem = bm[i].mnem; | 205 id->mnem = bm[i].mnem; |
206 id->op_order_ = bm[i].op_order_; | 206 id->op_order_ = bm[i].op_order_; |
207 assert(id->type == NO_INSTR); // Information already entered | 207 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered. |
208 id->type = type; | 208 id->type = type; |
209 } | 209 } |
210 } | 210 } |
211 | 211 |
212 | 212 |
213 void InstructionTable::SetTableRange(InstructionType type, | 213 void InstructionTable::SetTableRange(InstructionType type, |
214 byte start, | 214 byte start, |
215 byte end, | 215 byte end, |
216 const char* mnem) { | 216 const char* mnem) { |
217 for (byte b = start; b <= end; b++) { | 217 for (byte b = start; b <= end; b++) { |
218 InstructionDesc* id = &instructions_[b]; | 218 InstructionDesc* id = &instructions_[b]; |
219 assert(id->type == NO_INSTR); // Information already entered | 219 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered. |
220 id->mnem = mnem; | 220 id->mnem = mnem; |
221 id->type = type; | 221 id->type = type; |
222 } | 222 } |
223 } | 223 } |
224 | 224 |
225 | 225 |
226 void InstructionTable::AddJumpConditionalShort() { | 226 void InstructionTable::AddJumpConditionalShort() { |
227 for (byte b = 0x70; b <= 0x7F; b++) { | 227 for (byte b = 0x70; b <= 0x7F; b++) { |
228 InstructionDesc* id = &instructions_[b]; | 228 InstructionDesc* id = &instructions_[b]; |
229 assert(id->type == NO_INSTR); // Information already entered | 229 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered. |
230 id->mnem = jump_conditional_mnem[b & 0x0F]; | 230 id->mnem = jump_conditional_mnem[b & 0x0F]; |
231 id->type = JUMP_CONDITIONAL_SHORT_INSTR; | 231 id->type = JUMP_CONDITIONAL_SHORT_INSTR; |
232 } | 232 } |
233 } | 233 } |
234 | 234 |
235 | 235 |
236 static InstructionTable instruction_table; | 236 static InstructionTable instruction_table; |
237 | 237 |
238 | 238 |
239 // The IA32 disassembler implementation. | 239 // The IA32 disassembler implementation. |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
314 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data); | 314 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data); |
315 int PrintImmediateOp(byte* data); | 315 int PrintImmediateOp(byte* data); |
316 int F7Instruction(byte* data); | 316 int F7Instruction(byte* data); |
317 int D1D3C1Instruction(byte* data); | 317 int D1D3C1Instruction(byte* data); |
318 int JumpShort(byte* data); | 318 int JumpShort(byte* data); |
319 int JumpConditional(byte* data, const char* comment); | 319 int JumpConditional(byte* data, const char* comment); |
320 int JumpConditionalShort(byte* data, const char* comment); | 320 int JumpConditionalShort(byte* data, const char* comment); |
321 int SetCC(byte* data); | 321 int SetCC(byte* data); |
322 int CMov(byte* data); | 322 int CMov(byte* data); |
323 int FPUInstruction(byte* data); | 323 int FPUInstruction(byte* data); |
| 324 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start); |
| 325 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte); |
324 void AppendToBuffer(const char* format, ...); | 326 void AppendToBuffer(const char* format, ...); |
325 | 327 |
326 | 328 |
327 void UnimplementedInstruction() { | 329 void UnimplementedInstruction() { |
328 if (abort_on_unimplemented_) { | 330 if (abort_on_unimplemented_) { |
329 UNIMPLEMENTED(); | 331 UNIMPLEMENTED(); |
330 } else { | 332 } else { |
331 AppendToBuffer("'Unimplemented Instruction'"); | 333 AppendToBuffer("'Unimplemented Instruction'"); |
332 } | 334 } |
333 } | 335 } |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
486 return 1 + count + 1 /*int8*/; | 488 return 1 + count + 1 /*int8*/; |
487 } else { | 489 } else { |
488 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count)); | 490 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count)); |
489 return 1 + count + 4 /*int32_t*/; | 491 return 1 + count + 4 /*int32_t*/; |
490 } | 492 } |
491 } | 493 } |
492 | 494 |
493 | 495 |
494 // Returns number of bytes used, including *data. | 496 // Returns number of bytes used, including *data. |
495 int DisassemblerIA32::F7Instruction(byte* data) { | 497 int DisassemblerIA32::F7Instruction(byte* data) { |
496 assert(*data == 0xF7); | 498 ASSERT_EQ(0xF7, *data); |
497 byte modrm = *(data+1); | 499 byte modrm = *(data+1); |
498 int mod, regop, rm; | 500 int mod, regop, rm; |
499 get_modrm(modrm, &mod, ®op, &rm); | 501 get_modrm(modrm, &mod, ®op, &rm); |
500 if (mod == 3 && regop != 0) { | 502 if (mod == 3 && regop != 0) { |
501 const char* mnem = NULL; | 503 const char* mnem = NULL; |
502 switch (regop) { | 504 switch (regop) { |
503 case 2: mnem = "not"; break; | 505 case 2: mnem = "not"; break; |
504 case 3: mnem = "neg"; break; | 506 case 3: mnem = "neg"; break; |
505 case 4: mnem = "mul"; break; | 507 case 4: mnem = "mul"; break; |
506 case 7: mnem = "idiv"; break; | 508 case 7: mnem = "idiv"; break; |
(...skipping 12 matching lines...) Expand all Loading... |
519 AppendToBuffer(",0x%x", imm); | 521 AppendToBuffer(",0x%x", imm); |
520 return 1+count+4 /*int32_t*/; | 522 return 1+count+4 /*int32_t*/; |
521 } else { | 523 } else { |
522 UnimplementedInstruction(); | 524 UnimplementedInstruction(); |
523 return 2; | 525 return 2; |
524 } | 526 } |
525 } | 527 } |
526 | 528 |
527 int DisassemblerIA32::D1D3C1Instruction(byte* data) { | 529 int DisassemblerIA32::D1D3C1Instruction(byte* data) { |
528 byte op = *data; | 530 byte op = *data; |
529 assert(op == 0xD1 || op == 0xD3 || op == 0xC1); | 531 ASSERT(op == 0xD1 || op == 0xD3 || op == 0xC1); |
530 byte modrm = *(data+1); | 532 byte modrm = *(data+1); |
531 int mod, regop, rm; | 533 int mod, regop, rm; |
532 get_modrm(modrm, &mod, ®op, &rm); | 534 get_modrm(modrm, &mod, ®op, &rm); |
533 int imm8 = -1; | 535 int imm8 = -1; |
534 int num_bytes = 2; | 536 int num_bytes = 2; |
535 if (mod == 3) { | 537 if (mod == 3) { |
536 const char* mnem = NULL; | 538 const char* mnem = NULL; |
537 if (op == 0xD1) { | 539 if (op == 0xD1) { |
538 imm8 = 1; | 540 imm8 = 1; |
539 switch (regop) { | 541 switch (regop) { |
(...skipping 13 matching lines...) Expand all Loading... |
553 default: UnimplementedInstruction(); | 555 default: UnimplementedInstruction(); |
554 } | 556 } |
555 } else if (op == 0xD3) { | 557 } else if (op == 0xD3) { |
556 switch (regop) { | 558 switch (regop) { |
557 case esp: mnem = "shl"; break; | 559 case esp: mnem = "shl"; break; |
558 case ebp: mnem = "shr"; break; | 560 case ebp: mnem = "shr"; break; |
559 case edi: mnem = "sar"; break; | 561 case edi: mnem = "sar"; break; |
560 default: UnimplementedInstruction(); | 562 default: UnimplementedInstruction(); |
561 } | 563 } |
562 } | 564 } |
563 assert(mnem != NULL); | 565 ASSERT_NE(NULL, mnem); |
564 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(rm)); | 566 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(rm)); |
565 if (imm8 > 0) { | 567 if (imm8 > 0) { |
566 AppendToBuffer("%d", imm8); | 568 AppendToBuffer("%d", imm8); |
567 } else { | 569 } else { |
568 AppendToBuffer("cl"); | 570 AppendToBuffer("cl"); |
569 } | 571 } |
570 } else { | 572 } else { |
571 UnimplementedInstruction(); | 573 UnimplementedInstruction(); |
572 } | 574 } |
573 return num_bytes; | 575 return num_bytes; |
574 } | 576 } |
575 | 577 |
576 | 578 |
577 // Returns number of bytes used, including *data. | 579 // Returns number of bytes used, including *data. |
578 int DisassemblerIA32::JumpShort(byte* data) { | 580 int DisassemblerIA32::JumpShort(byte* data) { |
579 assert(*data == 0xEB); | 581 ASSERT_EQ(0xEB, *data); |
580 byte b = *(data+1); | 582 byte b = *(data+1); |
581 byte* dest = data + static_cast<int8_t>(b) + 2; | 583 byte* dest = data + static_cast<int8_t>(b) + 2; |
582 AppendToBuffer("jmp %s", NameOfAddress(dest)); | 584 AppendToBuffer("jmp %s", NameOfAddress(dest)); |
583 return 2; | 585 return 2; |
584 } | 586 } |
585 | 587 |
586 | 588 |
587 // Returns number of bytes used, including *data. | 589 // Returns number of bytes used, including *data. |
588 int DisassemblerIA32::JumpConditional(byte* data, const char* comment) { | 590 int DisassemblerIA32::JumpConditional(byte* data, const char* comment) { |
589 assert(*data == 0x0F); | 591 ASSERT_EQ(0x0F, *data); |
590 byte cond = *(data+1) & 0x0F; | 592 byte cond = *(data+1) & 0x0F; |
591 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6; | 593 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6; |
592 const char* mnem = jump_conditional_mnem[cond]; | 594 const char* mnem = jump_conditional_mnem[cond]; |
593 AppendToBuffer("%s %s", mnem, NameOfAddress(dest)); | 595 AppendToBuffer("%s %s", mnem, NameOfAddress(dest)); |
594 if (comment != NULL) { | 596 if (comment != NULL) { |
595 AppendToBuffer(", %s", comment); | 597 AppendToBuffer(", %s", comment); |
596 } | 598 } |
597 return 6; // includes 0x0F | 599 return 6; // includes 0x0F |
598 } | 600 } |
599 | 601 |
600 | 602 |
601 // Returns number of bytes used, including *data. | 603 // Returns number of bytes used, including *data. |
602 int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) { | 604 int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) { |
603 byte cond = *data & 0x0F; | 605 byte cond = *data & 0x0F; |
604 byte b = *(data+1); | 606 byte b = *(data+1); |
605 byte* dest = data + static_cast<int8_t>(b) + 2; | 607 byte* dest = data + static_cast<int8_t>(b) + 2; |
606 const char* mnem = jump_conditional_mnem[cond]; | 608 const char* mnem = jump_conditional_mnem[cond]; |
607 AppendToBuffer("%s %s", mnem, NameOfAddress(dest)); | 609 AppendToBuffer("%s %s", mnem, NameOfAddress(dest)); |
608 if (comment != NULL) { | 610 if (comment != NULL) { |
609 AppendToBuffer(", %s", comment); | 611 AppendToBuffer(", %s", comment); |
610 } | 612 } |
611 return 2; | 613 return 2; |
612 } | 614 } |
613 | 615 |
614 | 616 |
615 // Returns number of bytes used, including *data. | 617 // Returns number of bytes used, including *data. |
616 int DisassemblerIA32::SetCC(byte* data) { | 618 int DisassemblerIA32::SetCC(byte* data) { |
617 assert(*data == 0x0F); | 619 ASSERT_EQ(0x0F, *data); |
618 byte cond = *(data+1) & 0x0F; | 620 byte cond = *(data+1) & 0x0F; |
619 const char* mnem = set_conditional_mnem[cond]; | 621 const char* mnem = set_conditional_mnem[cond]; |
620 AppendToBuffer("%s ", mnem); | 622 AppendToBuffer("%s ", mnem); |
621 PrintRightByteOperand(data+2); | 623 PrintRightByteOperand(data+2); |
622 return 3; // includes 0x0F | 624 return 3; // Includes 0x0F. |
623 } | 625 } |
624 | 626 |
625 | 627 |
626 // Returns number of bytes used, including *data. | 628 // Returns number of bytes used, including *data. |
627 int DisassemblerIA32::CMov(byte* data) { | 629 int DisassemblerIA32::CMov(byte* data) { |
628 assert(*data == 0x0F); | 630 ASSERT_EQ(0x0F, *data); |
629 byte cond = *(data + 1) & 0x0F; | 631 byte cond = *(data + 1) & 0x0F; |
630 const char* mnem = conditional_move_mnem[cond]; | 632 const char* mnem = conditional_move_mnem[cond]; |
631 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2); | 633 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2); |
632 return 2 + op_size; // includes 0x0F | 634 return 2 + op_size; // includes 0x0F |
633 } | 635 } |
634 | 636 |
635 | 637 |
636 // Returns number of bytes used, including *data. | 638 // Returns number of bytes used, including *data. |
637 int DisassemblerIA32::FPUInstruction(byte* data) { | 639 int DisassemblerIA32::FPUInstruction(byte* data) { |
638 byte b1 = *data; | 640 byte escape_opcode = *data; |
639 byte b2 = *(data + 1); | 641 ASSERT_EQ(0xD8, escape_opcode & 0xF8); |
640 if (b1 == 0xD9) { | 642 byte modrm_byte = *(data+1); |
641 const char* mnem = NULL; | 643 |
642 switch (b2) { | 644 if (modrm_byte >= 0xC0) { |
643 case 0xE8: mnem = "fld1"; break; | 645 return RegisterFPUInstruction(escape_opcode, modrm_byte); |
644 case 0xEE: mnem = "fldz"; break; | 646 } else { |
645 case 0xE1: mnem = "fabs"; break; | 647 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1); |
646 case 0xE0: mnem = "fchs"; break; | 648 } |
647 case 0xF8: mnem = "fprem"; break; | 649 } |
648 case 0xF5: mnem = "fprem1"; break; | 650 |
649 case 0xF7: mnem = "fincstp"; break; | 651 int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode, |
650 case 0xE4: mnem = "ftst"; break; | 652 int modrm_byte, |
651 } | 653 byte* modrm_start) { |
652 if (mnem != NULL) { | 654 const char* mnem = "?"; |
653 AppendToBuffer("%s", mnem); | 655 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte. |
654 return 2; | 656 switch (escape_opcode) { |
655 } else if ((b2 & 0xF8) == 0xC8) { | 657 case 0xD9: switch (regop) { |
656 AppendToBuffer("fxch st%d", b2 & 0x7); | 658 case 0: mnem = "fld_s"; break; |
657 return 2; | 659 case 3: mnem = "fstp_s"; break; |
658 } else { | 660 case 7: mnem = "fstcw"; break; |
659 int mod, regop, rm; | |
660 get_modrm(*(data+1), &mod, ®op, &rm); | |
661 const char* mnem = "?"; | |
662 switch (regop) { | |
663 case eax: mnem = "fld_s"; break; | |
664 case ebx: mnem = "fstp_s"; break; | |
665 default: UnimplementedInstruction(); | 661 default: UnimplementedInstruction(); |
666 } | 662 } |
667 AppendToBuffer("%s ", mnem); | 663 break; |
668 int count = PrintRightOperand(data + 1); | 664 |
669 return count + 1; | 665 case 0xDB: switch (regop) { |
670 } | 666 case 0: mnem = "fild_s"; break; |
671 } else if (b1 == 0xDD) { | 667 case 1: mnem = "fisttp_s"; break; |
672 if ((b2 & 0xF8) == 0xC0) { | 668 case 2: mnem = "fist_s"; break; |
673 AppendToBuffer("ffree st%d", b2 & 0x7); | 669 case 3: mnem = "fistp_s"; break; |
674 return 2; | |
675 } else { | |
676 int mod, regop, rm; | |
677 get_modrm(*(data+1), &mod, ®op, &rm); | |
678 const char* mnem = "?"; | |
679 switch (regop) { | |
680 case eax: mnem = "fld_d"; break; | |
681 case ebx: mnem = "fstp_d"; break; | |
682 default: UnimplementedInstruction(); | 670 default: UnimplementedInstruction(); |
683 } | 671 } |
684 AppendToBuffer("%s ", mnem); | 672 break; |
685 int count = PrintRightOperand(data + 1); | 673 |
686 return count + 1; | 674 case 0xDD: switch (regop) { |
687 } | 675 case 0: mnem = "fld_d"; break; |
688 } else if (b1 == 0xDB) { | 676 case 3: mnem = "fstp_d"; break; |
689 int mod, regop, rm; | 677 default: UnimplementedInstruction(); |
690 get_modrm(*(data+1), &mod, ®op, &rm); | 678 } |
691 const char* mnem = "?"; | 679 break; |
692 switch (regop) { | 680 |
693 case eax: mnem = "fild_s"; break; | 681 case 0xDF: switch (regop) { |
694 case edx: mnem = "fist_s"; break; | 682 case 5: mnem = "fild_d"; break; |
695 case ebx: mnem = "fistp_s"; break; | 683 case 7: mnem = "fistp_d"; break; |
696 default: UnimplementedInstruction(); | 684 default: UnimplementedInstruction(); |
697 } | 685 } |
698 AppendToBuffer("%s ", mnem); | 686 break; |
699 int count = PrintRightOperand(data + 1); | 687 |
700 return count + 1; | 688 default: UnimplementedInstruction(); |
701 } else if (b1 == 0xDF) { | 689 } |
702 if (b2 == 0xE0) { | 690 AppendToBuffer("%s ", mnem); |
703 AppendToBuffer("fnstsw_ax"); | 691 int count = PrintRightOperand(modrm_start); |
704 return 2; | 692 return count + 1; |
705 } | 693 } |
706 int mod, regop, rm; | 694 |
707 get_modrm(*(data+1), &mod, ®op, &rm); | 695 int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode, |
708 const char* mnem = "?"; | 696 byte modrm_byte) { |
709 switch (regop) { | 697 bool has_register = false; // Is the FPU register encoded in modrm_byte? |
710 case ebp: mnem = "fild_d"; break; | 698 const char* mnem = "?"; |
711 case edi: mnem = "fistp_d"; break; | 699 |
712 default: UnimplementedInstruction(); | 700 switch (escape_opcode) { |
713 } | 701 case 0xD8: |
714 AppendToBuffer("%s ", mnem); | 702 UnimplementedInstruction(); |
715 int count = PrintRightOperand(data + 1); | 703 break; |
716 return count + 1; | 704 |
717 } else if (b1 == 0xDC || b1 == 0xDE) { | 705 case 0xD9: |
718 bool is_pop = (b1 == 0xDE); | 706 switch (modrm_byte & 0xF8) { |
719 if (is_pop && b2 == 0xD9) { | 707 case 0xC8: |
720 AppendToBuffer("fcompp"); | 708 mnem = "fxch"; |
721 return 2; | 709 has_register = true; |
722 } | 710 break; |
723 const char* mnem = "FP0xDC"; | 711 default: |
724 switch (b2 & 0xF8) { | 712 switch (modrm_byte) { |
725 case 0xC0: mnem = "fadd"; break; | 713 case 0xE0: mnem = "fchs"; break; |
726 case 0xE8: mnem = "fsub"; break; | 714 case 0xE1: mnem = "fabs"; break; |
727 case 0xC8: mnem = "fmul"; break; | 715 case 0xE4: mnem = "ftst"; break; |
728 case 0xF8: mnem = "fdiv"; break; | 716 case 0xE8: mnem = "fld1"; break; |
729 default: UnimplementedInstruction(); | 717 case 0xEE: mnem = "fldz"; break; |
730 } | 718 case 0xF5: mnem = "fprem1"; break; |
731 AppendToBuffer("%s%s st%d", mnem, is_pop ? "p" : "", b2 & 0x7); | 719 case 0xF7: mnem = "fincstp"; break; |
732 return 2; | 720 case 0xF8: mnem = "fprem"; break; |
733 } else if (b1 == 0xDA && b2 == 0xE9) { | 721 case 0xFE: mnem = "fsin"; break; |
734 const char* mnem = "fucompp"; | 722 case 0xFF: mnem = "fcos"; break; |
| 723 default: UnimplementedInstruction(); |
| 724 } |
| 725 } |
| 726 break; |
| 727 |
| 728 case 0xDA: |
| 729 if (modrm_byte == 0xE9) { |
| 730 mnem = "fucompp"; |
| 731 } else { |
| 732 UnimplementedInstruction(); |
| 733 } |
| 734 break; |
| 735 |
| 736 case 0xDB: |
| 737 if ((modrm_byte & 0xF8) == 0xE8) { |
| 738 mnem = "fucomi"; |
| 739 has_register = true; |
| 740 } else if (modrm_byte == 0xE2) { |
| 741 mnem = "fclex"; |
| 742 } else { |
| 743 UnimplementedInstruction(); |
| 744 } |
| 745 break; |
| 746 |
| 747 case 0xDC: |
| 748 has_register = true; |
| 749 switch (modrm_byte & 0xF8) { |
| 750 case 0xC0: mnem = "fadd"; break; |
| 751 case 0xE8: mnem = "fsub"; break; |
| 752 case 0xC8: mnem = "fmul"; break; |
| 753 case 0xF8: mnem = "fdiv"; break; |
| 754 default: UnimplementedInstruction(); |
| 755 } |
| 756 break; |
| 757 |
| 758 case 0xDD: |
| 759 has_register = true; |
| 760 switch (modrm_byte & 0xF8) { |
| 761 case 0xC0: mnem = "ffree"; break; |
| 762 case 0xD8: mnem = "fstp"; break; |
| 763 default: UnimplementedInstruction(); |
| 764 } |
| 765 break; |
| 766 |
| 767 case 0xDE: |
| 768 if (modrm_byte == 0xD9) { |
| 769 mnem = "fcompp"; |
| 770 } else { |
| 771 has_register = true; |
| 772 switch (modrm_byte & 0xF8) { |
| 773 case 0xC0: mnem = "faddp"; break; |
| 774 case 0xE8: mnem = "fsubp"; break; |
| 775 case 0xC8: mnem = "fmulp"; break; |
| 776 case 0xF8: mnem = "fdivp"; break; |
| 777 default: UnimplementedInstruction(); |
| 778 } |
| 779 } |
| 780 break; |
| 781 |
| 782 case 0xDF: |
| 783 if (modrm_byte == 0xE0) { |
| 784 mnem = "fnstsw_ax"; |
| 785 } else if ((modrm_byte & 0xF8) == 0xE8) { |
| 786 mnem = "fucomip"; |
| 787 has_register = true; |
| 788 } |
| 789 break; |
| 790 |
| 791 default: UnimplementedInstruction(); |
| 792 } |
| 793 |
| 794 if (has_register) { |
| 795 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7); |
| 796 } else { |
735 AppendToBuffer("%s", mnem); | 797 AppendToBuffer("%s", mnem); |
736 return 2; | |
737 } | 798 } |
738 AppendToBuffer("Unknown FP instruction"); | |
739 return 2; | 799 return 2; |
740 } | 800 } |
741 | 801 |
742 | 802 |
743 // Mnemonics for instructions 0xF0 byte. | 803 // Mnemonics for instructions 0xF0 byte. |
744 // Returns NULL if the instruction is not handled here. | 804 // Returns NULL if the instruction is not handled here. |
745 static const char* F0Mnem(byte f0byte) { | 805 static const char* F0Mnem(byte f0byte) { |
746 switch (f0byte) { | 806 switch (f0byte) { |
747 case 0xA2: return "cpuid"; | 807 case 0xA2: return "cpuid"; |
748 case 0x31: return "rdtsc"; | 808 case 0x31: return "rdtsc"; |
(...skipping 478 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1227 } | 1287 } |
1228 for (int i = 6 - (pc - prev_pc); i >= 0; i--) { | 1288 for (int i = 6 - (pc - prev_pc); i >= 0; i--) { |
1229 fprintf(f, " "); | 1289 fprintf(f, " "); |
1230 } | 1290 } |
1231 fprintf(f, " %s\n", buffer.start()); | 1291 fprintf(f, " %s\n", buffer.start()); |
1232 } | 1292 } |
1233 } | 1293 } |
1234 | 1294 |
1235 | 1295 |
1236 } // namespace disasm | 1296 } // namespace disasm |
OLD | NEW |