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_X64
13 #include "src/base/lazy-instance.h"
14 #include "src/disasm.h"
20 // Operand size decides between 16, 32 and 64 bit operands.
21 REG_OPER_OP_ORDER = 1, // Register destination, operand source.
22 OPER_REG_OP_ORDER = 2, // Operand destination, register source.
23 // Fixed 8-bit operands.
24 BYTE_SIZE_OPERAND_FLAG = 4,
25 BYTE_REG_OPER_OP_ORDER = REG_OPER_OP_ORDER | BYTE_SIZE_OPERAND_FLAG,
26 BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG
30 //------------------------------------------------------------------
32 //------------------------------------------------------------------
34 int b; // -1 terminates, otherwise must be in range (0..255)
35 OperandType op_order_;
40 static const ByteMnemonic two_operands_instr[] = {
41 { 0x00, BYTE_OPER_REG_OP_ORDER, "add" },
42 { 0x01, OPER_REG_OP_ORDER, "add" },
43 { 0x02, BYTE_REG_OPER_OP_ORDER, "add" },
44 { 0x03, REG_OPER_OP_ORDER, "add" },
45 { 0x08, BYTE_OPER_REG_OP_ORDER, "or" },
46 { 0x09, OPER_REG_OP_ORDER, "or" },
47 { 0x0A, BYTE_REG_OPER_OP_ORDER, "or" },
48 { 0x0B, REG_OPER_OP_ORDER, "or" },
49 { 0x10, BYTE_OPER_REG_OP_ORDER, "adc" },
50 { 0x11, OPER_REG_OP_ORDER, "adc" },
51 { 0x12, BYTE_REG_OPER_OP_ORDER, "adc" },
52 { 0x13, REG_OPER_OP_ORDER, "adc" },
53 { 0x18, BYTE_OPER_REG_OP_ORDER, "sbb" },
54 { 0x19, OPER_REG_OP_ORDER, "sbb" },
55 { 0x1A, BYTE_REG_OPER_OP_ORDER, "sbb" },
56 { 0x1B, REG_OPER_OP_ORDER, "sbb" },
57 { 0x20, BYTE_OPER_REG_OP_ORDER, "and" },
58 { 0x21, OPER_REG_OP_ORDER, "and" },
59 { 0x22, BYTE_REG_OPER_OP_ORDER, "and" },
60 { 0x23, REG_OPER_OP_ORDER, "and" },
61 { 0x28, BYTE_OPER_REG_OP_ORDER, "sub" },
62 { 0x29, OPER_REG_OP_ORDER, "sub" },
63 { 0x2A, BYTE_REG_OPER_OP_ORDER, "sub" },
64 { 0x2B, REG_OPER_OP_ORDER, "sub" },
65 { 0x30, BYTE_OPER_REG_OP_ORDER, "xor" },
66 { 0x31, OPER_REG_OP_ORDER, "xor" },
67 { 0x32, BYTE_REG_OPER_OP_ORDER, "xor" },
68 { 0x33, REG_OPER_OP_ORDER, "xor" },
69 { 0x38, BYTE_OPER_REG_OP_ORDER, "cmp" },
70 { 0x39, OPER_REG_OP_ORDER, "cmp" },
71 { 0x3A, BYTE_REG_OPER_OP_ORDER, "cmp" },
72 { 0x3B, REG_OPER_OP_ORDER, "cmp" },
73 { 0x63, REG_OPER_OP_ORDER, "movsxl" },
74 { 0x84, BYTE_REG_OPER_OP_ORDER, "test" },
75 { 0x85, REG_OPER_OP_ORDER, "test" },
76 { 0x86, BYTE_REG_OPER_OP_ORDER, "xchg" },
77 { 0x87, REG_OPER_OP_ORDER, "xchg" },
78 { 0x88, BYTE_OPER_REG_OP_ORDER, "mov" },
79 { 0x89, OPER_REG_OP_ORDER, "mov" },
80 { 0x8A, BYTE_REG_OPER_OP_ORDER, "mov" },
81 { 0x8B, REG_OPER_OP_ORDER, "mov" },
82 { 0x8D, REG_OPER_OP_ORDER, "lea" },
83 { -1, UNSET_OP_ORDER, "" }
87 static const ByteMnemonic zero_operands_instr[] = {
88 { 0xC3, UNSET_OP_ORDER, "ret" },
89 { 0xC9, UNSET_OP_ORDER, "leave" },
90 { 0xF4, UNSET_OP_ORDER, "hlt" },
91 { 0xFC, UNSET_OP_ORDER, "cld" },
92 { 0xCC, UNSET_OP_ORDER, "int3" },
93 { 0x60, UNSET_OP_ORDER, "pushad" },
94 { 0x61, UNSET_OP_ORDER, "popad" },
95 { 0x9C, UNSET_OP_ORDER, "pushfd" },
96 { 0x9D, UNSET_OP_ORDER, "popfd" },
97 { 0x9E, UNSET_OP_ORDER, "sahf" },
98 { 0x99, UNSET_OP_ORDER, "cdq" },
99 { 0x9B, UNSET_OP_ORDER, "fwait" },
100 { 0xA4, UNSET_OP_ORDER, "movs" },
101 { 0xA5, UNSET_OP_ORDER, "movs" },
102 { 0xA6, UNSET_OP_ORDER, "cmps" },
103 { 0xA7, UNSET_OP_ORDER, "cmps" },
104 { -1, UNSET_OP_ORDER, "" }
108 static const ByteMnemonic call_jump_instr[] = {
109 { 0xE8, UNSET_OP_ORDER, "call" },
110 { 0xE9, UNSET_OP_ORDER, "jmp" },
111 { -1, UNSET_OP_ORDER, "" }
115 static const ByteMnemonic short_immediate_instr[] = {
116 { 0x05, UNSET_OP_ORDER, "add" },
117 { 0x0D, UNSET_OP_ORDER, "or" },
118 { 0x15, UNSET_OP_ORDER, "adc" },
119 { 0x1D, UNSET_OP_ORDER, "sbb" },
120 { 0x25, UNSET_OP_ORDER, "and" },
121 { 0x2D, UNSET_OP_ORDER, "sub" },
122 { 0x35, UNSET_OP_ORDER, "xor" },
123 { 0x3D, UNSET_OP_ORDER, "cmp" },
124 { -1, UNSET_OP_ORDER, "" }
128 static const char* const conditional_code_suffix[] = {
129 "o", "no", "c", "nc", "z", "nz", "na", "a",
130 "s", "ns", "pe", "po", "l", "ge", "le", "g"
134 enum InstructionType {
138 JUMP_CONDITIONAL_SHORT_INSTR,
140 PUSHPOP_INSTR, // Has implicit 64-bit operand size.
143 SHORT_IMMEDIATE_INSTR
148 ESCAPE_PREFIX = 0x0F,
149 OPERAND_SIZE_OVERRIDE_PREFIX = 0x66,
150 ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67,
153 REPEQ_PREFIX = REP_PREFIX
157 struct InstructionDesc {
159 InstructionType type;
160 OperandType op_order_;
161 bool byte_size_operation; // Fixed 8-bit operation.
165 class InstructionTable {
168 const InstructionDesc& Get(byte x) const {
169 return instructions_[x];
173 InstructionDesc instructions_[256];
176 void CopyTable(const ByteMnemonic bm[], InstructionType type);
177 void SetTableRange(InstructionType type, byte start, byte end, bool byte_size,
179 void AddJumpConditionalShort();
183 InstructionTable::InstructionTable() {
189 void InstructionTable::Clear() {
190 for (int i = 0; i < 256; i++) {
191 instructions_[i].mnem = "(bad)";
192 instructions_[i].type = NO_INSTR;
193 instructions_[i].op_order_ = UNSET_OP_ORDER;
194 instructions_[i].byte_size_operation = false;
199 void InstructionTable::Init() {
200 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
201 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
202 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
203 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
204 AddJumpConditionalShort();
205 SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push");
206 SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop");
207 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov");
211 void InstructionTable::CopyTable(const ByteMnemonic bm[],
212 InstructionType type) {
213 for (int i = 0; bm[i].b >= 0; i++) {
214 InstructionDesc* id = &instructions_[bm[i].b];
215 id->mnem = bm[i].mnem;
216 OperandType op_order = bm[i].op_order_;
218 static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG);
219 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered
221 id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0);
226 void InstructionTable::SetTableRange(InstructionType type,
231 for (byte b = start; b <= end; b++) {
232 InstructionDesc* id = &instructions_[b];
233 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered
236 id->byte_size_operation = byte_size;
241 void InstructionTable::AddJumpConditionalShort() {
242 for (byte b = 0x70; b <= 0x7F; b++) {
243 InstructionDesc* id = &instructions_[b];
244 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered
245 id->mnem = NULL; // Computed depending on condition code.
246 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
251 static v8::base::LazyInstance<InstructionTable>::type instruction_table =
252 LAZY_INSTANCE_INITIALIZER;
255 static InstructionDesc cmov_instructions[16] = {
256 {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
257 {"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
258 {"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
259 {"cmovnc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
260 {"cmovz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
261 {"cmovnz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
262 {"cmovna", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
263 {"cmova", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
264 {"cmovs", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
265 {"cmovns", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
266 {"cmovpe", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
267 {"cmovpo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
268 {"cmovl", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
269 {"cmovge", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
270 {"cmovle", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
271 {"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}
275 //------------------------------------------------------------------------------
276 // DisassemblerX64 implementation.
278 enum UnimplementedOpcodeAction {
279 CONTINUE_ON_UNIMPLEMENTED_OPCODE,
280 ABORT_ON_UNIMPLEMENTED_OPCODE
284 // A new DisassemblerX64 object is created to disassemble each instruction.
285 // The object can only disassemble a single instruction.
286 class DisassemblerX64 {
288 DisassemblerX64(const NameConverter& converter,
289 UnimplementedOpcodeAction unimplemented_action =
290 ABORT_ON_UNIMPLEMENTED_OPCODE)
291 : converter_(converter),
293 abort_on_unimplemented_(
294 unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE),
298 byte_size_operand_(false),
299 instruction_table_(instruction_table.Pointer()) {
300 tmp_buffer_[0] = '\0';
303 virtual ~DisassemblerX64() {
306 // Writes one disassembled instruction into 'buffer' (0-terminated).
307 // Returns the length of the disassembled machine instruction in bytes.
308 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
312 OPERAND_BYTE_SIZE = 0,
313 OPERAND_WORD_SIZE = 1,
314 OPERAND_DOUBLEWORD_SIZE = 2,
315 OPERAND_QUADWORD_SIZE = 3
329 const NameConverter& converter_;
330 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
331 unsigned int tmp_buffer_pos_;
332 bool abort_on_unimplemented_;
335 byte operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0.
336 byte group_1_prefix_; // 0xF2, 0xF3, or (if no group 1 prefix is present) 0.
337 // Byte size operand override.
338 bool byte_size_operand_;
339 const InstructionTable* const instruction_table_;
341 void setRex(byte rex) {
342 ASSERT_EQ(0x40, rex & 0xF0);
346 bool rex() { return rex_ != 0; }
348 bool rex_b() { return (rex_ & 0x01) != 0; }
350 // Actual number of base register given the low bits and the rex.b state.
351 int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); }
353 bool rex_x() { return (rex_ & 0x02) != 0; }
355 bool rex_r() { return (rex_ & 0x04) != 0; }
357 bool rex_w() { return (rex_ & 0x08) != 0; }
359 OperandSize operand_size() {
360 if (byte_size_operand_) return OPERAND_BYTE_SIZE;
361 if (rex_w()) return OPERAND_QUADWORD_SIZE;
362 if (operand_size_ != 0) return OPERAND_WORD_SIZE;
363 return OPERAND_DOUBLEWORD_SIZE;
366 char operand_size_code() {
367 return "bwlq"[operand_size()];
370 const char* NameOfCPURegister(int reg) const {
371 return converter_.NameOfCPURegister(reg);
374 const char* NameOfByteCPURegister(int reg) const {
375 return converter_.NameOfByteCPURegister(reg);
378 const char* NameOfXMMRegister(int reg) const {
379 return converter_.NameOfXMMRegister(reg);
382 const char* NameOfAddress(byte* addr) const {
383 return converter_.NameOfAddress(addr);
386 // Disassembler helper functions.
387 void get_modrm(byte data,
391 *mod = (data >> 6) & 3;
392 *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0);
393 *rm = (data & 7) | (rex_b() ? 8 : 0);
396 void get_sib(byte data,
400 *scale = (data >> 6) & 3;
401 *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0);
402 *base = (data & 7) | (rex_b() ? 8 : 0);
405 typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const;
407 int PrintRightOperandHelper(byte* modrmp,
408 RegisterNameMapping register_name);
409 int PrintRightOperand(byte* modrmp);
410 int PrintRightByteOperand(byte* modrmp);
411 int PrintRightXMMOperand(byte* modrmp);
412 int PrintOperands(const char* mnem,
413 OperandType op_order,
415 int PrintImmediate(byte* data, OperandSize size);
416 int PrintImmediateOp(byte* data);
417 const char* TwoByteMnemonic(byte opcode);
418 int TwoByteOpcodeInstruction(byte* data);
419 int F6F7Instruction(byte* data);
420 int ShiftInstruction(byte* data);
421 int JumpShort(byte* data);
422 int JumpConditional(byte* data);
423 int JumpConditionalShort(byte* data);
424 int SetCC(byte* data);
425 int FPUInstruction(byte* data);
426 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
427 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
428 void AppendToBuffer(const char* format, ...);
430 void UnimplementedInstruction() {
431 if (abort_on_unimplemented_) {
434 AppendToBuffer("'Unimplemented Instruction'");
440 void DisassemblerX64::AppendToBuffer(const char* format, ...) {
441 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
443 va_start(args, format);
444 int result = v8::internal::VSNPrintF(buf, format, args);
446 tmp_buffer_pos_ += result;
450 int DisassemblerX64::PrintRightOperandHelper(
452 RegisterNameMapping direct_register_name) {
454 get_modrm(*modrmp, &mod, ®op, &rm);
455 RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
456 &DisassemblerX64::NameOfCPURegister;
460 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 1);
461 AppendToBuffer("[0x%x]", disp);
463 } else if ((rm & 7) == 4) {
464 // Codes for SIB byte.
465 byte sib = *(modrmp + 1);
466 int scale, index, base;
467 get_sib(sib, &scale, &index, &base);
468 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
469 // index == rsp means no index. Only use sib byte with no index for
471 AppendToBuffer("[%s]", NameOfCPURegister(base));
473 } else if (base == 5) {
474 // base == rbp means no base register (when mod == 0).
475 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
476 AppendToBuffer("[%s*%d%s0x%x]",
477 NameOfCPURegister(index),
479 disp < 0 ? "-" : "+",
480 disp < 0 ? -disp : disp);
482 } else if (index != 4 && base != 5) {
483 // [base+index*scale]
484 AppendToBuffer("[%s+%s*%d]",
485 NameOfCPURegister(base),
486 NameOfCPURegister(index),
490 UnimplementedInstruction();
494 AppendToBuffer("[%s]", NameOfCPURegister(rm));
498 case 1: // fall through
501 byte sib = *(modrmp + 1);
502 int scale, index, base;
503 get_sib(sib, &scale, &index, &base);
504 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 2)
505 : *reinterpret_cast<int8_t*>(modrmp + 2);
506 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
507 AppendToBuffer("[%s%s0x%x]",
508 NameOfCPURegister(base),
509 disp < 0 ? "-" : "+",
510 disp < 0 ? -disp : disp);
512 AppendToBuffer("[%s+%s*%d%s0x%x]",
513 NameOfCPURegister(base),
514 NameOfCPURegister(index),
516 disp < 0 ? "-" : "+",
517 disp < 0 ? -disp : disp);
519 return mod == 2 ? 6 : 3;
522 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 1)
523 : *reinterpret_cast<int8_t*>(modrmp + 1);
524 AppendToBuffer("[%s%s0x%x]",
525 NameOfCPURegister(rm),
526 disp < 0 ? "-" : "+",
527 disp < 0 ? -disp : disp);
528 return (mod == 2) ? 5 : 2;
532 AppendToBuffer("%s", (this->*register_name)(rm));
535 UnimplementedInstruction();
542 int DisassemblerX64::PrintImmediate(byte* data, OperandSize size) {
546 case OPERAND_BYTE_SIZE:
550 case OPERAND_WORD_SIZE:
551 value = *reinterpret_cast<int16_t*>(data);
554 case OPERAND_DOUBLEWORD_SIZE:
555 value = *reinterpret_cast<uint32_t*>(data);
558 case OPERAND_QUADWORD_SIZE:
559 value = *reinterpret_cast<int32_t*>(data);
564 value = 0; // Initialize variables on all paths to satisfy the compiler.
567 AppendToBuffer("%" V8_PTR_PREFIX "x", value);
572 int DisassemblerX64::PrintRightOperand(byte* modrmp) {
573 return PrintRightOperandHelper(modrmp,
574 &DisassemblerX64::NameOfCPURegister);
578 int DisassemblerX64::PrintRightByteOperand(byte* modrmp) {
579 return PrintRightOperandHelper(modrmp,
580 &DisassemblerX64::NameOfByteCPURegister);
584 int DisassemblerX64::PrintRightXMMOperand(byte* modrmp) {
585 return PrintRightOperandHelper(modrmp,
586 &DisassemblerX64::NameOfXMMRegister);
590 // Returns number of bytes used including the current *data.
591 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
592 int DisassemblerX64::PrintOperands(const char* mnem,
593 OperandType op_order,
597 get_modrm(modrm, &mod, ®op, &rm);
599 const char* register_name =
600 byte_size_operand_ ? NameOfByteCPURegister(regop)
601 : NameOfCPURegister(regop);
603 case REG_OPER_OP_ORDER: {
604 AppendToBuffer("%s%c %s,",
608 advance = byte_size_operand_ ? PrintRightByteOperand(data)
609 : PrintRightOperand(data);
612 case OPER_REG_OP_ORDER: {
613 AppendToBuffer("%s%c ", mnem, operand_size_code());
614 advance = byte_size_operand_ ? PrintRightByteOperand(data)
615 : PrintRightOperand(data);
616 AppendToBuffer(",%s", register_name);
627 // Returns number of bytes used by machine instruction, including *data byte.
628 // Writes immediate instructions to 'tmp_buffer_'.
629 int DisassemblerX64::PrintImmediateOp(byte* data) {
630 bool byte_size_immediate = (*data & 0x02) != 0;
631 byte modrm = *(data + 1);
633 get_modrm(modrm, &mod, ®op, &rm);
634 const char* mnem = "Imm???";
661 UnimplementedInstruction();
663 AppendToBuffer("%s%c ", mnem, operand_size_code());
664 int count = PrintRightOperand(data + 1);
665 AppendToBuffer(",0x");
666 OperandSize immediate_size =
667 byte_size_immediate ? OPERAND_BYTE_SIZE : operand_size();
668 count += PrintImmediate(data + 1 + count, immediate_size);
673 // Returns number of bytes used, including *data.
674 int DisassemblerX64::F6F7Instruction(byte* data) {
675 ASSERT(*data == 0xF7 || *data == 0xF6);
676 byte modrm = *(data + 1);
678 get_modrm(modrm, &mod, ®op, &rm);
679 if (mod == 3 && regop != 0) {
680 const char* mnem = NULL;
698 UnimplementedInstruction();
700 AppendToBuffer("%s%c %s",
703 NameOfCPURegister(rm));
705 } else if (regop == 0) {
706 AppendToBuffer("test%c ", operand_size_code());
707 int count = PrintRightOperand(data + 1); // Use name of 64-bit register.
708 AppendToBuffer(",0x");
709 count += PrintImmediate(data + 1 + count, operand_size());
712 UnimplementedInstruction();
718 int DisassemblerX64::ShiftInstruction(byte* data) {
719 byte op = *data & (~1);
720 if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
721 UnimplementedInstruction();
724 byte modrm = *(data + 1);
726 get_modrm(modrm, &mod, ®op, &rm);
727 regop &= 0x7; // The REX.R bit does not affect the operation.
731 UnimplementedInstruction();
734 const char* mnem = NULL;
758 UnimplementedInstruction();
761 ASSERT_NE(NULL, mnem);
764 } else if (op == 0xC0) {
768 AppendToBuffer("%s%c %s,",
771 byte_size_operand_ ? NameOfByteCPURegister(rm)
772 : NameOfCPURegister(rm));
774 AppendToBuffer("cl");
776 AppendToBuffer("%d", imm8);
782 // Returns number of bytes used, including *data.
783 int DisassemblerX64::JumpShort(byte* data) {
784 ASSERT_EQ(0xEB, *data);
785 byte b = *(data + 1);
786 byte* dest = data + static_cast<int8_t>(b) + 2;
787 AppendToBuffer("jmp %s", NameOfAddress(dest));
792 // Returns number of bytes used, including *data.
793 int DisassemblerX64::JumpConditional(byte* data) {
794 ASSERT_EQ(0x0F, *data);
795 byte cond = *(data + 1) & 0x0F;
796 byte* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6;
797 const char* mnem = conditional_code_suffix[cond];
798 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
799 return 6; // includes 0x0F
803 // Returns number of bytes used, including *data.
804 int DisassemblerX64::JumpConditionalShort(byte* data) {
805 byte cond = *data & 0x0F;
806 byte b = *(data + 1);
807 byte* dest = data + static_cast<int8_t>(b) + 2;
808 const char* mnem = conditional_code_suffix[cond];
809 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
814 // Returns number of bytes used, including *data.
815 int DisassemblerX64::SetCC(byte* data) {
816 ASSERT_EQ(0x0F, *data);
817 byte cond = *(data + 1) & 0x0F;
818 const char* mnem = conditional_code_suffix[cond];
819 AppendToBuffer("set%s%c ", mnem, operand_size_code());
820 PrintRightByteOperand(data + 2);
821 return 3; // includes 0x0F
825 // Returns number of bytes used, including *data.
826 int DisassemblerX64::FPUInstruction(byte* data) {
827 byte escape_opcode = *data;
828 ASSERT_EQ(0xD8, escape_opcode & 0xF8);
829 byte modrm_byte = *(data+1);
831 if (modrm_byte >= 0xC0) {
832 return RegisterFPUInstruction(escape_opcode, modrm_byte);
834 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
838 int DisassemblerX64::MemoryFPUInstruction(int escape_opcode,
841 const char* mnem = "?";
842 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
843 switch (escape_opcode) {
844 case 0xD9: switch (regop) {
845 case 0: mnem = "fld_s"; break;
846 case 3: mnem = "fstp_s"; break;
847 case 7: mnem = "fstcw"; break;
848 default: UnimplementedInstruction();
852 case 0xDB: switch (regop) {
853 case 0: mnem = "fild_s"; break;
854 case 1: mnem = "fisttp_s"; break;
855 case 2: mnem = "fist_s"; break;
856 case 3: mnem = "fistp_s"; break;
857 default: UnimplementedInstruction();
861 case 0xDD: switch (regop) {
862 case 0: mnem = "fld_d"; break;
863 case 3: mnem = "fstp_d"; break;
864 default: UnimplementedInstruction();
868 case 0xDF: switch (regop) {
869 case 5: mnem = "fild_d"; break;
870 case 7: mnem = "fistp_d"; break;
871 default: UnimplementedInstruction();
875 default: UnimplementedInstruction();
877 AppendToBuffer("%s ", mnem);
878 int count = PrintRightOperand(modrm_start);
882 int DisassemblerX64::RegisterFPUInstruction(int escape_opcode,
884 bool has_register = false; // Is the FPU register encoded in modrm_byte?
885 const char* mnem = "?";
887 switch (escape_opcode) {
889 UnimplementedInstruction();
893 switch (modrm_byte & 0xF8) {
903 switch (modrm_byte) {
904 case 0xE0: mnem = "fchs"; break;
905 case 0xE1: mnem = "fabs"; break;
906 case 0xE3: mnem = "fninit"; break;
907 case 0xE4: mnem = "ftst"; break;
908 case 0xE8: mnem = "fld1"; break;
909 case 0xEB: mnem = "fldpi"; break;
910 case 0xED: mnem = "fldln2"; break;
911 case 0xEE: mnem = "fldz"; break;
912 case 0xF0: mnem = "f2xm1"; break;
913 case 0xF1: mnem = "fyl2x"; break;
914 case 0xF2: mnem = "fptan"; break;
915 case 0xF5: mnem = "fprem1"; break;
916 case 0xF7: mnem = "fincstp"; break;
917 case 0xF8: mnem = "fprem"; break;
918 case 0xFC: mnem = "frndint"; break;
919 case 0xFD: mnem = "fscale"; break;
920 case 0xFE: mnem = "fsin"; break;
921 case 0xFF: mnem = "fcos"; break;
922 default: UnimplementedInstruction();
928 if (modrm_byte == 0xE9) {
931 UnimplementedInstruction();
936 if ((modrm_byte & 0xF8) == 0xE8) {
939 } else if (modrm_byte == 0xE2) {
941 } else if (modrm_byte == 0xE3) {
944 UnimplementedInstruction();
950 switch (modrm_byte & 0xF8) {
951 case 0xC0: mnem = "fadd"; break;
952 case 0xE8: mnem = "fsub"; break;
953 case 0xC8: mnem = "fmul"; break;
954 case 0xF8: mnem = "fdiv"; break;
955 default: UnimplementedInstruction();
961 switch (modrm_byte & 0xF8) {
962 case 0xC0: mnem = "ffree"; break;
963 case 0xD8: mnem = "fstp"; break;
964 default: UnimplementedInstruction();
969 if (modrm_byte == 0xD9) {
973 switch (modrm_byte & 0xF8) {
974 case 0xC0: mnem = "faddp"; break;
975 case 0xE8: mnem = "fsubp"; break;
976 case 0xC8: mnem = "fmulp"; break;
977 case 0xF8: mnem = "fdivp"; break;
978 default: UnimplementedInstruction();
984 if (modrm_byte == 0xE0) {
986 } else if ((modrm_byte & 0xF8) == 0xE8) {
992 default: UnimplementedInstruction();
996 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
998 AppendToBuffer("%s", mnem);
1005 // Handle all two-byte opcodes, which start with 0x0F.
1006 // These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix.
1007 // We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A.
1008 int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
1009 byte opcode = *(data + 1);
1010 byte* current = data + 2;
1011 // At return, "current" points to the start of the next instruction.
1012 const char* mnemonic = TwoByteMnemonic(opcode);
1013 if (operand_size_ == 0x66) {
1014 // 0x66 0x0F prefix.
1016 if (opcode == 0x3A) {
1017 byte third_byte = *current;
1019 if (third_byte == 0x17) {
1020 get_modrm(*current, &mod, ®op, &rm);
1021 AppendToBuffer("extractps "); // reg/m32, xmm, imm8
1022 current += PrintRightOperand(current);
1023 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
1025 } else if (third_byte == 0x21) {
1026 get_modrm(*current, &mod, ®op, &rm);
1027 // insertps xmm, xmm, imm8
1028 AppendToBuffer("insertps %s,%s,%d",
1029 NameOfXMMRegister(regop),
1030 NameOfXMMRegister(rm),
1031 (*(current + 1)) & 3);
1033 } else if (third_byte == 0x22) {
1034 get_modrm(*current, &mod, ®op, &rm);
1035 // pinsrd xmm, reg32, imm8
1036 AppendToBuffer("pinsrd %s,%s,%d",
1037 NameOfXMMRegister(regop),
1038 NameOfCPURegister(rm),
1039 (*(current + 1)) & 3);
1041 } else if (third_byte == 0x0b) {
1042 get_modrm(*current, &mod, ®op, &rm);
1043 // roundsd xmm, xmm/m64, imm8
1044 AppendToBuffer("roundsd %s,", NameOfXMMRegister(regop));
1045 current += PrintRightXMMOperand(current);
1046 AppendToBuffer(",%d", (*current) & 3);
1049 UnimplementedInstruction();
1051 } else if (opcode == 0x38) {
1052 byte third_byte = *current;
1054 if (third_byte == 0x40) {
1055 get_modrm(*current, &mod, ®op, &rm);
1056 AppendToBuffer("pmulld %s, ", NameOfXMMRegister(regop));
1057 current += PrintRightXMMOperand(current);
1059 UnimplementedInstruction();
1062 get_modrm(*current, &mod, ®op, &rm);
1063 if (opcode == 0x1f) {
1065 if (rm == 4) { // SIB byte present.
1068 if (mod == 1) { // Byte displacement.
1070 } else if (mod == 2) { // 32-bit displacement.
1072 } // else no immediate displacement.
1073 AppendToBuffer("nop");
1074 } else if (opcode == 0x28) {
1075 AppendToBuffer("movapd %s,", NameOfXMMRegister(regop));
1076 current += PrintRightXMMOperand(current);
1077 } else if (opcode == 0x29) {
1078 AppendToBuffer("movapd ");
1079 current += PrintRightXMMOperand(current);
1080 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1081 } else if (opcode == 0x6E) {
1082 AppendToBuffer("mov%c %s,",
1083 rex_w() ? 'q' : 'd',
1084 NameOfXMMRegister(regop));
1085 current += PrintRightOperand(current);
1086 } else if (opcode == 0x6F) {
1087 AppendToBuffer("movdqa %s,",
1088 NameOfXMMRegister(regop));
1089 current += PrintRightXMMOperand(current);
1090 } else if (opcode == 0x70) {
1091 AppendToBuffer("pshufd %s,",
1092 NameOfXMMRegister(regop));
1093 current += PrintRightXMMOperand(current);
1094 AppendToBuffer(",0x%x", (*current) & 0xff);
1096 } else if (opcode == 0x5B) {
1097 AppendToBuffer("cvtps2dq %s,",
1098 NameOfXMMRegister(regop));
1099 current += PrintRightXMMOperand(current);
1100 } else if (opcode == 0xFE) {
1101 AppendToBuffer("paddd %s,",
1102 NameOfXMMRegister(regop));
1103 current += PrintRightXMMOperand(current);
1104 } else if (opcode == 0xFA) {
1105 AppendToBuffer("psubd %s,",
1106 NameOfXMMRegister(regop));
1107 current += PrintRightXMMOperand(current);
1108 } else if (opcode == 0x7E) {
1109 AppendToBuffer("mov%c ",
1110 rex_w() ? 'q' : 'd');
1111 current += PrintRightOperand(current);
1112 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1113 } else if (opcode == 0x7F) {
1114 AppendToBuffer("movdqa ");
1115 current += PrintRightXMMOperand(current);
1116 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1117 } else if (opcode == 0xD6) {
1118 AppendToBuffer("movq ");
1119 current += PrintRightXMMOperand(current);
1120 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1121 } else if (opcode == 0x50) {
1122 AppendToBuffer("movmskpd %s,", NameOfCPURegister(regop));
1123 current += PrintRightXMMOperand(current);
1124 } else if (opcode == 0x73) {
1127 AppendToBuffer("psllq,%s,%d", NameOfXMMRegister(rm), *current & 0x7f);
1129 } else if (opcode == 0x62) {
1130 AppendToBuffer("punpackldq %s,", NameOfXMMRegister(regop));
1131 current += PrintRightXMMOperand(current);
1132 } else if (opcode == 0x72) {
1133 AppendToBuffer(regop == rsi ? "pslld "
1134 : regop == rdx ? "psrld" : "psrad");
1135 current += PrintRightXMMOperand(current);
1136 AppendToBuffer(",0x%x", (*current) & 0xff);
1138 } else if (opcode == 0xC6) {
1139 AppendToBuffer("shufpd %s,", NameOfXMMRegister(regop));
1140 current += PrintRightXMMOperand(current);
1141 AppendToBuffer(",0x%x", (*current) & 0xff);
1143 } else if (opcode == 0xF4) {
1144 AppendToBuffer("pmuludq %s,", NameOfXMMRegister(regop));
1145 current += PrintRightXMMOperand(current);
1147 const char* mnemonic = "?";
1148 if (opcode == 0x51) {
1149 mnemonic = "sqrtpd";
1150 } else if (opcode == 0x54) {
1152 } else if (opcode == 0x56) {
1154 } else if (opcode == 0x57) {
1156 } else if (opcode == 0x58) {
1158 } else if (opcode == 0x59) {
1160 } else if (opcode == 0x5C) {
1162 } else if (opcode == 0x5D) {
1164 } else if (opcode == 0x5E) {
1166 } else if (opcode == 0x5F) {
1168 } else if (opcode == 0x2E) {
1169 mnemonic = "ucomisd";
1170 } else if (opcode == 0x2F) {
1171 mnemonic = "comisd";
1172 } else if (opcode == 0x66) {
1173 mnemonic = "pcmpgtd";
1174 } else if (opcode == 0x76) {
1175 mnemonic = "pcmpeqd";
1176 } else if (opcode == 0xD2) {
1178 } else if (opcode == 0xE2) {
1180 } else if (opcode == 0xF2) {
1183 UnimplementedInstruction();
1185 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1186 current += PrintRightXMMOperand(current);
1189 } else if (group_1_prefix_ == 0xF2) {
1190 // Beginning of instructions with prefix 0xF2.
1192 if (opcode == 0x11 || opcode == 0x10) {
1193 // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
1194 AppendToBuffer("movsd ");
1196 get_modrm(*current, &mod, ®op, &rm);
1197 if (opcode == 0x11) {
1198 current += PrintRightXMMOperand(current);
1199 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1201 AppendToBuffer("%s,", NameOfXMMRegister(regop));
1202 current += PrintRightXMMOperand(current);
1204 } else if (opcode == 0x2A) {
1205 // CVTSI2SD: integer to XMM double conversion.
1207 get_modrm(*current, &mod, ®op, &rm);
1208 AppendToBuffer("%sd %s,", mnemonic, NameOfXMMRegister(regop));
1209 current += PrintRightOperand(current);
1210 } else if (opcode == 0x2C) {
1212 // Convert with truncation scalar double-precision FP to integer.
1214 get_modrm(*current, &mod, ®op, &rm);
1215 AppendToBuffer("cvttsd2si%c %s,",
1216 operand_size_code(), NameOfCPURegister(regop));
1217 current += PrintRightXMMOperand(current);
1218 } else if (opcode == 0x2D) {
1219 // CVTSD2SI: Convert scalar double-precision FP to integer.
1221 get_modrm(*current, &mod, ®op, &rm);
1222 AppendToBuffer("cvtsd2si%c %s,",
1223 operand_size_code(), NameOfCPURegister(regop));
1224 current += PrintRightXMMOperand(current);
1225 } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
1226 // XMM arithmetic. Mnemonic was retrieved at the start of this function.
1228 get_modrm(*current, &mod, ®op, &rm);
1229 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1230 current += PrintRightXMMOperand(current);
1231 } else if (opcode == 0xC2) {
1232 // Intel manual 2A, Table 3-18.
1234 get_modrm(*current, &mod, ®op, &rm);
1235 const char* const pseudo_op[] = {
1245 AppendToBuffer("%s %s,%s",
1246 pseudo_op[current[1]],
1247 NameOfXMMRegister(regop),
1248 NameOfXMMRegister(rm));
1251 UnimplementedInstruction();
1253 } else if (group_1_prefix_ == 0xF3) {
1254 // Instructions with prefix 0xF3.
1255 if (opcode == 0x11 || opcode == 0x10) {
1256 // MOVSS: Move scalar double-precision fp to/from/between XMM registers.
1257 AppendToBuffer("movss ");
1259 get_modrm(*current, &mod, ®op, &rm);
1260 if (opcode == 0x11) {
1261 current += PrintRightOperand(current);
1262 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1264 AppendToBuffer("%s,", NameOfXMMRegister(regop));
1265 current += PrintRightOperand(current);
1267 } else if (opcode == 0x2A) {
1268 // CVTSI2SS: integer to XMM single conversion.
1270 get_modrm(*current, &mod, ®op, &rm);
1271 AppendToBuffer("%ss %s,", mnemonic, NameOfXMMRegister(regop));
1272 current += PrintRightOperand(current);
1273 } else if (opcode == 0x2C) {
1275 // Convert with truncation scalar single-precision FP to dword integer.
1277 get_modrm(*current, &mod, ®op, &rm);
1278 AppendToBuffer("cvttss2si%c %s,",
1279 operand_size_code(), NameOfCPURegister(regop));
1280 current += PrintRightXMMOperand(current);
1281 } else if (opcode == 0x5A) {
1283 // Convert scalar single-precision FP to scalar double-precision FP.
1285 get_modrm(*current, &mod, ®op, &rm);
1286 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1287 current += PrintRightXMMOperand(current);
1288 } else if (opcode == 0x7E) {
1290 get_modrm(*current, &mod, ®op, &rm);
1291 AppendToBuffer("movq %s,", NameOfXMMRegister(regop));
1292 current += PrintRightXMMOperand(current);
1294 UnimplementedInstruction();
1296 } else if (opcode == 0x1F) {
1299 get_modrm(*current, &mod, ®op, &rm);
1301 if (rm == 4) { // SIB byte present.
1304 if (mod == 1) { // Byte displacement.
1306 } else if (mod == 2) { // 32-bit displacement.
1308 } // else no immediate displacement.
1309 AppendToBuffer("nop");
1311 } else if (opcode == 0x28) {
1312 // movaps xmm, xmm/m128
1314 get_modrm(*current, &mod, ®op, &rm);
1315 AppendToBuffer("movaps %s,", NameOfXMMRegister(regop));
1316 current += PrintRightXMMOperand(current);
1318 } else if (opcode == 0x29) {
1319 // movaps xmm/m128, xmm
1321 get_modrm(*current, &mod, ®op, &rm);
1322 AppendToBuffer("movaps ");
1323 current += PrintRightXMMOperand(current);
1324 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1326 } else if (opcode == 0x10) {
1327 // movups xmm, xmm/m128
1329 get_modrm(*current, &mod, ®op, &rm);
1330 AppendToBuffer("movups %s, ", NameOfXMMRegister(regop));
1331 current += PrintRightXMMOperand(current);
1333 } else if (opcode == 0x11) {
1334 // movups xmm/m128, xmm
1336 get_modrm(*current, &mod, ®op, &rm);
1337 AppendToBuffer("movups ");
1338 current += PrintRightXMMOperand(current);
1339 AppendToBuffer(", %s", NameOfXMMRegister(regop));
1341 } else if (opcode == 0xA2) {
1343 AppendToBuffer("%s", mnemonic);
1345 } else if ((opcode & 0xF0) == 0x40) {
1346 // CMOVcc: conditional move.
1347 int condition = opcode & 0x0F;
1348 const InstructionDesc& idesc = cmov_instructions[condition];
1349 byte_size_operand_ = idesc.byte_size_operation;
1350 current += PrintOperands(idesc.mnem, idesc.op_order_, current);
1352 } else if (opcode >= 0x53 && opcode <= 0x5F) {
1353 const char* const pseudo_op[] = {
1369 get_modrm(*current, &mod, ®op, &rm);
1370 AppendToBuffer("%s %s,",
1371 pseudo_op[opcode - 0x53],
1372 NameOfXMMRegister(regop));
1373 current += PrintRightXMMOperand(current);
1375 } else if (opcode == 0xC6) {
1376 // shufps xmm, xmm/m128, imm8
1378 get_modrm(*current, &mod, ®op, &rm);
1379 AppendToBuffer("shufps %s, ", NameOfXMMRegister(regop));
1380 current += PrintRightXMMOperand(current);
1381 AppendToBuffer(", %d", (*current) & 3);
1384 } else if (opcode == 0xC6) {
1385 // shufps xmm, xmm/m128, imm8
1387 get_modrm(*current, &mod, ®op, &rm);
1388 AppendToBuffer("shufps %s, ", NameOfXMMRegister(regop));
1389 current += PrintRightXMMOperand(current);
1390 AppendToBuffer(", %d", (*current) & 3);
1393 } else if (opcode == 0x54) {
1394 // andps xmm, xmm/m128
1396 get_modrm(*current, &mod, ®op, &rm);
1397 AppendToBuffer("andps %s, ", NameOfXMMRegister(regop));
1398 current += PrintRightXMMOperand(current);
1400 } else if (opcode == 0x56) {
1401 // orps xmm, xmm/m128
1403 get_modrm(*current, &mod, ®op, &rm);
1404 AppendToBuffer("orps %s, ", NameOfXMMRegister(regop));
1405 current += PrintRightXMMOperand(current);
1407 } else if (opcode == 0x58) {
1408 // addps xmm, xmm/m128
1410 get_modrm(*current, &mod, ®op, &rm);
1411 AppendToBuffer("addps %s, ", NameOfXMMRegister(regop));
1412 current += PrintRightXMMOperand(current);
1414 } else if (opcode == 0x59) {
1415 // mulps xmm, xmm/m128
1417 get_modrm(*current, &mod, ®op, &rm);
1418 AppendToBuffer("mulps %s, ", NameOfXMMRegister(regop));
1419 current += PrintRightXMMOperand(current);
1421 } else if (opcode == 0x5C) {
1422 // subps xmm, xmm/m128
1424 get_modrm(*current, &mod, ®op, &rm);
1425 AppendToBuffer("subps %s, ", NameOfXMMRegister(regop));
1426 current += PrintRightXMMOperand(current);
1428 } else if (opcode == 0x5E) {
1429 // divps xmm, xmm/m128
1431 get_modrm(*current, &mod, ®op, &rm);
1432 AppendToBuffer("divps %s, ", NameOfXMMRegister(regop));
1433 current += PrintRightXMMOperand(current);
1435 } else if (opcode == 0x5D) {
1436 // minps xmm, xmm/m128
1438 get_modrm(*current, &mod, ®op, &rm);
1439 AppendToBuffer("minps %s, ", NameOfXMMRegister(regop));
1440 current += PrintRightXMMOperand(current);
1442 } else if (opcode == 0x5F) {
1443 // maxps xmm, xmm/m128
1445 get_modrm(*current, &mod, ®op, &rm);
1446 AppendToBuffer("maxps %s, ", NameOfXMMRegister(regop));
1447 current += PrintRightXMMOperand(current);
1449 } else if (opcode == 0x5B) {
1450 // cvtdq2ps xmm, xmm/m128
1452 get_modrm(*current, &mod, ®op, &rm);
1453 AppendToBuffer("cvtdq2ps %s, ", NameOfXMMRegister(regop));
1454 current += PrintRightXMMOperand(current);
1457 } else if (opcode == 0x53) {
1458 // rcpps xmm, xmm/m128
1460 get_modrm(*current, &mod, ®op, &rm);
1461 AppendToBuffer("rcpps %s, ", NameOfXMMRegister(regop));
1462 current += PrintRightXMMOperand(current);
1464 } else if (opcode == 0x52) {
1465 // rsqrtps xmm, xmm/m128
1467 get_modrm(*current, &mod, ®op, &rm);
1468 AppendToBuffer("rsqrtps %s, ", NameOfXMMRegister(regop));
1469 current += PrintRightXMMOperand(current);
1471 } else if (opcode == 0x51) {
1472 // sqrtps xmm, xmm/m128
1474 get_modrm(*current, &mod, ®op, &rm);
1475 AppendToBuffer("sqrtps %s, ", NameOfXMMRegister(regop));
1476 current += PrintRightXMMOperand(current);
1478 } else if (opcode == 0x50) {
1479 // movmskps reg, xmm
1481 get_modrm(*current, &mod, ®op, &rm);
1482 AppendToBuffer("movmskps %s,", NameOfCPURegister(regop));
1483 current += PrintRightXMMOperand(current);
1485 } else if (opcode == 0xC2) {
1486 // Intel manual 2A, Table 3-11.
1488 get_modrm(*current, &mod, ®op, &rm);
1489 const char* const pseudo_op[] = {
1499 AppendToBuffer("%s %s,%s",
1500 pseudo_op[current[1]],
1501 NameOfXMMRegister(regop),
1502 NameOfXMMRegister(rm));
1505 } else if ((opcode & 0xF0) == 0x80) {
1506 // Jcc: Conditional jump (branch).
1507 current = data + JumpConditional(data);
1509 } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
1510 opcode == 0xB7 || opcode == 0xAF) {
1511 // Size-extending moves, IMUL.
1512 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1514 } else if ((opcode & 0xF0) == 0x90) {
1515 // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
1516 current = data + SetCC(data);
1518 } else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
1519 // SHLD, SHRD (double-precision shift), BTS (bit set).
1520 AppendToBuffer("%s ", mnemonic);
1522 get_modrm(*current, &mod, ®op, &rm);
1523 current += PrintRightOperand(current);
1524 if (opcode == 0xAB) {
1525 AppendToBuffer(",%s", NameOfCPURegister(regop));
1527 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1529 } else if (opcode == 0xBD) {
1530 AppendToBuffer("%s%c ", mnemonic, operand_size_code());
1532 get_modrm(*current, &mod, ®op, &rm);
1533 AppendToBuffer("%s,", NameOfCPURegister(regop));
1534 current += PrintRightOperand(current);
1536 UnimplementedInstruction();
1538 return static_cast<int>(current - data);
1542 // Mnemonics for two-byte opcode instructions starting with 0x0F.
1543 // The argument is the second byte of the two-byte opcode.
1544 // Returns NULL if the instruction is not handled here.
1545 const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
1549 case 0x2A: // F2/F3 prefix.
1551 case 0x51: // F2 prefix.
1553 case 0x58: // F2 prefix.
1555 case 0x59: // F2 prefix.
1557 case 0x5A: // F2 prefix.
1559 case 0x5C: // F2 prefix.
1561 case 0x5E: // F2 prefix.
1589 // Disassembles the instruction at instr, and writes it into out_buffer.
1590 int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
1592 tmp_buffer_pos_ = 0; // starting to write as position 0
1594 bool processed = true; // Will be set to false if the current instruction
1595 // is not in 'instructions' table.
1598 // Scan for prefixes.
1601 if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix.
1602 operand_size_ = current;
1603 } else if ((current & 0xF0) == 0x40) { // REX prefix.
1605 if (rex_w()) AppendToBuffer("REX.W ");
1606 } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3).
1607 group_1_prefix_ = current;
1608 } else { // Not a prefix - an opcode.
1614 const InstructionDesc& idesc = instruction_table_->Get(current);
1615 byte_size_operand_ = idesc.byte_size_operation;
1616 switch (idesc.type) {
1617 case ZERO_OPERANDS_INSTR:
1618 if (current >= 0xA4 && current <= 0xA7) {
1619 // String move or compare operations.
1620 if (group_1_prefix_ == REP_PREFIX) {
1622 AppendToBuffer("rep ");
1624 if (rex_w()) AppendToBuffer("REX.W ");
1625 AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
1627 AppendToBuffer("%s", idesc.mnem, operand_size_code());
1632 case TWO_OPERANDS_INSTR:
1634 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1637 case JUMP_CONDITIONAL_SHORT_INSTR:
1638 data += JumpConditionalShort(data);
1641 case REGISTER_INSTR:
1642 AppendToBuffer("%s%c %s",
1644 operand_size_code(),
1645 NameOfCPURegister(base_reg(current & 0x07)));
1649 AppendToBuffer("%s %s",
1651 NameOfCPURegister(base_reg(current & 0x07)));
1654 case MOVE_REG_INSTR: {
1656 switch (operand_size()) {
1657 case OPERAND_WORD_SIZE:
1658 addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
1661 case OPERAND_DOUBLEWORD_SIZE:
1663 reinterpret_cast<byte*>(*reinterpret_cast<uint32_t*>(data + 1));
1666 case OPERAND_QUADWORD_SIZE:
1667 addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
1673 AppendToBuffer("mov%c %s,%s",
1674 operand_size_code(),
1675 NameOfCPURegister(base_reg(current & 0x07)),
1676 NameOfAddress(addr));
1680 case CALL_JUMP_INSTR: {
1681 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
1682 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
1687 case SHORT_IMMEDIATE_INSTR: {
1689 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1690 AppendToBuffer("%s rax,%s", idesc.mnem, NameOfAddress(addr));
1700 UNIMPLEMENTED(); // This type is not implemented.
1703 // The first byte didn't match any of the simple opcodes, so we
1704 // need to do special processing on it.
1708 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1));
1712 case 0x69: // fall through
1715 get_modrm(*(data + 1), &mod, ®op, &rm);
1716 int32_t imm = *data == 0x6B ? *(data + 2)
1717 : *reinterpret_cast<int32_t*>(data + 2);
1718 AppendToBuffer("imul%c %s,%s,0x%x",
1719 operand_size_code(),
1720 NameOfCPURegister(regop),
1721 NameOfCPURegister(rm), imm);
1722 data += 2 + (*data == 0x6B ? 1 : 4);
1726 case 0x81: // fall through
1727 case 0x83: // 0x81 with sign extension bit set
1728 data += PrintImmediateOp(data);
1732 data += TwoByteOpcodeInstruction(data);
1738 get_modrm(*data, &mod, ®op, &rm);
1740 AppendToBuffer("pop ");
1741 data += PrintRightOperand(data);
1749 get_modrm(*data, &mod, ®op, &rm);
1750 const char* mnem = NULL;
1770 AppendToBuffer(((regop <= 1) ? "%s%c " : "%s "),
1772 operand_size_code());
1773 data += PrintRightOperand(data);
1777 case 0xC7: // imm32, fall through
1780 bool is_byte = *data == 0xC6;
1783 AppendToBuffer("movb ");
1784 data += PrintRightByteOperand(data);
1785 int32_t imm = *data;
1786 AppendToBuffer(",0x%x", imm);
1789 AppendToBuffer("mov%c ", operand_size_code());
1790 data += PrintRightOperand(data);
1791 if (operand_size() == OPERAND_WORD_SIZE) {
1792 int16_t imm = *reinterpret_cast<int16_t*>(data);
1793 AppendToBuffer(",0x%x", imm);
1796 int32_t imm = *reinterpret_cast<int32_t*>(data);
1797 AppendToBuffer(",0x%x", imm);
1806 AppendToBuffer("cmpb ");
1807 data += PrintRightByteOperand(data);
1808 int32_t imm = *data;
1809 AppendToBuffer(",0x%x", imm);
1814 case 0x88: // 8bit, fall through
1817 bool is_byte = *data == 0x88;
1820 get_modrm(*data, &mod, ®op, &rm);
1822 AppendToBuffer("movb ");
1823 data += PrintRightByteOperand(data);
1824 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1826 AppendToBuffer("mov%c ", operand_size_code());
1827 data += PrintRightOperand(data);
1828 AppendToBuffer(",%s", NameOfCPURegister(regop));
1841 int reg = (*data & 0x7) | (rex_b() ? 8 : 0);
1843 AppendToBuffer("nop"); // Common name for xchg rax,rax.
1845 AppendToBuffer("xchg%c rax,%s",
1846 operand_size_code(),
1847 NameOfCPURegister(reg));
1868 // mov reg8,imm8 or mov reg32,imm32
1869 byte opcode = *data;
1871 bool is_32bit = (opcode >= 0xB8);
1872 int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
1874 AppendToBuffer("mov%c %s,",
1875 operand_size_code(),
1876 NameOfCPURegister(reg));
1877 data += PrintImmediate(data, OPERAND_DOUBLEWORD_SIZE);
1879 AppendToBuffer("movb %s,",
1880 NameOfByteCPURegister(reg));
1881 data += PrintImmediate(data, OPERAND_BYTE_SIZE);
1888 get_modrm(*data, &mod, ®op, &rm);
1890 AppendToBuffer("decb ");
1891 data += PrintRightByteOperand(data);
1893 UnimplementedInstruction();
1898 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data + 1));
1903 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1907 case 0xA1: // Fall through.
1909 switch (operand_size()) {
1910 case OPERAND_DOUBLEWORD_SIZE: {
1911 const char* memory_location = NameOfAddress(
1912 reinterpret_cast<byte*>(
1913 *reinterpret_cast<int32_t*>(data + 1)));
1914 if (*data == 0xA1) { // Opcode 0xA1
1915 AppendToBuffer("movzxlq rax,(%s)", memory_location);
1916 } else { // Opcode 0xA3
1917 AppendToBuffer("movzxlq (%s),rax", memory_location);
1922 case OPERAND_QUADWORD_SIZE: {
1923 // New x64 instruction mov rax,(imm_64).
1924 const char* memory_location = NameOfAddress(
1925 *reinterpret_cast<byte**>(data + 1));
1926 if (*data == 0xA1) { // Opcode 0xA1
1927 AppendToBuffer("movq rax,(%s)", memory_location);
1928 } else { // Opcode 0xA3
1929 AppendToBuffer("movq (%s),rax", memory_location);
1935 UnimplementedInstruction();
1941 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1));
1947 switch (operand_size()) {
1948 case OPERAND_WORD_SIZE:
1949 value = *reinterpret_cast<uint16_t*>(data + 1);
1952 case OPERAND_DOUBLEWORD_SIZE:
1953 value = *reinterpret_cast<uint32_t*>(data + 1);
1956 case OPERAND_QUADWORD_SIZE:
1957 value = *reinterpret_cast<int32_t*>(data + 1);
1963 AppendToBuffer("test%c rax,0x%" V8_PTR_PREFIX "x",
1964 operand_size_code(),
1968 case 0xD1: // fall through
1969 case 0xD3: // fall through
1971 data += ShiftInstruction(data);
1973 case 0xD0: // fall through
1974 case 0xD2: // fall through
1976 byte_size_operand_ = true;
1977 data += ShiftInstruction(data);
1980 case 0xD9: // fall through
1981 case 0xDA: // fall through
1982 case 0xDB: // fall through
1983 case 0xDC: // fall through
1984 case 0xDD: // fall through
1985 case 0xDE: // fall through
1987 data += FPUInstruction(data);
1991 data += JumpShort(data);
1995 byte_size_operand_ = true; // fall through
1997 data += F6F7Instruction(data);
2001 AppendToBuffer("cmp al,0x%x", *reinterpret_cast<int8_t*>(data + 1));
2006 UnimplementedInstruction();
2011 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
2012 tmp_buffer_[tmp_buffer_pos_] = '\0';
2015 int instr_len = static_cast<int>(data - instr);
2016 ASSERT(instr_len > 0); // Ensure progress.
2019 // Instruction bytes.
2020 for (byte* bp = instr; bp < data; bp++) {
2021 outp += v8::internal::SNPrintF(out_buffer + outp, "%02x", *bp);
2023 for (int i = 6 - instr_len; i >= 0; i--) {
2024 outp += v8::internal::SNPrintF(out_buffer + outp, " ");
2027 outp += v8::internal::SNPrintF(out_buffer + outp, " %s",
2028 tmp_buffer_.start());
2033 //------------------------------------------------------------------------------
2036 static const char* cpu_regs[16] = {
2037 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
2038 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
2042 static const char* byte_cpu_regs[16] = {
2043 "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
2044 "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"
2048 static const char* xmm_regs[16] = {
2049 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
2050 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
2054 const char* NameConverter::NameOfAddress(byte* addr) const {
2055 v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
2056 return tmp_buffer_.start();
2060 const char* NameConverter::NameOfConstant(byte* addr) const {
2061 return NameOfAddress(addr);
2065 const char* NameConverter::NameOfCPURegister(int reg) const {
2066 if (0 <= reg && reg < 16)
2067 return cpu_regs[reg];
2072 const char* NameConverter::NameOfByteCPURegister(int reg) const {
2073 if (0 <= reg && reg < 16)
2074 return byte_cpu_regs[reg];
2079 const char* NameConverter::NameOfXMMRegister(int reg) const {
2080 if (0 <= reg && reg < 16)
2081 return xmm_regs[reg];
2086 const char* NameConverter::NameInCode(byte* addr) const {
2087 // X64 does not embed debug strings at the moment.
2093 //------------------------------------------------------------------------------
2095 Disassembler::Disassembler(const NameConverter& converter)
2096 : converter_(converter) { }
2098 Disassembler::~Disassembler() { }
2101 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
2102 byte* instruction) {
2103 DisassemblerX64 d(converter_, CONTINUE_ON_UNIMPLEMENTED_OPCODE);
2104 return d.InstructionDecode(buffer, instruction);
2108 // The X64 assembler does not use constant pools.
2109 int Disassembler::ConstantPoolSizeAt(byte* instruction) {
2114 void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
2115 NameConverter converter;
2116 Disassembler d(converter);
2117 for (byte* pc = begin; pc < end;) {
2118 v8::internal::EmbeddedVector<char, 128> buffer;
2121 pc += d.InstructionDecode(buffer, pc);
2122 fprintf(f, "%p", prev_pc);
2125 for (byte* bp = prev_pc; bp < pc; bp++) {
2126 fprintf(f, "%02x", *bp);
2128 for (int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) {
2131 fprintf(f, " %s\n", buffer.start());
2135 } // namespace disasm
2137 #endif // V8_TARGET_ARCH_X64