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 DCHECK_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 DCHECK_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 DCHECK_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 DCHECK_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 DCHECK(*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;
701 UnimplementedInstruction();
703 AppendToBuffer("%s%c %s",
706 NameOfCPURegister(rm));
708 } else if (regop == 0) {
709 AppendToBuffer("test%c ", operand_size_code());
710 int count = PrintRightOperand(data + 1); // Use name of 64-bit register.
711 AppendToBuffer(",0x");
712 count += PrintImmediate(data + 1 + count, operand_size());
715 UnimplementedInstruction();
721 int DisassemblerX64::ShiftInstruction(byte* data) {
722 byte op = *data & (~1);
723 if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
724 UnimplementedInstruction();
727 byte modrm = *(data + 1);
729 get_modrm(modrm, &mod, ®op, &rm);
730 regop &= 0x7; // The REX.R bit does not affect the operation.
734 UnimplementedInstruction();
737 const char* mnem = NULL;
761 UnimplementedInstruction();
764 DCHECK_NE(NULL, mnem);
767 } else if (op == 0xC0) {
771 AppendToBuffer("%s%c %s,",
774 byte_size_operand_ ? NameOfByteCPURegister(rm)
775 : NameOfCPURegister(rm));
777 AppendToBuffer("cl");
779 AppendToBuffer("%d", imm8);
785 // Returns number of bytes used, including *data.
786 int DisassemblerX64::JumpShort(byte* data) {
787 DCHECK_EQ(0xEB, *data);
788 byte b = *(data + 1);
789 byte* dest = data + static_cast<int8_t>(b) + 2;
790 AppendToBuffer("jmp %s", NameOfAddress(dest));
795 // Returns number of bytes used, including *data.
796 int DisassemblerX64::JumpConditional(byte* data) {
797 DCHECK_EQ(0x0F, *data);
798 byte cond = *(data + 1) & 0x0F;
799 byte* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6;
800 const char* mnem = conditional_code_suffix[cond];
801 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
802 return 6; // includes 0x0F
806 // Returns number of bytes used, including *data.
807 int DisassemblerX64::JumpConditionalShort(byte* data) {
808 byte cond = *data & 0x0F;
809 byte b = *(data + 1);
810 byte* dest = data + static_cast<int8_t>(b) + 2;
811 const char* mnem = conditional_code_suffix[cond];
812 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
817 // Returns number of bytes used, including *data.
818 int DisassemblerX64::SetCC(byte* data) {
819 DCHECK_EQ(0x0F, *data);
820 byte cond = *(data + 1) & 0x0F;
821 const char* mnem = conditional_code_suffix[cond];
822 AppendToBuffer("set%s%c ", mnem, operand_size_code());
823 PrintRightByteOperand(data + 2);
824 return 3; // includes 0x0F
828 // Returns number of bytes used, including *data.
829 int DisassemblerX64::FPUInstruction(byte* data) {
830 byte escape_opcode = *data;
831 DCHECK_EQ(0xD8, escape_opcode & 0xF8);
832 byte modrm_byte = *(data+1);
834 if (modrm_byte >= 0xC0) {
835 return RegisterFPUInstruction(escape_opcode, modrm_byte);
837 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
841 int DisassemblerX64::MemoryFPUInstruction(int escape_opcode,
844 const char* mnem = "?";
845 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
846 switch (escape_opcode) {
847 case 0xD9: switch (regop) {
848 case 0: mnem = "fld_s"; break;
849 case 3: mnem = "fstp_s"; break;
850 case 7: mnem = "fstcw"; break;
851 default: UnimplementedInstruction();
855 case 0xDB: switch (regop) {
856 case 0: mnem = "fild_s"; break;
857 case 1: mnem = "fisttp_s"; break;
858 case 2: mnem = "fist_s"; break;
859 case 3: mnem = "fistp_s"; break;
860 default: UnimplementedInstruction();
864 case 0xDD: switch (regop) {
865 case 0: mnem = "fld_d"; break;
866 case 3: mnem = "fstp_d"; break;
867 default: UnimplementedInstruction();
871 case 0xDF: switch (regop) {
872 case 5: mnem = "fild_d"; break;
873 case 7: mnem = "fistp_d"; break;
874 default: UnimplementedInstruction();
878 default: UnimplementedInstruction();
880 AppendToBuffer("%s ", mnem);
881 int count = PrintRightOperand(modrm_start);
885 int DisassemblerX64::RegisterFPUInstruction(int escape_opcode,
887 bool has_register = false; // Is the FPU register encoded in modrm_byte?
888 const char* mnem = "?";
890 switch (escape_opcode) {
892 UnimplementedInstruction();
896 switch (modrm_byte & 0xF8) {
906 switch (modrm_byte) {
907 case 0xE0: mnem = "fchs"; break;
908 case 0xE1: mnem = "fabs"; break;
909 case 0xE3: mnem = "fninit"; break;
910 case 0xE4: mnem = "ftst"; break;
911 case 0xE8: mnem = "fld1"; break;
912 case 0xEB: mnem = "fldpi"; break;
913 case 0xED: mnem = "fldln2"; break;
914 case 0xEE: mnem = "fldz"; break;
915 case 0xF0: mnem = "f2xm1"; break;
916 case 0xF1: mnem = "fyl2x"; break;
917 case 0xF2: mnem = "fptan"; break;
918 case 0xF5: mnem = "fprem1"; break;
919 case 0xF7: mnem = "fincstp"; break;
920 case 0xF8: mnem = "fprem"; break;
921 case 0xFC: mnem = "frndint"; break;
922 case 0xFD: mnem = "fscale"; break;
923 case 0xFE: mnem = "fsin"; break;
924 case 0xFF: mnem = "fcos"; break;
925 default: UnimplementedInstruction();
931 if (modrm_byte == 0xE9) {
934 UnimplementedInstruction();
939 if ((modrm_byte & 0xF8) == 0xE8) {
942 } else if (modrm_byte == 0xE2) {
944 } else if (modrm_byte == 0xE3) {
947 UnimplementedInstruction();
953 switch (modrm_byte & 0xF8) {
954 case 0xC0: mnem = "fadd"; break;
955 case 0xE8: mnem = "fsub"; break;
956 case 0xC8: mnem = "fmul"; break;
957 case 0xF8: mnem = "fdiv"; break;
958 default: UnimplementedInstruction();
964 switch (modrm_byte & 0xF8) {
965 case 0xC0: mnem = "ffree"; break;
966 case 0xD8: mnem = "fstp"; break;
967 default: UnimplementedInstruction();
972 if (modrm_byte == 0xD9) {
976 switch (modrm_byte & 0xF8) {
977 case 0xC0: mnem = "faddp"; break;
978 case 0xE8: mnem = "fsubp"; break;
979 case 0xC8: mnem = "fmulp"; break;
980 case 0xF8: mnem = "fdivp"; break;
981 default: UnimplementedInstruction();
987 if (modrm_byte == 0xE0) {
989 } else if ((modrm_byte & 0xF8) == 0xE8) {
995 default: UnimplementedInstruction();
999 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1001 AppendToBuffer("%s", mnem);
1008 // Handle all two-byte opcodes, which start with 0x0F.
1009 // These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix.
1010 // We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A.
1011 int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
1012 byte opcode = *(data + 1);
1013 byte* current = data + 2;
1014 // At return, "current" points to the start of the next instruction.
1015 const char* mnemonic = TwoByteMnemonic(opcode);
1016 if (operand_size_ == 0x66) {
1017 // 0x66 0x0F prefix.
1019 if (opcode == 0x3A) {
1020 byte third_byte = *current;
1022 if (third_byte == 0x17) {
1023 get_modrm(*current, &mod, ®op, &rm);
1024 AppendToBuffer("extractps "); // reg/m32, xmm, imm8
1025 current += PrintRightOperand(current);
1026 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
1028 } else if (third_byte == 0x21) {
1029 get_modrm(*current, &mod, ®op, &rm);
1030 // insertps xmm, xmm, imm8
1031 AppendToBuffer("insertps %s,%s,%d",
1032 NameOfXMMRegister(regop),
1033 NameOfXMMRegister(rm),
1034 (*(current + 1)) & 3);
1036 } else if (third_byte == 0x22) {
1037 get_modrm(*current, &mod, ®op, &rm);
1038 // pinsrd xmm, reg32, imm8
1039 AppendToBuffer("pinsrd %s,%s,%d",
1040 NameOfXMMRegister(regop),
1041 NameOfCPURegister(rm),
1042 (*(current + 1)) & 3);
1044 } else if (third_byte == 0x0b) {
1045 get_modrm(*current, &mod, ®op, &rm);
1046 // roundsd xmm, xmm/m64, imm8
1047 AppendToBuffer("roundsd %s,", NameOfXMMRegister(regop));
1048 current += PrintRightXMMOperand(current);
1049 AppendToBuffer(",%d", (*current) & 3);
1052 UnimplementedInstruction();
1054 } else if (opcode == 0x38) {
1055 byte third_byte = *current;
1057 if (third_byte == 0x40) {
1058 get_modrm(*current, &mod, ®op, &rm);
1059 AppendToBuffer("pmulld %s, ", NameOfXMMRegister(regop));
1060 current += PrintRightXMMOperand(current);
1062 UnimplementedInstruction();
1065 get_modrm(*current, &mod, ®op, &rm);
1066 if (opcode == 0x1f) {
1068 if (rm == 4) { // SIB byte present.
1071 if (mod == 1) { // Byte displacement.
1073 } else if (mod == 2) { // 32-bit displacement.
1075 } // else no immediate displacement.
1076 AppendToBuffer("nop");
1077 } else if (opcode == 0x28) {
1078 AppendToBuffer("movapd %s,", NameOfXMMRegister(regop));
1079 current += PrintRightXMMOperand(current);
1080 } else if (opcode == 0x29) {
1081 AppendToBuffer("movapd ");
1082 current += PrintRightXMMOperand(current);
1083 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1084 } else if (opcode == 0x6E) {
1085 AppendToBuffer("mov%c %s,",
1086 rex_w() ? 'q' : 'd',
1087 NameOfXMMRegister(regop));
1088 current += PrintRightOperand(current);
1089 } else if (opcode == 0x6F) {
1090 AppendToBuffer("movdqa %s,",
1091 NameOfXMMRegister(regop));
1092 current += PrintRightXMMOperand(current);
1093 } else if (opcode == 0x70) {
1094 AppendToBuffer("pshufd %s,",
1095 NameOfXMMRegister(regop));
1096 current += PrintRightXMMOperand(current);
1097 AppendToBuffer(",0x%x", (*current) & 0xff);
1099 } else if (opcode == 0x5B) {
1100 AppendToBuffer("cvtps2dq %s,",
1101 NameOfXMMRegister(regop));
1102 current += PrintRightXMMOperand(current);
1103 } else if (opcode == 0xFE) {
1104 AppendToBuffer("paddd %s,",
1105 NameOfXMMRegister(regop));
1106 current += PrintRightXMMOperand(current);
1107 } else if (opcode == 0xFA) {
1108 AppendToBuffer("psubd %s,",
1109 NameOfXMMRegister(regop));
1110 current += PrintRightXMMOperand(current);
1111 } else if (opcode == 0x7E) {
1112 AppendToBuffer("mov%c ",
1113 rex_w() ? 'q' : 'd');
1114 current += PrintRightOperand(current);
1115 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1116 } else if (opcode == 0x7F) {
1117 AppendToBuffer("movdqa ");
1118 current += PrintRightXMMOperand(current);
1119 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1120 } else if (opcode == 0xD6) {
1121 AppendToBuffer("movq ");
1122 current += PrintRightXMMOperand(current);
1123 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1124 } else if (opcode == 0x50) {
1125 AppendToBuffer("movmskpd %s,", NameOfCPURegister(regop));
1126 current += PrintRightXMMOperand(current);
1127 } else if (opcode == 0x73) {
1130 AppendToBuffer("psllq,%s,%d", NameOfXMMRegister(rm), *current & 0x7f);
1132 } else if (opcode == 0x62) {
1133 AppendToBuffer("punpackldq %s,", NameOfXMMRegister(regop));
1134 current += PrintRightXMMOperand(current);
1135 } else if (opcode == 0x72) {
1136 AppendToBuffer(regop == rsi ? "pslld "
1137 : regop == rdx ? "psrld" : "psrad");
1138 current += PrintRightXMMOperand(current);
1139 AppendToBuffer(",0x%x", (*current) & 0xff);
1141 } else if (opcode == 0xC6) {
1142 AppendToBuffer("shufpd %s,", NameOfXMMRegister(regop));
1143 current += PrintRightXMMOperand(current);
1144 AppendToBuffer(",0x%x", (*current) & 0xff);
1146 } else if (opcode == 0xF4) {
1147 AppendToBuffer("pmuludq %s,", NameOfXMMRegister(regop));
1148 current += PrintRightXMMOperand(current);
1150 const char* mnemonic = "?";
1151 if (opcode == 0x51) {
1152 mnemonic = "sqrtpd";
1153 } else if (opcode == 0x54) {
1155 } else if (opcode == 0x56) {
1157 } else if (opcode == 0x57) {
1159 } else if (opcode == 0x58) {
1161 } else if (opcode == 0x59) {
1163 } else if (opcode == 0x5C) {
1165 } else if (opcode == 0x5D) {
1167 } else if (opcode == 0x5E) {
1169 } else if (opcode == 0x5F) {
1171 } else if (opcode == 0x2E) {
1172 mnemonic = "ucomisd";
1173 } else if (opcode == 0x2F) {
1174 mnemonic = "comisd";
1175 } else if (opcode == 0x66) {
1176 mnemonic = "pcmpgtd";
1177 } else if (opcode == 0x76) {
1178 mnemonic = "pcmpeqd";
1179 } else if (opcode == 0xD2) {
1181 } else if (opcode == 0xE2) {
1183 } else if (opcode == 0xF2) {
1186 UnimplementedInstruction();
1188 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1189 current += PrintRightXMMOperand(current);
1192 } else if (group_1_prefix_ == 0xF2) {
1193 // Beginning of instructions with prefix 0xF2.
1195 if (opcode == 0x11 || opcode == 0x10) {
1196 // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
1197 AppendToBuffer("movsd ");
1199 get_modrm(*current, &mod, ®op, &rm);
1200 if (opcode == 0x11) {
1201 current += PrintRightXMMOperand(current);
1202 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1204 AppendToBuffer("%s,", NameOfXMMRegister(regop));
1205 current += PrintRightXMMOperand(current);
1207 } else if (opcode == 0x2A) {
1208 // CVTSI2SD: integer to XMM double conversion.
1210 get_modrm(*current, &mod, ®op, &rm);
1211 AppendToBuffer("%sd %s,", mnemonic, NameOfXMMRegister(regop));
1212 current += PrintRightOperand(current);
1213 } else if (opcode == 0x2C) {
1215 // Convert with truncation scalar double-precision FP to integer.
1217 get_modrm(*current, &mod, ®op, &rm);
1218 AppendToBuffer("cvttsd2si%c %s,",
1219 operand_size_code(), NameOfCPURegister(regop));
1220 current += PrintRightXMMOperand(current);
1221 } else if (opcode == 0x2D) {
1222 // CVTSD2SI: Convert scalar double-precision FP to integer.
1224 get_modrm(*current, &mod, ®op, &rm);
1225 AppendToBuffer("cvtsd2si%c %s,",
1226 operand_size_code(), NameOfCPURegister(regop));
1227 current += PrintRightXMMOperand(current);
1228 } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
1229 // XMM arithmetic. Mnemonic was retrieved at the start of this function.
1231 get_modrm(*current, &mod, ®op, &rm);
1232 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1233 current += PrintRightXMMOperand(current);
1234 } else if (opcode == 0xC2) {
1235 // Intel manual 2A, Table 3-18.
1237 get_modrm(*current, &mod, ®op, &rm);
1238 const char* const pseudo_op[] = {
1248 AppendToBuffer("%s %s,%s",
1249 pseudo_op[current[1]],
1250 NameOfXMMRegister(regop),
1251 NameOfXMMRegister(rm));
1254 UnimplementedInstruction();
1256 } else if (group_1_prefix_ == 0xF3) {
1257 // Instructions with prefix 0xF3.
1258 if (opcode == 0x11 || opcode == 0x10) {
1259 // MOVSS: Move scalar double-precision fp to/from/between XMM registers.
1260 AppendToBuffer("movss ");
1262 get_modrm(*current, &mod, ®op, &rm);
1263 if (opcode == 0x11) {
1264 current += PrintRightOperand(current);
1265 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1267 AppendToBuffer("%s,", NameOfXMMRegister(regop));
1268 current += PrintRightOperand(current);
1270 } else if (opcode == 0x2A) {
1271 // CVTSI2SS: integer to XMM single conversion.
1273 get_modrm(*current, &mod, ®op, &rm);
1274 AppendToBuffer("%ss %s,", mnemonic, NameOfXMMRegister(regop));
1275 current += PrintRightOperand(current);
1276 } else if (opcode == 0x2C) {
1278 // Convert with truncation scalar single-precision FP to dword integer.
1280 get_modrm(*current, &mod, ®op, &rm);
1281 AppendToBuffer("cvttss2si%c %s,",
1282 operand_size_code(), NameOfCPURegister(regop));
1283 current += PrintRightXMMOperand(current);
1284 } else if (opcode == 0x5A) {
1286 // Convert scalar single-precision FP to scalar double-precision FP.
1288 get_modrm(*current, &mod, ®op, &rm);
1289 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1290 current += PrintRightXMMOperand(current);
1291 } else if (opcode == 0x7E) {
1293 get_modrm(*current, &mod, ®op, &rm);
1294 AppendToBuffer("movq %s,", NameOfXMMRegister(regop));
1295 current += PrintRightXMMOperand(current);
1297 UnimplementedInstruction();
1299 } else if (opcode == 0x1F) {
1302 get_modrm(*current, &mod, ®op, &rm);
1304 if (rm == 4) { // SIB byte present.
1307 if (mod == 1) { // Byte displacement.
1309 } else if (mod == 2) { // 32-bit displacement.
1311 } // else no immediate displacement.
1312 AppendToBuffer("nop");
1314 } else if (opcode == 0x28) {
1315 // movaps xmm, xmm/m128
1317 get_modrm(*current, &mod, ®op, &rm);
1318 AppendToBuffer("movaps %s,", NameOfXMMRegister(regop));
1319 current += PrintRightXMMOperand(current);
1321 } else if (opcode == 0x29) {
1322 // movaps xmm/m128, xmm
1324 get_modrm(*current, &mod, ®op, &rm);
1325 AppendToBuffer("movaps ");
1326 current += PrintRightXMMOperand(current);
1327 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1329 } else if (opcode == 0x10) {
1330 // movups xmm, xmm/m128
1332 get_modrm(*current, &mod, ®op, &rm);
1333 AppendToBuffer("movups %s, ", NameOfXMMRegister(regop));
1334 current += PrintRightXMMOperand(current);
1336 } else if (opcode == 0x11) {
1337 // movups xmm/m128, xmm
1339 get_modrm(*current, &mod, ®op, &rm);
1340 AppendToBuffer("movups ");
1341 current += PrintRightXMMOperand(current);
1342 AppendToBuffer(", %s", NameOfXMMRegister(regop));
1344 } else if (opcode == 0xA2) {
1346 AppendToBuffer("%s", mnemonic);
1348 } else if ((opcode & 0xF0) == 0x40) {
1349 // CMOVcc: conditional move.
1350 int condition = opcode & 0x0F;
1351 const InstructionDesc& idesc = cmov_instructions[condition];
1352 byte_size_operand_ = idesc.byte_size_operation;
1353 current += PrintOperands(idesc.mnem, idesc.op_order_, current);
1355 } else if (opcode >= 0x53 && opcode <= 0x5F) {
1356 const char* const pseudo_op[] = {
1372 get_modrm(*current, &mod, ®op, &rm);
1373 AppendToBuffer("%s %s,",
1374 pseudo_op[opcode - 0x53],
1375 NameOfXMMRegister(regop));
1376 current += PrintRightXMMOperand(current);
1378 } else if (opcode == 0xC6) {
1379 // shufps xmm, xmm/m128, imm8
1381 get_modrm(*current, &mod, ®op, &rm);
1382 AppendToBuffer("shufps %s, ", NameOfXMMRegister(regop));
1383 current += PrintRightXMMOperand(current);
1384 AppendToBuffer(", %d", (*current) & 3);
1387 } else if (opcode == 0xC6) {
1388 // shufps xmm, xmm/m128, imm8
1390 get_modrm(*current, &mod, ®op, &rm);
1391 AppendToBuffer("shufps %s, ", NameOfXMMRegister(regop));
1392 current += PrintRightXMMOperand(current);
1393 AppendToBuffer(", %d", (*current) & 3);
1396 } else if (opcode == 0x54) {
1397 // andps xmm, xmm/m128
1399 get_modrm(*current, &mod, ®op, &rm);
1400 AppendToBuffer("andps %s, ", NameOfXMMRegister(regop));
1401 current += PrintRightXMMOperand(current);
1403 } else if (opcode == 0x56) {
1404 // orps xmm, xmm/m128
1406 get_modrm(*current, &mod, ®op, &rm);
1407 AppendToBuffer("orps %s, ", NameOfXMMRegister(regop));
1408 current += PrintRightXMMOperand(current);
1410 } else if (opcode == 0x58) {
1411 // addps xmm, xmm/m128
1413 get_modrm(*current, &mod, ®op, &rm);
1414 AppendToBuffer("addps %s, ", NameOfXMMRegister(regop));
1415 current += PrintRightXMMOperand(current);
1417 } else if (opcode == 0x59) {
1418 // mulps xmm, xmm/m128
1420 get_modrm(*current, &mod, ®op, &rm);
1421 AppendToBuffer("mulps %s, ", NameOfXMMRegister(regop));
1422 current += PrintRightXMMOperand(current);
1424 } else if (opcode == 0x5C) {
1425 // subps xmm, xmm/m128
1427 get_modrm(*current, &mod, ®op, &rm);
1428 AppendToBuffer("subps %s, ", NameOfXMMRegister(regop));
1429 current += PrintRightXMMOperand(current);
1431 } else if (opcode == 0x5E) {
1432 // divps xmm, xmm/m128
1434 get_modrm(*current, &mod, ®op, &rm);
1435 AppendToBuffer("divps %s, ", NameOfXMMRegister(regop));
1436 current += PrintRightXMMOperand(current);
1438 } else if (opcode == 0x5D) {
1439 // minps xmm, xmm/m128
1441 get_modrm(*current, &mod, ®op, &rm);
1442 AppendToBuffer("minps %s, ", NameOfXMMRegister(regop));
1443 current += PrintRightXMMOperand(current);
1445 } else if (opcode == 0x5F) {
1446 // maxps xmm, xmm/m128
1448 get_modrm(*current, &mod, ®op, &rm);
1449 AppendToBuffer("maxps %s, ", NameOfXMMRegister(regop));
1450 current += PrintRightXMMOperand(current);
1452 } else if (opcode == 0x5B) {
1453 // cvtdq2ps xmm, xmm/m128
1455 get_modrm(*current, &mod, ®op, &rm);
1456 AppendToBuffer("cvtdq2ps %s, ", NameOfXMMRegister(regop));
1457 current += PrintRightXMMOperand(current);
1460 } else if (opcode == 0x53) {
1461 // rcpps xmm, xmm/m128
1463 get_modrm(*current, &mod, ®op, &rm);
1464 AppendToBuffer("rcpps %s, ", NameOfXMMRegister(regop));
1465 current += PrintRightXMMOperand(current);
1467 } else if (opcode == 0x52) {
1468 // rsqrtps xmm, xmm/m128
1470 get_modrm(*current, &mod, ®op, &rm);
1471 AppendToBuffer("rsqrtps %s, ", NameOfXMMRegister(regop));
1472 current += PrintRightXMMOperand(current);
1474 } else if (opcode == 0x51) {
1475 // sqrtps xmm, xmm/m128
1477 get_modrm(*current, &mod, ®op, &rm);
1478 AppendToBuffer("sqrtps %s, ", NameOfXMMRegister(regop));
1479 current += PrintRightXMMOperand(current);
1481 } else if (opcode == 0x50) {
1482 // movmskps reg, xmm
1484 get_modrm(*current, &mod, ®op, &rm);
1485 AppendToBuffer("movmskps %s,", NameOfCPURegister(regop));
1486 current += PrintRightXMMOperand(current);
1488 } else if (opcode == 0xC2) {
1489 // Intel manual 2A, Table 3-11.
1491 get_modrm(*current, &mod, ®op, &rm);
1492 const char* const pseudo_op[] = {
1502 AppendToBuffer("%s %s,%s",
1503 pseudo_op[current[1]],
1504 NameOfXMMRegister(regop),
1505 NameOfXMMRegister(rm));
1508 } else if ((opcode & 0xF0) == 0x80) {
1509 // Jcc: Conditional jump (branch).
1510 current = data + JumpConditional(data);
1512 } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
1513 opcode == 0xB7 || opcode == 0xAF) {
1514 // Size-extending moves, IMUL.
1515 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1517 } else if ((opcode & 0xF0) == 0x90) {
1518 // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
1519 current = data + SetCC(data);
1521 } else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
1522 // SHLD, SHRD (double-precision shift), BTS (bit set).
1523 AppendToBuffer("%s ", mnemonic);
1525 get_modrm(*current, &mod, ®op, &rm);
1526 current += PrintRightOperand(current);
1527 if (opcode == 0xAB) {
1528 AppendToBuffer(",%s", NameOfCPURegister(regop));
1530 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1532 } else if (opcode == 0xBD) {
1533 AppendToBuffer("%s%c ", mnemonic, operand_size_code());
1535 get_modrm(*current, &mod, ®op, &rm);
1536 AppendToBuffer("%s,", NameOfCPURegister(regop));
1537 current += PrintRightOperand(current);
1539 UnimplementedInstruction();
1541 return static_cast<int>(current - data);
1545 // Mnemonics for two-byte opcode instructions starting with 0x0F.
1546 // The argument is the second byte of the two-byte opcode.
1547 // Returns NULL if the instruction is not handled here.
1548 const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
1552 case 0x2A: // F2/F3 prefix.
1554 case 0x51: // F2 prefix.
1556 case 0x58: // F2 prefix.
1558 case 0x59: // F2 prefix.
1560 case 0x5A: // F2 prefix.
1562 case 0x5C: // F2 prefix.
1564 case 0x5E: // F2 prefix.
1592 // Disassembles the instruction at instr, and writes it into out_buffer.
1593 int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
1595 tmp_buffer_pos_ = 0; // starting to write as position 0
1597 bool processed = true; // Will be set to false if the current instruction
1598 // is not in 'instructions' table.
1601 // Scan for prefixes.
1604 if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix.
1605 operand_size_ = current;
1606 } else if ((current & 0xF0) == 0x40) { // REX prefix.
1608 if (rex_w()) AppendToBuffer("REX.W ");
1609 } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3).
1610 group_1_prefix_ = current;
1611 } else { // Not a prefix - an opcode.
1617 const InstructionDesc& idesc = instruction_table_->Get(current);
1618 byte_size_operand_ = idesc.byte_size_operation;
1619 switch (idesc.type) {
1620 case ZERO_OPERANDS_INSTR:
1621 if (current >= 0xA4 && current <= 0xA7) {
1622 // String move or compare operations.
1623 if (group_1_prefix_ == REP_PREFIX) {
1625 AppendToBuffer("rep ");
1627 if (rex_w()) AppendToBuffer("REX.W ");
1628 AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
1630 AppendToBuffer("%s", idesc.mnem, operand_size_code());
1635 case TWO_OPERANDS_INSTR:
1637 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1640 case JUMP_CONDITIONAL_SHORT_INSTR:
1641 data += JumpConditionalShort(data);
1644 case REGISTER_INSTR:
1645 AppendToBuffer("%s%c %s",
1647 operand_size_code(),
1648 NameOfCPURegister(base_reg(current & 0x07)));
1652 AppendToBuffer("%s %s",
1654 NameOfCPURegister(base_reg(current & 0x07)));
1657 case MOVE_REG_INSTR: {
1659 switch (operand_size()) {
1660 case OPERAND_WORD_SIZE:
1661 addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
1664 case OPERAND_DOUBLEWORD_SIZE:
1666 reinterpret_cast<byte*>(*reinterpret_cast<uint32_t*>(data + 1));
1669 case OPERAND_QUADWORD_SIZE:
1670 addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
1676 AppendToBuffer("mov%c %s,%s",
1677 operand_size_code(),
1678 NameOfCPURegister(base_reg(current & 0x07)),
1679 NameOfAddress(addr));
1683 case CALL_JUMP_INSTR: {
1684 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
1685 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
1690 case SHORT_IMMEDIATE_INSTR: {
1692 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1693 AppendToBuffer("%s rax,%s", idesc.mnem, NameOfAddress(addr));
1703 UNIMPLEMENTED(); // This type is not implemented.
1706 // The first byte didn't match any of the simple opcodes, so we
1707 // need to do special processing on it.
1711 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1));
1715 case 0x69: // fall through
1718 get_modrm(*(data + 1), &mod, ®op, &rm);
1719 int32_t imm = *data == 0x6B ? *(data + 2)
1720 : *reinterpret_cast<int32_t*>(data + 2);
1721 AppendToBuffer("imul%c %s,%s,0x%x",
1722 operand_size_code(),
1723 NameOfCPURegister(regop),
1724 NameOfCPURegister(rm), imm);
1725 data += 2 + (*data == 0x6B ? 1 : 4);
1729 case 0x81: // fall through
1730 case 0x83: // 0x81 with sign extension bit set
1731 data += PrintImmediateOp(data);
1735 data += TwoByteOpcodeInstruction(data);
1741 get_modrm(*data, &mod, ®op, &rm);
1743 AppendToBuffer("pop ");
1744 data += PrintRightOperand(data);
1752 get_modrm(*data, &mod, ®op, &rm);
1753 const char* mnem = NULL;
1773 AppendToBuffer(((regop <= 1) ? "%s%c " : "%s "),
1775 operand_size_code());
1776 data += PrintRightOperand(data);
1780 case 0xC7: // imm32, fall through
1783 bool is_byte = *data == 0xC6;
1786 AppendToBuffer("movb ");
1787 data += PrintRightByteOperand(data);
1788 int32_t imm = *data;
1789 AppendToBuffer(",0x%x", imm);
1792 AppendToBuffer("mov%c ", operand_size_code());
1793 data += PrintRightOperand(data);
1794 if (operand_size() == OPERAND_WORD_SIZE) {
1795 int16_t imm = *reinterpret_cast<int16_t*>(data);
1796 AppendToBuffer(",0x%x", imm);
1799 int32_t imm = *reinterpret_cast<int32_t*>(data);
1800 AppendToBuffer(",0x%x", imm);
1809 AppendToBuffer("cmpb ");
1810 data += PrintRightByteOperand(data);
1811 int32_t imm = *data;
1812 AppendToBuffer(",0x%x", imm);
1817 case 0x88: // 8bit, fall through
1820 bool is_byte = *data == 0x88;
1823 get_modrm(*data, &mod, ®op, &rm);
1825 AppendToBuffer("movb ");
1826 data += PrintRightByteOperand(data);
1827 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1829 AppendToBuffer("mov%c ", operand_size_code());
1830 data += PrintRightOperand(data);
1831 AppendToBuffer(",%s", NameOfCPURegister(regop));
1844 int reg = (*data & 0x7) | (rex_b() ? 8 : 0);
1846 AppendToBuffer("nop"); // Common name for xchg rax,rax.
1848 AppendToBuffer("xchg%c rax,%s",
1849 operand_size_code(),
1850 NameOfCPURegister(reg));
1871 // mov reg8,imm8 or mov reg32,imm32
1872 byte opcode = *data;
1874 bool is_32bit = (opcode >= 0xB8);
1875 int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
1877 AppendToBuffer("mov%c %s,",
1878 operand_size_code(),
1879 NameOfCPURegister(reg));
1880 data += PrintImmediate(data, OPERAND_DOUBLEWORD_SIZE);
1882 AppendToBuffer("movb %s,",
1883 NameOfByteCPURegister(reg));
1884 data += PrintImmediate(data, OPERAND_BYTE_SIZE);
1891 get_modrm(*data, &mod, ®op, &rm);
1893 AppendToBuffer("decb ");
1894 data += PrintRightByteOperand(data);
1896 UnimplementedInstruction();
1901 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data + 1));
1906 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1910 case 0xA1: // Fall through.
1912 switch (operand_size()) {
1913 case OPERAND_DOUBLEWORD_SIZE: {
1914 const char* memory_location = NameOfAddress(
1915 reinterpret_cast<byte*>(
1916 *reinterpret_cast<int32_t*>(data + 1)));
1917 if (*data == 0xA1) { // Opcode 0xA1
1918 AppendToBuffer("movzxlq rax,(%s)", memory_location);
1919 } else { // Opcode 0xA3
1920 AppendToBuffer("movzxlq (%s),rax", memory_location);
1925 case OPERAND_QUADWORD_SIZE: {
1926 // New x64 instruction mov rax,(imm_64).
1927 const char* memory_location = NameOfAddress(
1928 *reinterpret_cast<byte**>(data + 1));
1929 if (*data == 0xA1) { // Opcode 0xA1
1930 AppendToBuffer("movq rax,(%s)", memory_location);
1931 } else { // Opcode 0xA3
1932 AppendToBuffer("movq (%s),rax", memory_location);
1938 UnimplementedInstruction();
1944 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1));
1950 switch (operand_size()) {
1951 case OPERAND_WORD_SIZE:
1952 value = *reinterpret_cast<uint16_t*>(data + 1);
1955 case OPERAND_DOUBLEWORD_SIZE:
1956 value = *reinterpret_cast<uint32_t*>(data + 1);
1959 case OPERAND_QUADWORD_SIZE:
1960 value = *reinterpret_cast<int32_t*>(data + 1);
1966 AppendToBuffer("test%c rax,0x%" V8_PTR_PREFIX "x",
1967 operand_size_code(),
1971 case 0xD1: // fall through
1972 case 0xD3: // fall through
1974 data += ShiftInstruction(data);
1976 case 0xD0: // fall through
1977 case 0xD2: // fall through
1979 byte_size_operand_ = true;
1980 data += ShiftInstruction(data);
1983 case 0xD9: // fall through
1984 case 0xDA: // fall through
1985 case 0xDB: // fall through
1986 case 0xDC: // fall through
1987 case 0xDD: // fall through
1988 case 0xDE: // fall through
1990 data += FPUInstruction(data);
1994 data += JumpShort(data);
1998 byte_size_operand_ = true; // fall through
2000 data += F6F7Instruction(data);
2004 AppendToBuffer("cmp al,0x%x", *reinterpret_cast<int8_t*>(data + 1));
2009 UnimplementedInstruction();
2014 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
2015 tmp_buffer_[tmp_buffer_pos_] = '\0';
2018 int instr_len = static_cast<int>(data - instr);
2019 DCHECK(instr_len > 0); // Ensure progress.
2022 // Instruction bytes.
2023 for (byte* bp = instr; bp < data; bp++) {
2024 outp += v8::internal::SNPrintF(out_buffer + outp, "%02x", *bp);
2026 for (int i = 6 - instr_len; i >= 0; i--) {
2027 outp += v8::internal::SNPrintF(out_buffer + outp, " ");
2030 outp += v8::internal::SNPrintF(out_buffer + outp, " %s",
2031 tmp_buffer_.start());
2036 //------------------------------------------------------------------------------
2039 static const char* cpu_regs[16] = {
2040 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
2041 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
2045 static const char* byte_cpu_regs[16] = {
2046 "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
2047 "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"
2051 static const char* xmm_regs[16] = {
2052 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
2053 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
2057 const char* NameConverter::NameOfAddress(byte* addr) const {
2058 v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
2059 return tmp_buffer_.start();
2063 const char* NameConverter::NameOfConstant(byte* addr) const {
2064 return NameOfAddress(addr);
2068 const char* NameConverter::NameOfCPURegister(int reg) const {
2069 if (0 <= reg && reg < 16)
2070 return cpu_regs[reg];
2075 const char* NameConverter::NameOfByteCPURegister(int reg) const {
2076 if (0 <= reg && reg < 16)
2077 return byte_cpu_regs[reg];
2082 const char* NameConverter::NameOfXMMRegister(int reg) const {
2083 if (0 <= reg && reg < 16)
2084 return xmm_regs[reg];
2089 const char* NameConverter::NameInCode(byte* addr) const {
2090 // X64 does not embed debug strings at the moment.
2096 //------------------------------------------------------------------------------
2098 Disassembler::Disassembler(const NameConverter& converter)
2099 : converter_(converter) { }
2101 Disassembler::~Disassembler() { }
2104 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
2105 byte* instruction) {
2106 DisassemblerX64 d(converter_, CONTINUE_ON_UNIMPLEMENTED_OPCODE);
2107 return d.InstructionDecode(buffer, instruction);
2111 // The X64 assembler does not use constant pools.
2112 int Disassembler::ConstantPoolSizeAt(byte* instruction) {
2117 void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
2118 NameConverter converter;
2119 Disassembler d(converter);
2120 for (byte* pc = begin; pc < end;) {
2121 v8::internal::EmbeddedVector<char, 128> buffer;
2124 pc += d.InstructionDecode(buffer, pc);
2125 fprintf(f, "%p", prev_pc);
2128 for (byte* bp = prev_pc; bp < pc; bp++) {
2129 fprintf(f, "%02x", *bp);
2131 for (int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) {
2134 fprintf(f, " %s\n", buffer.start());
2138 } // namespace disasm
2140 #endif // V8_TARGET_ARCH_X64