| Index: src/x64/disasm-x64.cc
|
| diff --git a/src/x64/disasm-x64.cc b/src/x64/disasm-x64.cc
|
| index 837da27941d33666b527f29a77632b7ee7dc84cc..bb8f5430ccb0d3e03ad565f9e38290ae81f26b6c 100644
|
| --- a/src/x64/disasm-x64.cc
|
| +++ b/src/x64/disasm-x64.cc
|
| @@ -148,6 +148,8 @@ enum Prefixes {
|
| ESCAPE_PREFIX = 0x0F,
|
| OPERAND_SIZE_OVERRIDE_PREFIX = 0x66,
|
| ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67,
|
| + VEX3_PREFIX = 0xC4,
|
| + VEX2_PREFIX = 0xC5,
|
| REPNE_PREFIX = 0xF2,
|
| REP_PREFIX = 0xF3,
|
| REPEQ_PREFIX = REP_PREFIX
|
| @@ -290,11 +292,14 @@ class DisassemblerX64 {
|
| ABORT_ON_UNIMPLEMENTED_OPCODE)
|
| : converter_(converter),
|
| tmp_buffer_pos_(0),
|
| - abort_on_unimplemented_(
|
| - unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE),
|
| + abort_on_unimplemented_(unimplemented_action ==
|
| + ABORT_ON_UNIMPLEMENTED_OPCODE),
|
| rex_(0),
|
| operand_size_(0),
|
| group_1_prefix_(0),
|
| + vex_byte0_(0),
|
| + vex_byte1_(0),
|
| + vex_byte2_(0),
|
| byte_size_operand_(false),
|
| instruction_table_(instruction_table.Pointer()) {
|
| tmp_buffer_[0] = '\0';
|
| @@ -323,6 +328,9 @@ class DisassemblerX64 {
|
| byte rex_;
|
| byte operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0.
|
| byte group_1_prefix_; // 0xF2, 0xF3, or (if no group 1 prefix is present) 0.
|
| + byte vex_byte0_; // 0xc4 or 0xc5
|
| + byte vex_byte1_;
|
| + byte vex_byte2_; // only for 3 bytes vex prefix
|
| // Byte size operand override.
|
| bool byte_size_operand_;
|
| const InstructionTable* const instruction_table_;
|
| @@ -345,6 +353,51 @@ class DisassemblerX64 {
|
|
|
| bool rex_w() { return (rex_ & 0x08) != 0; }
|
|
|
| + bool vex_128() {
|
| + DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
|
| + byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
|
| + return (checked & 4) != 1;
|
| + }
|
| +
|
| + bool vex_66() {
|
| + DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
|
| + byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
|
| + return (checked & 3) == 1;
|
| + }
|
| +
|
| + bool vex_f3() {
|
| + DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
|
| + byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
|
| + return (checked & 3) == 2;
|
| + }
|
| +
|
| + bool vex_f2() {
|
| + DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
|
| + byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
|
| + return (checked & 3) == 3;
|
| + }
|
| +
|
| + bool vex_0f() {
|
| + if (vex_byte0_ == VEX2_PREFIX) return true;
|
| + return (vex_byte1_ & 3) == 1;
|
| + }
|
| +
|
| + bool vex_0f38() {
|
| + DCHECK(vex_byte0_ == VEX3_PREFIX);
|
| + return (vex_byte1_ & 3) == 2;
|
| + }
|
| +
|
| + bool vex_0f3a() {
|
| + DCHECK(vex_byte0_ == VEX3_PREFIX);
|
| + return (vex_byte1_ & 3) == 3;
|
| + }
|
| +
|
| + int vex_vreg() {
|
| + DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
|
| + byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
|
| + return ~(checked >> 3) & 0xf;
|
| + }
|
| +
|
| OperandSize operand_size() {
|
| if (byte_size_operand_) return OPERAND_BYTE_SIZE;
|
| if (rex_w()) return OPERAND_QUADWORD_SIZE;
|
| @@ -356,6 +409,8 @@ class DisassemblerX64 {
|
| return "bwlq"[operand_size()];
|
| }
|
|
|
| + char float_size_code() { return "sd"[rex_w()]; }
|
| +
|
| const char* NameOfCPURegister(int reg) const {
|
| return converter_.NameOfCPURegister(reg);
|
| }
|
| @@ -414,6 +469,7 @@ class DisassemblerX64 {
|
| int FPUInstruction(byte* data);
|
| int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
|
| int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
|
| + int AVXInstruction(byte* data);
|
| void AppendToBuffer(const char* format, ...);
|
|
|
| void UnimplementedInstruction() {
|
| @@ -811,6 +867,92 @@ int DisassemblerX64::SetCC(byte* data) {
|
| }
|
|
|
|
|
| +int DisassemblerX64::AVXInstruction(byte* data) {
|
| + byte opcode = *data;
|
| + byte* current = data + 1;
|
| + if (vex_byte0_ == VEX3_PREFIX) {
|
| + if (vex_128()) {
|
| + if (vex_66() && vex_0f38()) {
|
| + int mod, regop, rm, vvvv = vex_vreg();
|
| + get_modrm(*current, &mod, ®op, &rm);
|
| + switch (opcode) {
|
| + case 0x99:
|
| + AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(),
|
| + NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
|
| + current += PrintRightXMMOperand(current);
|
| + break;
|
| + case 0xa9:
|
| + AppendToBuffer("vfmadd213s%c %s,%s,", float_size_code(),
|
| + NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
|
| + current += PrintRightXMMOperand(current);
|
| + break;
|
| + case 0xb9:
|
| + AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(),
|
| + NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
|
| + current += PrintRightXMMOperand(current);
|
| + break;
|
| + case 0x9b:
|
| + AppendToBuffer("vfmsub132s%c %s,%s,", float_size_code(),
|
| + NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
|
| + current += PrintRightXMMOperand(current);
|
| + break;
|
| + case 0xab:
|
| + AppendToBuffer("vfmsub213s%c %s,%s,", float_size_code(),
|
| + NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
|
| + current += PrintRightXMMOperand(current);
|
| + break;
|
| + case 0xbb:
|
| + AppendToBuffer("vfmsub231s%c %s,%s,", float_size_code(),
|
| + NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
|
| + current += PrintRightXMMOperand(current);
|
| + break;
|
| + case 0x9d:
|
| + AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(),
|
| + NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
|
| + current += PrintRightXMMOperand(current);
|
| + break;
|
| + case 0xad:
|
| + AppendToBuffer("vfnmadd213s%c %s,%s,", float_size_code(),
|
| + NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
|
| + current += PrintRightXMMOperand(current);
|
| + break;
|
| + case 0xbd:
|
| + AppendToBuffer("vfnmadd231s%c %s,%s,", float_size_code(),
|
| + NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
|
| + current += PrintRightXMMOperand(current);
|
| + break;
|
| + case 0x9f:
|
| + AppendToBuffer("vfnmsub132s%c %s,%s,", float_size_code(),
|
| + NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
|
| + current += PrintRightXMMOperand(current);
|
| + break;
|
| + case 0xaf:
|
| + AppendToBuffer("vfnmsub213s%c %s,%s,", float_size_code(),
|
| + NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
|
| + current += PrintRightXMMOperand(current);
|
| + break;
|
| + case 0xbf:
|
| + AppendToBuffer("vfnmsub231s%c %s,%s,", float_size_code(),
|
| + NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
|
| + current += PrintRightXMMOperand(current);
|
| + break;
|
| + default:
|
| + UnimplementedInstruction();
|
| + }
|
| + }
|
| + } else {
|
| + UnimplementedInstruction();
|
| + }
|
| + } else if (vex_byte0_ == VEX2_PREFIX) {
|
| + UnimplementedInstruction();
|
| + } else {
|
| + UNREACHABLE();
|
| + }
|
| +
|
| + return static_cast<int>(current - data);
|
| +}
|
| +
|
| +
|
| // Returns number of bytes used, including *data.
|
| int DisassemblerX64::FPUInstruction(byte* data) {
|
| byte escape_opcode = *data;
|
| @@ -1189,6 +1331,16 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
|
| AppendToBuffer("cvttss2si%c %s,",
|
| operand_size_code(), NameOfCPURegister(regop));
|
| current += PrintRightXMMOperand(current);
|
| + } else if (opcode == 0x58) {
|
| + int mod, regop, rm;
|
| + get_modrm(*current, &mod, ®op, &rm);
|
| + AppendToBuffer("addss %s,", NameOfXMMRegister(regop));
|
| + current += PrintRightXMMOperand(current);
|
| + } else if (opcode == 0x59) {
|
| + int mod, regop, rm;
|
| + get_modrm(*current, &mod, ®op, &rm);
|
| + AppendToBuffer("mulss %s,", NameOfXMMRegister(regop));
|
| + current += PrintRightXMMOperand(current);
|
| } else if (opcode == 0x5A) {
|
| // CVTSS2SD:
|
| // Convert scalar single-precision FP to scalar double-precision FP.
|
| @@ -1196,6 +1348,16 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
|
| get_modrm(*current, &mod, ®op, &rm);
|
| AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
|
| current += PrintRightXMMOperand(current);
|
| + } else if (opcode == 0x5c) {
|
| + int mod, regop, rm;
|
| + get_modrm(*current, &mod, ®op, &rm);
|
| + AppendToBuffer("subss %s,", NameOfXMMRegister(regop));
|
| + current += PrintRightXMMOperand(current);
|
| + } else if (opcode == 0x5e) {
|
| + int mod, regop, rm;
|
| + get_modrm(*current, &mod, ®op, &rm);
|
| + AppendToBuffer("divss %s,", NameOfXMMRegister(regop));
|
| + current += PrintRightXMMOperand(current);
|
| } else if (opcode == 0x7E) {
|
| int mod, regop, rm;
|
| get_modrm(*current, &mod, ®op, &rm);
|
| @@ -1234,6 +1396,11 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
|
| current += PrintRightXMMOperand(current);
|
| AppendToBuffer(",%s", NameOfXMMRegister(regop));
|
|
|
| + } else if (opcode == 0x2e) {
|
| + int mod, regop, rm;
|
| + get_modrm(*current, &mod, ®op, &rm);
|
| + AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
|
| + current += PrintRightXMMOperand(current);
|
| } else if (opcode == 0xA2) {
|
| // CPUID
|
| AppendToBuffer("%s", mnemonic);
|
| @@ -1387,99 +1554,114 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
|
| if (rex_w()) AppendToBuffer("REX.W ");
|
| } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3).
|
| group_1_prefix_ = current;
|
| + } else if (current == VEX3_PREFIX) {
|
| + vex_byte0_ = current;
|
| + vex_byte1_ = *(data + 1);
|
| + vex_byte2_ = *(data + 2);
|
| + setRex(0x40 | (~(vex_byte1_ >> 5) & 7) | ((vex_byte2_ >> 4) & 8));
|
| + data += 2;
|
| + } else if (current == VEX2_PREFIX) {
|
| + vex_byte0_ = current;
|
| + vex_byte1_ = *(data + 1);
|
| + setRex(0x40 | (~(vex_byte1_ >> 5) & 4));
|
| + data++;
|
| } else { // Not a prefix - an opcode.
|
| break;
|
| }
|
| data++;
|
| }
|
|
|
| - const InstructionDesc& idesc = instruction_table_->Get(current);
|
| - byte_size_operand_ = idesc.byte_size_operation;
|
| - switch (idesc.type) {
|
| - case ZERO_OPERANDS_INSTR:
|
| - if (current >= 0xA4 && current <= 0xA7) {
|
| - // String move or compare operations.
|
| - if (group_1_prefix_ == REP_PREFIX) {
|
| - // REP.
|
| - AppendToBuffer("rep ");
|
| + // Decode AVX instructions.
|
| + if (vex_byte0_ != 0) {
|
| + processed = true;
|
| + data += AVXInstruction(data);
|
| + } else {
|
| + const InstructionDesc& idesc = instruction_table_->Get(current);
|
| + byte_size_operand_ = idesc.byte_size_operation;
|
| + switch (idesc.type) {
|
| + case ZERO_OPERANDS_INSTR:
|
| + if (current >= 0xA4 && current <= 0xA7) {
|
| + // String move or compare operations.
|
| + if (group_1_prefix_ == REP_PREFIX) {
|
| + // REP.
|
| + AppendToBuffer("rep ");
|
| + }
|
| + if (rex_w()) AppendToBuffer("REX.W ");
|
| + AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
|
| + } else {
|
| + AppendToBuffer("%s", idesc.mnem, operand_size_code());
|
| }
|
| - if (rex_w()) AppendToBuffer("REX.W ");
|
| - AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
|
| - } else {
|
| - AppendToBuffer("%s", idesc.mnem, operand_size_code());
|
| - }
|
| - data++;
|
| - break;
|
| + data++;
|
| + break;
|
|
|
| - case TWO_OPERANDS_INSTR:
|
| - data++;
|
| - data += PrintOperands(idesc.mnem, idesc.op_order_, data);
|
| - break;
|
| + case TWO_OPERANDS_INSTR:
|
| + data++;
|
| + data += PrintOperands(idesc.mnem, idesc.op_order_, data);
|
| + break;
|
|
|
| - case JUMP_CONDITIONAL_SHORT_INSTR:
|
| - data += JumpConditionalShort(data);
|
| - break;
|
| + case JUMP_CONDITIONAL_SHORT_INSTR:
|
| + data += JumpConditionalShort(data);
|
| + break;
|
|
|
| - case REGISTER_INSTR:
|
| - AppendToBuffer("%s%c %s",
|
| - idesc.mnem,
|
| - operand_size_code(),
|
| - NameOfCPURegister(base_reg(current & 0x07)));
|
| - data++;
|
| - break;
|
| - case PUSHPOP_INSTR:
|
| - AppendToBuffer("%s %s",
|
| - idesc.mnem,
|
| - NameOfCPURegister(base_reg(current & 0x07)));
|
| - data++;
|
| - break;
|
| - case MOVE_REG_INSTR: {
|
| - byte* addr = NULL;
|
| - switch (operand_size()) {
|
| - case OPERAND_WORD_SIZE:
|
| - addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
|
| - data += 3;
|
| - break;
|
| - case OPERAND_DOUBLEWORD_SIZE:
|
| - addr =
|
| - reinterpret_cast<byte*>(*reinterpret_cast<uint32_t*>(data + 1));
|
| - data += 5;
|
| - break;
|
| - case OPERAND_QUADWORD_SIZE:
|
| - addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
|
| - data += 9;
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| + case REGISTER_INSTR:
|
| + AppendToBuffer("%s%c %s", idesc.mnem, operand_size_code(),
|
| + NameOfCPURegister(base_reg(current & 0x07)));
|
| + data++;
|
| + break;
|
| + case PUSHPOP_INSTR:
|
| + AppendToBuffer("%s %s", idesc.mnem,
|
| + NameOfCPURegister(base_reg(current & 0x07)));
|
| + data++;
|
| + break;
|
| + case MOVE_REG_INSTR: {
|
| + byte* addr = NULL;
|
| + switch (operand_size()) {
|
| + case OPERAND_WORD_SIZE:
|
| + addr =
|
| + reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
|
| + data += 3;
|
| + break;
|
| + case OPERAND_DOUBLEWORD_SIZE:
|
| + addr =
|
| + reinterpret_cast<byte*>(*reinterpret_cast<uint32_t*>(data + 1));
|
| + data += 5;
|
| + break;
|
| + case OPERAND_QUADWORD_SIZE:
|
| + addr =
|
| + reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
|
| + data += 9;
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| + AppendToBuffer("mov%c %s,%s", operand_size_code(),
|
| + NameOfCPURegister(base_reg(current & 0x07)),
|
| + NameOfAddress(addr));
|
| + break;
|
| }
|
| - AppendToBuffer("mov%c %s,%s",
|
| - operand_size_code(),
|
| - NameOfCPURegister(base_reg(current & 0x07)),
|
| - NameOfAddress(addr));
|
| - break;
|
| - }
|
|
|
| - case CALL_JUMP_INSTR: {
|
| - byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
|
| - AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
|
| - data += 5;
|
| - break;
|
| - }
|
| + case CALL_JUMP_INSTR: {
|
| + byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
|
| + AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
|
| + data += 5;
|
| + break;
|
| + }
|
|
|
| - case SHORT_IMMEDIATE_INSTR: {
|
| - byte* addr =
|
| - reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
|
| - AppendToBuffer("%s rax,%s", idesc.mnem, NameOfAddress(addr));
|
| - data += 5;
|
| - break;
|
| - }
|
| + case SHORT_IMMEDIATE_INSTR: {
|
| + byte* addr =
|
| + reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
|
| + AppendToBuffer("%s rax,%s", idesc.mnem, NameOfAddress(addr));
|
| + data += 5;
|
| + break;
|
| + }
|
|
|
| - case NO_INSTR:
|
| - processed = false;
|
| - break;
|
| + case NO_INSTR:
|
| + processed = false;
|
| + break;
|
|
|
| - default:
|
| - UNIMPLEMENTED(); // This type is not implemented.
|
| + default:
|
| + UNIMPLEMENTED(); // This type is not implemented.
|
| + }
|
| }
|
|
|
| // The first byte didn't match any of the simple opcodes, so we
|
|
|