in runtime/vm/compiler/assembler/disassembler_x86.cc [1645:1989]
int DisassemblerX64::InstructionDecode(uword pc) {
uint8_t* data = reinterpret_cast<uint8_t*>(pc);
const bool processed = DecodeInstructionType(&data);
if (!processed) {
switch (*data) {
case 0xC2:
Print("ret ");
PrintImmediateValue(*reinterpret_cast<uint16_t*>(data + 1));
data += 3;
break;
case 0xC8:
Print("enter %d, %d", *reinterpret_cast<uint16_t*>(data + 1), data[3]);
data += 4;
break;
case 0x69:
FALL_THROUGH;
case 0x6B: {
int mod, regop, rm;
get_modrm(*(data + 1), &mod, ®op, &rm);
int32_t imm = *data == 0x6B
? *(data + 2)
: LoadUnaligned(reinterpret_cast<int32_t*>(data + 2));
Print("imul%s %s,%s,", operand_size_code(), NameOfCPURegister(regop),
NameOfCPURegister(rm));
PrintImmediateValue(imm);
data += 2 + (*data == 0x6B ? 1 : 4);
break;
}
case 0x81:
FALL_THROUGH;
case 0x83: // 0x81 with sign extension bit set
data += PrintImmediateOp(data);
break;
case 0x0F:
data += TwoByteOpcodeInstruction(data);
break;
case 0x8F: {
data++;
int mod, regop, rm;
get_modrm(*data, &mod, ®op, &rm);
if (regop == 0) {
Print("pop ");
data += PrintRightOperand(data);
}
} break;
case 0xFF: {
data++;
int mod, regop, rm;
get_modrm(*data, &mod, ®op, &rm);
const char* mnem = NULL;
switch (regop) {
case 0:
mnem = "inc";
break;
case 1:
mnem = "dec";
break;
case 2:
mnem = "call";
break;
case 4:
mnem = "jmp";
break;
case 6:
mnem = "push";
break;
default:
mnem = "???";
}
if (regop <= 1) {
Print("%s%s ", mnem, operand_size_code());
} else {
Print("%s ", mnem);
}
data += PrintRightOperand(data);
} break;
case 0xC7: // imm32, fall through
case 0xC6: // imm8
{
bool is_byte = *data == 0xC6;
data++;
if (is_byte) {
Print("movb ");
data += PrintRightByteOperand(data);
Print(",");
data += PrintImmediate(data, BYTE_SIZE);
} else {
Print("mov%s ", operand_size_code());
data += PrintRightOperand(data);
Print(",");
data +=
PrintImmediate(data, operand_size(), /* sign extend = */ true);
}
} break;
case 0x80: {
byte_size_operand_ = true;
data += PrintImmediateOp(data);
} break;
case 0x88: // 8bit, fall through
case 0x89: // 32bit
{
bool is_byte = *data == 0x88;
int mod, regop, rm;
data++;
get_modrm(*data, &mod, ®op, &rm);
if (is_byte) {
Print("movb ");
data += PrintRightByteOperand(data);
Print(",%s", NameOfByteCPURegister(regop));
} else {
Print("mov%s ", operand_size_code());
data += PrintRightOperand(data);
Print(",%s", NameOfCPURegister(regop));
}
} break;
case 0x90:
case 0x91:
case 0x92:
case 0x93:
case 0x94:
case 0x95:
case 0x96:
case 0x97: {
int reg = (*data & 0x7) | (rex_b() ? 8 : 0);
if (reg == 0) {
Print("nop"); // Common name for xchg rax,rax.
} else {
Print("xchg%s %s, %s", operand_size_code(), Rax(),
NameOfCPURegister(reg));
}
data++;
} break;
case 0xB0:
case 0xB1:
case 0xB2:
case 0xB3:
case 0xB4:
case 0xB5:
case 0xB6:
case 0xB7:
case 0xB8:
case 0xB9:
case 0xBA:
case 0xBB:
case 0xBC:
case 0xBD:
case 0xBE:
case 0xBF: {
// mov reg8,imm8 or mov reg32,imm32
uint8_t opcode = *data;
data++;
const bool is_not_8bit = opcode >= 0xB8;
int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
if (is_not_8bit) {
Print("mov%s %s,", operand_size_code(), NameOfCPURegister(reg));
data +=
PrintImmediate(data, operand_size(), /* sign extend = */ false);
} else {
Print("movb %s,", NameOfByteCPURegister(reg));
data += PrintImmediate(data, BYTE_SIZE, /* sign extend = */ false);
}
break;
}
case 0xFE: {
data++;
int mod, regop, rm;
get_modrm(*data, &mod, ®op, &rm);
if (regop == 1) {
Print("decb ");
data += PrintRightByteOperand(data);
} else {
UnimplementedInstruction();
}
break;
}
case 0x68:
Print("push ");
PrintImmediateValue(
LoadUnaligned(reinterpret_cast<int32_t*>(data + 1)));
data += 5;
break;
case 0x6A:
Print("push ");
PrintImmediateValue(*reinterpret_cast<int8_t*>(data + 1));
data += 2;
break;
case 0xA1:
FALL_THROUGH;
case 0xA3:
switch (operand_size()) {
case DOUBLEWORD_SIZE: {
PrintAddress(reinterpret_cast<uint8_t*>(
*reinterpret_cast<int32_t*>(data + 1)));
if (*data == 0xA1) { // Opcode 0xA1
Print("movzxlq %s,(", Rax());
PrintAddress(reinterpret_cast<uint8_t*>(
*reinterpret_cast<int32_t*>(data + 1)));
Print(")");
} else { // Opcode 0xA3
Print("movzxlq (");
PrintAddress(reinterpret_cast<uint8_t*>(
*reinterpret_cast<int32_t*>(data + 1)));
Print("),%s", Rax());
}
data += 5;
break;
}
case QUADWORD_SIZE: {
// New x64 instruction mov rax,(imm_64).
if (*data == 0xA1) { // Opcode 0xA1
Print("movq %s,(", Rax());
PrintAddress(*reinterpret_cast<uint8_t**>(data + 1));
Print(")");
} else { // Opcode 0xA3
Print("movq (");
PrintAddress(*reinterpret_cast<uint8_t**>(data + 1));
Print("),%s", Rax());
}
data += 9;
break;
}
default:
UnimplementedInstruction();
data += 2;
}
break;
case 0xA8:
Print("test al,");
PrintImmediateValue(*reinterpret_cast<uint8_t*>(data + 1));
data += 2;
break;
case 0xA9: {
data++;
Print("test%s %s,", operand_size_code(), Rax());
data += PrintImmediate(data, operand_size());
break;
}
case 0xD1:
FALL_THROUGH;
case 0xD3:
FALL_THROUGH;
case 0xC1:
data += ShiftInstruction(data);
break;
case 0xD0:
FALL_THROUGH;
case 0xD2:
FALL_THROUGH;
case 0xC0:
byte_size_operand_ = true;
data += ShiftInstruction(data);
break;
case 0xD9:
FALL_THROUGH;
case 0xDA:
FALL_THROUGH;
case 0xDB:
FALL_THROUGH;
case 0xDC:
FALL_THROUGH;
case 0xDD:
FALL_THROUGH;
case 0xDE:
FALL_THROUGH;
case 0xDF:
data += FPUInstruction(data);
break;
case 0xEB:
data += JumpShort(data);
break;
case 0xF6:
byte_size_operand_ = true;
FALL_THROUGH;
case 0xF7:
data += F6F7Instruction(data);
break;
// These encodings for inc and dec are IA32 only, but we don't get here
// on X64 - the REX prefix recoginizer catches them earlier.
case 0x40:
case 0x41:
case 0x42:
case 0x43:
case 0x44:
case 0x45:
case 0x46:
case 0x47:
Print("inc %s", NameOfCPURegister(*data & 7));
data += 1;
break;
case 0x48:
case 0x49:
case 0x4a:
case 0x4b:
case 0x4c:
case 0x4d:
case 0x4e:
case 0x4f:
Print("dec %s", NameOfCPURegister(*data & 7));
data += 1;
break;
#if defined(TARGET_ARCH_IA32)
case 0x61:
Print("popad");
break;
case 0x60:
Print("pushad");
break;
#endif
default:
UnimplementedInstruction();
data += 1;
}
} // !processed
ASSERT(buffer_[buffer_pos_] == '\0');
int instr_len = data - reinterpret_cast<uint8_t*>(pc);
ASSERT(instr_len > 0); // Ensure progress.
return instr_len;
}