in runtime/disassembler-x64.cpp [1243:1583]
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;
getModRM(*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) {
getModRM(*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) {
getModRM(*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) {
getModRM(*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 {
getModRM(*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,", rexW() ? '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 ", rexW() ? '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 = kXmmInstructions[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;
getModRM(*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;
getModRM(*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;
getModRM(*current, &mod, ®op, &rm);
print("cvttsd2si%s %s,", operandSizeCode(), nameOfCPURegister(regop));
current += printRightXMMOperand(current);
} else if (opcode == 0x2D) {
// CVTSD2SI: Convert scalar double-precision FP to integer.
int mod, regop, rm;
getModRM(*current, &mod, ®op, &rm);
print("cvtsd2si%s %s,", operandSizeCode(), 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;
getModRM(*current, &mod, ®op, &rm);
const char* mnemonic =
opcode == 0x5A ? "cvtsd2ss" : kXmmInstructions[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;
getModRM(*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;
getModRM(*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;
getModRM(*current, &mod, ®op, &rm);
print("cvt%sss2si%s %s,", truncating ? "t" : "", operandSizeCode(),
nameOfCPURegister(regop));
current += printRightXMMOperand(current);
} else if (0x51 <= opcode && opcode <= 0x5F) {
int mod, regop, rm;
getModRM(*current, &mod, ®op, &rm);
const char* mnemonic =
opcode == 0x5A ? "cvtss2sd" : kXmmInstructions[opcode & 0xF].ss_name;
print("%s %s,", mnemonic, nameOfXMMRegister(regop));
current += printRightXMMOperand(current);
} else if (opcode == 0x7E) {
int mod, regop, rm;
getModRM(*current, &mod, ®op, &rm);
print("movq %s, ", nameOfXMMRegister(regop));
current += printRightXMMOperand(current);
} else if (opcode == 0xE6) {
int mod, regop, rm;
getModRM(*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;
getModRM(*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;
getModRM(*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;
getModRM(*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;
getModRM(*current, &mod, ®op, &rm);
print("movups ");
current += printRightXMMOperand(current);
print(",%s", nameOfXMMRegister(regop));
} else if (opcode == 0x50) {
int mod, regop, rm;
getModRM(*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* mnemonics[] = {"movups", nullptr, "movhlps",
nullptr, "unpcklps", "unpckhps",
"movlhps"};
const char* mnemonic = mnemonics[opcode - 0x10];
if (mnemonic == nullptr) {
unimplementedInstruction();
mnemonic = "???";
}
int mod, regop, rm;
getModRM(*current, &mod, ®op, &rm);
print("%s %s,", mnemonic, nameOfXMMRegister(regop));
current += printRightXMMOperand(current);
} else if (0x51 <= opcode && opcode <= 0x5F) {
int mod, regop, rm;
getModRM(*current, &mod, ®op, &rm);
const char* mnemonic =
opcode == 0x5A ? "cvtps2pd" : kXmmInstructions[opcode & 0xF].ps_name;
print("%s %s,", mnemonic, nameOfXMMRegister(regop));
current += printRightXMMOperand(current);
} else if (opcode == 0xC2 || opcode == 0xC6) {
int mod, regop, rm;
getModRM(*current, &mod, ®op, &rm);
if (opcode == 0xC2) {
print("cmpps %s,", nameOfXMMRegister(regop));
current += printRightXMMOperand(current);
print(" [%s]", kXmmConditionalCodeSuffix[*current]);
} else {
DCHECK(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, operandSizeCode());
int mod, regop, rm;
getModRM(*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 if (opcode == 0x0B) {
print("ud2");
} else {
unimplementedInstruction();
}
return static_cast<int>(current - data);
}