| 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 |