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;
713 UnimplementedInstruction();
715 AppendToBuffer(
"%s%c %s",
718 NameOfCPURegister(rm));
720 }
else if (regop == 0) {
721 AppendToBuffer(
"test%c ", operand_size_code());
722 int count = PrintRightOperand(data + 1);
723 AppendToBuffer(
",0x");
724 count += PrintImmediate(data + 1 + count, operand_size());
727 UnimplementedInstruction();
733 int DisassemblerX64::ShiftInstruction(
byte* data) {
734 byte op = *data & (~1);
735 if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
736 UnimplementedInstruction();
739 byte modrm = *(data + 1);
741 get_modrm(modrm, &mod, ®op, &rm);
746 UnimplementedInstruction();
749 const char* mnem =
NULL;
773 UnimplementedInstruction();
779 }
else if (op == 0xC0) {
783 AppendToBuffer(
"%s%c %s,",
786 byte_size_operand_ ? NameOfByteCPURegister(rm)
787 : NameOfCPURegister(rm));
789 AppendToBuffer(
"cl");
791 AppendToBuffer(
"%d", imm8);
798 int DisassemblerX64::JumpShort(
byte* data) {
800 byte b = *(data + 1);
801 byte* dest = data +
static_cast<int8_t
>(b) + 2;
802 AppendToBuffer(
"jmp %s", NameOfAddress(dest));
808 int DisassemblerX64::JumpConditional(
byte* data) {
810 byte cond = *(data + 1) & 0x0F;
811 byte* dest = data + *
reinterpret_cast<int32_t*
>(data + 2) + 6;
812 const char* mnem = conditional_code_suffix[cond];
813 AppendToBuffer(
"j%s %s", mnem, NameOfAddress(dest));
819 int DisassemblerX64::JumpConditionalShort(
byte* data) {
820 byte cond = *data & 0x0F;
821 byte b = *(data + 1);
822 byte* dest = data +
static_cast<int8_t
>(b) + 2;
823 const char* mnem = conditional_code_suffix[cond];
824 AppendToBuffer(
"j%s %s", mnem, NameOfAddress(dest));
832 byte cond = *(data + 1) & 0x0F;
833 const char* mnem = conditional_code_suffix[cond];
834 AppendToBuffer(
"set%s%c ", mnem, operand_size_code());
835 PrintRightByteOperand(data + 2);
841 int DisassemblerX64::FPUInstruction(
byte* data) {
842 byte escape_opcode = *data;
844 byte modrm_byte = *(data+1);
846 if (modrm_byte >= 0xC0) {
847 return RegisterFPUInstruction(escape_opcode, modrm_byte);
849 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
853 int DisassemblerX64::MemoryFPUInstruction(
int escape_opcode,
856 const char* mnem =
"?";
857 int regop = (modrm_byte >> 3) & 0x7;
858 switch (escape_opcode) {
859 case 0xD9:
switch (regop) {
860 case 0: mnem =
"fld_s";
break;
861 case 3: mnem =
"fstp_s";
break;
862 case 7: mnem =
"fstcw";
break;
863 default: UnimplementedInstruction();
867 case 0xDB:
switch (regop) {
868 case 0: mnem =
"fild_s";
break;
869 case 1: mnem =
"fisttp_s";
break;
870 case 2: mnem =
"fist_s";
break;
871 case 3: mnem =
"fistp_s";
break;
872 default: UnimplementedInstruction();
876 case 0xDD:
switch (regop) {
877 case 0: mnem =
"fld_d";
break;
878 case 3: mnem =
"fstp_d";
break;
879 default: UnimplementedInstruction();
883 case 0xDF:
switch (regop) {
884 case 5: mnem =
"fild_d";
break;
885 case 7: mnem =
"fistp_d";
break;
886 default: UnimplementedInstruction();
890 default: UnimplementedInstruction();
892 AppendToBuffer(
"%s ", mnem);
893 int count = PrintRightOperand(modrm_start);
897 int DisassemblerX64::RegisterFPUInstruction(
int escape_opcode,
899 bool has_register =
false;
900 const char* mnem =
"?";
902 switch (escape_opcode) {
904 UnimplementedInstruction();
908 switch (modrm_byte & 0xF8) {
918 switch (modrm_byte) {
919 case 0xE0: mnem =
"fchs";
break;
920 case 0xE1: mnem =
"fabs";
break;
921 case 0xE3: mnem =
"fninit";
break;
922 case 0xE4: mnem =
"ftst";
break;
923 case 0xE8: mnem =
"fld1";
break;
924 case 0xEB: mnem =
"fldpi";
break;
925 case 0xED: mnem =
"fldln2";
break;
926 case 0xEE: mnem =
"fldz";
break;
927 case 0xF0: mnem =
"f2xm1";
break;
928 case 0xF1: mnem =
"fyl2x";
break;
929 case 0xF2: mnem =
"fptan";
break;
930 case 0xF5: mnem =
"fprem1";
break;
931 case 0xF7: mnem =
"fincstp";
break;
932 case 0xF8: mnem =
"fprem";
break;
933 case 0xFD: mnem =
"fscale";
break;
934 case 0xFE: mnem =
"fsin";
break;
935 case 0xFF: mnem =
"fcos";
break;
936 default: UnimplementedInstruction();
942 if (modrm_byte == 0xE9) {
945 UnimplementedInstruction();
950 if ((modrm_byte & 0xF8) == 0xE8) {
953 }
else if (modrm_byte == 0xE2) {
956 UnimplementedInstruction();
962 switch (modrm_byte & 0xF8) {
963 case 0xC0: mnem =
"fadd";
break;
964 case 0xE8: mnem =
"fsub";
break;
965 case 0xC8: mnem =
"fmul";
break;
966 case 0xF8: mnem =
"fdiv";
break;
967 default: UnimplementedInstruction();
973 switch (modrm_byte & 0xF8) {
974 case 0xC0: mnem =
"ffree";
break;
975 case 0xD8: mnem =
"fstp";
break;
976 default: UnimplementedInstruction();
981 if (modrm_byte == 0xD9) {
985 switch (modrm_byte & 0xF8) {
986 case 0xC0: mnem =
"faddp";
break;
987 case 0xE8: mnem =
"fsubp";
break;
988 case 0xC8: mnem =
"fmulp";
break;
989 case 0xF8: mnem =
"fdivp";
break;
990 default: UnimplementedInstruction();
996 if (modrm_byte == 0xE0) {
998 }
else if ((modrm_byte & 0xF8) == 0xE8) {
1000 has_register =
true;
1004 default: UnimplementedInstruction();
1008 AppendToBuffer(
"%s st%d", mnem, modrm_byte & 0x7);
1010 AppendToBuffer(
"%s", mnem);
1020 int DisassemblerX64::TwoByteOpcodeInstruction(
byte* data) {
1021 byte opcode = *(data + 1);
1022 byte* current = data + 2;
1024 const char* mnemonic = TwoByteMnemonic(opcode);
1025 if (operand_size_ == 0x66) {
1028 if (opcode == 0x3A) {
1029 byte third_byte = *current;
1031 if (third_byte == 0x17) {
1032 get_modrm(*current, &mod, ®op, &rm);
1033 AppendToBuffer(
"extractps ");
1034 current += PrintRightOperand(current);
1035 AppendToBuffer(
", %s, %d", NameOfCPURegister(regop), (*current) & 3);
1037 }
else if (third_byte == 0x0b) {
1038 get_modrm(*current, &mod, ®op, &rm);
1040 AppendToBuffer(
"roundsd %s, ", NameOfCPURegister(regop));
1041 current += PrintRightOperand(current);
1042 AppendToBuffer(
", %d", (*current) & 3);
1045 UnimplementedInstruction();
1048 get_modrm(*current, &mod, ®op, &rm);
1049 if (opcode == 0x1f) {
1056 }
else if (mod == 2) {
1059 AppendToBuffer(
"nop");
1060 }
else if (opcode == 0x28) {
1061 AppendToBuffer(
"movapd %s, ", NameOfXMMRegister(regop));
1062 current += PrintRightXMMOperand(current);
1063 }
else if (opcode == 0x29) {
1064 AppendToBuffer(
"movapd ");
1065 current += PrintRightXMMOperand(current);
1066 AppendToBuffer(
", %s", NameOfXMMRegister(regop));
1067 }
else if (opcode == 0x6E) {
1068 AppendToBuffer(
"mov%c %s,",
1069 rex_w() ?
'q' :
'd',
1070 NameOfXMMRegister(regop));
1071 current += PrintRightOperand(current);
1072 }
else if (opcode == 0x6F) {
1073 AppendToBuffer(
"movdqa %s,",
1074 NameOfXMMRegister(regop));
1075 current += PrintRightXMMOperand(current);
1076 }
else if (opcode == 0x7E) {
1077 AppendToBuffer(
"mov%c ",
1078 rex_w() ?
'q' :
'd');
1079 current += PrintRightOperand(current);
1080 AppendToBuffer(
", %s", NameOfXMMRegister(regop));
1081 }
else if (opcode == 0x7F) {
1082 AppendToBuffer(
"movdqa ");
1083 current += PrintRightXMMOperand(current);
1084 AppendToBuffer(
", %s", NameOfXMMRegister(regop));
1085 }
else if (opcode == 0xD6) {
1086 AppendToBuffer(
"movq ");
1087 current += PrintRightXMMOperand(current);
1088 AppendToBuffer(
", %s", NameOfXMMRegister(regop));
1089 }
else if (opcode == 0x50) {
1090 AppendToBuffer(
"movmskpd %s,", NameOfCPURegister(regop));
1091 current += PrintRightXMMOperand(current);
1093 const char* mnemonic =
"?";
1094 if (opcode == 0x54) {
1096 }
else if (opcode == 0x56) {
1098 }
else if (opcode == 0x57) {
1100 }
else if (opcode == 0x2E) {
1101 mnemonic =
"ucomisd";
1102 }
else if (opcode == 0x2F) {
1103 mnemonic =
"comisd";
1105 UnimplementedInstruction();
1107 AppendToBuffer(
"%s %s,", mnemonic, NameOfXMMRegister(regop));
1108 current += PrintRightXMMOperand(current);
1111 }
else if (group_1_prefix_ == 0xF2) {
1114 if (opcode == 0x11 || opcode == 0x10) {
1116 AppendToBuffer(
"movsd ");
1118 get_modrm(*current, &mod, ®op, &rm);
1119 if (opcode == 0x11) {
1120 current += PrintRightXMMOperand(current);
1121 AppendToBuffer(
",%s", NameOfXMMRegister(regop));
1123 AppendToBuffer(
"%s,", NameOfXMMRegister(regop));
1124 current += PrintRightXMMOperand(current);
1126 }
else if (opcode == 0x2A) {
1129 get_modrm(*current, &mod, ®op, &rm);
1130 AppendToBuffer(
"%sd %s,", mnemonic, NameOfXMMRegister(regop));
1131 current += PrintRightOperand(current);
1132 }
else if (opcode == 0x2C) {
1136 get_modrm(*current, &mod, ®op, &rm);
1137 AppendToBuffer(
"cvttsd2si%c %s,",
1138 operand_size_code(), NameOfCPURegister(regop));
1139 current += PrintRightXMMOperand(current);
1140 }
else if (opcode == 0x2D) {
1143 get_modrm(*current, &mod, ®op, &rm);
1144 AppendToBuffer(
"cvtsd2si%c %s,",
1145 operand_size_code(), NameOfCPURegister(regop));
1146 current += PrintRightXMMOperand(current);
1147 }
else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
1150 get_modrm(*current, &mod, ®op, &rm);
1151 AppendToBuffer(
"%s %s,", mnemonic, NameOfXMMRegister(regop));
1152 current += PrintRightXMMOperand(current);
1154 UnimplementedInstruction();
1156 }
else if (group_1_prefix_ == 0xF3) {
1158 if (opcode == 0x11 || opcode == 0x10) {
1160 AppendToBuffer(
"movss ");
1162 get_modrm(*current, &mod, ®op, &rm);
1163 if (opcode == 0x11) {
1164 current += PrintRightOperand(current);
1165 AppendToBuffer(
",%s", NameOfXMMRegister(regop));
1167 AppendToBuffer(
"%s,", NameOfXMMRegister(regop));
1168 current += PrintRightOperand(current);
1170 }
else if (opcode == 0x2A) {
1173 get_modrm(*current, &mod, ®op, &rm);
1174 AppendToBuffer(
"%ss %s,", mnemonic, NameOfXMMRegister(regop));
1175 current += PrintRightOperand(current);
1176 }
else if (opcode == 0x2C) {
1180 get_modrm(*current, &mod, ®op, &rm);
1181 AppendToBuffer(
"cvttss2si%c %s,",
1182 operand_size_code(), NameOfCPURegister(regop));
1183 current += PrintRightXMMOperand(current);
1184 }
else if (opcode == 0x5A) {
1188 get_modrm(*current, &mod, ®op, &rm);
1189 AppendToBuffer(
"cvtss2sd %s,", NameOfXMMRegister(regop));
1190 current += PrintRightXMMOperand(current);
1191 }
else if (opcode == 0x7E) {
1193 get_modrm(*current, &mod, ®op, &rm);
1194 AppendToBuffer(
"movq %s, ", NameOfXMMRegister(regop));
1195 current += PrintRightXMMOperand(current);
1197 UnimplementedInstruction();
1199 }
else if (opcode == 0x1F) {
1202 get_modrm(*current, &mod, ®op, &rm);
1209 }
else if (mod == 2) {
1212 AppendToBuffer(
"nop");
1214 }
else if (opcode == 0x28) {
1217 get_modrm(*current, &mod, ®op, &rm);
1218 AppendToBuffer(
"movaps %s, ", NameOfXMMRegister(regop));
1219 current += PrintRightXMMOperand(current);
1221 }
else if (opcode == 0x29) {
1224 get_modrm(*current, &mod, ®op, &rm);
1225 AppendToBuffer(
"movaps ");
1226 current += PrintRightXMMOperand(current);
1227 AppendToBuffer(
", %s", NameOfXMMRegister(regop));
1229 }
else if (opcode == 0xA2 || opcode == 0x31) {
1231 AppendToBuffer(
"%s", mnemonic);
1233 }
else if ((opcode & 0xF0) == 0x40) {
1235 int condition = opcode & 0x0F;
1236 const InstructionDesc& idesc = cmov_instructions[condition];
1237 byte_size_operand_ = idesc.byte_size_operation;
1238 current += PrintOperands(idesc.mnem, idesc.op_order_, current);
1240 }
else if (opcode == 0x57) {
1243 get_modrm(*current, &mod, ®op, &rm);
1244 AppendToBuffer(
"xorps %s, ", NameOfXMMRegister(regop));
1245 current += PrintRightXMMOperand(current);
1247 }
else if ((opcode & 0xF0) == 0x80) {
1249 current = data + JumpConditional(data);
1251 }
else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
1252 opcode == 0xB7 || opcode == 0xAF) {
1254 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1256 }
else if ((opcode & 0xF0) == 0x90) {
1258 current = data +
SetCC(data);
1260 }
else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
1262 AppendToBuffer(
"%s ", mnemonic);
1264 get_modrm(*current, &mod, ®op, &rm);
1265 current += PrintRightOperand(current);
1266 if (opcode == 0xAB) {
1267 AppendToBuffer(
",%s", NameOfCPURegister(regop));
1269 AppendToBuffer(
",%s,cl", NameOfCPURegister(regop));
1272 UnimplementedInstruction();
1274 return static_cast<int>(current - data);
1281 const char* DisassemblerX64::TwoByteMnemonic(
byte opcode) {
1326 tmp_buffer_pos_ = 0;
1328 bool processed =
true;
1335 if (current == OPERAND_SIZE_OVERRIDE_PREFIX) {
1336 operand_size_ = current;
1337 }
else if ((current & 0xF0) == 0x40) {
1339 if (rex_w()) AppendToBuffer(
"REX.W ");
1340 }
else if ((current & 0xFE) == 0xF2) {
1341 group_1_prefix_ = current;
1348 const InstructionDesc& idesc = instruction_table_->Get(current);
1349 byte_size_operand_ = idesc.byte_size_operation;
1350 switch (idesc.type) {
1351 case ZERO_OPERANDS_INSTR:
1352 if (current >= 0xA4 && current <= 0xA7) {
1354 if (group_1_prefix_ == REP_PREFIX) {
1356 AppendToBuffer(
"rep ");
1358 if (rex_w()) AppendToBuffer(
"REX.W ");
1359 AppendToBuffer(
"%s%c", idesc.mnem, operand_size_code());
1361 AppendToBuffer(
"%s", idesc.mnem, operand_size_code());
1366 case TWO_OPERANDS_INSTR:
1368 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1371 case JUMP_CONDITIONAL_SHORT_INSTR:
1372 data += JumpConditionalShort(data);
1375 case REGISTER_INSTR:
1376 AppendToBuffer(
"%s%c %s",
1378 operand_size_code(),
1379 NameOfCPURegister(base_reg(current & 0x07)));
1383 AppendToBuffer(
"%s %s",
1385 NameOfCPURegister(base_reg(current & 0x07)));
1388 case MOVE_REG_INSTR: {
1390 switch (operand_size()) {
1392 addr =
reinterpret_cast<byte*
>(*
reinterpret_cast<int16_t*
>(data + 1));
1395 case DOUBLEWORD_SIZE:
1396 addr =
reinterpret_cast<byte*
>(*
reinterpret_cast<int32_t*
>(data + 1));
1400 addr =
reinterpret_cast<byte*
>(*
reinterpret_cast<int64_t*
>(data + 1));
1406 AppendToBuffer(
"mov%c %s,%s",
1407 operand_size_code(),
1408 NameOfCPURegister(base_reg(current & 0x07)),
1409 NameOfAddress(addr));
1413 case CALL_JUMP_INSTR: {
1414 byte* addr = data + *
reinterpret_cast<int32_t*
>(data + 1) + 5;
1415 AppendToBuffer(
"%s %s", idesc.mnem, NameOfAddress(addr));
1420 case SHORT_IMMEDIATE_INSTR: {
1422 reinterpret_cast<byte*
>(*
reinterpret_cast<int32_t*
>(data + 1));
1423 AppendToBuffer(
"%s rax, %s", idesc.mnem, NameOfAddress(addr));
1441 AppendToBuffer(
"ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1));
1448 get_modrm(*(data + 1), &mod, ®op, &rm);
1449 int32_t imm = *data == 0x6B ? *(data + 2)
1450 : *reinterpret_cast<int32_t*>(data + 2);
1451 AppendToBuffer(
"imul%c %s,%s,0x%x",
1452 operand_size_code(),
1453 NameOfCPURegister(regop),
1454 NameOfCPURegister(rm), imm);
1455 data += 2 + (*data == 0x6B ? 1 : 4);
1461 data += PrintImmediateOp(data);
1465 data += TwoByteOpcodeInstruction(data);
1471 get_modrm(*data, &mod, ®op, &rm);
1473 AppendToBuffer(
"pop ");
1474 data += PrintRightOperand(data);
1482 get_modrm(*data, &mod, ®op, &rm);
1483 const char* mnem =
NULL;
1503 AppendToBuffer(((regop <= 1) ?
"%s%c " :
"%s "),
1505 operand_size_code());
1506 data += PrintRightOperand(data);
1513 bool is_byte = *data == 0xC6;
1516 AppendToBuffer(
"movb ");
1517 data += PrintRightByteOperand(data);
1519 AppendToBuffer(
",0x%x", imm);
1522 AppendToBuffer(
"mov%c ", operand_size_code());
1523 data += PrintRightOperand(data);
1525 AppendToBuffer(
",0x%x", imm);
1533 AppendToBuffer(
"cmpb ");
1534 data += PrintRightByteOperand(data);
1536 AppendToBuffer(
",0x%x", imm);
1544 bool is_byte = *data == 0x88;
1547 get_modrm(*data, &mod, ®op, &rm);
1549 AppendToBuffer(
"movb ");
1550 data += PrintRightByteOperand(data);
1551 AppendToBuffer(
",%s", NameOfByteCPURegister(regop));
1553 AppendToBuffer(
"mov%c ", operand_size_code());
1554 data += PrintRightOperand(data);
1555 AppendToBuffer(
",%s", NameOfCPURegister(regop));
1568 int reg = (*data & 0x7) | (rex_b() ? 8 : 0);
1570 AppendToBuffer(
"nop");
1572 AppendToBuffer(
"xchg%c rax, %s",
1573 operand_size_code(),
1574 NameOfCPURegister(reg));
1596 byte opcode = *data;
1598 bool is_32bit = (opcode >= 0xB8);
1599 int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
1601 AppendToBuffer(
"mov%c %s, ",
1602 operand_size_code(),
1603 NameOfCPURegister(reg));
1604 data += PrintImmediate(data, DOUBLEWORD_SIZE);
1606 AppendToBuffer(
"movb %s, ",
1607 NameOfByteCPURegister(reg));
1608 data += PrintImmediate(data, BYTE_SIZE);
1615 get_modrm(*data, &mod, ®op, &rm);
1617 AppendToBuffer(
"decb ");
1618 data += PrintRightByteOperand(data);
1620 UnimplementedInstruction();
1625 AppendToBuffer(
"push 0x%x", *reinterpret_cast<int32_t*>(data + 1));
1630 AppendToBuffer(
"push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1636 switch (operand_size()) {
1637 case DOUBLEWORD_SIZE: {
1638 const char* memory_location = NameOfAddress(
1639 reinterpret_cast<byte*>(
1640 *reinterpret_cast<int32_t*>(data + 1)));
1641 if (*data == 0xA1) {
1642 AppendToBuffer(
"movzxlq rax,(%s)", memory_location);
1644 AppendToBuffer(
"movzxlq (%s),rax", memory_location);
1649 case QUADWORD_SIZE: {
1651 const char* memory_location = NameOfAddress(
1652 *reinterpret_cast<byte**>(data + 1));
1653 if (*data == 0xA1) {
1654 AppendToBuffer(
"movq rax,(%s)", memory_location);
1656 AppendToBuffer(
"movq (%s),rax", memory_location);
1662 UnimplementedInstruction();
1668 AppendToBuffer(
"test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1));
1674 switch (operand_size()) {
1676 value = *
reinterpret_cast<uint16_t*
>(data + 1);
1679 case DOUBLEWORD_SIZE:
1680 value = *
reinterpret_cast<uint32_t*
>(data + 1);
1684 value = *
reinterpret_cast<int32_t*
>(data + 1);
1691 operand_size_code(),
1698 data += ShiftInstruction(data);
1703 byte_size_operand_ =
true;
1704 data += ShiftInstruction(data);
1714 data += FPUInstruction(data);
1718 data += JumpShort(data);
1722 byte_size_operand_ =
true;
1724 data += F6F7Instruction(data);
1728 UnimplementedInstruction();
1733 if (tmp_buffer_pos_ <
sizeof tmp_buffer_) {
1734 tmp_buffer_[tmp_buffer_pos_] =
'\0';
1737 int instr_len =
static_cast<int>(data - instr);
1742 for (
byte* bp = instr; bp < data; bp++) {
1745 for (
int i = 6 - instr_len; i >= 0; i--) {
1750 tmp_buffer_.
start());
1757 static const char* cpu_regs[16] = {
1758 "rax",
"rcx",
"rdx",
"rbx",
"rsp",
"rbp",
"rsi",
"rdi",
1759 "r8",
"r9",
"r10",
"r11",
"r12",
"r13",
"r14",
"r15"
1763 static const char* byte_cpu_regs[16] = {
1764 "al",
"cl",
"dl",
"bl",
"spl",
"bpl",
"sil",
"dil",
1765 "r8l",
"r9l",
"r10l",
"r11l",
"r12l",
"r13l",
"r14l",
"r15l"
1769 static const char* xmm_regs[16] = {
1770 "xmm0",
"xmm1",
"xmm2",
"xmm3",
"xmm4",
"xmm5",
"xmm6",
"xmm7",
1771 "xmm8",
"xmm9",
"xmm10",
"xmm11",
"xmm12",
"xmm13",
"xmm14",
"xmm15"
1787 if (0 <= reg && reg < 16)
1788 return cpu_regs[reg];
1794 if (0 <= reg && reg < 16)
1795 return byte_cpu_regs[reg];
1801 if (0 <= reg && reg < 16)
1802 return xmm_regs[reg];
1816 : converter_(converter) { }
1818 Disassembler::~Disassembler() { }
1822 byte* instruction) {
1823 DisassemblerX64 d(converter_, CONTINUE_ON_UNIMPLEMENTED_OPCODE);
1824 return d.InstructionDecode(buffer, instruction);
1829 int Disassembler::ConstantPoolSizeAt(
byte* instruction) {
1834 void Disassembler::Disassemble(FILE* f,
byte* begin,
byte* end) {
1835 NameConverter converter;
1836 Disassembler d(converter);
1837 for (
byte*
pc = begin;
pc < end;) {
1841 pc += d.InstructionDecode(buffer,
pc);
1842 fprintf(f,
"%p", prev_pc);
1845 for (
byte* bp = prev_pc; bp <
pc; bp++) {
1846 fprintf(f,
"%02x", *bp);
1848 for (
int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) {
1851 fprintf(f,
" %s\n", buffer.
start());
1857 #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 false
virtual const char * NameOfAddress(byte *addr) const
static int SNPrintF(Vector< char > str, const char *format,...)
#define ASSERT_EQ(v1, v2)
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 use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra 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 and VFP2 enable use of VFP2 instructions if available enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of MIPS FPU instructions if NULL
#define ASSERT_NE(v1, v2)
#define LAZY_INSTANCE_INITIALIZER