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),
252 instruction_table_(InstructionTable::get_instance()),
254 abort_on_unimplemented_(abort_on_unimplemented) {
255 tmp_buffer_[0] = '\0';
258 virtual ~DisassemblerIA32() {}
260 // Writes one disassembled instruction into 'buffer' (0-terminated).
261 // Returns the length of the disassembled machine instruction in bytes.
262 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
265 const NameConverter& converter_;
266 byte vex_byte0_; // 0xc4 or 0xc5
268 byte vex_byte2_; // only for 3 bytes vex prefix
269 InstructionTable* instruction_table_;
270 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
271 unsigned int tmp_buffer_pos_;
272 bool abort_on_unimplemented_;
286 enum ShiftOpcodeExtension {
297 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
298 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
299 return (checked & 4) != 1;
303 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
304 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
305 return (checked & 3) == 1;
309 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
310 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
311 return (checked & 3) == 2;
315 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
316 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
317 return (checked & 3) == 3;
321 if (vex_byte0_ == 0xc5) return false;
322 return (vex_byte2_ & 0x80) != 0;
326 if (vex_byte0_ == 0xc5) return true;
327 return (vex_byte1_ & 3) == 1;
331 if (vex_byte0_ == 0xc5) return false;
332 return (vex_byte1_ & 3) == 2;
336 if (vex_byte0_ == 0xc5) return false;
337 return (vex_byte1_ & 3) == 3;
341 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
342 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
343 return ~(checked >> 3) & 0xf;
346 char float_size_code() { return "sd"[vex_w()]; }
348 const char* NameOfCPURegister(int reg) const {
349 return converter_.NameOfCPURegister(reg);
353 const char* NameOfByteCPURegister(int reg) const {
354 return converter_.NameOfByteCPURegister(reg);
358 const char* NameOfXMMRegister(int reg) const {
359 return converter_.NameOfXMMRegister(reg);
363 const char* NameOfAddress(byte* addr) const {
364 return converter_.NameOfAddress(addr);
368 // Disassembler helper functions.
369 static void get_modrm(byte data, int* mod, int* regop, int* rm) {
370 *mod = (data >> 6) & 3;
371 *regop = (data & 0x38) >> 3;
376 static void get_sib(byte data, int* scale, int* index, int* base) {
377 *scale = (data >> 6) & 3;
378 *index = (data >> 3) & 7;
382 typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const;
384 int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name);
385 int PrintRightOperand(byte* modrmp);
386 int PrintRightByteOperand(byte* modrmp);
387 int PrintRightXMMOperand(byte* modrmp);
388 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
389 int PrintImmediateOp(byte* data);
390 int F7Instruction(byte* data);
391 int D1D3C1Instruction(byte* data);
392 int JumpShort(byte* data);
393 int JumpConditional(byte* data, const char* comment);
394 int JumpConditionalShort(byte* data, const char* comment);
395 int SetCC(byte* data);
396 int CMov(byte* data);
397 int FPUInstruction(byte* data);
398 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
399 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
400 int AVXInstruction(byte* data);
401 void AppendToBuffer(const char* format, ...);
404 void UnimplementedInstruction() {
405 if (abort_on_unimplemented_) {
408 AppendToBuffer("'Unimplemented Instruction'");
414 void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
415 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
417 va_start(args, format);
418 int result = v8::internal::VSNPrintF(buf, format, args);
420 tmp_buffer_pos_ += result;
423 int DisassemblerIA32::PrintRightOperandHelper(
425 RegisterNameMapping direct_register_name) {
427 get_modrm(*modrmp, &mod, ®op, &rm);
428 RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
429 &DisassemblerIA32::NameOfCPURegister;
433 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1);
434 AppendToBuffer("[0x%x]", disp);
436 } else if (rm == esp) {
437 byte sib = *(modrmp + 1);
438 int scale, index, base;
439 get_sib(sib, &scale, &index, &base);
440 if (index == esp && base == esp && scale == 0 /*times_1*/) {
441 AppendToBuffer("[%s]", (this->*register_name)(rm));
443 } else if (base == ebp) {
444 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
445 AppendToBuffer("[%s*%d%s0x%x]",
446 (this->*register_name)(index),
448 disp < 0 ? "-" : "+",
449 disp < 0 ? -disp : disp);
451 } else if (index != esp && base != ebp) {
452 // [base+index*scale]
453 AppendToBuffer("[%s+%s*%d]",
454 (this->*register_name)(base),
455 (this->*register_name)(index),
459 UnimplementedInstruction();
463 AppendToBuffer("[%s]", (this->*register_name)(rm));
467 case 1: // fall through
470 byte sib = *(modrmp + 1);
471 int scale, index, base;
472 get_sib(sib, &scale, &index, &base);
473 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2)
474 : *reinterpret_cast<int8_t*>(modrmp + 2);
475 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
476 AppendToBuffer("[%s%s0x%x]",
477 (this->*register_name)(rm),
478 disp < 0 ? "-" : "+",
479 disp < 0 ? -disp : disp);
481 AppendToBuffer("[%s+%s*%d%s0x%x]",
482 (this->*register_name)(base),
483 (this->*register_name)(index),
485 disp < 0 ? "-" : "+",
486 disp < 0 ? -disp : disp);
488 return mod == 2 ? 6 : 3;
491 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1)
492 : *reinterpret_cast<int8_t*>(modrmp + 1);
493 AppendToBuffer("[%s%s0x%x]",
494 (this->*register_name)(rm),
495 disp < 0 ? "-" : "+",
496 disp < 0 ? -disp : disp);
497 return mod == 2 ? 5 : 2;
501 AppendToBuffer("%s", (this->*register_name)(rm));
504 UnimplementedInstruction();
511 int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
512 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
516 int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
517 return PrintRightOperandHelper(modrmp,
518 &DisassemblerIA32::NameOfByteCPURegister);
522 int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) {
523 return PrintRightOperandHelper(modrmp,
524 &DisassemblerIA32::NameOfXMMRegister);
528 // Returns number of bytes used including the current *data.
529 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
530 int DisassemblerIA32::PrintOperands(const char* mnem,
531 OperandOrder op_order,
535 get_modrm(modrm, &mod, ®op, &rm);
538 case REG_OPER_OP_ORDER: {
539 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
540 advance = PrintRightOperand(data);
543 case OPER_REG_OP_ORDER: {
544 AppendToBuffer("%s ", mnem);
545 advance = PrintRightOperand(data);
546 AppendToBuffer(",%s", NameOfCPURegister(regop));
557 // Returns number of bytes used by machine instruction, including *data byte.
558 // Writes immediate instructions to 'tmp_buffer_'.
559 int DisassemblerIA32::PrintImmediateOp(byte* data) {
560 bool sign_extension_bit = (*data & 0x02) != 0;
561 byte modrm = *(data+1);
563 get_modrm(modrm, &mod, ®op, &rm);
564 const char* mnem = "Imm???";
566 case 0: mnem = "add"; break;
567 case 1: mnem = "or"; break;
568 case 2: mnem = "adc"; break;
569 case 4: mnem = "and"; break;
570 case 5: mnem = "sub"; break;
571 case 6: mnem = "xor"; break;
572 case 7: mnem = "cmp"; break;
573 default: UnimplementedInstruction();
575 AppendToBuffer("%s ", mnem);
576 int count = PrintRightOperand(data+1);
577 if (sign_extension_bit) {
578 AppendToBuffer(",0x%x", *(data + 1 + count));
579 return 1 + count + 1 /*int8*/;
581 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
582 return 1 + count + 4 /*int32_t*/;
587 // Returns number of bytes used, including *data.
588 int DisassemblerIA32::F7Instruction(byte* data) {
589 DCHECK_EQ(0xF7, *data);
590 byte modrm = *++data;
592 get_modrm(modrm, &mod, ®op, &rm);
593 const char* mnem = NULL;
617 UnimplementedInstruction();
619 AppendToBuffer("%s ", mnem);
620 int count = PrintRightOperand(data);
622 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + count));
629 int DisassemblerIA32::D1D3C1Instruction(byte* data) {
631 DCHECK(op == 0xD1 || op == 0xD3 || op == 0xC1);
632 byte modrm = *++data;
634 get_modrm(modrm, &mod, ®op, &rm);
636 const char* mnem = NULL;
660 UnimplementedInstruction();
662 AppendToBuffer("%s ", mnem);
663 int count = PrintRightOperand(data);
666 } else if (op == 0xC1) {
669 } else if (op == 0xD3) {
670 // Shift/rotate by cl.
673 AppendToBuffer(",%d", imm8);
675 AppendToBuffer(",cl");
681 // Returns number of bytes used, including *data.
682 int DisassemblerIA32::JumpShort(byte* data) {
683 DCHECK_EQ(0xEB, *data);
685 byte* dest = data + static_cast<int8_t>(b) + 2;
686 AppendToBuffer("jmp %s", NameOfAddress(dest));
691 // Returns number of bytes used, including *data.
692 int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
693 DCHECK_EQ(0x0F, *data);
694 byte cond = *(data+1) & 0x0F;
695 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
696 const char* mnem = jump_conditional_mnem[cond];
697 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
698 if (comment != NULL) {
699 AppendToBuffer(", %s", comment);
701 return 6; // includes 0x0F
705 // Returns number of bytes used, including *data.
706 int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
707 byte cond = *data & 0x0F;
709 byte* dest = data + static_cast<int8_t>(b) + 2;
710 const char* mnem = jump_conditional_mnem[cond];
711 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
712 if (comment != NULL) {
713 AppendToBuffer(", %s", comment);
719 // Returns number of bytes used, including *data.
720 int DisassemblerIA32::SetCC(byte* data) {
721 DCHECK_EQ(0x0F, *data);
722 byte cond = *(data+1) & 0x0F;
723 const char* mnem = set_conditional_mnem[cond];
724 AppendToBuffer("%s ", mnem);
725 PrintRightByteOperand(data+2);
726 return 3; // Includes 0x0F.
730 // Returns number of bytes used, including *data.
731 int DisassemblerIA32::CMov(byte* data) {
732 DCHECK_EQ(0x0F, *data);
733 byte cond = *(data + 1) & 0x0F;
734 const char* mnem = conditional_move_mnem[cond];
735 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
736 return 2 + op_size; // includes 0x0F
740 int DisassemblerIA32::AVXInstruction(byte* data) {
742 byte* current = data + 1;
743 if (vex_66() && vex_0f38()) {
744 int mod, regop, rm, vvvv = vex_vreg();
745 get_modrm(*current, &mod, ®op, &rm);
748 AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(),
749 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
750 current += PrintRightXMMOperand(current);
753 AppendToBuffer("vfmadd213s%c %s,%s,", float_size_code(),
754 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
755 current += PrintRightXMMOperand(current);
758 AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(),
759 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
760 current += PrintRightXMMOperand(current);
763 AppendToBuffer("vfmsub132s%c %s,%s,", float_size_code(),
764 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
765 current += PrintRightXMMOperand(current);
768 AppendToBuffer("vfmsub213s%c %s,%s,", float_size_code(),
769 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
770 current += PrintRightXMMOperand(current);
773 AppendToBuffer("vfmsub231s%c %s,%s,", float_size_code(),
774 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
775 current += PrintRightXMMOperand(current);
778 AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(),
779 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
780 current += PrintRightXMMOperand(current);
783 AppendToBuffer("vfnmadd213s%c %s,%s,", float_size_code(),
784 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
785 current += PrintRightXMMOperand(current);
788 AppendToBuffer("vfnmadd231s%c %s,%s,", float_size_code(),
789 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
790 current += PrintRightXMMOperand(current);
793 AppendToBuffer("vfnmsub132s%c %s,%s,", float_size_code(),
794 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
795 current += PrintRightXMMOperand(current);
798 AppendToBuffer("vfnmsub213s%c %s,%s,", float_size_code(),
799 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
800 current += PrintRightXMMOperand(current);
803 AppendToBuffer("vfnmsub231s%c %s,%s,", float_size_code(),
804 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
805 current += PrintRightXMMOperand(current);
808 UnimplementedInstruction();
810 } else if (vex_f2() && vex_0f()) {
811 int mod, regop, rm, vvvv = vex_vreg();
812 get_modrm(*current, &mod, ®op, &rm);
815 AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop),
816 NameOfXMMRegister(vvvv));
817 current += PrintRightXMMOperand(current);
820 AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop),
821 NameOfXMMRegister(vvvv));
822 current += PrintRightXMMOperand(current);
825 AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop),
826 NameOfXMMRegister(vvvv));
827 current += PrintRightXMMOperand(current);
830 AppendToBuffer("vminsd %s,%s,", NameOfXMMRegister(regop),
831 NameOfXMMRegister(vvvv));
832 current += PrintRightXMMOperand(current);
835 AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
836 NameOfXMMRegister(vvvv));
837 current += PrintRightXMMOperand(current);
840 AppendToBuffer("vmaxsd %s,%s,", NameOfXMMRegister(regop),
841 NameOfXMMRegister(vvvv));
842 current += PrintRightXMMOperand(current);
845 UnimplementedInstruction();
848 UnimplementedInstruction();
851 return static_cast<int>(current - data);
855 // Returns number of bytes used, including *data.
856 int DisassemblerIA32::FPUInstruction(byte* data) {
857 byte escape_opcode = *data;
858 DCHECK_EQ(0xD8, escape_opcode & 0xF8);
859 byte modrm_byte = *(data+1);
861 if (modrm_byte >= 0xC0) {
862 return RegisterFPUInstruction(escape_opcode, modrm_byte);
864 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
868 int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
871 const char* mnem = "?";
872 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
873 switch (escape_opcode) {
874 case 0xD9: switch (regop) {
875 case 0: mnem = "fld_s"; break;
876 case 2: mnem = "fst_s"; break;
877 case 3: mnem = "fstp_s"; break;
878 case 7: mnem = "fstcw"; break;
879 default: UnimplementedInstruction();
883 case 0xDB: switch (regop) {
884 case 0: mnem = "fild_s"; break;
885 case 1: mnem = "fisttp_s"; break;
886 case 2: mnem = "fist_s"; break;
887 case 3: mnem = "fistp_s"; break;
888 default: UnimplementedInstruction();
892 case 0xDD: switch (regop) {
893 case 0: mnem = "fld_d"; break;
894 case 1: mnem = "fisttp_d"; break;
895 case 2: mnem = "fst_d"; break;
896 case 3: mnem = "fstp_d"; break;
897 default: UnimplementedInstruction();
901 case 0xDF: switch (regop) {
902 case 5: mnem = "fild_d"; break;
903 case 7: mnem = "fistp_d"; break;
904 default: UnimplementedInstruction();
908 default: UnimplementedInstruction();
910 AppendToBuffer("%s ", mnem);
911 int count = PrintRightOperand(modrm_start);
915 int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
917 bool has_register = false; // Is the FPU register encoded in modrm_byte?
918 const char* mnem = "?";
920 switch (escape_opcode) {
923 switch (modrm_byte & 0xF8) {
924 case 0xC0: mnem = "fadd_i"; break;
925 case 0xE0: mnem = "fsub_i"; break;
926 case 0xC8: mnem = "fmul_i"; break;
927 case 0xF0: mnem = "fdiv_i"; break;
928 default: UnimplementedInstruction();
933 switch (modrm_byte & 0xF8) {
943 switch (modrm_byte) {
944 case 0xE0: mnem = "fchs"; break;
945 case 0xE1: mnem = "fabs"; break;
946 case 0xE4: mnem = "ftst"; break;
947 case 0xE8: mnem = "fld1"; break;
948 case 0xEB: mnem = "fldpi"; break;
949 case 0xED: mnem = "fldln2"; break;
950 case 0xEE: mnem = "fldz"; break;
951 case 0xF0: mnem = "f2xm1"; break;
952 case 0xF1: mnem = "fyl2x"; break;
953 case 0xF4: mnem = "fxtract"; break;
954 case 0xF5: mnem = "fprem1"; break;
955 case 0xF7: mnem = "fincstp"; break;
956 case 0xF8: mnem = "fprem"; break;
957 case 0xFC: mnem = "frndint"; break;
958 case 0xFD: mnem = "fscale"; break;
959 case 0xFE: mnem = "fsin"; break;
960 case 0xFF: mnem = "fcos"; break;
961 default: UnimplementedInstruction();
967 if (modrm_byte == 0xE9) {
970 UnimplementedInstruction();
975 if ((modrm_byte & 0xF8) == 0xE8) {
978 } else if (modrm_byte == 0xE2) {
980 } else if (modrm_byte == 0xE3) {
983 UnimplementedInstruction();
989 switch (modrm_byte & 0xF8) {
990 case 0xC0: mnem = "fadd"; break;
991 case 0xE8: mnem = "fsub"; break;
992 case 0xC8: mnem = "fmul"; break;
993 case 0xF8: mnem = "fdiv"; break;
994 default: UnimplementedInstruction();
1000 switch (modrm_byte & 0xF8) {
1001 case 0xC0: mnem = "ffree"; break;
1002 case 0xD0: mnem = "fst"; break;
1003 case 0xD8: mnem = "fstp"; break;
1004 default: UnimplementedInstruction();
1009 if (modrm_byte == 0xD9) {
1012 has_register = true;
1013 switch (modrm_byte & 0xF8) {
1014 case 0xC0: mnem = "faddp"; break;
1015 case 0xE8: mnem = "fsubp"; break;
1016 case 0xC8: mnem = "fmulp"; break;
1017 case 0xF8: mnem = "fdivp"; break;
1018 default: UnimplementedInstruction();
1024 if (modrm_byte == 0xE0) {
1026 } else if ((modrm_byte & 0xF8) == 0xE8) {
1028 has_register = true;
1032 default: UnimplementedInstruction();
1036 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1038 AppendToBuffer("%s", mnem);
1044 // Mnemonics for instructions 0xF0 byte.
1045 // Returns NULL if the instruction is not handled here.
1046 static const char* F0Mnem(byte f0byte) {
1050 case 0x18: return "prefetch";
1051 case 0xA2: return "cpuid";
1052 case 0xBE: return "movsx_b";
1053 case 0xBF: return "movsx_w";
1054 case 0xB6: return "movzx_b";
1055 case 0xB7: return "movzx_w";
1056 case 0xAF: return "imul";
1057 case 0xA5: return "shld";
1058 case 0xAD: return "shrd";
1059 case 0xAC: return "shrd"; // 3-operand version.
1060 case 0xAB: return "bts";
1061 case 0xBD: return "bsr";
1062 default: return NULL;
1067 // Disassembled instruction '*instr' and writes it into 'out_buffer'.
1068 int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
1070 tmp_buffer_pos_ = 0; // starting to write as position 0
1073 const char* branch_hint = NULL;
1074 // We use these two prefixes only with branch prediction
1075 if (*data == 0x3E /*ds*/) {
1076 branch_hint = "predicted taken";
1078 } else if (*data == 0x2E /*cs*/) {
1079 branch_hint = "predicted not taken";
1081 } else if (*data == 0xC4 && *(data + 1) >= 0xc0) {
1083 vex_byte1_ = *(data + 1);
1084 vex_byte2_ = *(data + 2);
1086 } else if (*data == 0xC5 && *(data + 1) >= 0xc0) {
1088 vex_byte1_ = *(data + 1);
1092 bool processed = true; // Will be set to false if the current instruction
1093 // is not in 'instructions' table.
1094 // Decode AVX instructions.
1095 if (vex_byte0_ != 0) {
1096 data += AVXInstruction(data);
1098 const InstructionDesc& idesc = instruction_table_->Get(*data);
1099 switch (idesc.type) {
1100 case ZERO_OPERANDS_INSTR:
1101 AppendToBuffer(idesc.mnem);
1105 case TWO_OPERANDS_INSTR:
1107 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1110 case JUMP_CONDITIONAL_SHORT_INSTR:
1111 data += JumpConditionalShort(data, branch_hint);
1114 case REGISTER_INSTR:
1115 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
1119 case MOVE_REG_INSTR: {
1121 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1122 AppendToBuffer("mov %s,%s", NameOfCPURegister(*data & 0x07),
1123 NameOfAddress(addr));
1128 case CALL_JUMP_INSTR: {
1129 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
1130 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
1135 case SHORT_IMMEDIATE_INSTR: {
1137 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1138 AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
1143 case BYTE_IMMEDIATE_INSTR: {
1144 AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
1154 UNIMPLEMENTED(); // This type is not implemented.
1157 //----------------------------
1161 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
1167 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1168 AppendToBuffer(",%d", *data);
1174 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1175 AppendToBuffer(",%d", *reinterpret_cast<int32_t*>(data));
1183 get_modrm(*data, &mod, ®op, &rm);
1185 AppendToBuffer("test_b ");
1186 data += PrintRightByteOperand(data);
1187 int32_t imm = *data;
1188 AppendToBuffer(",0x%x", imm);
1191 UnimplementedInstruction();
1196 case 0x81: // fall through
1197 case 0x83: // 0x81 with sign extension bit set
1198 data += PrintImmediateOp(data);
1202 { byte f0byte = data[1];
1203 const char* f0mnem = F0Mnem(f0byte);
1204 if (f0byte == 0x18) {
1207 get_modrm(*data, &mod, ®op, &rm);
1208 const char* suffix[] = {"nta", "1", "2", "3"};
1209 AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
1210 data += PrintRightOperand(data);
1211 } else if (f0byte == 0x1F && data[2] == 0) {
1212 AppendToBuffer("nop"); // 3 byte nop.
1214 } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1215 AppendToBuffer("nop"); // 4 byte nop.
1217 } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1219 AppendToBuffer("nop"); // 5 byte nop.
1221 } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1222 data[4] == 0 && data[5] == 0 && data[6] == 0) {
1223 AppendToBuffer("nop"); // 7 byte nop.
1225 } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1226 data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1228 AppendToBuffer("nop"); // 8 byte nop.
1230 } else if (f0byte == 0x0B || f0byte == 0xA2 || f0byte == 0x31) {
1231 AppendToBuffer("%s", f0mnem);
1233 } else if (f0byte == 0x28) {
1236 get_modrm(*data, &mod, ®op, &rm);
1237 AppendToBuffer("movaps %s,%s",
1238 NameOfXMMRegister(regop),
1239 NameOfXMMRegister(rm));
1241 } else if (f0byte == 0x2e) {
1244 get_modrm(*data, &mod, ®op, &rm);
1245 AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
1246 data += PrintRightXMMOperand(data);
1247 } else if (f0byte >= 0x53 && f0byte <= 0x5F) {
1248 const char* const pseudo_op[] = {
1266 get_modrm(*data, &mod, ®op, &rm);
1267 AppendToBuffer("%s %s,",
1268 pseudo_op[f0byte - 0x53],
1269 NameOfXMMRegister(regop));
1270 data += PrintRightXMMOperand(data);
1271 } else if (f0byte == 0x50) {
1274 get_modrm(*data, &mod, ®op, &rm);
1275 AppendToBuffer("movmskps %s,%s",
1276 NameOfCPURegister(regop),
1277 NameOfXMMRegister(rm));
1279 } else if (f0byte== 0xC6) {
1280 // shufps xmm, xmm/m128, imm8
1283 get_modrm(*data, &mod, ®op, &rm);
1284 int8_t imm8 = static_cast<int8_t>(data[1]);
1285 AppendToBuffer("shufps %s,%s,%d",
1286 NameOfXMMRegister(rm),
1287 NameOfXMMRegister(regop),
1288 static_cast<int>(imm8));
1290 } else if ((f0byte & 0xF0) == 0x80) {
1291 data += JumpConditional(data, branch_hint);
1292 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1293 f0byte == 0xB7 || f0byte == 0xAF) {
1295 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1296 } else if ((f0byte & 0xF0) == 0x90) {
1297 data += SetCC(data);
1298 } else if ((f0byte & 0xF0) == 0x40) {
1300 } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
1303 AppendToBuffer("%s ", f0mnem);
1305 get_modrm(*data, &mod, ®op, &rm);
1306 data += PrintRightOperand(data);
1307 if (f0byte == 0xAB) {
1308 AppendToBuffer(",%s", NameOfCPURegister(regop));
1310 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1312 } else if (f0byte == 0xBD) {
1315 get_modrm(*data, &mod, ®op, &rm);
1316 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1317 data += PrintRightOperand(data);
1319 UnimplementedInstruction();
1327 get_modrm(*data, &mod, ®op, &rm);
1329 AppendToBuffer("pop ");
1330 data += PrintRightOperand(data);
1338 get_modrm(*data, &mod, ®op, &rm);
1339 const char* mnem = NULL;
1341 case esi: mnem = "push"; break;
1342 case eax: mnem = "inc"; break;
1343 case ecx: mnem = "dec"; break;
1344 case edx: mnem = "call"; break;
1345 case esp: mnem = "jmp"; break;
1346 default: mnem = "???";
1348 AppendToBuffer("%s ", mnem);
1349 data += PrintRightOperand(data);
1353 case 0xC7: // imm32, fall through
1355 { bool is_byte = *data == 0xC6;
1358 AppendToBuffer("%s ", "mov_b");
1359 data += PrintRightByteOperand(data);
1360 int32_t imm = *data;
1361 AppendToBuffer(",0x%x", imm);
1364 AppendToBuffer("%s ", "mov");
1365 data += PrintRightOperand(data);
1366 int32_t imm = *reinterpret_cast<int32_t*>(data);
1367 AppendToBuffer(",0x%x", imm);
1376 get_modrm(*data, &mod, ®op, &rm);
1377 const char* mnem = NULL;
1379 case 5: mnem = "subb"; break;
1380 case 7: mnem = "cmpb"; break;
1381 default: UnimplementedInstruction();
1383 AppendToBuffer("%s ", mnem);
1384 data += PrintRightByteOperand(data);
1385 int32_t imm = *data;
1386 AppendToBuffer(",0x%x", imm);
1391 case 0x88: // 8bit, fall through
1393 { bool is_byte = *data == 0x88;
1396 get_modrm(*data, &mod, ®op, &rm);
1398 AppendToBuffer("%s ", "mov_b");
1399 data += PrintRightByteOperand(data);
1400 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1402 AppendToBuffer("%s ", "mov");
1403 data += PrintRightOperand(data);
1404 AppendToBuffer(",%s", NameOfCPURegister(regop));
1409 case 0x66: // prefix
1410 while (*data == 0x66) data++;
1411 if (*data == 0xf && data[1] == 0x1f) {
1412 AppendToBuffer("nop"); // 0x66 prefix
1413 } else if (*data == 0x90) {
1414 AppendToBuffer("nop"); // 0x66 prefix
1415 } else if (*data == 0x8B) {
1417 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
1418 } else if (*data == 0x89) {
1421 get_modrm(*data, &mod, ®op, &rm);
1422 AppendToBuffer("mov_w ");
1423 data += PrintRightOperand(data);
1424 AppendToBuffer(",%s", NameOfCPURegister(regop));
1425 } else if (*data == 0xC7) {
1427 AppendToBuffer("%s ", "mov_w");
1428 data += PrintRightOperand(data);
1429 int imm = *reinterpret_cast<int16_t*>(data);
1430 AppendToBuffer(",0x%x", imm);
1432 } else if (*data == 0x0F) {
1434 if (*data == 0x38) {
1436 if (*data == 0x17) {
1439 get_modrm(*data, &mod, ®op, &rm);
1440 AppendToBuffer("ptest %s,%s",
1441 NameOfXMMRegister(regop),
1442 NameOfXMMRegister(rm));
1444 } else if (*data == 0x2A) {
1448 get_modrm(*data, &mod, ®op, &rm);
1449 AppendToBuffer("movntdqa %s,", NameOfXMMRegister(regop));
1450 data += PrintRightOperand(data);
1452 UnimplementedInstruction();
1454 } else if (*data == 0x3A) {
1456 if (*data == 0x0B) {
1459 get_modrm(*data, &mod, ®op, &rm);
1460 int8_t imm8 = static_cast<int8_t>(data[1]);
1461 AppendToBuffer("roundsd %s,%s,%d",
1462 NameOfXMMRegister(regop),
1463 NameOfXMMRegister(rm),
1464 static_cast<int>(imm8));
1466 } else if (*data == 0x16) {
1469 get_modrm(*data, &mod, ®op, &rm);
1470 int8_t imm8 = static_cast<int8_t>(data[1]);
1471 AppendToBuffer("pextrd %s,%s,%d",
1472 NameOfCPURegister(regop),
1473 NameOfXMMRegister(rm),
1474 static_cast<int>(imm8));
1476 } else if (*data == 0x17) {
1479 get_modrm(*data, &mod, ®op, &rm);
1480 int8_t imm8 = static_cast<int8_t>(data[1]);
1481 AppendToBuffer("extractps %s,%s,%d",
1482 NameOfCPURegister(rm),
1483 NameOfXMMRegister(regop),
1484 static_cast<int>(imm8));
1486 } else if (*data == 0x22) {
1489 get_modrm(*data, &mod, ®op, &rm);
1490 int8_t imm8 = static_cast<int8_t>(data[1]);
1491 AppendToBuffer("pinsrd %s,%s,%d",
1492 NameOfXMMRegister(regop),
1493 NameOfCPURegister(rm),
1494 static_cast<int>(imm8));
1497 UnimplementedInstruction();
1499 } else if (*data == 0x2E || *data == 0x2F) {
1500 const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
1503 get_modrm(*data, &mod, ®op, &rm);
1505 AppendToBuffer("%s %s,%s", mnem,
1506 NameOfXMMRegister(regop),
1507 NameOfXMMRegister(rm));
1510 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1511 data += PrintRightOperand(data);
1513 } else if (*data == 0x50) {
1516 get_modrm(*data, &mod, ®op, &rm);
1517 AppendToBuffer("movmskpd %s,%s",
1518 NameOfCPURegister(regop),
1519 NameOfXMMRegister(rm));
1521 } else if (*data == 0x54) {
1524 get_modrm(*data, &mod, ®op, &rm);
1525 AppendToBuffer("andpd %s,%s",
1526 NameOfXMMRegister(regop),
1527 NameOfXMMRegister(rm));
1529 } else if (*data == 0x56) {
1532 get_modrm(*data, &mod, ®op, &rm);
1533 AppendToBuffer("orpd %s,%s",
1534 NameOfXMMRegister(regop),
1535 NameOfXMMRegister(rm));
1537 } else if (*data == 0x57) {
1540 get_modrm(*data, &mod, ®op, &rm);
1541 AppendToBuffer("xorpd %s,%s",
1542 NameOfXMMRegister(regop),
1543 NameOfXMMRegister(rm));
1545 } else if (*data == 0x6E) {
1548 get_modrm(*data, &mod, ®op, &rm);
1549 AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
1550 data += PrintRightOperand(data);
1551 } else if (*data == 0x6F) {
1554 get_modrm(*data, &mod, ®op, &rm);
1555 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
1556 data += PrintRightXMMOperand(data);
1557 } else if (*data == 0x70) {
1560 get_modrm(*data, &mod, ®op, &rm);
1561 int8_t imm8 = static_cast<int8_t>(data[1]);
1562 AppendToBuffer("pshufd %s,%s,%d",
1563 NameOfXMMRegister(regop),
1564 NameOfXMMRegister(rm),
1565 static_cast<int>(imm8));
1567 } else if (*data == 0x62) {
1570 get_modrm(*data, &mod, ®op, &rm);
1571 AppendToBuffer("punpckldq %s,%s", NameOfXMMRegister(regop),
1572 NameOfXMMRegister(rm));
1574 } else if (*data == 0x6A) {
1577 get_modrm(*data, &mod, ®op, &rm);
1578 AppendToBuffer("punpckhdq %s,%s", NameOfXMMRegister(regop),
1579 NameOfXMMRegister(rm));
1581 } else if (*data == 0x76) {
1584 get_modrm(*data, &mod, ®op, &rm);
1585 AppendToBuffer("pcmpeqd %s,%s",
1586 NameOfXMMRegister(regop),
1587 NameOfXMMRegister(rm));
1589 } else if (*data == 0x90) {
1591 AppendToBuffer("nop"); // 2 byte nop.
1592 } else if (*data == 0xF3) {
1595 get_modrm(*data, &mod, ®op, &rm);
1596 AppendToBuffer("psllq %s,%s",
1597 NameOfXMMRegister(regop),
1598 NameOfXMMRegister(rm));
1600 } else if (*data == 0x72) {
1603 get_modrm(*data, &mod, ®op, &rm);
1604 int8_t imm8 = static_cast<int8_t>(data[1]);
1605 DCHECK(regop == esi || regop == edx);
1606 AppendToBuffer("%s %s,%d", (regop == esi) ? "pslld" : "psrld",
1607 NameOfXMMRegister(rm), static_cast<int>(imm8));
1609 } else if (*data == 0x73) {
1612 get_modrm(*data, &mod, ®op, &rm);
1613 int8_t imm8 = static_cast<int8_t>(data[1]);
1614 DCHECK(regop == esi || regop == edx);
1615 AppendToBuffer("%s %s,%d",
1616 (regop == esi) ? "psllq" : "psrlq",
1617 NameOfXMMRegister(rm),
1618 static_cast<int>(imm8));
1620 } else if (*data == 0xD3) {
1623 get_modrm(*data, &mod, ®op, &rm);
1624 AppendToBuffer("psrlq %s,%s",
1625 NameOfXMMRegister(regop),
1626 NameOfXMMRegister(rm));
1628 } else if (*data == 0x7F) {
1629 AppendToBuffer("movdqa ");
1632 get_modrm(*data, &mod, ®op, &rm);
1633 data += PrintRightXMMOperand(data);
1634 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1635 } else if (*data == 0x7E) {
1638 get_modrm(*data, &mod, ®op, &rm);
1639 AppendToBuffer("movd ");
1640 data += PrintRightOperand(data);
1641 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1642 } else if (*data == 0xDB) {
1645 get_modrm(*data, &mod, ®op, &rm);
1646 AppendToBuffer("pand %s,%s",
1647 NameOfXMMRegister(regop),
1648 NameOfXMMRegister(rm));
1650 } else if (*data == 0xE7) {
1653 get_modrm(*data, &mod, ®op, &rm);
1655 AppendToBuffer("movntdq ");
1656 data += PrintRightOperand(data);
1657 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1659 UnimplementedInstruction();
1661 } else if (*data == 0xEF) {
1664 get_modrm(*data, &mod, ®op, &rm);
1665 AppendToBuffer("pxor %s,%s",
1666 NameOfXMMRegister(regop),
1667 NameOfXMMRegister(rm));
1669 } else if (*data == 0xEB) {
1672 get_modrm(*data, &mod, ®op, &rm);
1673 AppendToBuffer("por %s,%s",
1674 NameOfXMMRegister(regop),
1675 NameOfXMMRegister(rm));
1678 UnimplementedInstruction();
1681 UnimplementedInstruction();
1688 get_modrm(*data, &mod, ®op, &rm);
1690 AppendToBuffer("dec_b ");
1691 data += PrintRightOperand(data);
1693 UnimplementedInstruction();
1699 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1704 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1709 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1714 AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1718 case 0xD1: // fall through
1719 case 0xD3: // fall through
1721 data += D1D3C1Instruction(data);
1724 case 0xD8: // fall through
1725 case 0xD9: // fall through
1726 case 0xDA: // fall through
1727 case 0xDB: // fall through
1728 case 0xDC: // fall through
1729 case 0xDD: // fall through
1730 case 0xDE: // fall through
1732 data += FPUInstruction(data);
1736 data += JumpShort(data);
1740 if (*(data+1) == 0x0F) {
1741 byte b2 = *(data+2);
1743 AppendToBuffer("movsd ");
1746 get_modrm(*data, &mod, ®op, &rm);
1747 data += PrintRightXMMOperand(data);
1748 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1749 } else if (b2 == 0x10) {
1752 get_modrm(*data, &mod, ®op, &rm);
1753 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
1754 data += PrintRightXMMOperand(data);
1755 } else if (b2 == 0x5A) {
1758 get_modrm(*data, &mod, ®op, &rm);
1759 AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
1760 data += PrintRightXMMOperand(data);
1762 const char* mnem = "?";
1764 case 0x2A: mnem = "cvtsi2sd"; break;
1765 case 0x2C: mnem = "cvttsd2si"; break;
1766 case 0x2D: mnem = "cvtsd2si"; break;
1767 case 0x51: mnem = "sqrtsd"; break;
1768 case 0x58: mnem = "addsd"; break;
1769 case 0x59: mnem = "mulsd"; break;
1770 case 0x5C: mnem = "subsd"; break;
1774 case 0x5E: mnem = "divsd"; break;
1781 get_modrm(*data, &mod, ®op, &rm);
1783 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1784 data += PrintRightOperand(data);
1785 } else if (b2 == 0x2C || b2 == 0x2D) {
1786 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
1787 data += PrintRightXMMOperand(data);
1788 } else if (b2 == 0xC2) {
1789 // Intel manual 2A, Table 3-18.
1790 const char* const pseudo_op[] = {
1800 AppendToBuffer("%s %s,%s",
1802 NameOfXMMRegister(regop),
1803 NameOfXMMRegister(rm));
1806 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1807 data += PrintRightXMMOperand(data);
1811 UnimplementedInstruction();
1816 if (*(data+1) == 0x0F) {
1817 byte b2 = *(data+2);
1819 AppendToBuffer("movss ");
1822 get_modrm(*data, &mod, ®op, &rm);
1823 data += PrintRightXMMOperand(data);
1824 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1825 } else if (b2 == 0x10) {
1828 get_modrm(*data, &mod, ®op, &rm);
1829 AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
1830 data += PrintRightXMMOperand(data);
1831 } else if (b2 == 0x2C) {
1834 get_modrm(*data, &mod, ®op, &rm);
1835 AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
1836 data += PrintRightXMMOperand(data);
1837 } else if (b2 == 0x58) {
1840 get_modrm(*data, &mod, ®op, &rm);
1841 AppendToBuffer("addss %s,", NameOfXMMRegister(regop));
1842 data += PrintRightXMMOperand(data);
1843 } else if (b2 == 0x59) {
1846 get_modrm(*data, &mod, ®op, &rm);
1847 AppendToBuffer("mulss %s,", NameOfXMMRegister(regop));
1848 data += PrintRightXMMOperand(data);
1849 } else if (b2 == 0x5A) {
1852 get_modrm(*data, &mod, ®op, &rm);
1853 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1854 data += PrintRightXMMOperand(data);
1855 } else if (b2 == 0x5c) {
1858 get_modrm(*data, &mod, ®op, &rm);
1859 AppendToBuffer("subss %s,", NameOfXMMRegister(regop));
1860 data += PrintRightXMMOperand(data);
1861 } else if (b2 == 0x5e) {
1864 get_modrm(*data, &mod, ®op, &rm);
1865 AppendToBuffer("divss %s,", NameOfXMMRegister(regop));
1866 data += PrintRightXMMOperand(data);
1867 } else if (b2 == 0x6F) {
1870 get_modrm(*data, &mod, ®op, &rm);
1871 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
1872 data += PrintRightXMMOperand(data);
1873 } else if (b2 == 0x7F) {
1874 AppendToBuffer("movdqu ");
1877 get_modrm(*data, &mod, ®op, &rm);
1878 data += PrintRightXMMOperand(data);
1879 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1881 UnimplementedInstruction();
1883 } else if (*(data+1) == 0xA5) {
1885 AppendToBuffer("rep_movs");
1886 } else if (*(data+1) == 0xAB) {
1888 AppendToBuffer("rep_stos");
1890 UnimplementedInstruction();
1895 data += F7Instruction(data);
1899 UnimplementedInstruction();
1903 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1904 tmp_buffer_[tmp_buffer_pos_] = '\0';
1907 int instr_len = data - instr;
1908 if (instr_len == 0) {
1909 printf("%02x", *data);
1911 DCHECK(instr_len > 0); // Ensure progress.
1914 // Instruction bytes.
1915 for (byte* bp = instr; bp < data; bp++) {
1916 outp += v8::internal::SNPrintF(out_buffer + outp,
1920 for (int i = 6 - instr_len; i >= 0; i--) {
1921 outp += v8::internal::SNPrintF(out_buffer + outp, " ");
1924 outp += v8::internal::SNPrintF(out_buffer + outp,
1926 tmp_buffer_.start());
1928 } // NOLINT (function is too long)
1931 //------------------------------------------------------------------------------
1934 static const char* const cpu_regs[8] = {
1935 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
1939 static const char* const byte_cpu_regs[8] = {
1940 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
1944 static const char* const xmm_regs[8] = {
1945 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
1949 const char* NameConverter::NameOfAddress(byte* addr) const {
1950 v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
1951 return tmp_buffer_.start();
1955 const char* NameConverter::NameOfConstant(byte* addr) const {
1956 return NameOfAddress(addr);
1960 const char* NameConverter::NameOfCPURegister(int reg) const {
1961 if (0 <= reg && reg < 8) return cpu_regs[reg];
1966 const char* NameConverter::NameOfByteCPURegister(int reg) const {
1967 if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
1972 const char* NameConverter::NameOfXMMRegister(int reg) const {
1973 if (0 <= reg && reg < 8) return xmm_regs[reg];
1978 const char* NameConverter::NameInCode(byte* addr) const {
1979 // IA32 does not embed debug strings at the moment.
1985 //------------------------------------------------------------------------------
1987 Disassembler::Disassembler(const NameConverter& converter)
1988 : converter_(converter) {}
1991 Disassembler::~Disassembler() {}
1994 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1995 byte* instruction) {
1996 DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
1997 return d.InstructionDecode(buffer, instruction);
2001 // The IA-32 assembler does not currently use constant pools.
2002 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
2005 /*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
2006 NameConverter converter;
2007 Disassembler d(converter);
2008 for (byte* pc = begin; pc < end;) {
2009 v8::internal::EmbeddedVector<char, 128> buffer;
2012 pc += d.InstructionDecode(buffer, pc);
2013 fprintf(f, "%p", prev_pc);
2016 for (byte* bp = prev_pc; bp < pc; bp++) {
2017 fprintf(f, "%02x", *bp);
2019 for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
2022 fprintf(f, " %s\n", buffer.start());
2027 } // namespace disasm
2029 #endif // V8_TARGET_ARCH_IA32