1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
11 #if V8_TARGET_ARCH_IA32
13 #include "src/disasm.h"
24 //------------------------------------------------------------------
26 //------------------------------------------------------------------
28 int b; // -1 terminates, otherwise must be in range (0..255)
30 OperandOrder op_order_;
34 static const ByteMnemonic two_operands_instr[] = {
35 {0x01, "add", OPER_REG_OP_ORDER},
36 {0x03, "add", REG_OPER_OP_ORDER},
37 {0x09, "or", OPER_REG_OP_ORDER},
38 {0x0B, "or", REG_OPER_OP_ORDER},
39 {0x1B, "sbb", REG_OPER_OP_ORDER},
40 {0x21, "and", OPER_REG_OP_ORDER},
41 {0x23, "and", REG_OPER_OP_ORDER},
42 {0x29, "sub", OPER_REG_OP_ORDER},
43 {0x2A, "subb", REG_OPER_OP_ORDER},
44 {0x2B, "sub", REG_OPER_OP_ORDER},
45 {0x31, "xor", OPER_REG_OP_ORDER},
46 {0x33, "xor", REG_OPER_OP_ORDER},
47 {0x38, "cmpb", OPER_REG_OP_ORDER},
48 {0x3A, "cmpb", REG_OPER_OP_ORDER},
49 {0x3B, "cmp", REG_OPER_OP_ORDER},
50 {0x84, "test_b", REG_OPER_OP_ORDER},
51 {0x85, "test", REG_OPER_OP_ORDER},
52 {0x87, "xchg", REG_OPER_OP_ORDER},
53 {0x8A, "mov_b", REG_OPER_OP_ORDER},
54 {0x8B, "mov", REG_OPER_OP_ORDER},
55 {0x8D, "lea", REG_OPER_OP_ORDER},
56 {-1, "", UNSET_OP_ORDER}
60 static const ByteMnemonic zero_operands_instr[] = {
61 {0xC3, "ret", UNSET_OP_ORDER},
62 {0xC9, "leave", UNSET_OP_ORDER},
63 {0x90, "nop", UNSET_OP_ORDER},
64 {0xF4, "hlt", UNSET_OP_ORDER},
65 {0xCC, "int3", UNSET_OP_ORDER},
66 {0x60, "pushad", UNSET_OP_ORDER},
67 {0x61, "popad", UNSET_OP_ORDER},
68 {0x9C, "pushfd", UNSET_OP_ORDER},
69 {0x9D, "popfd", UNSET_OP_ORDER},
70 {0x9E, "sahf", UNSET_OP_ORDER},
71 {0x99, "cdq", UNSET_OP_ORDER},
72 {0x9B, "fwait", UNSET_OP_ORDER},
73 {0xFC, "cld", UNSET_OP_ORDER},
74 {0xAB, "stos", UNSET_OP_ORDER},
75 {-1, "", UNSET_OP_ORDER}
79 static const ByteMnemonic call_jump_instr[] = {
80 {0xE8, "call", UNSET_OP_ORDER},
81 {0xE9, "jmp", UNSET_OP_ORDER},
82 {-1, "", UNSET_OP_ORDER}
86 static const ByteMnemonic short_immediate_instr[] = {
87 {0x05, "add", UNSET_OP_ORDER},
88 {0x0D, "or", UNSET_OP_ORDER},
89 {0x15, "adc", UNSET_OP_ORDER},
90 {0x25, "and", UNSET_OP_ORDER},
91 {0x2D, "sub", UNSET_OP_ORDER},
92 {0x35, "xor", UNSET_OP_ORDER},
93 {0x3D, "cmp", UNSET_OP_ORDER},
94 {-1, "", UNSET_OP_ORDER}
98 // Generally we don't want to generate these because they are subject to partial
99 // register stalls. They are included for completeness and because the cmp
100 // variant is used by the RecordWrite stub. Because it does not update the
101 // register it is not subject to partial register stalls.
102 static ByteMnemonic byte_immediate_instr[] = {
103 {0x0c, "or", UNSET_OP_ORDER},
104 {0x24, "and", UNSET_OP_ORDER},
105 {0x34, "xor", UNSET_OP_ORDER},
106 {0x3c, "cmp", UNSET_OP_ORDER},
107 {-1, "", UNSET_OP_ORDER}
111 static const char* const jump_conditional_mnem[] = {
112 /*0*/ "jo", "jno", "jc", "jnc",
113 /*4*/ "jz", "jnz", "jna", "ja",
114 /*8*/ "js", "jns", "jpe", "jpo",
115 /*12*/ "jl", "jnl", "jng", "jg"
119 static const char* const set_conditional_mnem[] = {
120 /*0*/ "seto", "setno", "setc", "setnc",
121 /*4*/ "setz", "setnz", "setna", "seta",
122 /*8*/ "sets", "setns", "setpe", "setpo",
123 /*12*/ "setl", "setnl", "setng", "setg"
127 static const char* const conditional_move_mnem[] = {
128 /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc",
129 /*4*/ "cmovz", "cmovnz", "cmovna", "cmova",
130 /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo",
131 /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg"
135 enum InstructionType {
139 JUMP_CONDITIONAL_SHORT_INSTR,
143 SHORT_IMMEDIATE_INSTR,
148 struct InstructionDesc {
150 InstructionType type;
151 OperandOrder op_order_;
155 class InstructionTable {
158 const InstructionDesc& Get(byte x) const { return instructions_[x]; }
159 static InstructionTable* get_instance() {
160 static InstructionTable table;
165 InstructionDesc instructions_[256];
168 void CopyTable(const ByteMnemonic bm[], InstructionType type);
169 void SetTableRange(InstructionType type,
173 void AddJumpConditionalShort();
177 InstructionTable::InstructionTable() {
183 void InstructionTable::Clear() {
184 for (int i = 0; i < 256; i++) {
185 instructions_[i].mnem = "";
186 instructions_[i].type = NO_INSTR;
187 instructions_[i].op_order_ = UNSET_OP_ORDER;
192 void InstructionTable::Init() {
193 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
194 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
195 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
196 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
197 CopyTable(byte_immediate_instr, BYTE_IMMEDIATE_INSTR);
198 AddJumpConditionalShort();
199 SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc");
200 SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec");
201 SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push");
202 SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop");
203 SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop.
204 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
208 void InstructionTable::CopyTable(const ByteMnemonic bm[],
209 InstructionType type) {
210 for (int i = 0; bm[i].b >= 0; i++) {
211 InstructionDesc* id = &instructions_[bm[i].b];
212 id->mnem = bm[i].mnem;
213 id->op_order_ = bm[i].op_order_;
214 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
220 void InstructionTable::SetTableRange(InstructionType type,
224 for (byte b = start; b <= end; b++) {
225 InstructionDesc* id = &instructions_[b];
226 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
233 void InstructionTable::AddJumpConditionalShort() {
234 for (byte b = 0x70; b <= 0x7F; b++) {
235 InstructionDesc* id = &instructions_[b];
236 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
237 id->mnem = jump_conditional_mnem[b & 0x0F];
238 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
243 // The IA32 disassembler implementation.
244 class DisassemblerIA32 {
246 DisassemblerIA32(const NameConverter& converter,
247 bool abort_on_unimplemented = true)
248 : converter_(converter),
249 instruction_table_(InstructionTable::get_instance()),
251 abort_on_unimplemented_(abort_on_unimplemented) {
252 tmp_buffer_[0] = '\0';
255 virtual ~DisassemblerIA32() {}
257 // Writes one disassembled instruction into 'buffer' (0-terminated).
258 // Returns the length of the disassembled machine instruction in bytes.
259 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
262 const NameConverter& converter_;
263 InstructionTable* instruction_table_;
264 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
265 unsigned int tmp_buffer_pos_;
266 bool abort_on_unimplemented_;
280 enum ShiftOpcodeExtension {
291 const char* NameOfCPURegister(int reg) const {
292 return converter_.NameOfCPURegister(reg);
296 const char* NameOfByteCPURegister(int reg) const {
297 return converter_.NameOfByteCPURegister(reg);
301 const char* NameOfXMMRegister(int reg) const {
302 return converter_.NameOfXMMRegister(reg);
306 const char* NameOfAddress(byte* addr) const {
307 return converter_.NameOfAddress(addr);
311 // Disassembler helper functions.
312 static void get_modrm(byte data, int* mod, int* regop, int* rm) {
313 *mod = (data >> 6) & 3;
314 *regop = (data & 0x38) >> 3;
319 static void get_sib(byte data, int* scale, int* index, int* base) {
320 *scale = (data >> 6) & 3;
321 *index = (data >> 3) & 7;
325 typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const;
327 int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name);
328 int PrintRightOperand(byte* modrmp);
329 int PrintRightByteOperand(byte* modrmp);
330 int PrintRightXMMOperand(byte* modrmp);
331 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
332 int PrintImmediateOp(byte* data);
333 int F7Instruction(byte* data);
334 int D1D3C1Instruction(byte* data);
335 int JumpShort(byte* data);
336 int JumpConditional(byte* data, const char* comment);
337 int JumpConditionalShort(byte* data, const char* comment);
338 int SetCC(byte* data);
339 int CMov(byte* data);
340 int FPUInstruction(byte* data);
341 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
342 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
343 void AppendToBuffer(const char* format, ...);
346 void UnimplementedInstruction() {
347 if (abort_on_unimplemented_) {
350 AppendToBuffer("'Unimplemented Instruction'");
356 void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
357 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
359 va_start(args, format);
360 int result = v8::internal::VSNPrintF(buf, format, args);
362 tmp_buffer_pos_ += result;
365 int DisassemblerIA32::PrintRightOperandHelper(
367 RegisterNameMapping direct_register_name) {
369 get_modrm(*modrmp, &mod, ®op, &rm);
370 RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
371 &DisassemblerIA32::NameOfCPURegister;
375 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1);
376 AppendToBuffer("[0x%x]", disp);
378 } else if (rm == esp) {
379 byte sib = *(modrmp + 1);
380 int scale, index, base;
381 get_sib(sib, &scale, &index, &base);
382 if (index == esp && base == esp && scale == 0 /*times_1*/) {
383 AppendToBuffer("[%s]", (this->*register_name)(rm));
385 } else if (base == ebp) {
386 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
387 AppendToBuffer("[%s*%d%s0x%x]",
388 (this->*register_name)(index),
390 disp < 0 ? "-" : "+",
391 disp < 0 ? -disp : disp);
393 } else if (index != esp && base != ebp) {
394 // [base+index*scale]
395 AppendToBuffer("[%s+%s*%d]",
396 (this->*register_name)(base),
397 (this->*register_name)(index),
401 UnimplementedInstruction();
405 AppendToBuffer("[%s]", (this->*register_name)(rm));
409 case 1: // fall through
412 byte sib = *(modrmp + 1);
413 int scale, index, base;
414 get_sib(sib, &scale, &index, &base);
415 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2)
416 : *reinterpret_cast<int8_t*>(modrmp + 2);
417 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
418 AppendToBuffer("[%s%s0x%x]",
419 (this->*register_name)(rm),
420 disp < 0 ? "-" : "+",
421 disp < 0 ? -disp : disp);
423 AppendToBuffer("[%s+%s*%d%s0x%x]",
424 (this->*register_name)(base),
425 (this->*register_name)(index),
427 disp < 0 ? "-" : "+",
428 disp < 0 ? -disp : disp);
430 return mod == 2 ? 6 : 3;
433 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1)
434 : *reinterpret_cast<int8_t*>(modrmp + 1);
435 AppendToBuffer("[%s%s0x%x]",
436 (this->*register_name)(rm),
437 disp < 0 ? "-" : "+",
438 disp < 0 ? -disp : disp);
439 return mod == 2 ? 5 : 2;
443 AppendToBuffer("%s", (this->*register_name)(rm));
446 UnimplementedInstruction();
453 int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
454 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
458 int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
459 return PrintRightOperandHelper(modrmp,
460 &DisassemblerIA32::NameOfByteCPURegister);
464 int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) {
465 return PrintRightOperandHelper(modrmp,
466 &DisassemblerIA32::NameOfXMMRegister);
470 // Returns number of bytes used including the current *data.
471 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
472 int DisassemblerIA32::PrintOperands(const char* mnem,
473 OperandOrder op_order,
477 get_modrm(modrm, &mod, ®op, &rm);
480 case REG_OPER_OP_ORDER: {
481 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
482 advance = PrintRightOperand(data);
485 case OPER_REG_OP_ORDER: {
486 AppendToBuffer("%s ", mnem);
487 advance = PrintRightOperand(data);
488 AppendToBuffer(",%s", NameOfCPURegister(regop));
499 // Returns number of bytes used by machine instruction, including *data byte.
500 // Writes immediate instructions to 'tmp_buffer_'.
501 int DisassemblerIA32::PrintImmediateOp(byte* data) {
502 bool sign_extension_bit = (*data & 0x02) != 0;
503 byte modrm = *(data+1);
505 get_modrm(modrm, &mod, ®op, &rm);
506 const char* mnem = "Imm???";
508 case 0: mnem = "add"; break;
509 case 1: mnem = "or"; break;
510 case 2: mnem = "adc"; break;
511 case 4: mnem = "and"; break;
512 case 5: mnem = "sub"; break;
513 case 6: mnem = "xor"; break;
514 case 7: mnem = "cmp"; break;
515 default: UnimplementedInstruction();
517 AppendToBuffer("%s ", mnem);
518 int count = PrintRightOperand(data+1);
519 if (sign_extension_bit) {
520 AppendToBuffer(",0x%x", *(data + 1 + count));
521 return 1 + count + 1 /*int8*/;
523 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
524 return 1 + count + 4 /*int32_t*/;
529 // Returns number of bytes used, including *data.
530 int DisassemblerIA32::F7Instruction(byte* data) {
531 DCHECK_EQ(0xF7, *data);
532 byte modrm = *++data;
534 get_modrm(modrm, &mod, ®op, &rm);
535 const char* mnem = NULL;
559 UnimplementedInstruction();
561 AppendToBuffer("%s ", mnem);
562 int count = PrintRightOperand(data);
564 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + count));
571 int DisassemblerIA32::D1D3C1Instruction(byte* data) {
573 DCHECK(op == 0xD1 || op == 0xD3 || op == 0xC1);
574 byte modrm = *++data;
576 get_modrm(modrm, &mod, ®op, &rm);
578 const char* mnem = NULL;
602 UnimplementedInstruction();
604 AppendToBuffer("%s ", mnem);
605 int count = PrintRightOperand(data);
608 } else if (op == 0xC1) {
611 } else if (op == 0xD3) {
612 // Shift/rotate by cl.
615 AppendToBuffer(",%d", imm8);
617 AppendToBuffer(",cl");
623 // Returns number of bytes used, including *data.
624 int DisassemblerIA32::JumpShort(byte* data) {
625 DCHECK_EQ(0xEB, *data);
627 byte* dest = data + static_cast<int8_t>(b) + 2;
628 AppendToBuffer("jmp %s", NameOfAddress(dest));
633 // Returns number of bytes used, including *data.
634 int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
635 DCHECK_EQ(0x0F, *data);
636 byte cond = *(data+1) & 0x0F;
637 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
638 const char* mnem = jump_conditional_mnem[cond];
639 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
640 if (comment != NULL) {
641 AppendToBuffer(", %s", comment);
643 return 6; // includes 0x0F
647 // Returns number of bytes used, including *data.
648 int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
649 byte cond = *data & 0x0F;
651 byte* dest = data + static_cast<int8_t>(b) + 2;
652 const char* mnem = jump_conditional_mnem[cond];
653 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
654 if (comment != NULL) {
655 AppendToBuffer(", %s", comment);
661 // Returns number of bytes used, including *data.
662 int DisassemblerIA32::SetCC(byte* data) {
663 DCHECK_EQ(0x0F, *data);
664 byte cond = *(data+1) & 0x0F;
665 const char* mnem = set_conditional_mnem[cond];
666 AppendToBuffer("%s ", mnem);
667 PrintRightByteOperand(data+2);
668 return 3; // Includes 0x0F.
672 // Returns number of bytes used, including *data.
673 int DisassemblerIA32::CMov(byte* data) {
674 DCHECK_EQ(0x0F, *data);
675 byte cond = *(data + 1) & 0x0F;
676 const char* mnem = conditional_move_mnem[cond];
677 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
678 return 2 + op_size; // includes 0x0F
682 // Returns number of bytes used, including *data.
683 int DisassemblerIA32::FPUInstruction(byte* data) {
684 byte escape_opcode = *data;
685 DCHECK_EQ(0xD8, escape_opcode & 0xF8);
686 byte modrm_byte = *(data+1);
688 if (modrm_byte >= 0xC0) {
689 return RegisterFPUInstruction(escape_opcode, modrm_byte);
691 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
695 int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
698 const char* mnem = "?";
699 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
700 switch (escape_opcode) {
701 case 0xD9: switch (regop) {
702 case 0: mnem = "fld_s"; break;
703 case 2: mnem = "fst_s"; break;
704 case 3: mnem = "fstp_s"; break;
705 case 7: mnem = "fstcw"; break;
706 default: UnimplementedInstruction();
710 case 0xDB: switch (regop) {
711 case 0: mnem = "fild_s"; break;
712 case 1: mnem = "fisttp_s"; break;
713 case 2: mnem = "fist_s"; break;
714 case 3: mnem = "fistp_s"; break;
715 default: UnimplementedInstruction();
719 case 0xDD: switch (regop) {
720 case 0: mnem = "fld_d"; break;
721 case 1: mnem = "fisttp_d"; break;
722 case 2: mnem = "fst_d"; break;
723 case 3: mnem = "fstp_d"; break;
724 default: UnimplementedInstruction();
728 case 0xDF: switch (regop) {
729 case 5: mnem = "fild_d"; break;
730 case 7: mnem = "fistp_d"; break;
731 default: UnimplementedInstruction();
735 default: UnimplementedInstruction();
737 AppendToBuffer("%s ", mnem);
738 int count = PrintRightOperand(modrm_start);
742 int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
744 bool has_register = false; // Is the FPU register encoded in modrm_byte?
745 const char* mnem = "?";
747 switch (escape_opcode) {
750 switch (modrm_byte & 0xF8) {
751 case 0xC0: mnem = "fadd_i"; break;
752 case 0xE0: mnem = "fsub_i"; break;
753 case 0xC8: mnem = "fmul_i"; break;
754 case 0xF0: mnem = "fdiv_i"; break;
755 default: UnimplementedInstruction();
760 switch (modrm_byte & 0xF8) {
770 switch (modrm_byte) {
771 case 0xE0: mnem = "fchs"; break;
772 case 0xE1: mnem = "fabs"; break;
773 case 0xE4: mnem = "ftst"; break;
774 case 0xE8: mnem = "fld1"; break;
775 case 0xEB: mnem = "fldpi"; break;
776 case 0xED: mnem = "fldln2"; break;
777 case 0xEE: mnem = "fldz"; break;
778 case 0xF0: mnem = "f2xm1"; break;
779 case 0xF1: mnem = "fyl2x"; break;
780 case 0xF4: mnem = "fxtract"; break;
781 case 0xF5: mnem = "fprem1"; break;
782 case 0xF7: mnem = "fincstp"; break;
783 case 0xF8: mnem = "fprem"; break;
784 case 0xFC: mnem = "frndint"; break;
785 case 0xFD: mnem = "fscale"; break;
786 case 0xFE: mnem = "fsin"; break;
787 case 0xFF: mnem = "fcos"; break;
788 default: UnimplementedInstruction();
794 if (modrm_byte == 0xE9) {
797 UnimplementedInstruction();
802 if ((modrm_byte & 0xF8) == 0xE8) {
805 } else if (modrm_byte == 0xE2) {
807 } else if (modrm_byte == 0xE3) {
810 UnimplementedInstruction();
816 switch (modrm_byte & 0xF8) {
817 case 0xC0: mnem = "fadd"; break;
818 case 0xE8: mnem = "fsub"; break;
819 case 0xC8: mnem = "fmul"; break;
820 case 0xF8: mnem = "fdiv"; break;
821 default: UnimplementedInstruction();
827 switch (modrm_byte & 0xF8) {
828 case 0xC0: mnem = "ffree"; break;
829 case 0xD0: mnem = "fst"; break;
830 case 0xD8: mnem = "fstp"; break;
831 default: UnimplementedInstruction();
836 if (modrm_byte == 0xD9) {
840 switch (modrm_byte & 0xF8) {
841 case 0xC0: mnem = "faddp"; break;
842 case 0xE8: mnem = "fsubp"; break;
843 case 0xC8: mnem = "fmulp"; break;
844 case 0xF8: mnem = "fdivp"; break;
845 default: UnimplementedInstruction();
851 if (modrm_byte == 0xE0) {
853 } else if ((modrm_byte & 0xF8) == 0xE8) {
859 default: UnimplementedInstruction();
863 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
865 AppendToBuffer("%s", mnem);
871 // Mnemonics for instructions 0xF0 byte.
872 // Returns NULL if the instruction is not handled here.
873 static const char* F0Mnem(byte f0byte) {
875 case 0x18: return "prefetch";
876 case 0xA2: return "cpuid";
877 case 0xBE: return "movsx_b";
878 case 0xBF: return "movsx_w";
879 case 0xB6: return "movzx_b";
880 case 0xB7: return "movzx_w";
881 case 0xAF: return "imul";
882 case 0xA5: return "shld";
883 case 0xAD: return "shrd";
884 case 0xAC: return "shrd"; // 3-operand version.
885 case 0xAB: return "bts";
886 case 0xBD: return "bsr";
887 default: return NULL;
892 // Disassembled instruction '*instr' and writes it into 'out_buffer'.
893 int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
895 tmp_buffer_pos_ = 0; // starting to write as position 0
898 const char* branch_hint = NULL;
899 // We use these two prefixes only with branch prediction
900 if (*data == 0x3E /*ds*/) {
901 branch_hint = "predicted taken";
903 } else if (*data == 0x2E /*cs*/) {
904 branch_hint = "predicted not taken";
907 bool processed = true; // Will be set to false if the current instruction
908 // is not in 'instructions' table.
909 const InstructionDesc& idesc = instruction_table_->Get(*data);
910 switch (idesc.type) {
911 case ZERO_OPERANDS_INSTR:
912 AppendToBuffer(idesc.mnem);
916 case TWO_OPERANDS_INSTR:
918 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
921 case JUMP_CONDITIONAL_SHORT_INSTR:
922 data += JumpConditionalShort(data, branch_hint);
926 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
930 case MOVE_REG_INSTR: {
931 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
932 AppendToBuffer("mov %s,%s",
933 NameOfCPURegister(*data & 0x07),
934 NameOfAddress(addr));
939 case CALL_JUMP_INSTR: {
940 byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5;
941 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
946 case SHORT_IMMEDIATE_INSTR: {
947 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
948 AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
953 case BYTE_IMMEDIATE_INSTR: {
954 AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
964 UNIMPLEMENTED(); // This type is not implemented.
966 //----------------------------
970 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
976 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
977 AppendToBuffer(",%d", *data);
983 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
984 AppendToBuffer(",%d", *reinterpret_cast<int32_t*>(data));
992 get_modrm(*data, &mod, ®op, &rm);
994 AppendToBuffer("test_b ");
995 data += PrintRightByteOperand(data);
997 AppendToBuffer(",0x%x", imm);
1000 UnimplementedInstruction();
1005 case 0x81: // fall through
1006 case 0x83: // 0x81 with sign extension bit set
1007 data += PrintImmediateOp(data);
1011 { byte f0byte = data[1];
1012 const char* f0mnem = F0Mnem(f0byte);
1013 if (f0byte == 0x18) {
1016 get_modrm(*data, &mod, ®op, &rm);
1017 const char* suffix[] = {"nta", "1", "2", "3"};
1018 AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
1019 data += PrintRightOperand(data);
1020 } else if (f0byte == 0x1F && data[2] == 0) {
1021 AppendToBuffer("nop"); // 3 byte nop.
1023 } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1024 AppendToBuffer("nop"); // 4 byte nop.
1026 } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1028 AppendToBuffer("nop"); // 5 byte nop.
1030 } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1031 data[4] == 0 && data[5] == 0 && data[6] == 0) {
1032 AppendToBuffer("nop"); // 7 byte nop.
1034 } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1035 data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1037 AppendToBuffer("nop"); // 8 byte nop.
1039 } else if (f0byte == 0xA2 || f0byte == 0x31) {
1040 AppendToBuffer("%s", f0mnem);
1042 } else if (f0byte == 0x28) {
1045 get_modrm(*data, &mod, ®op, &rm);
1046 AppendToBuffer("movaps %s,%s",
1047 NameOfXMMRegister(regop),
1048 NameOfXMMRegister(rm));
1050 } else if (f0byte == 0x12) {
1053 get_modrm(*data, &mod, ®op, &rm);
1054 AppendToBuffer("movhlps %s,%s",
1055 NameOfXMMRegister(regop),
1056 NameOfXMMRegister(rm));
1058 } else if (f0byte == 0x16) {
1061 get_modrm(*data, &mod, ®op, &rm);
1062 AppendToBuffer("movlhps %s,%s",
1063 NameOfXMMRegister(regop),
1064 NameOfXMMRegister(rm));
1066 } else if (f0byte == 0x10) {
1069 get_modrm(*data, &mod, ®op, &rm);
1070 AppendToBuffer("movups %s,", NameOfXMMRegister(regop));
1071 data += PrintRightXMMOperand(data);
1072 } else if (f0byte == 0x11) {
1073 AppendToBuffer("movups ");
1076 get_modrm(*data, &mod, ®op, &rm);
1077 data += PrintRightXMMOperand(data);
1078 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1079 } else if (f0byte >= 0x51 && f0byte <= 0x5F) {
1080 const char* const pseudo_op[] = {
1100 get_modrm(*data, &mod, ®op, &rm);
1101 AppendToBuffer("%s %s,",
1102 pseudo_op[f0byte - 0x51],
1103 NameOfXMMRegister(regop));
1104 data += PrintRightXMMOperand(data);
1105 } else if (f0byte == 0x50) {
1108 get_modrm(*data, &mod, ®op, &rm);
1109 AppendToBuffer("movmskps %s,%s",
1110 NameOfCPURegister(regop),
1111 NameOfXMMRegister(rm));
1113 } else if (f0byte == 0xC2) {
1114 // Intel manual 2A, Table 3-11.
1117 get_modrm(*data, &mod, ®op, &rm);
1118 const char* const pseudo_op[] = {
1128 AppendToBuffer("%s %s,%s",
1130 NameOfXMMRegister(regop),
1131 NameOfXMMRegister(rm));
1133 } else if (f0byte== 0xC6) {
1134 // shufps xmm, xmm/m128, imm8
1137 get_modrm(*data, &mod, ®op, &rm);
1138 int8_t imm8 = static_cast<int8_t>(data[1]);
1139 AppendToBuffer("shufps %s,%s,%d",
1140 NameOfXMMRegister(rm),
1141 NameOfXMMRegister(regop),
1142 static_cast<int>(imm8));
1144 } else if (f0byte== 0x5B) {
1147 get_modrm(*data, &mod, ®op, &rm);
1148 AppendToBuffer("cvtdq2ps %s,",
1149 NameOfXMMRegister(rm));
1150 data += PrintRightXMMOperand(data);
1151 } else if ((f0byte & 0xF0) == 0x80) {
1152 data += JumpConditional(data, branch_hint);
1153 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1154 f0byte == 0xB7 || f0byte == 0xAF) {
1156 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1157 } else if ((f0byte & 0xF0) == 0x90) {
1158 data += SetCC(data);
1159 } else if ((f0byte & 0xF0) == 0x40) {
1161 } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
1164 AppendToBuffer("%s ", f0mnem);
1166 get_modrm(*data, &mod, ®op, &rm);
1167 data += PrintRightOperand(data);
1168 if (f0byte == 0xAB) {
1169 AppendToBuffer(",%s", NameOfCPURegister(regop));
1171 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1173 } else if (f0byte == 0xBD) {
1176 get_modrm(*data, &mod, ®op, &rm);
1177 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1178 data += PrintRightOperand(data);
1180 UnimplementedInstruction();
1188 get_modrm(*data, &mod, ®op, &rm);
1190 AppendToBuffer("pop ");
1191 data += PrintRightOperand(data);
1199 get_modrm(*data, &mod, ®op, &rm);
1200 const char* mnem = NULL;
1202 case esi: mnem = "push"; break;
1203 case eax: mnem = "inc"; break;
1204 case ecx: mnem = "dec"; break;
1205 case edx: mnem = "call"; break;
1206 case esp: mnem = "jmp"; break;
1207 default: mnem = "???";
1209 AppendToBuffer("%s ", mnem);
1210 data += PrintRightOperand(data);
1214 case 0xC7: // imm32, fall through
1216 { bool is_byte = *data == 0xC6;
1219 AppendToBuffer("%s ", "mov_b");
1220 data += PrintRightByteOperand(data);
1221 int32_t imm = *data;
1222 AppendToBuffer(",0x%x", imm);
1225 AppendToBuffer("%s ", "mov");
1226 data += PrintRightOperand(data);
1227 int32_t imm = *reinterpret_cast<int32_t*>(data);
1228 AppendToBuffer(",0x%x", imm);
1237 get_modrm(*data, &mod, ®op, &rm);
1238 const char* mnem = NULL;
1240 case 5: mnem = "subb"; break;
1241 case 7: mnem = "cmpb"; break;
1242 default: UnimplementedInstruction();
1244 AppendToBuffer("%s ", mnem);
1245 data += PrintRightByteOperand(data);
1246 int32_t imm = *data;
1247 AppendToBuffer(",0x%x", imm);
1252 case 0x88: // 8bit, fall through
1254 { bool is_byte = *data == 0x88;
1257 get_modrm(*data, &mod, ®op, &rm);
1259 AppendToBuffer("%s ", "mov_b");
1260 data += PrintRightByteOperand(data);
1261 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1263 AppendToBuffer("%s ", "mov");
1264 data += PrintRightOperand(data);
1265 AppendToBuffer(",%s", NameOfCPURegister(regop));
1270 case 0x66: // prefix
1271 while (*data == 0x66) data++;
1272 if (*data == 0xf && data[1] == 0x1f) {
1273 AppendToBuffer("nop"); // 0x66 prefix
1274 } else if (*data == 0x90) {
1275 AppendToBuffer("nop"); // 0x66 prefix
1276 } else if (*data == 0x8B) {
1278 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
1279 } else if (*data == 0x89) {
1282 get_modrm(*data, &mod, ®op, &rm);
1283 AppendToBuffer("mov_w ");
1284 data += PrintRightOperand(data);
1285 AppendToBuffer(",%s", NameOfCPURegister(regop));
1286 } else if (*data == 0xC7) {
1288 AppendToBuffer("%s ", "mov_w");
1289 data += PrintRightOperand(data);
1290 int imm = *reinterpret_cast<int16_t*>(data);
1291 AppendToBuffer(",0x%x", imm);
1293 } else if (*data == 0x0F) {
1295 if (*data == 0x38) {
1297 if (*data == 0x17) {
1300 get_modrm(*data, &mod, ®op, &rm);
1301 AppendToBuffer("ptest %s,%s",
1302 NameOfXMMRegister(regop),
1303 NameOfXMMRegister(rm));
1305 } else if (*data == 0x40) {
1308 get_modrm(*data, &mod, ®op, &rm);
1309 AppendToBuffer("pmulld %s,%s",
1310 NameOfXMMRegister(regop));
1311 data += PrintRightXMMOperand(data);
1312 } else if (*data == 0x2A) {
1316 get_modrm(*data, &mod, ®op, &rm);
1317 AppendToBuffer("movntdqa %s,", NameOfXMMRegister(regop));
1318 data += PrintRightOperand(data);
1320 UnimplementedInstruction();
1322 } else if (*data == 0x3A) {
1324 if (*data == 0x0B) {
1327 get_modrm(*data, &mod, ®op, &rm);
1328 int8_t imm8 = static_cast<int8_t>(data[1]);
1329 AppendToBuffer("roundsd %s,%s,%d",
1330 NameOfXMMRegister(regop),
1331 NameOfXMMRegister(rm),
1332 static_cast<int>(imm8));
1334 } else if (*data == 0x16) {
1337 get_modrm(*data, &mod, ®op, &rm);
1338 int8_t imm8 = static_cast<int8_t>(data[1]);
1339 AppendToBuffer("pextrd %s,%s,%d",
1340 NameOfCPURegister(regop),
1341 NameOfXMMRegister(rm),
1342 static_cast<int>(imm8));
1344 } else if (*data == 0x21) {
1347 get_modrm(*data, &mod, ®op, &rm);
1348 int8_t imm8 = static_cast<int8_t>(data[1]);
1349 AppendToBuffer("insertps %s,%s,%d",
1350 NameOfXMMRegister(regop),
1351 NameOfXMMRegister(rm),
1352 static_cast<int>(imm8));
1354 } else if (*data == 0x17) {
1357 get_modrm(*data, &mod, ®op, &rm);
1358 int8_t imm8 = static_cast<int8_t>(data[1]);
1359 AppendToBuffer("extractps %s,%s,%d",
1360 NameOfCPURegister(rm),
1361 NameOfXMMRegister(regop),
1362 static_cast<int>(imm8));
1364 } else if (*data == 0x22) {
1367 get_modrm(*data, &mod, ®op, &rm);
1368 int8_t imm8 = static_cast<int8_t>(data[1]);
1369 AppendToBuffer("pinsrd %s,%s,%d",
1370 NameOfXMMRegister(regop),
1371 NameOfCPURegister(rm),
1372 static_cast<int>(imm8));
1375 UnimplementedInstruction();
1377 } else if (*data == 0x2E || *data == 0x2F) {
1378 const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
1381 get_modrm(*data, &mod, ®op, &rm);
1383 AppendToBuffer("%s %s,%s", mnem,
1384 NameOfXMMRegister(regop),
1385 NameOfXMMRegister(rm));
1388 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1389 data += PrintRightOperand(data);
1391 } else if (*data == 0x50) {
1394 get_modrm(*data, &mod, ®op, &rm);
1395 AppendToBuffer("movmskpd %s,%s",
1396 NameOfCPURegister(regop),
1397 NameOfXMMRegister(rm));
1399 } else if (*data == 0x51) {
1402 get_modrm(*data, &mod, ®op, &rm);
1403 AppendToBuffer("sqrtpd %s,%s",
1404 NameOfXMMRegister(regop),
1405 NameOfXMMRegister(rm));
1407 } else if (*data == 0x54) {
1410 get_modrm(*data, &mod, ®op, &rm);
1411 AppendToBuffer("andpd %s,%s",
1412 NameOfXMMRegister(regop),
1413 NameOfXMMRegister(rm));
1415 } else if (*data == 0x56) {
1418 get_modrm(*data, &mod, ®op, &rm);
1419 AppendToBuffer("orpd %s,%s",
1420 NameOfXMMRegister(regop),
1421 NameOfXMMRegister(rm));
1423 } else if (*data == 0x57) {
1426 get_modrm(*data, &mod, ®op, &rm);
1427 AppendToBuffer("xorpd %s,",
1428 NameOfXMMRegister(regop));
1429 data += PrintRightXMMOperand(data);
1430 } else if (*data == 0x58) {
1433 get_modrm(*data, &mod, ®op, &rm);
1434 AppendToBuffer("addpd %s,",
1435 NameOfXMMRegister(regop));
1436 data += PrintRightXMMOperand(data);
1437 } else if (*data == 0x59) {
1440 get_modrm(*data, &mod, ®op, &rm);
1441 AppendToBuffer("mulpd %s,",
1442 NameOfXMMRegister(regop));
1443 data += PrintRightXMMOperand(data);
1444 } else if (*data == 0x5B) {
1447 get_modrm(*data, &mod, ®op, &rm);
1448 AppendToBuffer("cvtps2dq %s,",
1449 NameOfXMMRegister(regop));
1450 data += PrintRightXMMOperand(data);
1451 } else if (*data == 0x5C) {
1454 get_modrm(*data, &mod, ®op, &rm);
1455 AppendToBuffer("subpd %s,",
1456 NameOfXMMRegister(regop));
1457 data += PrintRightXMMOperand(data);
1458 } else if (*data == 0x5D) {
1461 get_modrm(*data, &mod, ®op, &rm);
1462 AppendToBuffer("minpd %s,",
1463 NameOfXMMRegister(regop));
1464 data += PrintRightXMMOperand(data);
1465 } else if (*data == 0x5E) {
1468 get_modrm(*data, &mod, ®op, &rm);
1469 AppendToBuffer("divpd %s,",
1470 NameOfXMMRegister(regop));
1471 data += PrintRightXMMOperand(data);
1472 } else if (*data == 0x5F) {
1475 get_modrm(*data, &mod, ®op, &rm);
1476 AppendToBuffer("maxpd %s,",
1477 NameOfXMMRegister(regop));
1478 data += PrintRightXMMOperand(data);
1479 } else if (*data == 0x62) {
1482 get_modrm(*data, &mod, ®op, &rm);
1483 AppendToBuffer("punpackldq %s,",
1484 NameOfXMMRegister(regop));
1485 data += PrintRightXMMOperand(data);
1486 } else if (*data == 0xD6) {
1487 AppendToBuffer("movq ");
1490 get_modrm(*data, &mod, ®op, &rm);
1491 data += PrintRightXMMOperand(data);
1492 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1493 } else if (*data == 0xF4) {
1496 get_modrm(*data, &mod, ®op, &rm);
1497 AppendToBuffer("pmuludq %s,",
1498 NameOfXMMRegister(regop));
1499 data += PrintRightXMMOperand(data);
1500 } else if (*data == 0xFA) {
1503 get_modrm(*data, &mod, ®op, &rm);
1504 AppendToBuffer("psubd %s,",
1505 NameOfXMMRegister(regop));
1506 data += PrintRightXMMOperand(data);
1507 } else if (*data == 0xFE) {
1510 get_modrm(*data, &mod, ®op, &rm);
1511 AppendToBuffer("paddd %s,",
1512 NameOfXMMRegister(regop));
1513 data += PrintRightXMMOperand(data);
1514 } else if (*data == 0x6E) {
1517 get_modrm(*data, &mod, ®op, &rm);
1518 AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
1519 data += PrintRightOperand(data);
1520 } else if (*data == 0x6F) {
1523 get_modrm(*data, &mod, ®op, &rm);
1524 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
1525 data += PrintRightXMMOperand(data);
1526 } else if (*data == 0x70) {
1529 get_modrm(*data, &mod, ®op, &rm);
1530 int8_t imm8 = static_cast<int8_t>(data[1]);
1531 AppendToBuffer("pshufd %s,%s,%d",
1532 NameOfXMMRegister(regop),
1533 NameOfXMMRegister(rm),
1534 static_cast<int>(imm8));
1536 } else if (*data == 0x66) {
1539 get_modrm(*data, &mod, ®op, &rm);
1540 AppendToBuffer("pcmpgtd %s,%s",
1541 NameOfXMMRegister(regop),
1542 NameOfXMMRegister(rm));
1544 } else if (*data == 0x76) {
1547 get_modrm(*data, &mod, ®op, &rm);
1548 AppendToBuffer("pcmpeqd %s,%s",
1549 NameOfXMMRegister(regop),
1550 NameOfXMMRegister(rm));
1552 } else if (*data == 0x90) {
1554 AppendToBuffer("nop"); // 2 byte nop.
1555 } else if (*data == 0xF3) {
1558 get_modrm(*data, &mod, ®op, &rm);
1559 AppendToBuffer("psllq %s,%s",
1560 NameOfXMMRegister(regop),
1561 NameOfXMMRegister(rm));
1563 } else if (*data == 0x72) {
1566 get_modrm(*data, &mod, ®op, &rm);
1567 int8_t imm8 = static_cast<int8_t>(data[1]);
1568 DCHECK(regop == esi || regop == edx);
1569 AppendToBuffer("%s %s,%d", (regop == esi) ? "pslld" : "psrld",
1570 NameOfXMMRegister(rm), static_cast<int>(imm8));
1572 } else if (*data == 0x73) {
1575 get_modrm(*data, &mod, ®op, &rm);
1576 int8_t imm8 = static_cast<int8_t>(data[1]);
1577 DCHECK(regop == esi || regop == edx);
1578 AppendToBuffer("%s %s,%d",
1579 (regop == esi) ? "psllq" : "psrlq",
1580 NameOfXMMRegister(rm),
1581 static_cast<int>(imm8));
1583 } else if (*data == 0xF2) {
1586 get_modrm(*data, &mod, ®op, &rm);
1587 AppendToBuffer("pslld %s,%s",
1588 NameOfXMMRegister(regop),
1589 NameOfXMMRegister(rm));
1591 } else if (*data == 0x72) {
1594 get_modrm(*data, &mod, ®op, &rm);
1595 int8_t imm8 = static_cast<int8_t>(data[1]);
1596 DCHECK(regop == esi || regop == edx);
1597 AppendToBuffer("%s %s,%d",
1598 (regop == esi) ? "pslld"
1599 : ((regop == edx) ? "psrld" : "psrad"),
1600 NameOfXMMRegister(rm),
1601 static_cast<int>(imm8));
1603 } else if (*data == 0xC6) {
1606 get_modrm(*data, &mod, ®op, &rm);
1607 int8_t imm8 = static_cast<int8_t>(data[1]);
1608 AppendToBuffer("shufpd %s,%s,%d",
1609 NameOfXMMRegister(regop),
1610 NameOfXMMRegister(rm),
1611 static_cast<int>(imm8));
1613 } else if (*data == 0xD2) {
1616 get_modrm(*data, &mod, ®op, &rm);
1617 AppendToBuffer("psrld %s,%s",
1618 NameOfXMMRegister(regop),
1619 NameOfXMMRegister(rm));
1621 } else if (*data == 0xD3) {
1624 get_modrm(*data, &mod, ®op, &rm);
1625 AppendToBuffer("psrlq %s,%s",
1626 NameOfXMMRegister(regop),
1627 NameOfXMMRegister(rm));
1629 } else if (*data == 0xE2) {
1632 get_modrm(*data, &mod, ®op, &rm);
1633 AppendToBuffer("psrad %s,%s",
1634 NameOfXMMRegister(regop),
1635 NameOfXMMRegister(rm));
1637 } else if (*data == 0x7F) {
1638 AppendToBuffer("movdqa ");
1641 get_modrm(*data, &mod, ®op, &rm);
1642 data += PrintRightXMMOperand(data);
1643 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1644 } else if (*data == 0x7E) {
1647 get_modrm(*data, &mod, ®op, &rm);
1648 AppendToBuffer("movd ");
1649 data += PrintRightOperand(data);
1650 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1651 } else if (*data == 0xDB) {
1654 get_modrm(*data, &mod, ®op, &rm);
1655 AppendToBuffer("pand %s,%s",
1656 NameOfXMMRegister(regop),
1657 NameOfXMMRegister(rm));
1659 } else if (*data == 0xE7) {
1662 get_modrm(*data, &mod, ®op, &rm);
1664 AppendToBuffer("movntdq ");
1665 data += PrintRightOperand(data);
1666 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1668 UnimplementedInstruction();
1670 } else if (*data == 0xEF) {
1673 get_modrm(*data, &mod, ®op, &rm);
1674 AppendToBuffer("pxor %s,%s",
1675 NameOfXMMRegister(regop),
1676 NameOfXMMRegister(rm));
1678 } else if (*data == 0xEB) {
1681 get_modrm(*data, &mod, ®op, &rm);
1682 AppendToBuffer("por %s,%s",
1683 NameOfXMMRegister(regop),
1684 NameOfXMMRegister(rm));
1687 UnimplementedInstruction();
1690 UnimplementedInstruction();
1697 get_modrm(*data, &mod, ®op, &rm);
1699 AppendToBuffer("dec_b ");
1700 data += PrintRightOperand(data);
1702 UnimplementedInstruction();
1708 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1713 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1718 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1723 AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1727 case 0xD1: // fall through
1728 case 0xD3: // fall through
1730 data += D1D3C1Instruction(data);
1733 case 0xD8: // fall through
1734 case 0xD9: // fall through
1735 case 0xDA: // fall through
1736 case 0xDB: // fall through
1737 case 0xDC: // fall through
1738 case 0xDD: // fall through
1739 case 0xDE: // fall through
1741 data += FPUInstruction(data);
1745 data += JumpShort(data);
1749 if (*(data+1) == 0x0F) {
1750 byte b2 = *(data+2);
1752 AppendToBuffer("movsd ");
1755 get_modrm(*data, &mod, ®op, &rm);
1756 data += PrintRightXMMOperand(data);
1757 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1758 } else if (b2 == 0x10) {
1761 get_modrm(*data, &mod, ®op, &rm);
1762 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
1763 data += PrintRightXMMOperand(data);
1764 } else if (b2 == 0x5A) {
1767 get_modrm(*data, &mod, ®op, &rm);
1768 AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
1769 data += PrintRightXMMOperand(data);
1771 const char* mnem = "?";
1773 case 0x2A: mnem = "cvtsi2sd"; break;
1774 case 0x2C: mnem = "cvttsd2si"; break;
1775 case 0x2D: mnem = "cvtsd2si"; break;
1776 case 0x51: mnem = "sqrtsd"; break;
1777 case 0x58: mnem = "addsd"; break;
1778 case 0x59: mnem = "mulsd"; break;
1779 case 0x5C: mnem = "subsd"; break;
1780 case 0x5E: mnem = "divsd"; break;
1784 get_modrm(*data, &mod, ®op, &rm);
1786 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1787 data += PrintRightOperand(data);
1788 } else if (b2 == 0x2C || b2 == 0x2D) {
1789 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
1790 data += PrintRightXMMOperand(data);
1791 } else if (b2 == 0xC2) {
1792 // Intel manual 2A, Table 3-18.
1793 const char* const pseudo_op[] = {
1803 AppendToBuffer("%s %s,%s",
1805 NameOfXMMRegister(regop),
1806 NameOfXMMRegister(rm));
1809 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1810 data += PrintRightXMMOperand(data);
1814 UnimplementedInstruction();
1819 if (*(data+1) == 0x0F) {
1820 byte b2 = *(data+2);
1822 AppendToBuffer("movss ");
1825 get_modrm(*data, &mod, ®op, &rm);
1826 data += PrintRightXMMOperand(data);
1827 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1828 } else if (b2 == 0x10) {
1831 get_modrm(*data, &mod, ®op, &rm);
1832 AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
1833 data += PrintRightXMMOperand(data);
1834 } else if (b2 == 0x2C) {
1837 get_modrm(*data, &mod, ®op, &rm);
1838 AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
1839 data += PrintRightXMMOperand(data);
1840 } else if (b2 == 0x5A) {
1843 get_modrm(*data, &mod, ®op, &rm);
1844 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1845 data += PrintRightXMMOperand(data);
1846 } else if (b2 == 0x6F) {
1849 get_modrm(*data, &mod, ®op, &rm);
1850 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
1851 data += PrintRightXMMOperand(data);
1852 } else if (b2 == 0x7F) {
1853 AppendToBuffer("movdqu ");
1856 get_modrm(*data, &mod, ®op, &rm);
1857 data += PrintRightXMMOperand(data);
1858 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1859 } else if (b2 == 0x7E) {
1862 get_modrm(*data, &mod, ®op, &rm);
1863 AppendToBuffer("movq %s,", NameOfXMMRegister(regop));
1864 data += PrintRightXMMOperand(data);
1866 UnimplementedInstruction();
1868 } else if (*(data+1) == 0xA5) {
1870 AppendToBuffer("rep_movs");
1871 } else if (*(data+1) == 0xAB) {
1873 AppendToBuffer("rep_stos");
1875 UnimplementedInstruction();
1880 data += F7Instruction(data);
1884 UnimplementedInstruction();
1888 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1889 tmp_buffer_[tmp_buffer_pos_] = '\0';
1892 int instr_len = data - instr;
1893 if (instr_len == 0) {
1894 printf("%02x", *data);
1896 DCHECK(instr_len > 0); // Ensure progress.
1899 // Instruction bytes.
1900 for (byte* bp = instr; bp < data; bp++) {
1901 outp += v8::internal::SNPrintF(out_buffer + outp,
1905 for (int i = 6 - instr_len; i >= 0; i--) {
1906 outp += v8::internal::SNPrintF(out_buffer + outp, " ");
1909 outp += v8::internal::SNPrintF(out_buffer + outp,
1911 tmp_buffer_.start());
1913 } // NOLINT (function is too long)
1916 //------------------------------------------------------------------------------
1919 static const char* const cpu_regs[8] = {
1920 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
1924 static const char* const byte_cpu_regs[8] = {
1925 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
1929 static const char* const xmm_regs[8] = {
1930 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
1934 const char* NameConverter::NameOfAddress(byte* addr) const {
1935 v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
1936 return tmp_buffer_.start();
1940 const char* NameConverter::NameOfConstant(byte* addr) const {
1941 return NameOfAddress(addr);
1945 const char* NameConverter::NameOfCPURegister(int reg) const {
1946 if (0 <= reg && reg < 8) return cpu_regs[reg];
1951 const char* NameConverter::NameOfByteCPURegister(int reg) const {
1952 if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
1957 const char* NameConverter::NameOfXMMRegister(int reg) const {
1958 if (0 <= reg && reg < 8) return xmm_regs[reg];
1963 const char* NameConverter::NameInCode(byte* addr) const {
1964 // IA32 does not embed debug strings at the moment.
1970 //------------------------------------------------------------------------------
1972 Disassembler::Disassembler(const NameConverter& converter)
1973 : converter_(converter) {}
1976 Disassembler::~Disassembler() {}
1979 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1980 byte* instruction) {
1981 DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
1982 return d.InstructionDecode(buffer, instruction);
1986 // The IA-32 assembler does not currently use constant pools.
1987 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
1990 /*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1991 NameConverter converter;
1992 Disassembler d(converter);
1993 for (byte* pc = begin; pc < end;) {
1994 v8::internal::EmbeddedVector<char, 128> buffer;
1997 pc += d.InstructionDecode(buffer, pc);
1998 fprintf(f, "%p", prev_pc);
2001 for (byte* bp = prev_pc; bp < pc; bp++) {
2002 fprintf(f, "%02x", *bp);
2004 for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
2007 fprintf(f, " %s\n", buffer.start());
2012 } // namespace disasm
2014 #endif // V8_TARGET_ARCH_IA32