diff --git a/src/ia32/disasm-ia32.cc b/src/ia32/disasm-ia32.cc index adedf34899..3e3ca73e6b 100644 --- a/src/ia32/disasm-ia32.cc +++ b/src/ia32/disasm-ia32.cc @@ -204,7 +204,7 @@ void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) { InstructionDesc* id = &instructions_[bm[i].b]; id->mnem = bm[i].mnem; id->op_order_ = bm[i].op_order_; - assert(id->type == NO_INSTR); // Information already entered + ASSERT_EQ(NO_INSTR, id->type); // Information not already entered. id->type = type; } } @@ -216,7 +216,7 @@ void InstructionTable::SetTableRange(InstructionType type, const char* mnem) { for (byte b = start; b <= end; b++) { InstructionDesc* id = &instructions_[b]; - assert(id->type == NO_INSTR); // Information already entered + ASSERT_EQ(NO_INSTR, id->type); // Information not already entered. id->mnem = mnem; id->type = type; } @@ -226,7 +226,7 @@ void InstructionTable::SetTableRange(InstructionType type, void InstructionTable::AddJumpConditionalShort() { for (byte b = 0x70; b <= 0x7F; b++) { InstructionDesc* id = &instructions_[b]; - assert(id->type == NO_INSTR); // Information already entered + ASSERT_EQ(NO_INSTR, id->type); // Information not already entered. id->mnem = jump_conditional_mnem[b & 0x0F]; id->type = JUMP_CONDITIONAL_SHORT_INSTR; } @@ -321,6 +321,8 @@ class DisassemblerIA32 { int SetCC(byte* data); int CMov(byte* data); int FPUInstruction(byte* data); + int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start); + int RegisterFPUInstruction(int escape_opcode, byte modrm_byte); void AppendToBuffer(const char* format, ...); @@ -493,7 +495,7 @@ int DisassemblerIA32::PrintImmediateOp(byte* data) { // Returns number of bytes used, including *data. int DisassemblerIA32::F7Instruction(byte* data) { - assert(*data == 0xF7); + ASSERT_EQ(0xF7, *data); byte modrm = *(data+1); int mod, regop, rm; get_modrm(modrm, &mod, ®op, &rm); @@ -526,7 +528,7 @@ int DisassemblerIA32::F7Instruction(byte* data) { int DisassemblerIA32::D1D3C1Instruction(byte* data) { byte op = *data; - assert(op == 0xD1 || op == 0xD3 || op == 0xC1); + ASSERT(op == 0xD1 || op == 0xD3 || op == 0xC1); byte modrm = *(data+1); int mod, regop, rm; get_modrm(modrm, &mod, ®op, &rm); @@ -560,7 +562,7 @@ int DisassemblerIA32::D1D3C1Instruction(byte* data) { default: UnimplementedInstruction(); } } - assert(mnem != NULL); + ASSERT_NE(NULL, mnem); AppendToBuffer("%s %s,", mnem, NameOfCPURegister(rm)); if (imm8 > 0) { AppendToBuffer("%d", imm8); @@ -576,7 +578,7 @@ int DisassemblerIA32::D1D3C1Instruction(byte* data) { // Returns number of bytes used, including *data. int DisassemblerIA32::JumpShort(byte* data) { - assert(*data == 0xEB); + ASSERT_EQ(0xEB, *data); byte b = *(data+1); byte* dest = data + static_cast(b) + 2; AppendToBuffer("jmp %s", NameOfAddress(dest)); @@ -586,7 +588,7 @@ int DisassemblerIA32::JumpShort(byte* data) { // Returns number of bytes used, including *data. int DisassemblerIA32::JumpConditional(byte* data, const char* comment) { - assert(*data == 0x0F); + ASSERT_EQ(0x0F, *data); byte cond = *(data+1) & 0x0F; byte* dest = data + *reinterpret_cast(data+2) + 6; const char* mnem = jump_conditional_mnem[cond]; @@ -614,18 +616,18 @@ int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) { // Returns number of bytes used, including *data. int DisassemblerIA32::SetCC(byte* data) { - assert(*data == 0x0F); + ASSERT_EQ(0x0F, *data); byte cond = *(data+1) & 0x0F; const char* mnem = set_conditional_mnem[cond]; AppendToBuffer("%s ", mnem); PrintRightByteOperand(data+2); - return 3; // includes 0x0F + return 3; // Includes 0x0F. } // Returns number of bytes used, including *data. int DisassemblerIA32::CMov(byte* data) { - assert(*data == 0x0F); + ASSERT_EQ(0x0F, *data); byte cond = *(data + 1) & 0x0F; const char* mnem = conditional_move_mnem[cond]; int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2); @@ -635,107 +637,165 @@ int DisassemblerIA32::CMov(byte* data) { // Returns number of bytes used, including *data. int DisassemblerIA32::FPUInstruction(byte* data) { - byte b1 = *data; - byte b2 = *(data + 1); - if (b1 == 0xD9) { - const char* mnem = NULL; - switch (b2) { - case 0xE8: mnem = "fld1"; break; - case 0xEE: mnem = "fldz"; break; - case 0xE1: mnem = "fabs"; break; - case 0xE0: mnem = "fchs"; break; - case 0xF8: mnem = "fprem"; break; - case 0xF5: mnem = "fprem1"; break; - case 0xF7: mnem = "fincstp"; break; - case 0xE4: mnem = "ftst"; break; - } - if (mnem != NULL) { - AppendToBuffer("%s", mnem); - return 2; - } else if ((b2 & 0xF8) == 0xC8) { - AppendToBuffer("fxch st%d", b2 & 0x7); - return 2; - } else { - int mod, regop, rm; - get_modrm(*(data+1), &mod, ®op, &rm); - const char* mnem = "?"; - switch (regop) { - case eax: mnem = "fld_s"; break; - case ebx: mnem = "fstp_s"; break; - default: UnimplementedInstruction(); - } - AppendToBuffer("%s ", mnem); - int count = PrintRightOperand(data + 1); - return count + 1; - } - } else if (b1 == 0xDD) { - if ((b2 & 0xF8) == 0xC0) { - AppendToBuffer("ffree st%d", b2 & 0x7); - return 2; - } else { - int mod, regop, rm; - get_modrm(*(data+1), &mod, ®op, &rm); - const char* mnem = "?"; - switch (regop) { - case eax: mnem = "fld_d"; break; - case ebx: mnem = "fstp_d"; break; - default: UnimplementedInstruction(); - } - AppendToBuffer("%s ", mnem); - int count = PrintRightOperand(data + 1); - return count + 1; - } - } else if (b1 == 0xDB) { - int mod, regop, rm; - get_modrm(*(data+1), &mod, ®op, &rm); - const char* mnem = "?"; - switch (regop) { - case eax: mnem = "fild_s"; break; - case edx: mnem = "fist_s"; break; - case ebx: mnem = "fistp_s"; break; - default: UnimplementedInstruction(); - } - AppendToBuffer("%s ", mnem); - int count = PrintRightOperand(data + 1); - return count + 1; - } else if (b1 == 0xDF) { - if (b2 == 0xE0) { - AppendToBuffer("fnstsw_ax"); - return 2; - } - int mod, regop, rm; - get_modrm(*(data+1), &mod, ®op, &rm); - const char* mnem = "?"; - switch (regop) { - case ebp: mnem = "fild_d"; break; - case edi: mnem = "fistp_d"; break; - default: UnimplementedInstruction(); - } - AppendToBuffer("%s ", mnem); - int count = PrintRightOperand(data + 1); - return count + 1; - } else if (b1 == 0xDC || b1 == 0xDE) { - bool is_pop = (b1 == 0xDE); - if (is_pop && b2 == 0xD9) { - AppendToBuffer("fcompp"); - return 2; - } - const char* mnem = "FP0xDC"; - switch (b2 & 0xF8) { - case 0xC0: mnem = "fadd"; break; - case 0xE8: mnem = "fsub"; break; - case 0xC8: mnem = "fmul"; break; - case 0xF8: mnem = "fdiv"; break; - default: UnimplementedInstruction(); - } - AppendToBuffer("%s%s st%d", mnem, is_pop ? "p" : "", b2 & 0x7); - return 2; - } else if (b1 == 0xDA && b2 == 0xE9) { - const char* mnem = "fucompp"; - AppendToBuffer("%s", mnem); - return 2; + byte escape_opcode = *data; + ASSERT_EQ(0xD8, escape_opcode & 0xF8); + byte modrm_byte = *(data+1); + + if (modrm_byte >= 0xC0) { + return RegisterFPUInstruction(escape_opcode, modrm_byte); + } else { + return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1); + } +} + +int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode, + int modrm_byte, + byte* modrm_start) { + const char* mnem = "?"; + int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte. + switch (escape_opcode) { + case 0xD9: switch (regop) { + case 0: mnem = "fld_s"; break; + case 3: mnem = "fstp_s"; break; + case 7: mnem = "fstcw"; break; + default: UnimplementedInstruction(); + } + break; + + case 0xDB: switch (regop) { + case 0: mnem = "fild_s"; break; + case 1: mnem = "fisttp_s"; break; + case 2: mnem = "fist_s"; break; + case 3: mnem = "fistp_s"; break; + default: UnimplementedInstruction(); + } + break; + + case 0xDD: switch (regop) { + case 0: mnem = "fld_d"; break; + case 3: mnem = "fstp_d"; break; + default: UnimplementedInstruction(); + } + break; + + case 0xDF: switch (regop) { + case 5: mnem = "fild_d"; break; + case 7: mnem = "fistp_d"; break; + default: UnimplementedInstruction(); + } + break; + + default: UnimplementedInstruction(); + } + AppendToBuffer("%s ", mnem); + int count = PrintRightOperand(modrm_start); + return count + 1; +} + +int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode, + byte modrm_byte) { + bool has_register = false; // Is the FPU register encoded in modrm_byte? + const char* mnem = "?"; + + switch (escape_opcode) { + case 0xD8: + UnimplementedInstruction(); + break; + + case 0xD9: + switch (modrm_byte & 0xF8) { + case 0xC8: + mnem = "fxch"; + has_register = true; + break; + default: + switch (modrm_byte) { + case 0xE0: mnem = "fchs"; break; + case 0xE1: mnem = "fabs"; break; + case 0xE4: mnem = "ftst"; break; + case 0xE8: mnem = "fld1"; break; + case 0xEE: mnem = "fldz"; break; + case 0xF5: mnem = "fprem1"; break; + case 0xF7: mnem = "fincstp"; break; + case 0xF8: mnem = "fprem"; break; + case 0xFE: mnem = "fsin"; break; + case 0xFF: mnem = "fcos"; break; + default: UnimplementedInstruction(); + } + } + break; + + case 0xDA: + if (modrm_byte == 0xE9) { + mnem = "fucompp"; + } else { + UnimplementedInstruction(); + } + break; + + case 0xDB: + if ((modrm_byte & 0xF8) == 0xE8) { + mnem = "fucomi"; + has_register = true; + } else if (modrm_byte == 0xE2) { + mnem = "fclex"; + } else { + UnimplementedInstruction(); + } + break; + + case 0xDC: + has_register = true; + switch (modrm_byte & 0xF8) { + case 0xC0: mnem = "fadd"; break; + case 0xE8: mnem = "fsub"; break; + case 0xC8: mnem = "fmul"; break; + case 0xF8: mnem = "fdiv"; break; + default: UnimplementedInstruction(); + } + break; + + case 0xDD: + has_register = true; + switch (modrm_byte & 0xF8) { + case 0xC0: mnem = "ffree"; break; + case 0xD8: mnem = "fstp"; break; + default: UnimplementedInstruction(); + } + break; + + case 0xDE: + if (modrm_byte == 0xD9) { + mnem = "fcompp"; + } else { + has_register = true; + switch (modrm_byte & 0xF8) { + case 0xC0: mnem = "faddp"; break; + case 0xE8: mnem = "fsubp"; break; + case 0xC8: mnem = "fmulp"; break; + case 0xF8: mnem = "fdivp"; break; + default: UnimplementedInstruction(); + } + } + break; + + case 0xDF: + if (modrm_byte == 0xE0) { + mnem = "fnstsw_ax"; + } else if ((modrm_byte & 0xF8) == 0xE8) { + mnem = "fucomip"; + has_register = true; + } + break; + + default: UnimplementedInstruction(); + } + + if (has_register) { + AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7); + } else { + AppendToBuffer("%s", mnem); } - AppendToBuffer("Unknown FP instruction"); return 2; } diff --git a/src/x64/disasm-x64.cc b/src/x64/disasm-x64.cc index 19bcf66382..9fd581df39 100644 --- a/src/x64/disasm-x64.cc +++ b/src/x64/disasm-x64.cc @@ -218,7 +218,7 @@ void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) { OperandType op_order = bm[i].op_order_; id->op_order_ = static_cast(op_order & ~BYTE_SIZE_OPERAND_FLAG); - assert(id->type == NO_INSTR); // Information not already entered + ASSERT_EQ(NO_INSTR, id->type); // Information not already entered id->type = type; id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0); } @@ -232,7 +232,7 @@ void InstructionTable::SetTableRange(InstructionType type, const char* mnem) { for (byte b = start; b <= end; b++) { InstructionDesc* id = &instructions_[b]; - assert(id->type == NO_INSTR); // Information already entered + ASSERT_EQ(NO_INSTR, id->type); // Information not already entered id->mnem = mnem; id->type = type; id->byte_size_operation = byte_size; @@ -243,7 +243,7 @@ void InstructionTable::SetTableRange(InstructionType type, void InstructionTable::AddJumpConditionalShort() { for (byte b = 0x70; b <= 0x7F; b++) { InstructionDesc* id = &instructions_[b]; - assert(id->type == NO_INSTR); // Information already entered + ASSERT_EQ(NO_INSTR, id->type); // Information not already entered id->mnem = NULL; // Computed depending on condition code. id->type = JUMP_CONDITIONAL_SHORT_INSTR; } @@ -393,6 +393,7 @@ class DisassemblerX64 { RegisterNameMapping register_name); int PrintRightOperand(byte* modrmp); int PrintRightByteOperand(byte* modrmp); + int PrintRightXMMOperand(byte* modrmp); int PrintOperands(const char* mnem, OperandType op_order, byte* data); @@ -400,13 +401,15 @@ class DisassemblerX64 { int PrintImmediateOp(byte* data); const char* TwoByteMnemonic(byte opcode); int TwoByteOpcodeInstruction(byte* data); - int F7Instruction(byte* data); + int F6F7Instruction(byte* data); int ShiftInstruction(byte* data); int JumpShort(byte* data); int JumpConditional(byte* data); int JumpConditionalShort(byte* data); int SetCC(byte* data); int FPUInstruction(byte* data); + int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start); + int RegisterFPUInstruction(int escape_opcode, byte modrm_byte); void AppendToBuffer(const char* format, ...); void UnimplementedInstruction() { @@ -568,6 +571,12 @@ int DisassemblerX64::PrintRightByteOperand(byte* modrmp) { } +int DisassemblerX64::PrintRightXMMOperand(byte* modrmp) { + return PrintRightOperandHelper(modrmp, + &DisassemblerX64::NameOfXMMRegister); +} + + // Returns number of bytes used including the current *data. // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'. int DisassemblerX64::PrintOperands(const char* mnem, @@ -648,8 +657,8 @@ int DisassemblerX64::PrintImmediateOp(byte* data) { // Returns number of bytes used, including *data. -int DisassemblerX64::F7Instruction(byte* data) { - assert(*data == 0xF7); +int DisassemblerX64::F6F7Instruction(byte* data) { + ASSERT(*data == 0xF7 || *data == 0xF6); byte modrm = *(data + 1); int mod, regop, rm; get_modrm(modrm, &mod, ®op, &rm); @@ -676,19 +685,12 @@ int DisassemblerX64::F7Instruction(byte* data) { operand_size_code(), NameOfCPURegister(rm)); return 2; - } else if (mod == 3 && regop == 0) { - int32_t imm = *reinterpret_cast(data + 2); - AppendToBuffer("test%c %s,0x%x", - operand_size_code(), - NameOfCPURegister(rm), - imm); - return 6; } else if (regop == 0) { AppendToBuffer("test%c ", operand_size_code()); - int count = PrintRightOperand(data + 1); - int32_t imm = *reinterpret_cast(data + 1 + count); - AppendToBuffer(",0x%x", imm); - return 1 + count + 4 /*int32_t*/; + int count = PrintRightOperand(data + 1); // Use name of 64-bit register. + AppendToBuffer(",0x"); + count += PrintImmediate(data + 1 + count, operand_size()); + return 1 + count; } else { UnimplementedInstruction(); return 2; @@ -739,7 +741,7 @@ int DisassemblerX64::ShiftInstruction(byte* data) { UnimplementedInstruction(); return num_bytes; } - assert(mnem != NULL); + ASSERT_NE(NULL, mnem); if (op == 0xD0) { imm8 = 1; } else if (op == 0xC0) { @@ -762,7 +764,7 @@ int DisassemblerX64::ShiftInstruction(byte* data) { // Returns number of bytes used, including *data. int DisassemblerX64::JumpShort(byte* data) { - assert(*data == 0xEB); + ASSERT_EQ(0xEB, *data); byte b = *(data + 1); byte* dest = data + static_cast(b) + 2; AppendToBuffer("jmp %s", NameOfAddress(dest)); @@ -772,7 +774,7 @@ int DisassemblerX64::JumpShort(byte* data) { // Returns number of bytes used, including *data. int DisassemblerX64::JumpConditional(byte* data) { - assert(*data == 0x0F); + ASSERT_EQ(0x0F, *data); byte cond = *(data + 1) & 0x0F; byte* dest = data + *reinterpret_cast(data + 2) + 6; const char* mnem = conditional_code_suffix[cond]; @@ -794,7 +796,7 @@ int DisassemblerX64::JumpConditionalShort(byte* data) { // Returns number of bytes used, including *data. int DisassemblerX64::SetCC(byte* data) { - assert(*data == 0x0F); + ASSERT_EQ(0x0F, *data); byte cond = *(data + 1) & 0x0F; const char* mnem = conditional_code_suffix[cond]; AppendToBuffer("set%s%c ", mnem, operand_size_code()); @@ -805,168 +807,170 @@ int DisassemblerX64::SetCC(byte* data) { // Returns number of bytes used, including *data. int DisassemblerX64::FPUInstruction(byte* data) { - byte b1 = *data; - byte b2 = *(data + 1); - if (b1 == 0xD9) { - const char* mnem = NULL; - switch (b2) { - case 0xE0: - mnem = "fchs"; - break; - case 0xE1: - mnem = "fabs"; - break; - case 0xE4: - mnem = "ftst"; - break; - case 0xF5: - mnem = "fprem1"; - break; - case 0xF7: - mnem = "fincstp"; - break; - case 0xE8: - mnem = "fld1"; - break; - case 0xEE: - mnem = "fldz"; - break; - case 0xF8: - mnem = "fprem"; - break; - } - if (mnem != NULL) { - AppendToBuffer("%s", mnem); - return 2; - } else if ((b2 & 0xF8) == 0xC8) { - AppendToBuffer("fxch st%d", b2 & 0x7); - return 2; - } else { - int mod, regop, rm; - get_modrm(*(data + 1), &mod, ®op, &rm); - const char* mnem = "?"; - switch (regop) { - case 0: - mnem = "fld_s"; - break; - case 3: - mnem = "fstp_s"; - break; - default: - UnimplementedInstruction(); - } - AppendToBuffer("%s ", mnem); - int count = PrintRightOperand(data + 1); - return count + 1; - } - } else if (b1 == 0xDD) { - int mod, regop, rm; - get_modrm(*(data + 1), &mod, ®op, &rm); - if (mod == 3) { - switch (regop) { - case 0: - AppendToBuffer("ffree st%d", rm & 7); - break; - case 2: - AppendToBuffer("fstp st%d", rm & 7); - break; - default: - UnimplementedInstruction(); - break; - } - return 2; - } else { - const char* mnem = "?"; - switch (regop) { - case 0: - mnem = "fld_d"; - break; - case 3: - mnem = "fstp_d"; - break; - default: - UnimplementedInstruction(); - } - AppendToBuffer("%s ", mnem); - int count = PrintRightOperand(data + 1); - return count + 1; - } - } else if (b1 == 0xDB) { - int mod, regop, rm; - get_modrm(*(data + 1), &mod, ®op, &rm); - const char* mnem = "?"; - switch (regop) { - case 0: - mnem = "fild_s"; - break; - case 2: - mnem = "fist_s"; - break; - case 3: - mnem = "fistp_s"; - break; - default: - UnimplementedInstruction(); - } - AppendToBuffer("%s ", mnem); - int count = PrintRightOperand(data + 1); - return count + 1; - } else if (b1 == 0xDF) { - if (b2 == 0xE0) { - AppendToBuffer("fnstsw_ax"); - return 2; - } - int mod, regop, rm; - get_modrm(*(data + 1), &mod, ®op, &rm); - const char* mnem = "?"; - switch (regop) { - case 5: - mnem = "fild_d"; - break; - case 7: - mnem = "fistp_d"; - break; - default: - UnimplementedInstruction(); - } - AppendToBuffer("%s ", mnem); - int count = PrintRightOperand(data + 1); - return count + 1; - } else if (b1 == 0xDC || b1 == 0xDE) { - bool is_pop = (b1 == 0xDE); - if (is_pop && b2 == 0xD9) { - AppendToBuffer("fcompp"); - return 2; - } - const char* mnem = "FP0xDC"; - switch (b2 & 0xF8) { - case 0xC0: - mnem = "fadd"; - break; - case 0xE8: - mnem = "fsub"; - break; - case 0xC8: - mnem = "fmul"; - break; - case 0xF8: - mnem = "fdiv"; - break; - default: - UnimplementedInstruction(); - } - AppendToBuffer("%s%s st%d", mnem, is_pop ? "p" : "", b2 & 0x7); - return 2; - } else if (b1 == 0xDA && b2 == 0xE9) { - const char* mnem = "fucompp"; - AppendToBuffer("%s", mnem); - return 2; + byte escape_opcode = *data; + ASSERT_EQ(0xD8, escape_opcode & 0xF8); + byte modrm_byte = *(data+1); + + if (modrm_byte >= 0xC0) { + return RegisterFPUInstruction(escape_opcode, modrm_byte); + } else { + return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1); + } +} + +int DisassemblerX64::MemoryFPUInstruction(int escape_opcode, + int modrm_byte, + byte* modrm_start) { + const char* mnem = "?"; + int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte. + switch (escape_opcode) { + case 0xD9: switch (regop) { + case 0: mnem = "fld_s"; break; + case 3: mnem = "fstp_s"; break; + case 7: mnem = "fstcw"; break; + default: UnimplementedInstruction(); + } + break; + + case 0xDB: switch (regop) { + case 0: mnem = "fild_s"; break; + case 1: mnem = "fisttp_s"; break; + case 2: mnem = "fist_s"; break; + case 3: mnem = "fistp_s"; break; + default: UnimplementedInstruction(); + } + break; + + case 0xDD: switch (regop) { + case 0: mnem = "fld_d"; break; + case 3: mnem = "fstp_d"; break; + default: UnimplementedInstruction(); + } + break; + + case 0xDF: switch (regop) { + case 5: mnem = "fild_d"; break; + case 7: mnem = "fistp_d"; break; + default: UnimplementedInstruction(); + } + break; + + default: UnimplementedInstruction(); + } + AppendToBuffer("%s ", mnem); + int count = PrintRightOperand(modrm_start); + return count + 1; +} + +int DisassemblerX64::RegisterFPUInstruction(int escape_opcode, + byte modrm_byte) { + bool has_register = false; // Is the FPU register encoded in modrm_byte? + const char* mnem = "?"; + + switch (escape_opcode) { + case 0xD8: + UnimplementedInstruction(); + break; + + case 0xD9: + switch (modrm_byte & 0xF8) { + case 0xC8: + mnem = "fxch"; + has_register = true; + break; + default: + switch (modrm_byte) { + case 0xE0: mnem = "fchs"; break; + case 0xE1: mnem = "fabs"; break; + case 0xE4: mnem = "ftst"; break; + case 0xE8: mnem = "fld1"; break; + case 0xEE: mnem = "fldz"; break; + case 0xF5: mnem = "fprem1"; break; + case 0xF7: mnem = "fincstp"; break; + case 0xF8: mnem = "fprem"; break; + case 0xFE: mnem = "fsin"; break; + case 0xFF: mnem = "fcos"; break; + default: UnimplementedInstruction(); + } + } + break; + + case 0xDA: + if (modrm_byte == 0xE9) { + mnem = "fucompp"; + } else { + UnimplementedInstruction(); + } + break; + + case 0xDB: + if ((modrm_byte & 0xF8) == 0xE8) { + mnem = "fucomi"; + has_register = true; + } else if (modrm_byte == 0xE2) { + mnem = "fclex"; + } else { + UnimplementedInstruction(); + } + break; + + case 0xDC: + has_register = true; + switch (modrm_byte & 0xF8) { + case 0xC0: mnem = "fadd"; break; + case 0xE8: mnem = "fsub"; break; + case 0xC8: mnem = "fmul"; break; + case 0xF8: mnem = "fdiv"; break; + default: UnimplementedInstruction(); + } + break; + + case 0xDD: + has_register = true; + switch (modrm_byte & 0xF8) { + case 0xC0: mnem = "ffree"; break; + case 0xD8: mnem = "fstp"; break; + default: UnimplementedInstruction(); + } + break; + + case 0xDE: + if (modrm_byte == 0xD9) { + mnem = "fcompp"; + } else { + has_register = true; + switch (modrm_byte & 0xF8) { + case 0xC0: mnem = "faddp"; break; + case 0xE8: mnem = "fsubp"; break; + case 0xC8: mnem = "fmulp"; break; + case 0xF8: mnem = "fdivp"; break; + default: UnimplementedInstruction(); + } + } + break; + + case 0xDF: + if (modrm_byte == 0xE0) { + mnem = "fnstsw_ax"; + } else if ((modrm_byte & 0xF8) == 0xE8) { + mnem = "fucomip"; + has_register = true; + } + break; + + default: UnimplementedInstruction(); + } + + if (has_register) { + AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7); + } else { + AppendToBuffer("%s", mnem); } - AppendToBuffer("Unknown FP instruction"); return 2; } + // Handle all two-byte opcodes, which start with 0x0F. // These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix. // We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A. @@ -1045,13 +1049,13 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { int mod, regop, rm; get_modrm(*current, &mod, ®op, &rm); AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop)); - data += PrintRightOperand(data); + current += PrintRightOperand(current); } else if ((opcode & 0xF8) == 0x58) { // XMM arithmetic. Mnemonic was retrieved at the start of this function. int mod, regop, rm; get_modrm(*current, &mod, ®op, &rm); - AppendToBuffer("%s %s,%s", mnemonic, NameOfXMMRegister(regop), - NameOfXMMRegister(rm)); + AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop)); + current += PrintRightXMMOperand(current); } else { UnimplementedInstruction(); } @@ -1060,7 +1064,7 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { // CVTTSS2SI: Convert scalar single-precision FP to dword integer. // Assert that mod is not 3, so source is memory, not an XMM register. - ASSERT((*current & 0xC0) != 0xC0); + ASSERT_NE(0xC0, *current & 0xC0); current += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, current); } else { UnimplementedInstruction(); @@ -1236,18 +1240,6 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector out_buffer, break; } - case 0xF6: { - int mod, regop, rm; - get_modrm(*(data + 1), &mod, ®op, &rm); - if (mod == 3 && regop == 0) { - AppendToBuffer("testb %s,%d", NameOfCPURegister(rm), *(data + 2)); - } else { - UnimplementedInstruction(); - } - data += 3; - break; - } - case 0x81: // fall through case 0x83: // 0x81 with sign extension bit set data += PrintImmediateOp(data); @@ -1344,7 +1336,7 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector out_buffer, case 0x95: case 0x96: case 0x97: { - int reg = (current & 0x7) | (rex_b() ? 8 : 0); + int reg = (*data & 0x7) | (rex_b() ? 8 : 0); if (reg == 0) { AppendToBuffer("nop"); // Common name for xchg rax,rax. } else { @@ -1352,8 +1344,9 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector out_buffer, operand_size_code(), NameOfCPURegister(reg)); } + data++; } - + break; case 0xFE: { data++; @@ -1465,8 +1458,10 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector out_buffer, data += JumpShort(data); break; + case 0xF6: + byte_size_operand_ = true; // fall through case 0xF7: - data += F7Instruction(data); + data += F6F7Instruction(data); break; default: