34 #if defined(V8_TARGET_ARCH_IA32)
53 OperandOrder op_order_;
57 static const ByteMnemonic two_operands_instr[] = {
58 {0x01,
"add", OPER_REG_OP_ORDER},
59 {0x03,
"add", REG_OPER_OP_ORDER},
60 {0x09,
"or", OPER_REG_OP_ORDER},
61 {0x0B,
"or", REG_OPER_OP_ORDER},
62 {0x1B,
"sbb", REG_OPER_OP_ORDER},
63 {0x21,
"and", OPER_REG_OP_ORDER},
64 {0x23,
"and", REG_OPER_OP_ORDER},
65 {0x29,
"sub", OPER_REG_OP_ORDER},
66 {0x2A,
"subb", REG_OPER_OP_ORDER},
67 {0x2B,
"sub", REG_OPER_OP_ORDER},
68 {0x31,
"xor", OPER_REG_OP_ORDER},
69 {0x33,
"xor", REG_OPER_OP_ORDER},
70 {0x38,
"cmpb", OPER_REG_OP_ORDER},
71 {0x3A,
"cmpb", REG_OPER_OP_ORDER},
72 {0x3B,
"cmp", REG_OPER_OP_ORDER},
73 {0x84,
"test_b", REG_OPER_OP_ORDER},
74 {0x85,
"test", REG_OPER_OP_ORDER},
75 {0x87,
"xchg", REG_OPER_OP_ORDER},
76 {0x8A,
"mov_b", REG_OPER_OP_ORDER},
77 {0x8B,
"mov", REG_OPER_OP_ORDER},
78 {0x8D,
"lea", REG_OPER_OP_ORDER},
79 {-1,
"", UNSET_OP_ORDER}
83 static const ByteMnemonic zero_operands_instr[] = {
84 {0xC3,
"ret", UNSET_OP_ORDER},
85 {0xC9,
"leave", UNSET_OP_ORDER},
86 {0x90,
"nop", UNSET_OP_ORDER},
87 {0xF4,
"hlt", UNSET_OP_ORDER},
88 {0xCC,
"int3", UNSET_OP_ORDER},
89 {0x60,
"pushad", UNSET_OP_ORDER},
90 {0x61,
"popad", UNSET_OP_ORDER},
91 {0x9C,
"pushfd", UNSET_OP_ORDER},
92 {0x9D,
"popfd", UNSET_OP_ORDER},
93 {0x9E,
"sahf", UNSET_OP_ORDER},
94 {0x99,
"cdq", UNSET_OP_ORDER},
95 {0x9B,
"fwait", UNSET_OP_ORDER},
96 {0xFC,
"cld", UNSET_OP_ORDER},
97 {0xAB,
"stos", UNSET_OP_ORDER},
98 {-1,
"", UNSET_OP_ORDER}
102 static const ByteMnemonic call_jump_instr[] = {
103 {0xE8,
"call", UNSET_OP_ORDER},
104 {0xE9,
"jmp", UNSET_OP_ORDER},
105 {-1,
"", UNSET_OP_ORDER}
109 static const ByteMnemonic short_immediate_instr[] = {
110 {0x05,
"add", UNSET_OP_ORDER},
111 {0x0D,
"or", UNSET_OP_ORDER},
112 {0x15,
"adc", UNSET_OP_ORDER},
113 {0x25,
"and", UNSET_OP_ORDER},
114 {0x2D,
"sub", UNSET_OP_ORDER},
115 {0x35,
"xor", UNSET_OP_ORDER},
116 {0x3D,
"cmp", UNSET_OP_ORDER},
117 {-1,
"", UNSET_OP_ORDER}
125 static ByteMnemonic byte_immediate_instr[] = {
126 {0x0c,
"or", UNSET_OP_ORDER},
127 {0x24,
"and", UNSET_OP_ORDER},
128 {0x34,
"xor", UNSET_OP_ORDER},
129 {0x3c,
"cmp", UNSET_OP_ORDER},
130 {-1,
"", UNSET_OP_ORDER}
134 static const char*
const jump_conditional_mnem[] = {
135 "jo",
"jno",
"jc",
"jnc",
136 "jz",
"jnz",
"jna",
"ja",
137 "js",
"jns",
"jpe",
"jpo",
138 "jl",
"jnl",
"jng",
"jg"
142 static const char*
const set_conditional_mnem[] = {
143 "seto",
"setno",
"setc",
"setnc",
144 "setz",
"setnz",
"setna",
"seta",
145 "sets",
"setns",
"setpe",
"setpo",
146 "setl",
"setnl",
"setng",
"setg"
150 static const char*
const conditional_move_mnem[] = {
151 "cmovo",
"cmovno",
"cmovc",
"cmovnc",
152 "cmovz",
"cmovnz",
"cmovna",
"cmova",
153 "cmovs",
"cmovns",
"cmovpe",
"cmovpo",
154 "cmovl",
"cmovnl",
"cmovng",
"cmovg"
158 enum InstructionType {
162 JUMP_CONDITIONAL_SHORT_INSTR,
166 SHORT_IMMEDIATE_INSTR,
171 struct InstructionDesc {
173 InstructionType type;
174 OperandOrder op_order_;
178 class InstructionTable {
181 const InstructionDesc& Get(
byte x)
const {
return instructions_[x]; }
182 static InstructionTable* get_instance() {
183 static InstructionTable table;
188 InstructionDesc instructions_[256];
191 void CopyTable(
const ByteMnemonic bm[], InstructionType type);
192 void SetTableRange(InstructionType type,
196 void AddJumpConditionalShort();
200 InstructionTable::InstructionTable() {
206 void InstructionTable::Clear() {
207 for (
int i = 0; i < 256; i++) {
208 instructions_[i].mnem =
"";
209 instructions_[i].type = NO_INSTR;
210 instructions_[i].op_order_ = UNSET_OP_ORDER;
215 void InstructionTable::Init() {
216 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
217 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
218 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
219 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
220 CopyTable(byte_immediate_instr, BYTE_IMMEDIATE_INSTR);
221 AddJumpConditionalShort();
222 SetTableRange(REGISTER_INSTR, 0x40, 0x47,
"inc");
223 SetTableRange(REGISTER_INSTR, 0x48, 0x4F,
"dec");
224 SetTableRange(REGISTER_INSTR, 0x50, 0x57,
"push");
225 SetTableRange(REGISTER_INSTR, 0x58, 0x5F,
"pop");
226 SetTableRange(REGISTER_INSTR, 0x91, 0x97,
"xchg eax,");
227 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF,
"mov");
231 void InstructionTable::CopyTable(
const ByteMnemonic bm[],
232 InstructionType type) {
233 for (
int i = 0; bm[i].b >= 0; i++) {
234 InstructionDesc*
id = &instructions_[bm[i].b];
235 id->mnem = bm[i].mnem;
236 id->op_order_ = bm[i].op_order_;
243 void InstructionTable::SetTableRange(InstructionType type,
247 for (
byte b = start; b <= end; b++) {
248 InstructionDesc*
id = &instructions_[b];
256 void InstructionTable::AddJumpConditionalShort() {
257 for (
byte b = 0x70; b <= 0x7F; b++) {
258 InstructionDesc*
id = &instructions_[b];
260 id->mnem = jump_conditional_mnem[b & 0x0F];
261 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
267 class DisassemblerIA32 {
269 DisassemblerIA32(
const NameConverter& converter,
270 bool abort_on_unimplemented =
true)
271 : converter_(converter),
272 instruction_table_(InstructionTable::get_instance()),
274 abort_on_unimplemented_(abort_on_unimplemented) {
275 tmp_buffer_[0] =
'\0';
278 virtual ~DisassemblerIA32() {}
285 const NameConverter& converter_;
286 InstructionTable* instruction_table_;
288 unsigned int tmp_buffer_pos_;
289 bool abort_on_unimplemented_;
303 enum ShiftOpcodeExtension {
314 const char* NameOfCPURegister(
int reg)
const {
315 return converter_.NameOfCPURegister(reg);
319 const char* NameOfByteCPURegister(
int reg)
const {
320 return converter_.NameOfByteCPURegister(reg);
324 const char* NameOfXMMRegister(
int reg)
const {
325 return converter_.NameOfXMMRegister(reg);
329 const char* NameOfAddress(
byte* addr)
const {
330 return converter_.NameOfAddress(addr);
335 static void get_modrm(
byte data,
int* mod,
int* regop,
int* rm) {
336 *mod = (data >> 6) & 3;
337 *regop = (data & 0x38) >> 3;
342 static void get_sib(
byte data,
int* scale,
int* index,
int* base) {
343 *scale = (data >> 6) & 3;
344 *index = (data >> 3) & 7;
348 typedef const char* (DisassemblerIA32::*RegisterNameMapping)(
int reg)
const;
350 int PrintRightOperandHelper(
byte* modrmp, RegisterNameMapping register_name);
351 int PrintRightOperand(
byte* modrmp);
352 int PrintRightByteOperand(
byte* modrmp);
353 int PrintRightXMMOperand(
byte* modrmp);
354 int PrintOperands(
const char* mnem, OperandOrder op_order,
byte* data);
355 int PrintImmediateOp(
byte* data);
356 int F7Instruction(
byte* data);
357 int D1D3C1Instruction(
byte* data);
358 int JumpShort(
byte* data);
359 int JumpConditional(
byte* data,
const char* comment);
360 int JumpConditionalShort(
byte* data,
const char* comment);
362 int CMov(
byte* data);
363 int FPUInstruction(
byte* data);
364 int MemoryFPUInstruction(
int escape_opcode,
int regop,
byte* modrm_start);
365 int RegisterFPUInstruction(
int escape_opcode,
byte modrm_byte);
366 void AppendToBuffer(
const char* format, ...);
369 void UnimplementedInstruction() {
370 if (abort_on_unimplemented_) {
373 AppendToBuffer(
"'Unimplemented Instruction'");
379 void DisassemblerIA32::AppendToBuffer(
const char* format, ...) {
382 va_start(args, format);
385 tmp_buffer_pos_ += result;
388 int DisassemblerIA32::PrintRightOperandHelper(
390 RegisterNameMapping direct_register_name) {
392 get_modrm(*modrmp, &mod, ®op, &rm);
393 RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
394 &DisassemblerIA32::NameOfCPURegister;
399 AppendToBuffer(
"[0x%x]", disp);
401 }
else if (rm ==
esp) {
402 byte sib = *(modrmp + 1);
403 int scale, index, base;
404 get_sib(sib, &scale, &index, &base);
405 if (index ==
esp && base ==
esp && scale == 0 ) {
406 AppendToBuffer(
"[%s]", (this->*register_name)(rm));
408 }
else if (base ==
ebp) {
410 AppendToBuffer(
"[%s*%d+0x%x]",
411 (this->*register_name)(index),
415 }
else if (index !=
esp && base !=
ebp) {
417 AppendToBuffer(
"[%s+%s*%d]",
418 (this->*register_name)(base),
419 (this->*register_name)(index),
423 UnimplementedInstruction();
427 AppendToBuffer(
"[%s]", (this->*register_name)(rm));
434 byte sib = *(modrmp + 1);
435 int scale, index, base;
436 get_sib(sib, &scale, &index, &base);
438 mod == 2 ? *
reinterpret_cast<int32_t*
>(modrmp + 2) : *(modrmp + 2);
439 if (index == base && index == rm && scale == 0 ) {
440 AppendToBuffer(
"[%s+0x%x]", (this->*register_name)(rm), disp);
442 AppendToBuffer(
"[%s+%s*%d+0x%x]",
443 (this->*register_name)(base),
444 (this->*register_name)(index),
448 return mod == 2 ? 6 : 3;
452 mod == 2 ? *
reinterpret_cast<int32_t*
>(modrmp + 1) : *(modrmp + 1);
453 AppendToBuffer(
"[%s+0x%x]", (this->*register_name)(rm), disp);
454 return mod == 2 ? 5 : 2;
458 AppendToBuffer(
"%s", (this->*register_name)(rm));
461 UnimplementedInstruction();
468 int DisassemblerIA32::PrintRightOperand(
byte* modrmp) {
469 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
473 int DisassemblerIA32::PrintRightByteOperand(
byte* modrmp) {
474 return PrintRightOperandHelper(modrmp,
475 &DisassemblerIA32::NameOfByteCPURegister);
479 int DisassemblerIA32::PrintRightXMMOperand(
byte* modrmp) {
480 return PrintRightOperandHelper(modrmp,
481 &DisassemblerIA32::NameOfXMMRegister);
487 int DisassemblerIA32::PrintOperands(
const char* mnem,
488 OperandOrder op_order,
492 get_modrm(modrm, &mod, ®op, &rm);
495 case REG_OPER_OP_ORDER: {
496 AppendToBuffer(
"%s %s,", mnem, NameOfCPURegister(regop));
497 advance = PrintRightOperand(data);
500 case OPER_REG_OP_ORDER: {
501 AppendToBuffer(
"%s ", mnem);
502 advance = PrintRightOperand(data);
503 AppendToBuffer(
",%s", NameOfCPURegister(regop));
516 int DisassemblerIA32::PrintImmediateOp(
byte* data) {
517 bool sign_extension_bit = (*data & 0x02) != 0;
518 byte modrm = *(data+1);
520 get_modrm(modrm, &mod, ®op, &rm);
521 const char* mnem =
"Imm???";
523 case 0: mnem =
"add";
break;
524 case 1: mnem =
"or";
break;
525 case 2: mnem =
"adc";
break;
526 case 4: mnem =
"and";
break;
527 case 5: mnem =
"sub";
break;
528 case 6: mnem =
"xor";
break;
529 case 7: mnem =
"cmp";
break;
530 default: UnimplementedInstruction();
532 AppendToBuffer(
"%s ", mnem);
533 int count = PrintRightOperand(data+1);
534 if (sign_extension_bit) {
535 AppendToBuffer(
",0x%x", *(data + 1 + count));
536 return 1 + count + 1 ;
538 AppendToBuffer(
",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
539 return 1 + count + 4 ;
545 int DisassemblerIA32::F7Instruction(
byte* data) {
547 byte modrm = *(data+1);
549 get_modrm(modrm, &mod, ®op, &rm);
550 if (mod == 3 && regop != 0) {
551 const char* mnem =
NULL;
553 case 2: mnem =
"not";
break;
554 case 3: mnem =
"neg";
break;
555 case 4: mnem =
"mul";
break;
556 case 5: mnem =
"imul";
break;
557 case 7: mnem =
"idiv";
break;
558 default: UnimplementedInstruction();
560 AppendToBuffer(
"%s %s", mnem, NameOfCPURegister(rm));
562 }
else if (mod == 3 && regop ==
eax) {
564 AppendToBuffer(
"test %s,0x%x", NameOfCPURegister(rm), imm);
566 }
else if (regop ==
eax) {
567 AppendToBuffer(
"test ");
568 int count = PrintRightOperand(data+1);
570 AppendToBuffer(
",0x%x", imm);
573 UnimplementedInstruction();
578 int DisassemblerIA32::D1D3C1Instruction(
byte* data) {
580 ASSERT(op == 0xD1 || op == 0xD3 || op == 0xC1);
581 byte modrm = *(data+1);
583 get_modrm(modrm, &mod, ®op, &rm);
587 const char* mnem =
NULL;
589 case kROL: mnem =
"rol";
break;
590 case kROR: mnem =
"ror";
break;
591 case kRCL: mnem =
"rcl";
break;
592 case kRCR: mnem =
"rcr";
break;
593 case kSHL: mnem =
"shl";
break;
594 case KSHR: mnem =
"shr";
break;
595 case kSAR: mnem =
"sar";
break;
596 default: UnimplementedInstruction();
600 }
else if (op == 0xC1) {
603 }
else if (op == 0xD3) {
607 AppendToBuffer(
"%s %s,", mnem, NameOfCPURegister(rm));
609 AppendToBuffer(
"%d", imm8);
611 AppendToBuffer(
"cl");
614 UnimplementedInstruction();
621 int DisassemblerIA32::JumpShort(
byte* data) {
624 byte* dest = data +
static_cast<int8_t
>(b) + 2;
625 AppendToBuffer(
"jmp %s", NameOfAddress(dest));
631 int DisassemblerIA32::JumpConditional(
byte* data,
const char* comment) {
633 byte cond = *(data+1) & 0x0F;
634 byte* dest = data + *
reinterpret_cast<int32_t*
>(data+2) + 6;
635 const char* mnem = jump_conditional_mnem[cond];
636 AppendToBuffer(
"%s %s", mnem, NameOfAddress(dest));
637 if (comment !=
NULL) {
638 AppendToBuffer(
", %s", comment);
645 int DisassemblerIA32::JumpConditionalShort(
byte* data,
const char* comment) {
646 byte cond = *data & 0x0F;
648 byte* dest = data +
static_cast<int8_t
>(b) + 2;
649 const char* mnem = jump_conditional_mnem[cond];
650 AppendToBuffer(
"%s %s", mnem, NameOfAddress(dest));
651 if (comment !=
NULL) {
652 AppendToBuffer(
", %s", comment);
661 byte cond = *(data+1) & 0x0F;
662 const char* mnem = set_conditional_mnem[cond];
663 AppendToBuffer(
"%s ", mnem);
664 PrintRightByteOperand(data+2);
670 int DisassemblerIA32::CMov(
byte* data) {
672 byte cond = *(data + 1) & 0x0F;
673 const char* mnem = conditional_move_mnem[cond];
674 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
680 int DisassemblerIA32::FPUInstruction(
byte* data) {
681 byte escape_opcode = *data;
683 byte modrm_byte = *(data+1);
685 if (modrm_byte >= 0xC0) {
686 return RegisterFPUInstruction(escape_opcode, modrm_byte);
688 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
692 int DisassemblerIA32::MemoryFPUInstruction(
int escape_opcode,
695 const char* mnem =
"?";
696 int regop = (modrm_byte >> 3) & 0x7;
697 switch (escape_opcode) {
698 case 0xD9:
switch (regop) {
699 case 0: mnem =
"fld_s";
break;
700 case 3: mnem =
"fstp_s";
break;
701 case 7: mnem =
"fstcw";
break;
702 default: UnimplementedInstruction();
706 case 0xDB:
switch (regop) {
707 case 0: mnem =
"fild_s";
break;
708 case 1: mnem =
"fisttp_s";
break;
709 case 2: mnem =
"fist_s";
break;
710 case 3: mnem =
"fistp_s";
break;
711 default: UnimplementedInstruction();
715 case 0xDD:
switch (regop) {
716 case 0: mnem =
"fld_d";
break;
717 case 1: mnem =
"fisttp_d";
break;
718 case 2: mnem =
"fst_d";
break;
719 case 3: mnem =
"fstp_d";
break;
720 default: UnimplementedInstruction();
724 case 0xDF:
switch (regop) {
725 case 5: mnem =
"fild_d";
break;
726 case 7: mnem =
"fistp_d";
break;
727 default: UnimplementedInstruction();
731 default: UnimplementedInstruction();
733 AppendToBuffer(
"%s ", mnem);
734 int count = PrintRightOperand(modrm_start);
738 int DisassemblerIA32::RegisterFPUInstruction(
int escape_opcode,
740 bool has_register =
false;
741 const char* mnem =
"?";
743 switch (escape_opcode) {
745 UnimplementedInstruction();
749 switch (modrm_byte & 0xF8) {
759 switch (modrm_byte) {
760 case 0xE0: mnem =
"fchs";
break;
761 case 0xE1: mnem =
"fabs";
break;
762 case 0xE4: mnem =
"ftst";
break;
763 case 0xE8: mnem =
"fld1";
break;
764 case 0xEB: mnem =
"fldpi";
break;
765 case 0xED: mnem =
"fldln2";
break;
766 case 0xEE: mnem =
"fldz";
break;
767 case 0xF0: mnem =
"f2xm1";
break;
768 case 0xF1: mnem =
"fyl2x";
break;
769 case 0xF5: mnem =
"fprem1";
break;
770 case 0xF7: mnem =
"fincstp";
break;
771 case 0xF8: mnem =
"fprem";
break;
772 case 0xFC: mnem =
"frndint";
break;
773 case 0xFD: mnem =
"fscale";
break;
774 case 0xFE: mnem =
"fsin";
break;
775 case 0xFF: mnem =
"fcos";
break;
776 default: UnimplementedInstruction();
782 if (modrm_byte == 0xE9) {
785 UnimplementedInstruction();
790 if ((modrm_byte & 0xF8) == 0xE8) {
793 }
else if (modrm_byte == 0xE2) {
795 }
else if (modrm_byte == 0xE3) {
798 UnimplementedInstruction();
804 switch (modrm_byte & 0xF8) {
805 case 0xC0: mnem =
"fadd";
break;
806 case 0xE8: mnem =
"fsub";
break;
807 case 0xC8: mnem =
"fmul";
break;
808 case 0xF8: mnem =
"fdiv";
break;
809 default: UnimplementedInstruction();
815 switch (modrm_byte & 0xF8) {
816 case 0xC0: mnem =
"ffree";
break;
817 case 0xD8: mnem =
"fstp";
break;
818 default: UnimplementedInstruction();
823 if (modrm_byte == 0xD9) {
827 switch (modrm_byte & 0xF8) {
828 case 0xC0: mnem =
"faddp";
break;
829 case 0xE8: mnem =
"fsubp";
break;
830 case 0xC8: mnem =
"fmulp";
break;
831 case 0xF8: mnem =
"fdivp";
break;
832 default: UnimplementedInstruction();
838 if (modrm_byte == 0xE0) {
840 }
else if ((modrm_byte & 0xF8) == 0xE8) {
846 default: UnimplementedInstruction();
850 AppendToBuffer(
"%s st%d", mnem, modrm_byte & 0x7);
852 AppendToBuffer(
"%s", mnem);
860 static const char* F0Mnem(
byte f0byte) {
862 case 0x18:
return "prefetch";
863 case 0xA2:
return "cpuid";
864 case 0x31:
return "rdtsc";
865 case 0xBE:
return "movsx_b";
866 case 0xBF:
return "movsx_w";
867 case 0xB6:
return "movzx_b";
868 case 0xB7:
return "movzx_w";
869 case 0xAF:
return "imul";
870 case 0xA5:
return "shld";
871 case 0xAD:
return "shrd";
872 case 0xAB:
return "bts";
873 default:
return NULL;
884 const char* branch_hint =
NULL;
886 if (*data == 0x3E ) {
887 branch_hint =
"predicted taken";
889 }
else if (*data == 0x2E ) {
890 branch_hint =
"predicted not taken";
893 bool processed =
true;
895 const InstructionDesc& idesc = instruction_table_->Get(*data);
896 switch (idesc.type) {
897 case ZERO_OPERANDS_INSTR:
898 AppendToBuffer(idesc.mnem);
902 case TWO_OPERANDS_INSTR:
904 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
907 case JUMP_CONDITIONAL_SHORT_INSTR:
908 data += JumpConditionalShort(data, branch_hint);
912 AppendToBuffer(
"%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
916 case MOVE_REG_INSTR: {
917 byte* addr =
reinterpret_cast<byte*
>(*
reinterpret_cast<int32_t*
>(data+1));
918 AppendToBuffer(
"mov %s,%s",
919 NameOfCPURegister(*data & 0x07),
920 NameOfAddress(addr));
925 case CALL_JUMP_INSTR: {
926 byte* addr = data + *
reinterpret_cast<int32_t*
>(data+1) + 5;
927 AppendToBuffer(
"%s %s", idesc.mnem, NameOfAddress(addr));
932 case SHORT_IMMEDIATE_INSTR: {
933 byte* addr =
reinterpret_cast<byte*
>(*
reinterpret_cast<int32_t*
>(data+1));
934 AppendToBuffer(
"%s eax, %s", idesc.mnem, NameOfAddress(addr));
939 case BYTE_IMMEDIATE_INSTR: {
940 AppendToBuffer(
"%s al, 0x%x", idesc.mnem, data[1]);
956 AppendToBuffer(
"ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
962 {
int mod, regop, rm;
963 get_modrm(*(data+1), &mod, ®op, &rm);
965 *data == 0x6B ? *(data+2) : *reinterpret_cast<int32_t*>(data+2);
966 AppendToBuffer(
"imul %s,%s,0x%x",
967 NameOfCPURegister(regop),
968 NameOfCPURegister(rm),
970 data += 2 + (*data == 0x6B ? 1 : 4);
977 get_modrm(*data, &mod, ®op, &rm);
979 AppendToBuffer(
"test_b ");
980 data += PrintRightByteOperand(data);
982 AppendToBuffer(
",0x%x", imm);
985 UnimplementedInstruction();
992 data += PrintImmediateOp(data);
996 {
byte f0byte = data[1];
997 const char* f0mnem = F0Mnem(f0byte);
998 if (f0byte == 0x18) {
1000 get_modrm(*data, &mod, ®op, &rm);
1001 const char* suffix[] = {
"nta",
"1",
"2",
"3"};
1002 AppendToBuffer(
"%s%s ", f0mnem, suffix[regop & 0x03]);
1003 data += PrintRightOperand(data);
1004 }
else if (f0byte == 0x1F && data[2] == 0) {
1005 AppendToBuffer(
"nop");
1007 }
else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1008 AppendToBuffer(
"nop");
1010 }
else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1012 AppendToBuffer(
"nop");
1014 }
else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1015 data[4] == 0 && data[5] == 0 && data[6] == 0) {
1016 AppendToBuffer(
"nop");
1018 }
else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1019 data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1021 AppendToBuffer(
"nop");
1023 }
else if (f0byte == 0xA2 || f0byte == 0x31) {
1024 AppendToBuffer(
"%s", f0mnem);
1026 }
else if (f0byte == 0x28) {
1029 get_modrm(*data, &mod, ®op, &rm);
1030 AppendToBuffer(
"movaps %s,%s",
1031 NameOfXMMRegister(regop),
1032 NameOfXMMRegister(rm));
1034 }
else if (f0byte == 0x57) {
1037 get_modrm(*data, &mod, ®op, &rm);
1038 AppendToBuffer(
"xorps %s,%s",
1039 NameOfXMMRegister(regop),
1040 NameOfXMMRegister(rm));
1042 }
else if ((f0byte & 0xF0) == 0x80) {
1043 data += JumpConditional(data, branch_hint);
1044 }
else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1045 f0byte == 0xB7 || f0byte == 0xAF) {
1047 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1048 }
else if ((f0byte & 0xF0) == 0x90) {
1049 data +=
SetCC(data);
1050 }
else if ((f0byte & 0xF0) == 0x40) {
1054 if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
1056 AppendToBuffer(
"%s ", f0mnem);
1058 get_modrm(*data, &mod, ®op, &rm);
1059 data += PrintRightOperand(data);
1060 if (f0byte == 0xAB) {
1061 AppendToBuffer(
",%s", NameOfCPURegister(regop));
1063 AppendToBuffer(
",%s,cl", NameOfCPURegister(regop));
1066 UnimplementedInstruction();
1075 get_modrm(*data, &mod, ®op, &rm);
1077 AppendToBuffer(
"pop ");
1078 data += PrintRightOperand(data);
1086 get_modrm(*data, &mod, ®op, &rm);
1087 const char* mnem =
NULL;
1089 case esi: mnem =
"push";
break;
1090 case eax: mnem =
"inc";
break;
1091 case ecx: mnem =
"dec";
break;
1092 case edx: mnem =
"call";
break;
1093 case esp: mnem =
"jmp";
break;
1094 default: mnem =
"???";
1096 AppendToBuffer(
"%s ", mnem);
1097 data += PrintRightOperand(data);
1103 {
bool is_byte = *data == 0xC6;
1106 AppendToBuffer(
"%s ",
"mov_b");
1107 data += PrintRightByteOperand(data);
1109 AppendToBuffer(
",0x%x", imm);
1112 AppendToBuffer(
"%s ",
"mov");
1113 data += PrintRightOperand(data);
1115 AppendToBuffer(
",0x%x", imm);
1124 get_modrm(*data, &mod, ®op, &rm);
1125 const char* mnem =
NULL;
1127 case 5: mnem =
"subb";
break;
1128 case 7: mnem =
"cmpb";
break;
1129 default: UnimplementedInstruction();
1131 AppendToBuffer(
"%s ", mnem);
1132 data += PrintRightByteOperand(data);
1134 AppendToBuffer(
",0x%x", imm);
1141 {
bool is_byte = *data == 0x88;
1144 get_modrm(*data, &mod, ®op, &rm);
1146 AppendToBuffer(
"%s ",
"mov_b");
1147 data += PrintRightByteOperand(data);
1148 AppendToBuffer(
",%s", NameOfByteCPURegister(regop));
1150 AppendToBuffer(
"%s ",
"mov");
1151 data += PrintRightOperand(data);
1152 AppendToBuffer(
",%s", NameOfCPURegister(regop));
1158 while (*data == 0x66) data++;
1159 if (*data == 0xf && data[1] == 0x1f) {
1160 AppendToBuffer(
"nop");
1161 }
else if (*data == 0x90) {
1162 AppendToBuffer(
"nop");
1163 }
else if (*data == 0x8B) {
1165 data += PrintOperands(
"mov_w", REG_OPER_OP_ORDER, data);
1166 }
else if (*data == 0x89) {
1169 get_modrm(*data, &mod, ®op, &rm);
1170 AppendToBuffer(
"mov_w ");
1171 data += PrintRightOperand(data);
1172 AppendToBuffer(
",%s", NameOfCPURegister(regop));
1173 }
else if (*data == 0x0F) {
1175 if (*data == 0x38) {
1177 if (*data == 0x17) {
1180 get_modrm(*data, &mod, ®op, &rm);
1181 AppendToBuffer(
"ptest %s,%s",
1182 NameOfXMMRegister(regop),
1183 NameOfXMMRegister(rm));
1185 }
else if (*data == 0x2A) {
1189 get_modrm(*data, &mod, ®op, &rm);
1190 AppendToBuffer(
"movntdqa %s,", NameOfXMMRegister(regop));
1191 data += PrintRightOperand(data);
1193 UnimplementedInstruction();
1195 }
else if (*data == 0x3A) {
1197 if (*data == 0x0B) {
1200 get_modrm(*data, &mod, ®op, &rm);
1201 int8_t imm8 =
static_cast<int8_t
>(data[1]);
1202 AppendToBuffer(
"roundsd %s,%s,%d",
1203 NameOfXMMRegister(regop),
1204 NameOfXMMRegister(rm),
1205 static_cast<int>(imm8));
1207 }
else if (*data == 0x16) {
1210 get_modrm(*data, &mod, ®op, &rm);
1211 int8_t imm8 =
static_cast<int8_t
>(data[1]);
1212 AppendToBuffer(
"pextrd %s,%s,%d",
1213 NameOfCPURegister(regop),
1214 NameOfXMMRegister(rm),
1215 static_cast<int>(imm8));
1217 }
else if (*data == 0x17) {
1220 get_modrm(*data, &mod, ®op, &rm);
1221 int8_t imm8 =
static_cast<int8_t
>(data[1]);
1222 AppendToBuffer(
"extractps %s,%s,%d",
1223 NameOfCPURegister(regop),
1224 NameOfXMMRegister(rm),
1225 static_cast<int>(imm8));
1227 }
else if (*data == 0x22) {
1230 get_modrm(*data, &mod, ®op, &rm);
1231 int8_t imm8 =
static_cast<int8_t
>(data[1]);
1232 AppendToBuffer(
"pinsrd %s,%s,%d",
1233 NameOfXMMRegister(regop),
1234 NameOfCPURegister(rm),
1235 static_cast<int>(imm8));
1238 UnimplementedInstruction();
1240 }
else if (*data == 0x2E || *data == 0x2F) {
1241 const char* mnem = (*data == 0x2E) ?
"ucomisd" :
"comisd";
1244 get_modrm(*data, &mod, ®op, &rm);
1246 AppendToBuffer(
"%s %s,%s", mnem,
1247 NameOfXMMRegister(regop),
1248 NameOfXMMRegister(rm));
1251 AppendToBuffer(
"%s %s,", mnem, NameOfXMMRegister(regop));
1252 data += PrintRightOperand(data);
1254 }
else if (*data == 0x50) {
1257 get_modrm(*data, &mod, ®op, &rm);
1258 AppendToBuffer(
"movmskpd %s,%s",
1259 NameOfCPURegister(regop),
1260 NameOfXMMRegister(rm));
1262 }
else if (*data == 0x54) {
1265 get_modrm(*data, &mod, ®op, &rm);
1266 AppendToBuffer(
"andpd %s,%s",
1267 NameOfXMMRegister(regop),
1268 NameOfXMMRegister(rm));
1270 }
else if (*data == 0x56) {
1273 get_modrm(*data, &mod, ®op, &rm);
1274 AppendToBuffer(
"orpd %s,%s",
1275 NameOfXMMRegister(regop),
1276 NameOfXMMRegister(rm));
1278 }
else if (*data == 0x57) {
1281 get_modrm(*data, &mod, ®op, &rm);
1282 AppendToBuffer(
"xorpd %s,%s",
1283 NameOfXMMRegister(regop),
1284 NameOfXMMRegister(rm));
1286 }
else if (*data == 0x6E) {
1289 get_modrm(*data, &mod, ®op, &rm);
1290 AppendToBuffer(
"movd %s,", NameOfXMMRegister(regop));
1291 data += PrintRightOperand(data);
1292 }
else if (*data == 0x6F) {
1295 get_modrm(*data, &mod, ®op, &rm);
1296 AppendToBuffer(
"movdqa %s,", NameOfXMMRegister(regop));
1297 data += PrintRightXMMOperand(data);
1298 }
else if (*data == 0x70) {
1301 get_modrm(*data, &mod, ®op, &rm);
1302 int8_t imm8 =
static_cast<int8_t
>(data[1]);
1303 AppendToBuffer(
"pshufd %s,%s,%d",
1304 NameOfXMMRegister(regop),
1305 NameOfXMMRegister(rm),
1306 static_cast<int>(imm8));
1308 }
else if (*data == 0x76) {
1311 get_modrm(*data, &mod, ®op, &rm);
1312 AppendToBuffer(
"pcmpeqd %s,%s",
1313 NameOfXMMRegister(regop),
1314 NameOfXMMRegister(rm));
1316 }
else if (*data == 0x90) {
1318 AppendToBuffer(
"nop");
1319 }
else if (*data == 0xF3) {
1322 get_modrm(*data, &mod, ®op, &rm);
1323 AppendToBuffer(
"psllq %s,%s",
1324 NameOfXMMRegister(regop),
1325 NameOfXMMRegister(rm));
1327 }
else if (*data == 0x73) {
1330 get_modrm(*data, &mod, ®op, &rm);
1331 int8_t imm8 =
static_cast<int8_t
>(data[1]);
1333 AppendToBuffer(
"%s %s,%d",
1334 (regop ==
esi) ?
"psllq" :
"psrlq",
1335 NameOfXMMRegister(rm),
1336 static_cast<int>(imm8));
1338 }
else if (*data == 0xD3) {
1341 get_modrm(*data, &mod, ®op, &rm);
1342 AppendToBuffer(
"psrlq %s,%s",
1343 NameOfXMMRegister(regop),
1344 NameOfXMMRegister(rm));
1346 }
else if (*data == 0x7F) {
1347 AppendToBuffer(
"movdqa ");
1350 get_modrm(*data, &mod, ®op, &rm);
1351 data += PrintRightXMMOperand(data);
1352 AppendToBuffer(
",%s", NameOfXMMRegister(regop));
1353 }
else if (*data == 0x7E) {
1356 get_modrm(*data, &mod, ®op, &rm);
1357 AppendToBuffer(
"movd ");
1358 data += PrintRightOperand(data);
1359 AppendToBuffer(
",%s", NameOfXMMRegister(regop));
1360 }
else if (*data == 0xDB) {
1363 get_modrm(*data, &mod, ®op, &rm);
1364 AppendToBuffer(
"pand %s,%s",
1365 NameOfXMMRegister(regop),
1366 NameOfXMMRegister(rm));
1368 }
else if (*data == 0xE7) {
1371 get_modrm(*data, &mod, ®op, &rm);
1373 AppendToBuffer(
"movntdq ");
1374 data += PrintRightOperand(data);
1375 AppendToBuffer(
",%s", NameOfXMMRegister(regop));
1377 UnimplementedInstruction();
1379 }
else if (*data == 0xEF) {
1382 get_modrm(*data, &mod, ®op, &rm);
1383 AppendToBuffer(
"pxor %s,%s",
1384 NameOfXMMRegister(regop),
1385 NameOfXMMRegister(rm));
1387 }
else if (*data == 0xEB) {
1390 get_modrm(*data, &mod, ®op, &rm);
1391 AppendToBuffer(
"por %s,%s",
1392 NameOfXMMRegister(regop),
1393 NameOfXMMRegister(rm));
1396 UnimplementedInstruction();
1399 UnimplementedInstruction();
1406 get_modrm(*data, &mod, ®op, &rm);
1408 AppendToBuffer(
"dec_b ");
1409 data += PrintRightOperand(data);
1411 UnimplementedInstruction();
1417 AppendToBuffer(
"push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1422 AppendToBuffer(
"push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1427 AppendToBuffer(
"test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1432 AppendToBuffer(
"test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1439 data += D1D3C1Instruction(data);
1449 data += FPUInstruction(data);
1453 data += JumpShort(data);
1457 if (*(data+1) == 0x0F) {
1458 byte b2 = *(data+2);
1460 AppendToBuffer(
"movsd ");
1463 get_modrm(*data, &mod, ®op, &rm);
1464 data += PrintRightXMMOperand(data);
1465 AppendToBuffer(
",%s", NameOfXMMRegister(regop));
1466 }
else if (b2 == 0x10) {
1469 get_modrm(*data, &mod, ®op, &rm);
1470 AppendToBuffer(
"movsd %s,", NameOfXMMRegister(regop));
1471 data += PrintRightXMMOperand(data);
1472 }
else if (b2 == 0x5A) {
1475 get_modrm(*data, &mod, ®op, &rm);
1476 AppendToBuffer(
"cvtsd2ss %s,", NameOfXMMRegister(regop));
1477 data += PrintRightXMMOperand(data);
1479 const char* mnem =
"?";
1481 case 0x2A: mnem =
"cvtsi2sd";
break;
1482 case 0x2C: mnem =
"cvttsd2si";
break;
1483 case 0x2D: mnem =
"cvtsd2si";
break;
1484 case 0x51: mnem =
"sqrtsd";
break;
1485 case 0x58: mnem =
"addsd";
break;
1486 case 0x59: mnem =
"mulsd";
break;
1487 case 0x5C: mnem =
"subsd";
break;
1488 case 0x5E: mnem =
"divsd";
break;
1492 get_modrm(*data, &mod, ®op, &rm);
1494 AppendToBuffer(
"%s %s,", mnem, NameOfXMMRegister(regop));
1495 data += PrintRightOperand(data);
1496 }
else if (b2 == 0x2C || b2 == 0x2D) {
1497 AppendToBuffer(
"%s %s,", mnem, NameOfCPURegister(regop));
1498 data += PrintRightXMMOperand(data);
1499 }
else if (b2 == 0xC2) {
1501 const char*
const pseudo_op[] = {
1511 AppendToBuffer(
"%s %s,%s",
1513 NameOfXMMRegister(regop),
1514 NameOfXMMRegister(rm));
1517 AppendToBuffer(
"%s %s,", mnem, NameOfXMMRegister(regop));
1518 data += PrintRightXMMOperand(data);
1522 UnimplementedInstruction();
1527 if (*(data+1) == 0x0F) {
1528 byte b2 = *(data+2);
1530 AppendToBuffer(
"movss ");
1533 get_modrm(*data, &mod, ®op, &rm);
1534 data += PrintRightXMMOperand(data);
1535 AppendToBuffer(
",%s", NameOfXMMRegister(regop));
1536 }
else if (b2 == 0x10) {
1539 get_modrm(*data, &mod, ®op, &rm);
1540 AppendToBuffer(
"movss %s,", NameOfXMMRegister(regop));
1541 data += PrintRightXMMOperand(data);
1542 }
else if (b2 == 0x2C) {
1545 get_modrm(*data, &mod, ®op, &rm);
1546 AppendToBuffer(
"cvttss2si %s,", NameOfCPURegister(regop));
1547 data += PrintRightXMMOperand(data);
1548 }
else if (b2 == 0x5A) {
1551 get_modrm(*data, &mod, ®op, &rm);
1552 AppendToBuffer(
"cvtss2sd %s,", NameOfXMMRegister(regop));
1553 data += PrintRightXMMOperand(data);
1554 }
else if (b2 == 0x6F) {
1557 get_modrm(*data, &mod, ®op, &rm);
1558 AppendToBuffer(
"movdqu %s,", NameOfXMMRegister(regop));
1559 data += PrintRightXMMOperand(data);
1560 }
else if (b2 == 0x7F) {
1561 AppendToBuffer(
"movdqu ");
1564 get_modrm(*data, &mod, ®op, &rm);
1565 data += PrintRightXMMOperand(data);
1566 AppendToBuffer(
",%s", NameOfXMMRegister(regop));
1568 UnimplementedInstruction();
1570 }
else if (*(data+1) == 0xA5) {
1572 AppendToBuffer(
"rep_movs");
1573 }
else if (*(data+1) == 0xAB) {
1575 AppendToBuffer(
"rep_stos");
1577 UnimplementedInstruction();
1582 data += F7Instruction(data);
1586 UnimplementedInstruction();
1590 if (tmp_buffer_pos_ <
sizeof tmp_buffer_) {
1591 tmp_buffer_[tmp_buffer_pos_] =
'\0';
1594 int instr_len = data - instr;
1595 if (instr_len == 0) {
1596 printf(
"%02x", *data);
1602 for (
byte* bp = instr; bp < data; bp++) {
1607 for (
int i = 6 - instr_len; i >= 0; i--) {
1614 tmp_buffer_.
start());
1622 static const char* cpu_regs[8] = {
1623 "eax",
"ecx",
"edx",
"ebx",
"esp",
"ebp",
"esi",
"edi"
1627 static const char* byte_cpu_regs[8] = {
1628 "al",
"cl",
"dl",
"bl",
"ah",
"ch",
"dh",
"bh"
1632 static const char* xmm_regs[8] = {
1633 "xmm0",
"xmm1",
"xmm2",
"xmm3",
"xmm4",
"xmm5",
"xmm6",
"xmm7"
1649 if (0 <= reg && reg < 8)
return cpu_regs[reg];
1655 if (0 <= reg && reg < 8)
return byte_cpu_regs[reg];
1661 if (0 <= reg && reg < 8)
return xmm_regs[reg];
1676 : converter_(converter) {}
1679 Disassembler::~Disassembler() {}
1683 byte* instruction) {
1684 DisassemblerIA32 d(converter_,
false );
1685 return d.InstructionDecode(buffer, instruction);
1690 int Disassembler::ConstantPoolSizeAt(
byte* instruction) {
return -1; }
1693 void Disassembler::Disassemble(FILE* f,
byte* begin,
byte* end) {
1694 NameConverter converter;
1695 Disassembler d(converter);
1696 for (
byte*
pc = begin;
pc < end;) {
1700 pc += d.InstructionDecode(buffer,
pc);
1701 fprintf(f,
"%p", prev_pc);
1704 for (
byte* bp = prev_pc; bp <
pc; bp++) {
1705 fprintf(f,
"%02x", *bp);
1707 for (
int i = 6 - (pc - prev_pc); i >= 0; i--) {
1710 fprintf(f,
" %s\n", buffer.
start());
1717 #endif // V8_TARGET_ARCH_IA32
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
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)