34 #if defined(V8_TARGET_ARCH_X64)
44 REG_OPER_OP_ORDER = 1,
45 OPER_REG_OP_ORDER = 2,
47 BYTE_SIZE_OPERAND_FLAG = 4,
48 BYTE_REG_OPER_OP_ORDER = REG_OPER_OP_ORDER | BYTE_SIZE_OPERAND_FLAG,
49 BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG
57 OperandType op_order_;
62 static const ByteMnemonic two_operands_instr[] = {
63 { 0x00, BYTE_OPER_REG_OP_ORDER,
"add" },
64 { 0x01, OPER_REG_OP_ORDER,
"add" },
65 { 0x02, BYTE_REG_OPER_OP_ORDER,
"add" },
66 { 0x03, REG_OPER_OP_ORDER,
"add" },
67 { 0x08, BYTE_OPER_REG_OP_ORDER,
"or" },
68 { 0x09, OPER_REG_OP_ORDER,
"or" },
69 { 0x0A, BYTE_REG_OPER_OP_ORDER,
"or" },
70 { 0x0B, REG_OPER_OP_ORDER,
"or" },
71 { 0x10, BYTE_OPER_REG_OP_ORDER,
"adc" },
72 { 0x11, OPER_REG_OP_ORDER,
"adc" },
73 { 0x12, BYTE_REG_OPER_OP_ORDER,
"adc" },
74 { 0x13, REG_OPER_OP_ORDER,
"adc" },
75 { 0x18, BYTE_OPER_REG_OP_ORDER,
"sbb" },
76 { 0x19, OPER_REG_OP_ORDER,
"sbb" },
77 { 0x1A, BYTE_REG_OPER_OP_ORDER,
"sbb" },
78 { 0x1B, REG_OPER_OP_ORDER,
"sbb" },
79 { 0x20, BYTE_OPER_REG_OP_ORDER,
"and" },
80 { 0x21, OPER_REG_OP_ORDER,
"and" },
81 { 0x22, BYTE_REG_OPER_OP_ORDER,
"and" },
82 { 0x23, REG_OPER_OP_ORDER,
"and" },
83 { 0x28, BYTE_OPER_REG_OP_ORDER,
"sub" },
84 { 0x29, OPER_REG_OP_ORDER,
"sub" },
85 { 0x2A, BYTE_REG_OPER_OP_ORDER,
"sub" },
86 { 0x2B, REG_OPER_OP_ORDER,
"sub" },
87 { 0x30, BYTE_OPER_REG_OP_ORDER,
"xor" },
88 { 0x31, OPER_REG_OP_ORDER,
"xor" },
89 { 0x32, BYTE_REG_OPER_OP_ORDER,
"xor" },
90 { 0x33, REG_OPER_OP_ORDER,
"xor" },
91 { 0x38, BYTE_OPER_REG_OP_ORDER,
"cmp" },
92 { 0x39, OPER_REG_OP_ORDER,
"cmp" },
93 { 0x3A, BYTE_REG_OPER_OP_ORDER,
"cmp" },
94 { 0x3B, REG_OPER_OP_ORDER,
"cmp" },
95 { 0x63, REG_OPER_OP_ORDER,
"movsxlq" },
96 { 0x84, BYTE_REG_OPER_OP_ORDER,
"test" },
97 { 0x85, REG_OPER_OP_ORDER,
"test" },
98 { 0x86, BYTE_REG_OPER_OP_ORDER,
"xchg" },
99 { 0x87, REG_OPER_OP_ORDER,
"xchg" },
100 { 0x88, BYTE_OPER_REG_OP_ORDER,
"mov" },
101 { 0x89, OPER_REG_OP_ORDER,
"mov" },
102 { 0x8A, BYTE_REG_OPER_OP_ORDER,
"mov" },
103 { 0x8B, REG_OPER_OP_ORDER,
"mov" },
104 { 0x8D, REG_OPER_OP_ORDER,
"lea" },
105 { -1, UNSET_OP_ORDER,
"" }
109 static const ByteMnemonic zero_operands_instr[] = {
110 { 0xC3, UNSET_OP_ORDER,
"ret" },
111 { 0xC9, UNSET_OP_ORDER,
"leave" },
112 { 0xF4, UNSET_OP_ORDER,
"hlt" },
113 { 0xFC, UNSET_OP_ORDER,
"cld" },
114 { 0xCC, UNSET_OP_ORDER,
"int3" },
115 { 0x60, UNSET_OP_ORDER,
"pushad" },
116 { 0x61, UNSET_OP_ORDER,
"popad" },
117 { 0x9C, UNSET_OP_ORDER,
"pushfd" },
118 { 0x9D, UNSET_OP_ORDER,
"popfd" },
119 { 0x9E, UNSET_OP_ORDER,
"sahf" },
120 { 0x99, UNSET_OP_ORDER,
"cdq" },
121 { 0x9B, UNSET_OP_ORDER,
"fwait" },
122 { 0xA4, UNSET_OP_ORDER,
"movs" },
123 { 0xA5, UNSET_OP_ORDER,
"movs" },
124 { 0xA6, UNSET_OP_ORDER,
"cmps" },
125 { 0xA7, UNSET_OP_ORDER,
"cmps" },
126 { -1, UNSET_OP_ORDER,
"" }
130 static const ByteMnemonic call_jump_instr[] = {
131 { 0xE8, UNSET_OP_ORDER,
"call" },
132 { 0xE9, UNSET_OP_ORDER,
"jmp" },
133 { -1, UNSET_OP_ORDER,
"" }
137 static const ByteMnemonic short_immediate_instr[] = {
138 { 0x05, UNSET_OP_ORDER,
"add" },
139 { 0x0D, UNSET_OP_ORDER,
"or" },
140 { 0x15, UNSET_OP_ORDER,
"adc" },
141 { 0x1D, UNSET_OP_ORDER,
"sbb" },
142 { 0x25, UNSET_OP_ORDER,
"and" },
143 { 0x2D, UNSET_OP_ORDER,
"sub" },
144 { 0x35, UNSET_OP_ORDER,
"xor" },
145 { 0x3D, UNSET_OP_ORDER,
"cmp" },
146 { -1, UNSET_OP_ORDER,
"" }
150 static const char*
const conditional_code_suffix[] = {
151 "o",
"no",
"c",
"nc",
"z",
"nz",
"na",
"a",
152 "s",
"ns",
"pe",
"po",
"l",
"ge",
"le",
"g"
156 enum InstructionType {
160 JUMP_CONDITIONAL_SHORT_INSTR,
165 SHORT_IMMEDIATE_INSTR
170 ESCAPE_PREFIX = 0x0F,
171 OPERAND_SIZE_OVERRIDE_PREFIX = 0x66,
172 ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67,
175 REPEQ_PREFIX = REP_PREFIX
179 struct InstructionDesc {
181 InstructionType
type;
182 OperandType op_order_;
183 bool byte_size_operation;
187 class InstructionTable {
190 const InstructionDesc& Get(
byte x)
const {
191 return instructions_[x];
195 InstructionDesc instructions_[256];
198 void CopyTable(
const ByteMnemonic bm[], InstructionType
type);
199 void SetTableRange(InstructionType
type,
byte start,
byte end,
bool byte_size,
201 void AddJumpConditionalShort();
205 InstructionTable::InstructionTable() {
211 void InstructionTable::Clear() {
212 for (
int i = 0; i < 256; i++) {
213 instructions_[i].mnem =
"(bad)";
214 instructions_[i].type = NO_INSTR;
215 instructions_[i].op_order_ = UNSET_OP_ORDER;
216 instructions_[i].byte_size_operation =
false;
221 void InstructionTable::Init() {
222 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
223 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
224 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
225 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
226 AddJumpConditionalShort();
227 SetTableRange(PUSHPOP_INSTR, 0x50, 0x57,
false,
"push");
228 SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F,
false,
"pop");
229 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF,
false,
"mov");
233 void InstructionTable::CopyTable(
const ByteMnemonic bm[],
234 InstructionType
type) {
235 for (
int i = 0; bm[i].b >= 0; i++) {
236 InstructionDesc*
id = &instructions_[bm[i].b];
237 id->mnem = bm[i].mnem;
238 OperandType op_order = bm[i].op_order_;
240 static_cast<OperandType
>(op_order & ~BYTE_SIZE_OPERAND_FLAG);
243 id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0);
248 void InstructionTable::SetTableRange(InstructionType type,
253 for (
byte b = start; b <= end; b++) {
254 InstructionDesc*
id = &instructions_[b];
258 id->byte_size_operation = byte_size;
263 void InstructionTable::AddJumpConditionalShort() {
264 for (
byte b = 0x70; b <= 0x7F; b++) {
265 InstructionDesc*
id = &instructions_[b];
268 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
277 static InstructionDesc cmov_instructions[16] = {
278 {
"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
279 {
"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
280 {
"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
281 {
"cmovnc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
282 {
"cmovz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
283 {
"cmovnz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
284 {
"cmovna", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
285 {
"cmova", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
286 {
"cmovs", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
287 {
"cmovns", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
288 {
"cmovpe", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
289 {
"cmovpo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
290 {
"cmovl", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
291 {
"cmovge", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
292 {
"cmovle", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
293 {
"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false}
299 enum UnimplementedOpcodeAction {
300 CONTINUE_ON_UNIMPLEMENTED_OPCODE,
301 ABORT_ON_UNIMPLEMENTED_OPCODE
306 class DisassemblerX64 {
308 DisassemblerX64(
const NameConverter& converter,
309 UnimplementedOpcodeAction unimplemented_action =
310 ABORT_ON_UNIMPLEMENTED_OPCODE)
311 : converter_(converter),
313 abort_on_unimplemented_(
314 unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE),
318 byte_size_operand_(
false),
319 instruction_table_(instruction_table.Pointer()) {
320 tmp_buffer_[0] =
'\0';
323 virtual ~DisassemblerX64() {
338 const NameConverter& converter_;
340 unsigned int tmp_buffer_pos_;
341 bool abort_on_unimplemented_;
345 byte group_1_prefix_;
347 bool byte_size_operand_;
348 const InstructionTable*
const instruction_table_;
350 void setRex(
byte rex) {
355 bool rex() {
return rex_ != 0; }
357 bool rex_b() {
return (rex_ & 0x01) != 0; }
360 int base_reg(
int low_bits) {
return low_bits | ((rex_ & 0x01) << 3); }
362 bool rex_x() {
return (rex_ & 0x02) != 0; }
364 bool rex_r() {
return (rex_ & 0x04) != 0; }
366 bool rex_w() {
return (rex_ & 0x08) != 0; }
368 OperandSize operand_size() {
369 if (byte_size_operand_)
return BYTE_SIZE;
370 if (rex_w())
return QUADWORD_SIZE;
371 if (operand_size_ != 0)
return WORD_SIZE;
372 return DOUBLEWORD_SIZE;
375 char operand_size_code() {
376 return "bwlq"[operand_size()];
379 const char* NameOfCPURegister(
int reg)
const {
380 return converter_.NameOfCPURegister(reg);
383 const char* NameOfByteCPURegister(
int reg)
const {
384 return converter_.NameOfByteCPURegister(reg);
387 const char* NameOfXMMRegister(
int reg)
const {
388 return converter_.NameOfXMMRegister(reg);
391 const char* NameOfAddress(
byte* addr)
const {
392 return converter_.NameOfAddress(addr);
396 void get_modrm(
byte data,
400 *mod = (data >> 6) & 3;
401 *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0);
402 *rm = (data & 7) | (rex_b() ? 8 : 0);
405 void get_sib(
byte data,
409 *scale = (data >> 6) & 3;
410 *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0);
411 *base = (data & 7) | (rex_b() ? 8 : 0);
414 typedef const char* (DisassemblerX64::*RegisterNameMapping)(
int reg)
const;
416 int PrintRightOperandHelper(
byte* modrmp,
417 RegisterNameMapping register_name);
418 int PrintRightOperand(
byte* modrmp);
419 int PrintRightByteOperand(
byte* modrmp);
420 int PrintRightXMMOperand(
byte* modrmp);
421 int PrintOperands(
const char* mnem,
422 OperandType op_order,
424 int PrintImmediate(
byte* data, OperandSize size);
425 int PrintImmediateOp(
byte* data);
426 const char* TwoByteMnemonic(
byte opcode);
427 int TwoByteOpcodeInstruction(
byte* data);
428 int F6F7Instruction(
byte* data);
429 int ShiftInstruction(
byte* data);
430 int JumpShort(
byte* data);
431 int JumpConditional(
byte* data);
432 int JumpConditionalShort(
byte* data);
434 int FPUInstruction(
byte* data);
435 int MemoryFPUInstruction(
int escape_opcode,
int regop,
byte* modrm_start);
436 int RegisterFPUInstruction(
int escape_opcode,
byte modrm_byte);
437 void AppendToBuffer(
const char* format, ...);
439 void UnimplementedInstruction() {
440 if (abort_on_unimplemented_) {
443 AppendToBuffer(
"'Unimplemented Instruction'");
449 void DisassemblerX64::AppendToBuffer(
const char* format, ...) {
452 va_start(args, format);
455 tmp_buffer_pos_ += result;
459 int DisassemblerX64::PrintRightOperandHelper(
461 RegisterNameMapping direct_register_name) {
463 get_modrm(*modrmp, &mod, ®op, &rm);
464 RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
465 &DisassemblerX64::NameOfCPURegister;
470 AppendToBuffer(
"[0x%x]", disp);
472 }
else if ((rm & 7) == 4) {
474 byte sib = *(modrmp + 1);
475 int scale, index, base;
476 get_sib(sib, &scale, &index, &base);
477 if (index == 4 && (base & 7) == 4 && scale == 0 ) {
480 AppendToBuffer(
"[%s]", NameOfCPURegister(base));
482 }
else if (base == 5) {
485 AppendToBuffer(
"[%s*%d+0x%x]",
486 NameOfCPURegister(index),
489 }
else if (index != 4 && base != 5) {
491 AppendToBuffer(
"[%s+%s*%d]",
492 NameOfCPURegister(base),
493 NameOfCPURegister(index),
497 UnimplementedInstruction();
501 AppendToBuffer(
"[%s]", NameOfCPURegister(rm));
508 byte sib = *(modrmp + 1);
509 int scale, index, base;
510 get_sib(sib, &scale, &index, &base);
511 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 2)
512 : *
reinterpret_cast<char*
>(modrmp + 2);
513 if (index == 4 && (base & 7) == 4 && scale == 0 ) {
515 AppendToBuffer(
"[%s-0x%x]", NameOfCPURegister(base), -disp);
517 AppendToBuffer(
"[%s+0x%x]", NameOfCPURegister(base), disp);
521 AppendToBuffer(
"[%s+%s*%d-0x%x]",
522 NameOfCPURegister(base),
523 NameOfCPURegister(index),
527 AppendToBuffer(
"[%s+%s*%d+0x%x]",
528 NameOfCPURegister(base),
529 NameOfCPURegister(index),
534 return mod == 2 ? 6 : 3;
537 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 1)
538 : *
reinterpret_cast<char*
>(modrmp + 1);
540 AppendToBuffer(
"[%s-0x%x]", NameOfCPURegister(rm), -disp);
542 AppendToBuffer(
"[%s+0x%x]", NameOfCPURegister(rm), disp);
544 return (mod == 2) ? 5 : 2;
548 AppendToBuffer(
"%s", (this->*register_name)(rm));
551 UnimplementedInstruction();
558 int DisassemblerX64::PrintImmediate(
byte* data, OperandSize size) {
567 value = *
reinterpret_cast<int16_t*
>(data);
570 case DOUBLEWORD_SIZE:
571 value = *
reinterpret_cast<uint32_t*
>(data);
575 value = *
reinterpret_cast<int32_t*
>(data);
588 int DisassemblerX64::PrintRightOperand(
byte* modrmp) {
589 return PrintRightOperandHelper(modrmp,
590 &DisassemblerX64::NameOfCPURegister);
594 int DisassemblerX64::PrintRightByteOperand(
byte* modrmp) {
595 return PrintRightOperandHelper(modrmp,
596 &DisassemblerX64::NameOfByteCPURegister);
600 int DisassemblerX64::PrintRightXMMOperand(
byte* modrmp) {
601 return PrintRightOperandHelper(modrmp,
602 &DisassemblerX64::NameOfXMMRegister);
608 int DisassemblerX64::PrintOperands(
const char* mnem,
609 OperandType op_order,
613 get_modrm(modrm, &mod, ®op, &rm);
615 const char* register_name =
616 byte_size_operand_ ? NameOfByteCPURegister(regop)
617 : NameOfCPURegister(regop);
619 case REG_OPER_OP_ORDER: {
620 AppendToBuffer(
"%s%c %s,",
624 advance = byte_size_operand_ ? PrintRightByteOperand(data)
625 : PrintRightOperand(data);
628 case OPER_REG_OP_ORDER: {
629 AppendToBuffer(
"%s%c ", mnem, operand_size_code());
630 advance = byte_size_operand_ ? PrintRightByteOperand(data)
631 : PrintRightOperand(data);
632 AppendToBuffer(
",%s", register_name);
645 int DisassemblerX64::PrintImmediateOp(
byte* data) {
646 bool byte_size_immediate = (*data & 0x02) != 0;
647 byte modrm = *(data + 1);
649 get_modrm(modrm, &mod, ®op, &rm);
650 const char* mnem =
"Imm???";
677 UnimplementedInstruction();
679 AppendToBuffer(
"%s%c ", mnem, operand_size_code());
680 int count = PrintRightOperand(data + 1);
681 AppendToBuffer(
",0x");
682 OperandSize immediate_size = byte_size_immediate ? BYTE_SIZE : operand_size();
683 count += PrintImmediate(data + 1 + count, immediate_size);
689 int DisassemblerX64::F6F7Instruction(
byte* data) {
690 ASSERT(*data == 0xF7 || *data == 0xF6);
691 byte modrm = *(data + 1);
693 get_modrm(modrm, &mod, ®op, &rm);
694 if (mod == 3 && regop != 0) {
695 const char* mnem =
NULL;
710 UnimplementedInstruction();
712 AppendToBuffer(
"%s%c %s",
715 NameOfCPURegister(rm));
717 }
else if (regop == 0) {
718 AppendToBuffer(
"test%c ", operand_size_code());
719 int count = PrintRightOperand(data + 1);
720 AppendToBuffer(
",0x");
721 count += PrintImmediate(data + 1 + count, operand_size());
724 UnimplementedInstruction();
730 int DisassemblerX64::ShiftInstruction(
byte* data) {
731 byte op = *data & (~1);
732 if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
733 UnimplementedInstruction();
736 byte modrm = *(data + 1);
738 get_modrm(modrm, &mod, ®op, &rm);
743 UnimplementedInstruction();
746 const char* mnem =
NULL;
770 UnimplementedInstruction();
776 }
else if (op == 0xC0) {
780 AppendToBuffer(
"%s%c %s,",
783 byte_size_operand_ ? NameOfByteCPURegister(rm)
784 : NameOfCPURegister(rm));
786 AppendToBuffer(
"cl");
788 AppendToBuffer(
"%d", imm8);
795 int DisassemblerX64::JumpShort(
byte* data) {
797 byte b = *(data + 1);
798 byte* dest = data +
static_cast<int8_t
>(b) + 2;
799 AppendToBuffer(
"jmp %s", NameOfAddress(dest));
805 int DisassemblerX64::JumpConditional(
byte* data) {
807 byte cond = *(data + 1) & 0x0F;
808 byte* dest = data + *
reinterpret_cast<int32_t*
>(data + 2) + 6;
809 const char* mnem = conditional_code_suffix[cond];
810 AppendToBuffer(
"j%s %s", mnem, NameOfAddress(dest));
816 int DisassemblerX64::JumpConditionalShort(
byte* data) {
817 byte cond = *data & 0x0F;
818 byte b = *(data + 1);
819 byte* dest = data +
static_cast<int8_t
>(b) + 2;
820 const char* mnem = conditional_code_suffix[cond];
821 AppendToBuffer(
"j%s %s", mnem, NameOfAddress(dest));
829 byte cond = *(data + 1) & 0x0F;
830 const char* mnem = conditional_code_suffix[cond];
831 AppendToBuffer(
"set%s%c ", mnem, operand_size_code());
832 PrintRightByteOperand(data + 2);
838 int DisassemblerX64::FPUInstruction(
byte* data) {
839 byte escape_opcode = *data;
841 byte modrm_byte = *(data+1);
843 if (modrm_byte >= 0xC0) {
844 return RegisterFPUInstruction(escape_opcode, modrm_byte);
846 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
850 int DisassemblerX64::MemoryFPUInstruction(
int escape_opcode,
853 const char* mnem =
"?";
854 int regop = (modrm_byte >> 3) & 0x7;
855 switch (escape_opcode) {
856 case 0xD9:
switch (regop) {
857 case 0: mnem =
"fld_s";
break;
858 case 3: mnem =
"fstp_s";
break;
859 case 7: mnem =
"fstcw";
break;
860 default: UnimplementedInstruction();
864 case 0xDB:
switch (regop) {
865 case 0: mnem =
"fild_s";
break;
866 case 1: mnem =
"fisttp_s";
break;
867 case 2: mnem =
"fist_s";
break;
868 case 3: mnem =
"fistp_s";
break;
869 default: UnimplementedInstruction();
873 case 0xDD:
switch (regop) {
874 case 0: mnem =
"fld_d";
break;
875 case 3: mnem =
"fstp_d";
break;
876 default: UnimplementedInstruction();
880 case 0xDF:
switch (regop) {
881 case 5: mnem =
"fild_d";
break;
882 case 7: mnem =
"fistp_d";
break;
883 default: UnimplementedInstruction();
887 default: UnimplementedInstruction();
889 AppendToBuffer(
"%s ", mnem);
890 int count = PrintRightOperand(modrm_start);
894 int DisassemblerX64::RegisterFPUInstruction(
int escape_opcode,
896 bool has_register =
false;
897 const char* mnem =
"?";
899 switch (escape_opcode) {
901 UnimplementedInstruction();
905 switch (modrm_byte & 0xF8) {
915 switch (modrm_byte) {
916 case 0xE0: mnem =
"fchs";
break;
917 case 0xE1: mnem =
"fabs";
break;
918 case 0xE3: mnem =
"fninit";
break;
919 case 0xE4: mnem =
"ftst";
break;
920 case 0xE8: mnem =
"fld1";
break;
921 case 0xEB: mnem =
"fldpi";
break;
922 case 0xED: mnem =
"fldln2";
break;
923 case 0xEE: mnem =
"fldz";
break;
924 case 0xF0: mnem =
"f2xm1";
break;
925 case 0xF1: mnem =
"fyl2x";
break;
926 case 0xF2: mnem =
"fptan";
break;
927 case 0xF5: mnem =
"fprem1";
break;
928 case 0xF7: mnem =
"fincstp";
break;
929 case 0xF8: mnem =
"fprem";
break;
930 case 0xFD: mnem =
"fscale";
break;
931 case 0xFE: mnem =
"fsin";
break;
932 case 0xFF: mnem =
"fcos";
break;
933 default: UnimplementedInstruction();
939 if (modrm_byte == 0xE9) {
942 UnimplementedInstruction();
947 if ((modrm_byte & 0xF8) == 0xE8) {
950 }
else if (modrm_byte == 0xE2) {
953 UnimplementedInstruction();
959 switch (modrm_byte & 0xF8) {
960 case 0xC0: mnem =
"fadd";
break;
961 case 0xE8: mnem =
"fsub";
break;
962 case 0xC8: mnem =
"fmul";
break;
963 case 0xF8: mnem =
"fdiv";
break;
964 default: UnimplementedInstruction();
970 switch (modrm_byte & 0xF8) {
971 case 0xC0: mnem =
"ffree";
break;
972 case 0xD8: mnem =
"fstp";
break;
973 default: UnimplementedInstruction();
978 if (modrm_byte == 0xD9) {
982 switch (modrm_byte & 0xF8) {
983 case 0xC0: mnem =
"faddp";
break;
984 case 0xE8: mnem =
"fsubp";
break;
985 case 0xC8: mnem =
"fmulp";
break;
986 case 0xF8: mnem =
"fdivp";
break;
987 default: UnimplementedInstruction();
993 if (modrm_byte == 0xE0) {
995 }
else if ((modrm_byte & 0xF8) == 0xE8) {
1001 default: UnimplementedInstruction();
1005 AppendToBuffer(
"%s st%d", mnem, modrm_byte & 0x7);
1007 AppendToBuffer(
"%s", mnem);
1017 int DisassemblerX64::TwoByteOpcodeInstruction(
byte* data) {
1018 byte opcode = *(data + 1);
1019 byte* current = data + 2;
1021 const char* mnemonic = TwoByteMnemonic(opcode);
1022 if (operand_size_ == 0x66) {
1025 if (opcode == 0x3A) {
1026 byte third_byte = *current;
1028 if (third_byte == 0x17) {
1029 get_modrm(*current, &mod, ®op, &rm);
1030 AppendToBuffer(
"extractps ");
1031 current += PrintRightOperand(current);
1032 AppendToBuffer(
", %s, %d", NameOfCPURegister(regop), (*current) & 3);
1034 }
else if (third_byte == 0x0b) {
1035 get_modrm(*current, &mod, ®op, &rm);
1037 AppendToBuffer(
"roundsd %s, ", NameOfCPURegister(regop));
1038 current += PrintRightOperand(current);
1039 AppendToBuffer(
", %d", (*current) & 3);
1042 UnimplementedInstruction();
1045 get_modrm(*current, &mod, ®op, &rm);
1046 if (opcode == 0x1f) {
1053 }
else if (mod == 2) {
1056 AppendToBuffer(
"nop");
1057 }
else if (opcode == 0x28) {
1058 AppendToBuffer(
"movapd %s, ", NameOfXMMRegister(regop));
1059 current += PrintRightXMMOperand(current);
1060 }
else if (opcode == 0x29) {
1061 AppendToBuffer(
"movapd ");
1062 current += PrintRightXMMOperand(current);
1063 AppendToBuffer(
", %s", NameOfXMMRegister(regop));
1064 }
else if (opcode == 0x6E) {
1065 AppendToBuffer(
"mov%c %s,",
1066 rex_w() ?
'q' :
'd',
1067 NameOfXMMRegister(regop));
1068 current += PrintRightOperand(current);
1069 }
else if (opcode == 0x6F) {
1070 AppendToBuffer(
"movdqa %s,",
1071 NameOfXMMRegister(regop));
1072 current += PrintRightXMMOperand(current);
1073 }
else if (opcode == 0x7E) {
1074 AppendToBuffer(
"mov%c ",
1075 rex_w() ?
'q' :
'd');
1076 current += PrintRightOperand(current);
1077 AppendToBuffer(
", %s", NameOfXMMRegister(regop));
1078 }
else if (opcode == 0x7F) {
1079 AppendToBuffer(
"movdqa ");
1080 current += PrintRightXMMOperand(current);
1081 AppendToBuffer(
", %s", NameOfXMMRegister(regop));
1082 }
else if (opcode == 0xD6) {
1083 AppendToBuffer(
"movq ");
1084 current += PrintRightXMMOperand(current);
1085 AppendToBuffer(
", %s", NameOfXMMRegister(regop));
1086 }
else if (opcode == 0x50) {
1087 AppendToBuffer(
"movmskpd %s,", NameOfCPURegister(regop));
1088 current += PrintRightXMMOperand(current);
1090 const char* mnemonic =
"?";
1091 if (opcode == 0x54) {
1093 }
else if (opcode == 0x56) {
1095 }
else if (opcode == 0x57) {
1097 }
else if (opcode == 0x2E) {
1098 mnemonic =
"ucomisd";
1099 }
else if (opcode == 0x2F) {
1100 mnemonic =
"comisd";
1102 UnimplementedInstruction();
1104 AppendToBuffer(
"%s %s,", mnemonic, NameOfXMMRegister(regop));
1105 current += PrintRightXMMOperand(current);
1108 }
else if (group_1_prefix_ == 0xF2) {
1111 if (opcode == 0x11 || opcode == 0x10) {
1113 AppendToBuffer(
"movsd ");
1115 get_modrm(*current, &mod, ®op, &rm);
1116 if (opcode == 0x11) {
1117 current += PrintRightXMMOperand(current);
1118 AppendToBuffer(
",%s", NameOfXMMRegister(regop));
1120 AppendToBuffer(
"%s,", NameOfXMMRegister(regop));
1121 current += PrintRightXMMOperand(current);
1123 }
else if (opcode == 0x2A) {
1126 get_modrm(*current, &mod, ®op, &rm);
1127 AppendToBuffer(
"%sd %s,", mnemonic, NameOfXMMRegister(regop));
1128 current += PrintRightOperand(current);
1129 }
else if (opcode == 0x2C) {
1133 get_modrm(*current, &mod, ®op, &rm);
1134 AppendToBuffer(
"cvttsd2si%c %s,",
1135 operand_size_code(), NameOfCPURegister(regop));
1136 current += PrintRightXMMOperand(current);
1137 }
else if (opcode == 0x2D) {
1140 get_modrm(*current, &mod, ®op, &rm);
1141 AppendToBuffer(
"cvtsd2si%c %s,",
1142 operand_size_code(), NameOfCPURegister(regop));
1143 current += PrintRightXMMOperand(current);
1144 }
else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
1147 get_modrm(*current, &mod, ®op, &rm);
1148 AppendToBuffer(
"%s %s,", mnemonic, NameOfXMMRegister(regop));
1149 current += PrintRightXMMOperand(current);
1151 UnimplementedInstruction();
1153 }
else if (group_1_prefix_ == 0xF3) {
1155 if (opcode == 0x11 || opcode == 0x10) {
1157 AppendToBuffer(
"movss ");
1159 get_modrm(*current, &mod, ®op, &rm);
1160 if (opcode == 0x11) {
1161 current += PrintRightOperand(current);
1162 AppendToBuffer(
",%s", NameOfXMMRegister(regop));
1164 AppendToBuffer(
"%s,", NameOfXMMRegister(regop));
1165 current += PrintRightOperand(current);
1167 }
else if (opcode == 0x2A) {
1170 get_modrm(*current, &mod, ®op, &rm);
1171 AppendToBuffer(
"%ss %s,", mnemonic, NameOfXMMRegister(regop));
1172 current += PrintRightOperand(current);
1173 }
else if (opcode == 0x2C) {
1177 get_modrm(*current, &mod, ®op, &rm);
1178 AppendToBuffer(
"cvttss2si%c %s,",
1179 operand_size_code(), NameOfCPURegister(regop));
1180 current += PrintRightXMMOperand(current);
1181 }
else if (opcode == 0x5A) {
1185 get_modrm(*current, &mod, ®op, &rm);
1186 AppendToBuffer(
"cvtss2sd %s,", NameOfXMMRegister(regop));
1187 current += PrintRightXMMOperand(current);
1188 }
else if (opcode == 0x7E) {
1190 get_modrm(*current, &mod, ®op, &rm);
1191 AppendToBuffer(
"movq %s, ", NameOfXMMRegister(regop));
1192 current += PrintRightXMMOperand(current);
1194 UnimplementedInstruction();
1196 }
else if (opcode == 0x1F) {
1199 get_modrm(*current, &mod, ®op, &rm);
1206 }
else if (mod == 2) {
1209 AppendToBuffer(
"nop");
1211 }
else if (opcode == 0x28) {
1214 get_modrm(*current, &mod, ®op, &rm);
1215 AppendToBuffer(
"movaps %s, ", NameOfXMMRegister(regop));
1216 current += PrintRightXMMOperand(current);
1218 }
else if (opcode == 0x29) {
1221 get_modrm(*current, &mod, ®op, &rm);
1222 AppendToBuffer(
"movaps ");
1223 current += PrintRightXMMOperand(current);
1224 AppendToBuffer(
", %s", NameOfXMMRegister(regop));
1226 }
else if (opcode == 0xA2 || opcode == 0x31) {
1228 AppendToBuffer(
"%s", mnemonic);
1230 }
else if ((opcode & 0xF0) == 0x40) {
1232 int condition = opcode & 0x0F;
1233 const InstructionDesc& idesc = cmov_instructions[condition];
1234 byte_size_operand_ = idesc.byte_size_operation;
1235 current += PrintOperands(idesc.mnem, idesc.op_order_, current);
1237 }
else if (opcode == 0x57) {
1240 get_modrm(*current, &mod, ®op, &rm);
1241 AppendToBuffer(
"xorps %s, ", NameOfXMMRegister(regop));
1242 current += PrintRightXMMOperand(current);
1244 }
else if ((opcode & 0xF0) == 0x80) {
1246 current = data + JumpConditional(data);
1248 }
else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
1249 opcode == 0xB7 || opcode == 0xAF) {
1251 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1253 }
else if ((opcode & 0xF0) == 0x90) {
1255 current = data +
SetCC(data);
1257 }
else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
1259 AppendToBuffer(
"%s ", mnemonic);
1261 get_modrm(*current, &mod, ®op, &rm);
1262 current += PrintRightOperand(current);
1263 if (opcode == 0xAB) {
1264 AppendToBuffer(
",%s", NameOfCPURegister(regop));
1266 AppendToBuffer(
",%s,cl", NameOfCPURegister(regop));
1269 UnimplementedInstruction();
1271 return static_cast<int>(current - data);
1278 const char* DisassemblerX64::TwoByteMnemonic(
byte opcode) {
1323 tmp_buffer_pos_ = 0;
1325 bool processed =
true;
1332 if (current == OPERAND_SIZE_OVERRIDE_PREFIX) {
1333 operand_size_ = current;
1334 }
else if ((current & 0xF0) == 0x40) {
1336 if (rex_w()) AppendToBuffer(
"REX.W ");
1337 }
else if ((current & 0xFE) == 0xF2) {
1338 group_1_prefix_ = current;
1345 const InstructionDesc& idesc = instruction_table_->Get(current);
1346 byte_size_operand_ = idesc.byte_size_operation;
1347 switch (idesc.type) {
1348 case ZERO_OPERANDS_INSTR:
1349 if (current >= 0xA4 && current <= 0xA7) {
1351 if (group_1_prefix_ == REP_PREFIX) {
1353 AppendToBuffer(
"rep ");
1355 if (rex_w()) AppendToBuffer(
"REX.W ");
1356 AppendToBuffer(
"%s%c", idesc.mnem, operand_size_code());
1358 AppendToBuffer(
"%s", idesc.mnem, operand_size_code());
1363 case TWO_OPERANDS_INSTR:
1365 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1368 case JUMP_CONDITIONAL_SHORT_INSTR:
1369 data += JumpConditionalShort(data);
1372 case REGISTER_INSTR:
1373 AppendToBuffer(
"%s%c %s",
1375 operand_size_code(),
1376 NameOfCPURegister(base_reg(current & 0x07)));
1380 AppendToBuffer(
"%s %s",
1382 NameOfCPURegister(base_reg(current & 0x07)));
1385 case MOVE_REG_INSTR: {
1387 switch (operand_size()) {
1389 addr =
reinterpret_cast<byte*
>(*
reinterpret_cast<int16_t*
>(data + 1));
1392 case DOUBLEWORD_SIZE:
1393 addr =
reinterpret_cast<byte*
>(*
reinterpret_cast<int32_t*
>(data + 1));
1397 addr =
reinterpret_cast<byte*
>(*
reinterpret_cast<int64_t*
>(data + 1));
1403 AppendToBuffer(
"mov%c %s,%s",
1404 operand_size_code(),
1405 NameOfCPURegister(base_reg(current & 0x07)),
1406 NameOfAddress(addr));
1410 case CALL_JUMP_INSTR: {
1411 byte* addr = data + *
reinterpret_cast<int32_t*
>(data + 1) + 5;
1412 AppendToBuffer(
"%s %s", idesc.mnem, NameOfAddress(addr));
1417 case SHORT_IMMEDIATE_INSTR: {
1419 reinterpret_cast<byte*
>(*
reinterpret_cast<int32_t*
>(data + 1));
1420 AppendToBuffer(
"%s rax, %s", idesc.mnem, NameOfAddress(addr));
1438 AppendToBuffer(
"ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1));
1445 get_modrm(*(data + 1), &mod, ®op, &rm);
1446 int32_t imm = *data == 0x6B ? *(data + 2)
1447 : *reinterpret_cast<int32_t*>(data + 2);
1448 AppendToBuffer(
"imul%c %s,%s,0x%x",
1449 operand_size_code(),
1450 NameOfCPURegister(regop),
1451 NameOfCPURegister(rm), imm);
1452 data += 2 + (*data == 0x6B ? 1 : 4);
1458 data += PrintImmediateOp(data);
1462 data += TwoByteOpcodeInstruction(data);
1468 get_modrm(*data, &mod, ®op, &rm);
1470 AppendToBuffer(
"pop ");
1471 data += PrintRightOperand(data);
1479 get_modrm(*data, &mod, ®op, &rm);
1480 const char* mnem =
NULL;
1500 AppendToBuffer(((regop <= 1) ?
"%s%c " :
"%s "),
1502 operand_size_code());
1503 data += PrintRightOperand(data);
1510 bool is_byte = *data == 0xC6;
1513 AppendToBuffer(
"movb ");
1514 data += PrintRightByteOperand(data);
1516 AppendToBuffer(
",0x%x", imm);
1519 AppendToBuffer(
"mov%c ", operand_size_code());
1520 data += PrintRightOperand(data);
1522 AppendToBuffer(
",0x%x", imm);
1530 AppendToBuffer(
"cmpb ");
1531 data += PrintRightByteOperand(data);
1533 AppendToBuffer(
",0x%x", imm);
1541 bool is_byte = *data == 0x88;
1544 get_modrm(*data, &mod, ®op, &rm);
1546 AppendToBuffer(
"movb ");
1547 data += PrintRightByteOperand(data);
1548 AppendToBuffer(
",%s", NameOfByteCPURegister(regop));
1550 AppendToBuffer(
"mov%c ", operand_size_code());
1551 data += PrintRightOperand(data);
1552 AppendToBuffer(
",%s", NameOfCPURegister(regop));
1565 int reg = (*data & 0x7) | (rex_b() ? 8 : 0);
1567 AppendToBuffer(
"nop");
1569 AppendToBuffer(
"xchg%c rax, %s",
1570 operand_size_code(),
1571 NameOfCPURegister(reg));
1593 byte opcode = *data;
1595 bool is_32bit = (opcode >= 0xB8);
1596 int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
1598 AppendToBuffer(
"mov%c %s, ",
1599 operand_size_code(),
1600 NameOfCPURegister(reg));
1601 data += PrintImmediate(data, DOUBLEWORD_SIZE);
1603 AppendToBuffer(
"movb %s, ",
1604 NameOfByteCPURegister(reg));
1605 data += PrintImmediate(data, BYTE_SIZE);
1612 get_modrm(*data, &mod, ®op, &rm);
1614 AppendToBuffer(
"decb ");
1615 data += PrintRightByteOperand(data);
1617 UnimplementedInstruction();
1622 AppendToBuffer(
"push 0x%x", *reinterpret_cast<int32_t*>(data + 1));
1627 AppendToBuffer(
"push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1633 switch (operand_size()) {
1634 case DOUBLEWORD_SIZE: {
1635 const char* memory_location = NameOfAddress(
1636 reinterpret_cast<byte*>(
1637 *reinterpret_cast<int32_t*>(data + 1)));
1638 if (*data == 0xA1) {
1639 AppendToBuffer(
"movzxlq rax,(%s)", memory_location);
1641 AppendToBuffer(
"movzxlq (%s),rax", memory_location);
1646 case QUADWORD_SIZE: {
1648 const char* memory_location = NameOfAddress(
1649 *reinterpret_cast<byte**>(data + 1));
1650 if (*data == 0xA1) {
1651 AppendToBuffer(
"movq rax,(%s)", memory_location);
1653 AppendToBuffer(
"movq (%s),rax", memory_location);
1659 UnimplementedInstruction();
1665 AppendToBuffer(
"test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1));
1671 switch (operand_size()) {
1673 value = *
reinterpret_cast<uint16_t*
>(data + 1);
1676 case DOUBLEWORD_SIZE:
1677 value = *
reinterpret_cast<uint32_t*
>(data + 1);
1681 value = *
reinterpret_cast<int32_t*
>(data + 1);
1688 operand_size_code(),
1695 data += ShiftInstruction(data);
1700 byte_size_operand_ =
true;
1701 data += ShiftInstruction(data);
1711 data += FPUInstruction(data);
1715 data += JumpShort(data);
1719 byte_size_operand_ =
true;
1721 data += F6F7Instruction(data);
1725 UnimplementedInstruction();
1730 if (tmp_buffer_pos_ <
sizeof tmp_buffer_) {
1731 tmp_buffer_[tmp_buffer_pos_] =
'\0';
1734 int instr_len =
static_cast<int>(data - instr);
1739 for (
byte* bp = instr; bp < data; bp++) {
1742 for (
int i = 6 - instr_len; i >= 0; i--) {
1747 tmp_buffer_.
start());
1754 static const char* cpu_regs[16] = {
1755 "rax",
"rcx",
"rdx",
"rbx",
"rsp",
"rbp",
"rsi",
"rdi",
1756 "r8",
"r9",
"r10",
"r11",
"r12",
"r13",
"r14",
"r15"
1760 static const char* byte_cpu_regs[16] = {
1761 "al",
"cl",
"dl",
"bl",
"spl",
"bpl",
"sil",
"dil",
1762 "r8l",
"r9l",
"r10l",
"r11l",
"r12l",
"r13l",
"r14l",
"r15l"
1766 static const char* xmm_regs[16] = {
1767 "xmm0",
"xmm1",
"xmm2",
"xmm3",
"xmm4",
"xmm5",
"xmm6",
"xmm7",
1768 "xmm8",
"xmm9",
"xmm10",
"xmm11",
"xmm12",
"xmm13",
"xmm14",
"xmm15"
1784 if (0 <= reg && reg < 16)
1785 return cpu_regs[reg];
1791 if (0 <= reg && reg < 16)
1792 return byte_cpu_regs[reg];
1798 if (0 <= reg && reg < 16)
1799 return xmm_regs[reg];
1813 : converter_(converter) { }
1815 Disassembler::~Disassembler() { }
1819 byte* instruction) {
1820 DisassemblerX64 d(converter_, CONTINUE_ON_UNIMPLEMENTED_OPCODE);
1821 return d.InstructionDecode(buffer, instruction);
1826 int Disassembler::ConstantPoolSizeAt(
byte* instruction) {
1831 void Disassembler::Disassemble(FILE* f,
byte* begin,
byte* end) {
1832 NameConverter converter;
1833 Disassembler d(converter);
1834 for (
byte*
pc = begin;
pc < end;) {
1838 pc += d.InstructionDecode(buffer,
pc);
1839 fprintf(f,
"%p", prev_pc);
1842 for (
byte* bp = prev_pc; bp <
pc; bp++) {
1843 fprintf(f,
"%02x", *bp);
1845 for (
int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) {
1848 fprintf(f,
" %s\n", buffer.
start());
1854 #endif // V8_TARGET_ARCH_X64
Disassembler(const NameConverter &converter)
static int VSNPrintF(Vector< char > str, const char *format, va_list args)
virtual const char * NameOfXMMRegister(int reg) const
v8::internal::EmbeddedVector< char, 128 > tmp_buffer_
virtual const char * NameOfConstant(byte *addr) const
#define ASSERT(condition)
virtual const char * NameInCode(byte *addr) const
virtual const char * NameOfByteCPURegister(int reg) const
virtual const char * NameOfCPURegister(int reg) const
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination trace on stack replacement optimize closures functions with arguments object optimize functions containing for in loops profiler considers IC stability primitive functions trigger their own optimization re try self optimization if it failed insert an interrupt check at function exit execution budget before interrupt is triggered call count before self optimization self_optimization count_based_interrupts weighted_back_edges trace_opt emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 enable use of ARMv7 instructions if enable use of MIPS FPU instructions if NULL
virtual const char * NameOfAddress(byte *addr) const
static int SNPrintF(Vector< char > str, const char *format,...)
#define ASSERT_EQ(v1, v2)
#define ASSERT_NE(v1, v2)
#define LAZY_INSTANCE_INITIALIZER