in runtime/vm/compiler/assembler/disassembler_x86.cc [1272:1609]
int DisassemblerX64::TwoByteOpcodeInstruction(uint8_t* data) {
uint8_t opcode = *(data + 1);
uint8_t* current = data + 2;
// At return, "current" points to the start of the next instruction.
const char* mnemonic = TwoByteMnemonic(opcode);
if (operand_size_ == 0x66) {
// 0x66 0x0F prefix.
int mod, regop, rm;
if (opcode == 0xC6) {
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
Print("shufpd %s, ", NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
Print(" [%x]", *current);
current++;
} else if (opcode == 0x3A) {
uint8_t third_byte = *current;
current = data + 3;
if (third_byte == 0x16) {
get_modrm(*current, &mod, ®op, &rm);
Print("pextrd "); // reg/m32, xmm, imm8
current += PrintRightOperand(current);
Print(",%s,%d", NameOfXMMRegister(regop), (*current) & 7);
current += 1;
} else if (third_byte == 0x17) {
get_modrm(*current, &mod, ®op, &rm);
Print("extractps "); // reg/m32, xmm, imm8
current += PrintRightOperand(current);
Print(", %s, %d", NameOfCPURegister(regop), (*current) & 3);
current += 1;
} else if (third_byte == 0x0b) {
get_modrm(*current, &mod, ®op, &rm);
// roundsd xmm, xmm/m64, imm8
Print("roundsd %s, ", NameOfCPURegister(regop));
current += PrintRightOperand(current);
Print(", %d", (*current) & 3);
current += 1;
} else {
UnimplementedInstruction();
}
} else {
get_modrm(*current, &mod, ®op, &rm);
if (opcode == 0x1f) {
current++;
if (rm == 4) { // SIB byte present.
current++;
}
if (mod == 1) { // Byte displacement.
current += 1;
} else if (mod == 2) { // 32-bit displacement.
current += 4;
} // else no immediate displacement.
Print("nop");
} else if (opcode == 0x28) {
Print("movapd %s, ", NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
} else if (opcode == 0x29) {
Print("movapd ");
current += PrintRightXMMOperand(current);
Print(", %s", NameOfXMMRegister(regop));
} else if (opcode == 0x38) {
current += Print660F38Instruction(current);
} else if (opcode == 0x6E) {
Print("mov%c %s,", rex_w() ? 'q' : 'd', NameOfXMMRegister(regop));
current += PrintRightOperand(current);
} else if (opcode == 0x6F) {
Print("movdqa %s,", NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
} else if (opcode == 0x7E) {
Print("mov%c ", rex_w() ? 'q' : 'd');
current += PrintRightOperand(current);
Print(",%s", NameOfXMMRegister(regop));
} else if (opcode == 0x7F) {
Print("movdqa ");
current += PrintRightXMMOperand(current);
Print(",%s", NameOfXMMRegister(regop));
} else if (opcode == 0xD6) {
Print("movq ");
current += PrintRightXMMOperand(current);
Print(",%s", NameOfXMMRegister(regop));
} else if (opcode == 0x50) {
Print("movmskpd %s,", NameOfCPURegister(regop));
current += PrintRightXMMOperand(current);
} else if (opcode == 0xD7) {
Print("pmovmskb %s,", NameOfCPURegister(regop));
current += PrintRightXMMOperand(current);
} else {
const char* mnemonic = "?";
if (opcode == 0x5A) {
mnemonic = "cvtpd2ps";
} else if (0x51 <= opcode && opcode <= 0x5F) {
mnemonic = xmm_instructions[opcode & 0xF].pd_name;
} else if (opcode == 0x14) {
mnemonic = "unpcklpd";
} else if (opcode == 0x15) {
mnemonic = "unpckhpd";
} else if (opcode == 0x2E) {
mnemonic = "ucomisd";
} else if (opcode == 0x2F) {
mnemonic = "comisd";
} else if (opcode == 0xFE) {
mnemonic = "paddd";
} else if (opcode == 0xFA) {
mnemonic = "psubd";
} else if (opcode == 0xEF) {
mnemonic = "pxor";
} else {
UnimplementedInstruction();
}
Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
}
}
} else if (group_1_prefix_ == 0xF2) {
// Beginning of instructions with prefix 0xF2.
if (opcode == 0x11 || opcode == 0x10) {
// MOVSD: Move scalar double-precision fp to/from/between XMM registers.
Print("movsd ");
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
if (opcode == 0x11) {
current += PrintRightXMMOperand(current);
Print(",%s", NameOfXMMRegister(regop));
} else {
Print("%s,", NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
}
} else if (opcode == 0x2A) {
// CVTSI2SD: integer to XMM double conversion.
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
Print("%sd %s,", mnemonic, NameOfXMMRegister(regop));
current += PrintRightOperand(current);
} else if (opcode == 0x2C) {
// CVTTSD2SI:
// Convert with truncation scalar double-precision FP to integer.
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
Print("cvttsd2si%s %s,", operand_size_code(), NameOfCPURegister(regop));
current += PrintRightXMMOperand(current);
} else if (opcode == 0x2D) {
// CVTSD2SI: Convert scalar double-precision FP to integer.
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
Print("cvtsd2si%s %s,", operand_size_code(), NameOfCPURegister(regop));
current += PrintRightXMMOperand(current);
} else if (0x51 <= opcode && opcode <= 0x5F) {
// XMM arithmetic. Get the F2 0F prefix version of the mnemonic.
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
const char* mnemonic =
opcode == 0x5A ? "cvtsd2ss" : xmm_instructions[opcode & 0xF].sd_name;
Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
} else {
UnimplementedInstruction();
}
} else if (group_1_prefix_ == 0xF3) {
// Instructions with prefix 0xF3.
if (opcode == 0x11 || opcode == 0x10) {
// MOVSS: Move scalar double-precision fp to/from/between XMM registers.
Print("movss ");
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
if (opcode == 0x11) {
current += PrintRightOperand(current);
Print(",%s", NameOfXMMRegister(regop));
} else {
Print("%s,", NameOfXMMRegister(regop));
current += PrintRightOperand(current);
}
} else if (opcode == 0x2A) {
// CVTSI2SS: integer to XMM single conversion.
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
Print("%ss %s,", mnemonic, NameOfXMMRegister(regop));
current += PrintRightOperand(current);
} else if (opcode == 0x2C || opcode == 0x2D) {
bool truncating = (opcode & 1) == 0;
// CVTTSS2SI/CVTSS2SI:
// Convert (with truncation) scalar single-precision FP to dword integer.
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
Print("cvt%sss2si%s %s,", truncating ? "t" : "", operand_size_code(),
NameOfCPURegister(regop));
current += PrintRightXMMOperand(current);
} else if (0x51 <= opcode && opcode <= 0x5F) {
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
const char* mnemonic =
opcode == 0x5A ? "cvtss2sd" : xmm_instructions[opcode & 0xF].ss_name;
Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
} else if (opcode == 0x7E) {
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
Print("movq %s, ", NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
} else if (opcode == 0xE6) {
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
Print("cvtdq2pd %s,", NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
} else if (opcode == 0xB8) {
// POPCNT.
current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
} else if (opcode == 0xBD) {
// LZCNT (rep BSR encoding).
current += PrintOperands("lzcnt", REG_OPER_OP_ORDER, current);
} else {
UnimplementedInstruction();
}
} else if (opcode == 0x1F) {
// NOP
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
current++;
if (rm == 4) { // SIB byte present.
current++;
}
if (mod == 1) { // Byte displacement.
current += 1;
} else if (mod == 2) { // 32-bit displacement.
current += 4;
} // else no immediate displacement.
Print("nop");
} else if (opcode == 0x28 || opcode == 0x2f) {
// ...s xmm, xmm/m128
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
const char* mnemonic = opcode == 0x28 ? "movaps" : "comiss";
Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
} else if (opcode == 0x29) {
// movaps xmm/m128, xmm
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
Print("movaps ");
current += PrintRightXMMOperand(current);
Print(",%s", NameOfXMMRegister(regop));
} else if (opcode == 0x11) {
// movups xmm/m128, xmm
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
Print("movups ");
current += PrintRightXMMOperand(current);
Print(",%s", NameOfXMMRegister(regop));
} else if (opcode == 0x50) {
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
Print("movmskps %s,", NameOfCPURegister(regop));
current += PrintRightXMMOperand(current);
} else if (opcode == 0xA2 || opcode == 0x31) {
// RDTSC or CPUID
Print("%s", mnemonic);
} else if ((opcode & 0xF0) == 0x40) {
// CMOVcc: conditional move.
int condition = opcode & 0x0F;
const InstructionDesc& idesc = cmov_instructions[condition];
byte_size_operand_ = idesc.byte_size_operation;
current += PrintOperands(idesc.mnem, idesc.op_order_, current);
} else if (0x10 <= opcode && opcode <= 0x16) {
// ...ps xmm, xmm/m128
static const char* const mnemonics[] = {
"movups", NULL, "movhlps", NULL, "unpcklps", "unpckhps", "movlhps"};
const char* mnemonic = mnemonics[opcode - 0x10];
if (mnemonic == NULL) {
UnimplementedInstruction();
mnemonic = "???";
}
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
} else if (0x51 <= opcode && opcode <= 0x5F) {
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
const char* mnemonic =
opcode == 0x5A ? "cvtps2pd" : xmm_instructions[opcode & 0xF].ps_name;
Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
} else if (opcode == 0xC2 || opcode == 0xC6) {
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
if (opcode == 0xC2) {
Print("cmpps %s,", NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
Print(" [%s]", xmm_conditional_code_suffix[*current]);
} else {
ASSERT(opcode == 0xC6);
Print("shufps %s,", NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
Print(" [%x]", *current);
}
current++;
} else if ((opcode & 0xF0) == 0x80) {
// Jcc: Conditional jump (branch).
current = data + JumpConditional(data);
} else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
opcode == 0xB7 || opcode == 0xAF || opcode == 0xB0 ||
opcode == 0xB1 || opcode == 0xBC || opcode == 0xBD) {
// Size-extending moves, IMUL, cmpxchg, BSF, BSR.
current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
} else if ((opcode & 0xF0) == 0x90) {
// SETcc: Set byte on condition. Needs pointer to beginning of instruction.
current = data + SetCC(data);
} else if (((opcode & 0xFE) == 0xA4) || ((opcode & 0xFE) == 0xAC) ||
(opcode == 0xAB) || (opcode == 0xA3)) {
// SHLD, SHRD (double-prec. shift), BTS (bit test and set), BT (bit test).
Print("%s%s ", mnemonic, operand_size_code());
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
current += PrintRightOperand(current);
Print(",%s", NameOfCPURegister(regop));
if ((opcode == 0xAB) || (opcode == 0xA3) || (opcode == 0xBD)) {
// Done.
} else if ((opcode == 0xA5) || (opcode == 0xAD)) {
Print(",cl");
} else {
Print(",");
current += PrintImmediate(current, BYTE_SIZE);
}
} else if (opcode == 0xBA && (*current & 0x60) == 0x60) {
// bt? immediate instruction
int r = (*current >> 3) & 7;
static const char* const names[4] = {"bt", "bts", "btr", "btc"};
Print("%s ", names[r - 4]);
current += PrintRightOperand(current);
uint8_t bit = *current++;
Print(",%d", bit);
} else {
UnimplementedInstruction();
}
return static_cast<int>(current - data);
}