| Index: src/x64/disasm-x64.cc
|
| ===================================================================
|
| --- src/x64/disasm-x64.cc (revision 3139)
|
| +++ src/x64/disasm-x64.cc (working copy)
|
| @@ -218,7 +218,7 @@
|
| OperandType op_order = bm[i].op_order_;
|
| id->op_order_ =
|
| static_cast<OperandType>(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 @@
|
| 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::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 @@
|
| 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 @@
|
| 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::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 @@
|
|
|
|
|
| // 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 @@
|
| operand_size_code(),
|
| NameOfCPURegister(rm));
|
| return 2;
|
| - } else if (mod == 3 && regop == 0) {
|
| - int32_t imm = *reinterpret_cast<int32_t*>(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<int32_t*>(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 @@
|
| UnimplementedInstruction();
|
| return num_bytes;
|
| }
|
| - assert(mnem != NULL);
|
| + ASSERT_NE(NULL, mnem);
|
| if (op == 0xD0) {
|
| imm8 = 1;
|
| } else if (op == 0xC0) {
|
| @@ -762,7 +764,7 @@
|
|
|
| // 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<int8_t>(b) + 2;
|
| AppendToBuffer("jmp %s", NameOfAddress(dest));
|
| @@ -772,7 +774,7 @@
|
|
|
| // 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<int32_t*>(data + 2) + 6;
|
| const char* mnem = conditional_code_suffix[cond];
|
| @@ -794,7 +796,7 @@
|
|
|
| // 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 @@
|
|
|
| // 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();
|
| + 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();
|
| }
|
| - 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;
|
| + 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();
|
| }
|
| - return 2;
|
| - } else {
|
| - const char* mnem = "?";
|
| - switch (regop) {
|
| - case 0:
|
| - mnem = "fld_d";
|
| + 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;
|
| - case 3:
|
| - mnem = "fstp_d";
|
| - break;
|
| default:
|
| - UnimplementedInstruction();
|
| + 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();
|
| + }
|
| }
|
| - 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:
|
| + break;
|
| +
|
| + case 0xDA:
|
| + if (modrm_byte == 0xE9) {
|
| + mnem = "fucompp";
|
| + } else {
|
| 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:
|
| + }
|
| + break;
|
| +
|
| + case 0xDB:
|
| + if ((modrm_byte & 0xF8) == 0xE8) {
|
| + mnem = "fucomi";
|
| + has_register = true;
|
| + } else if (modrm_byte == 0xE2) {
|
| + mnem = "fclex";
|
| + } else {
|
| 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";
|
| + }
|
| + 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);
|
| - return 2;
|
| }
|
| - 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 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 @@
|
|
|
| // 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 @@
|
| 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 @@
|
| 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,9 +1344,10 @@
|
| operand_size_code(),
|
| NameOfCPURegister(reg));
|
| }
|
| + data++;
|
| }
|
| + break;
|
|
|
| -
|
| case 0xFE: {
|
| data++;
|
| int mod, regop, rm;
|
| @@ -1465,8 +1458,10 @@
|
| data += JumpShort(data);
|
| break;
|
|
|
| + case 0xF6:
|
| + byte_size_operand_ = true; // fall through
|
| case 0xF7:
|
| - data += F7Instruction(data);
|
| + data += F6F7Instruction(data);
|
| break;
|
|
|
| default:
|
|
|