SSE disassembler support.
Change-Id: I43f5d52ea960e9410cd4db61a14e16eb919419fc
diff --git a/src/disassembler_x86.cc b/src/disassembler_x86.cc
index 496da2a..ed0cd25 100644
--- a/src/disassembler_x86.cc
+++ b/src/disassembler_x86.cc
@@ -52,10 +52,18 @@
}
}
+enum RegFile { GPR, MMX, SSE };
+
static void DumpReg(std::ostream& os, uint8_t rex, uint8_t reg,
- bool byte_operand, uint8_t size_override) {
+ bool byte_operand, uint8_t size_override, RegFile reg_file) {
size_t reg_num = reg; // TODO: combine with REX.R on 64bit
- DumpReg0(os, rex, reg_num, byte_operand, size_override);
+ if (reg_file == GPR) {
+ DumpReg0(os, rex, reg_num, byte_operand, size_override);
+ } else if (reg_file == SSE) {
+ os << "xmm" << reg_num;
+ } else {
+ os << "mm" << reg_num;
+ }
}
static void DumpBaseReg(std::ostream& os, uint8_t rex, uint8_t reg) {
@@ -138,6 +146,8 @@
bool byte_operand = false;
bool ax = false; // implicit use of ax
bool reg_in_opcode = false; // low 3-bits of opcode encode register parameter
+ RegFile src_reg_file = GPR;
+ RegFile dst_reg_file = GPR;
switch (*instr) {
#define DISASSEMBLER_ENTRY(opname, \
rm8_r8, rm32_r32, \
@@ -222,6 +232,7 @@
opcode << "movups";
}
has_modrm = true;
+ src_reg_file = dst_reg_file = SSE;
load = *instr == 0x10;
store = !load;
break;
@@ -231,6 +242,102 @@
case 0x3A: // 3 byte extended opcode
opcode << StringPrintf("unknown opcode '0F 3A %02X'", *instr);
break;
+ case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
+ case 0x58: case 0x59: case 0x5C: case 0x5D: case 0x5E: case 0x5F: {
+ switch (*instr) {
+ case 0x50: opcode << "movmsk"; break;
+ case 0x51: opcode << "sqrt"; break;
+ case 0x52: opcode << "rsqrt"; break;
+ case 0x53: opcode << "rcp"; break;
+ case 0x54: opcode << "and"; break;
+ case 0x55: opcode << "andn"; break;
+ case 0x56: opcode << "or"; break;
+ case 0x57: opcode << "xor"; break;
+ case 0x58: opcode << "add"; break;
+ case 0x59: opcode << "mul"; break;
+ case 0x5C: opcode << "sub"; break;
+ case 0x5D: opcode << "min"; break;
+ case 0x5E: opcode << "div"; break;
+ case 0x5F: opcode << "max"; break;
+ default: LOG(FATAL) << "Unreachable";
+ }
+ if (prefix[2] == 0x66) {
+ opcode << "pd";
+ prefix[2] = 0; // clear prefix now its served its purpose as part of the opcode
+ } else if (prefix[0] == 0xF2) {
+ opcode << "sd";
+ prefix[0] = 0; // clear prefix now its served its purpose as part of the opcode
+ } else if (prefix[0] == 0xF3) {
+ opcode << "ss";
+ prefix[0] = 0; // clear prefix now its served its purpose as part of the opcode
+ } else {
+ opcode << "ps";
+ }
+ load = true;
+ has_modrm = true;
+ src_reg_file = dst_reg_file = SSE;
+ break;
+ }
+ case 0x5A:
+ if (prefix[2] == 0x66) {
+ opcode << "cvtpd2ps";
+ prefix[2] = 0; // clear prefix now its served its purpose as part of the opcode
+ } else if (prefix[0] == 0xF2) {
+ opcode << "cvtsd2ss";
+ prefix[0] = 0; // clear prefix now its served its purpose as part of the opcode
+ } else if (prefix[0] == 0xF3) {
+ opcode << "cvtss2sd";
+ prefix[0] = 0; // clear prefix now its served its purpose as part of the opcode
+ } else {
+ opcode << "cvtps2pd";
+ }
+ load = true;
+ has_modrm = true;
+ src_reg_file = dst_reg_file = SSE;
+ break;
+ case 0x5B:
+ if (prefix[2] == 0x66) {
+ opcode << "cvtps2dq";
+ prefix[2] = 0; // clear prefix now its served its purpose as part of the opcode
+ } else if (prefix[0] == 0xF2) {
+ opcode << "bad opcode F2 0F 5B";
+ } else if (prefix[0] == 0xF3) {
+ opcode << "cvttps2dq";
+ prefix[0] = 0; // clear prefix now its served its purpose as part of the opcode
+ } else {
+ opcode << "cvtdq2ps";
+ }
+ load = true;
+ has_modrm = true;
+ src_reg_file = dst_reg_file = SSE;
+ break;
+ case 0x6E:
+ if (prefix[2] == 0x66) {
+ dst_reg_file = SSE;
+ opcode << "movq";
+ prefix[2] = 0; // clear prefix now its served its purpose as part of the opcode
+ } else {
+ dst_reg_file = MMX;
+ opcode << "movd";
+ }
+ load = true;
+ has_modrm = true;
+ break;
+ case 0x6F:
+ if (prefix[2] == 0x66) {
+ dst_reg_file = SSE;
+ opcode << "movdqa";
+ } else if (prefix[0] == 0xF3) {
+ dst_reg_file = SSE;
+ opcode << "movdqu";
+ prefix[0] = 0; // clear prefix now its served its purpose as part of the opcode
+ } else {
+ dst_reg_file = MMX;
+ opcode << "movq";
+ }
+ load = true;
+ has_modrm = true;
+ break;
case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F:
opcode << "j" << condition_codes[*instr & 0xF];
@@ -312,7 +419,7 @@
std::ostringstream args;
if (reg_in_opcode) {
DCHECK(!has_modrm);
- DumpReg(args, rex, *instr & 0x7, false, prefix[2]);
+ DumpReg(args, rex, *instr & 0x7, false, prefix[2], GPR);
}
instr++;
uint32_t address_bits = 0;
@@ -355,18 +462,18 @@
}
address << "]";
} else {
- if (mod != 3) {
+ if (mod == 3) {
+ DumpReg(address, rex, rm, byte_operand, prefix[2], load ? src_reg_file : dst_reg_file);
+ } else {
address << "[";
- }
- DumpBaseReg(address, rex, rm);
- if (mod == 1) {
- address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(instr));
- instr++;
- } else if (mod == 2) {
- address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(instr));
- instr += 4;
- }
- if (mod != 3) {
+ DumpBaseReg(address, rex, rm);
+ if (mod == 1) {
+ address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(instr));
+ instr++;
+ } else if (mod == 2) {
+ address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(instr));
+ instr += 4;
+ }
address << "]";
}
}
@@ -376,7 +483,7 @@
}
if (load) {
if (!reg_is_opcode) {
- DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2]);
+ DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], dst_reg_file);
args << ", ";
}
DumpSegmentOverride(args, prefix[1]);
@@ -387,12 +494,12 @@
args << address.str();
if (!reg_is_opcode) {
args << ", ";
- DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2]);
+ DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], src_reg_file);
}
}
}
if (ax) {
- DumpReg(args, rex, 0 /* EAX */, byte_operand, prefix[2]);
+ DumpReg(args, rex, 0 /* EAX */, byte_operand, prefix[2], GPR);
}
if (immediate_bytes > 0) {
if (has_modrm || reg_in_opcode || ax) {