V8 Project
disasm-x64.cc
Go to the documentation of this file.
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.
4 
5 #include <assert.h>
6 #include <stdarg.h>
7 #include <stdio.h>
8 
9 #include "src/v8.h"
10 
11 #if V8_TARGET_ARCH_X64
12 
13 #include "src/base/lazy-instance.h"
14 #include "src/disasm.h"
15 
16 namespace disasm {
17 
18 enum OperandType {
19  UNSET_OP_ORDER = 0,
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
27 };
28 
29 
30 //------------------------------------------------------------------
31 // Tables
32 //------------------------------------------------------------------
33 struct ByteMnemonic {
34  int b; // -1 terminates, otherwise must be in range (0..255)
35  OperandType op_order_;
36  const char* mnem;
37 };
38 
39 
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, "" }
84 };
85 
86 
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, "" }
105 };
106 
107 
108 static const ByteMnemonic call_jump_instr[] = {
109  { 0xE8, UNSET_OP_ORDER, "call" },
110  { 0xE9, UNSET_OP_ORDER, "jmp" },
111  { -1, UNSET_OP_ORDER, "" }
112 };
113 
114 
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, "" }
125 };
126 
127 
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"
131 };
132 
133 
134 enum InstructionType {
135  NO_INSTR,
136  ZERO_OPERANDS_INSTR,
137  TWO_OPERANDS_INSTR,
138  JUMP_CONDITIONAL_SHORT_INSTR,
139  REGISTER_INSTR,
140  PUSHPOP_INSTR, // Has implicit 64-bit operand size.
141  MOVE_REG_INSTR,
142  CALL_JUMP_INSTR,
143  SHORT_IMMEDIATE_INSTR
144 };
145 
146 
147 enum Prefixes {
148  ESCAPE_PREFIX = 0x0F,
149  OPERAND_SIZE_OVERRIDE_PREFIX = 0x66,
150  ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67,
151  REPNE_PREFIX = 0xF2,
152  REP_PREFIX = 0xF3,
153  REPEQ_PREFIX = REP_PREFIX
154 };
155 
156 
157 struct InstructionDesc {
158  const char* mnem;
159  InstructionType type;
160  OperandType op_order_;
161  bool byte_size_operation; // Fixed 8-bit operation.
162 };
163 
164 
165 class InstructionTable {
166  public:
167  InstructionTable();
168  const InstructionDesc& Get(byte x) const {
169  return instructions_[x];
170  }
171 
172  private:
173  InstructionDesc instructions_[256];
174  void Clear();
175  void Init();
176  void CopyTable(const ByteMnemonic bm[], InstructionType type);
177  void SetTableRange(InstructionType type, byte start, byte end, bool byte_size,
178  const char* mnem);
179  void AddJumpConditionalShort();
180 };
181 
182 
183 InstructionTable::InstructionTable() {
184  Clear();
185  Init();
186 }
187 
188 
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;
195  }
196 }
197 
198 
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");
208 }
209 
210 
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_;
217  id->op_order_ =
218  static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG);
219  DCHECK_EQ(NO_INSTR, id->type); // Information not already entered
220  id->type = type;
221  id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0);
222  }
223 }
224 
225 
226 void InstructionTable::SetTableRange(InstructionType type,
227  byte start,
228  byte end,
229  bool byte_size,
230  const char* mnem) {
231  for (byte b = start; b <= end; b++) {
232  InstructionDesc* id = &instructions_[b];
233  DCHECK_EQ(NO_INSTR, id->type); // Information not already entered
234  id->mnem = mnem;
235  id->type = type;
236  id->byte_size_operation = byte_size;
237  }
238 }
239 
240 
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;
247  }
248 }
249 
250 
251 static v8::base::LazyInstance<InstructionTable>::type instruction_table =
253 
254 
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}
272 };
273 
274 
275 //------------------------------------------------------------------------------
276 // DisassemblerX64 implementation.
277 
278 enum UnimplementedOpcodeAction {
279  CONTINUE_ON_UNIMPLEMENTED_OPCODE,
280  ABORT_ON_UNIMPLEMENTED_OPCODE
281 };
282 
283 
284 // A new DisassemblerX64 object is created to disassemble each instruction.
285 // The object can only disassemble a single instruction.
286 class DisassemblerX64 {
287  public:
288  DisassemblerX64(const NameConverter& converter,
289  UnimplementedOpcodeAction unimplemented_action =
290  ABORT_ON_UNIMPLEMENTED_OPCODE)
291  : converter_(converter),
292  tmp_buffer_pos_(0),
293  abort_on_unimplemented_(
294  unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE),
295  rex_(0),
296  operand_size_(0),
297  group_1_prefix_(0),
298  byte_size_operand_(false),
299  instruction_table_(instruction_table.Pointer()) {
300  tmp_buffer_[0] = '\0';
301  }
302 
303  virtual ~DisassemblerX64() {
304  }
305 
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);
309 
310  private:
311  enum OperandSize {
312  OPERAND_BYTE_SIZE = 0,
313  OPERAND_WORD_SIZE = 1,
314  OPERAND_DOUBLEWORD_SIZE = 2,
315  OPERAND_QUADWORD_SIZE = 3
316  };
317 
318  const NameConverter& converter_;
320  unsigned int tmp_buffer_pos_;
321  bool abort_on_unimplemented_;
322  // Prefixes parsed
323  byte rex_;
324  byte operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0.
325  byte group_1_prefix_; // 0xF2, 0xF3, or (if no group 1 prefix is present) 0.
326  // Byte size operand override.
327  bool byte_size_operand_;
328  const InstructionTable* const instruction_table_;
329 
330  void setRex(byte rex) {
331  DCHECK_EQ(0x40, rex & 0xF0);
332  rex_ = rex;
333  }
334 
335  bool rex() { return rex_ != 0; }
336 
337  bool rex_b() { return (rex_ & 0x01) != 0; }
338 
339  // Actual number of base register given the low bits and the rex.b state.
340  int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); }
341 
342  bool rex_x() { return (rex_ & 0x02) != 0; }
343 
344  bool rex_r() { return (rex_ & 0x04) != 0; }
345 
346  bool rex_w() { return (rex_ & 0x08) != 0; }
347 
348  OperandSize operand_size() {
349  if (byte_size_operand_) return OPERAND_BYTE_SIZE;
350  if (rex_w()) return OPERAND_QUADWORD_SIZE;
351  if (operand_size_ != 0) return OPERAND_WORD_SIZE;
352  return OPERAND_DOUBLEWORD_SIZE;
353  }
354 
355  char operand_size_code() {
356  return "bwlq"[operand_size()];
357  }
358 
359  const char* NameOfCPURegister(int reg) const {
360  return converter_.NameOfCPURegister(reg);
361  }
362 
363  const char* NameOfByteCPURegister(int reg) const {
364  return converter_.NameOfByteCPURegister(reg);
365  }
366 
367  const char* NameOfXMMRegister(int reg) const {
368  return converter_.NameOfXMMRegister(reg);
369  }
370 
371  const char* NameOfAddress(byte* addr) const {
372  return converter_.NameOfAddress(addr);
373  }
374 
375  // Disassembler helper functions.
376  void get_modrm(byte data,
377  int* mod,
378  int* regop,
379  int* rm) {
380  *mod = (data >> 6) & 3;
381  *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0);
382  *rm = (data & 7) | (rex_b() ? 8 : 0);
383  }
384 
385  void get_sib(byte data,
386  int* scale,
387  int* index,
388  int* base) {
389  *scale = (data >> 6) & 3;
390  *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0);
391  *base = (data & 7) | (rex_b() ? 8 : 0);
392  }
393 
394  typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const;
395 
396  int PrintRightOperandHelper(byte* modrmp,
397  RegisterNameMapping register_name);
398  int PrintRightOperand(byte* modrmp);
399  int PrintRightByteOperand(byte* modrmp);
400  int PrintRightXMMOperand(byte* modrmp);
401  int PrintOperands(const char* mnem,
402  OperandType op_order,
403  byte* data);
404  int PrintImmediate(byte* data, OperandSize size);
405  int PrintImmediateOp(byte* data);
406  const char* TwoByteMnemonic(byte opcode);
407  int TwoByteOpcodeInstruction(byte* data);
408  int F6F7Instruction(byte* data);
409  int ShiftInstruction(byte* data);
410  int JumpShort(byte* data);
411  int JumpConditional(byte* data);
412  int JumpConditionalShort(byte* data);
413  int SetCC(byte* data);
414  int FPUInstruction(byte* data);
415  int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
416  int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
417  void AppendToBuffer(const char* format, ...);
418 
419  void UnimplementedInstruction() {
420  if (abort_on_unimplemented_) {
421  CHECK(false);
422  } else {
423  AppendToBuffer("'Unimplemented Instruction'");
424  }
425  }
426 };
427 
428 
429 void DisassemblerX64::AppendToBuffer(const char* format, ...) {
430  v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
431  va_list args;
432  va_start(args, format);
433  int result = v8::internal::VSNPrintF(buf, format, args);
434  va_end(args);
435  tmp_buffer_pos_ += result;
436 }
437 
438 
439 int DisassemblerX64::PrintRightOperandHelper(
440  byte* modrmp,
441  RegisterNameMapping direct_register_name) {
442  int mod, regop, rm;
443  get_modrm(*modrmp, &mod, &regop, &rm);
444  RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
445  &DisassemblerX64::NameOfCPURegister;
446  switch (mod) {
447  case 0:
448  if ((rm & 7) == 5) {
449  int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 1);
450  AppendToBuffer("[0x%x]", disp);
451  return 5;
452  } else if ((rm & 7) == 4) {
453  // Codes for SIB byte.
454  byte sib = *(modrmp + 1);
455  int scale, index, base;
456  get_sib(sib, &scale, &index, &base);
457  if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
458  // index == rsp means no index. Only use sib byte with no index for
459  // rsp and r12 base.
460  AppendToBuffer("[%s]", NameOfCPURegister(base));
461  return 2;
462  } else if (base == 5) {
463  // base == rbp means no base register (when mod == 0).
464  int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
465  AppendToBuffer("[%s*%d%s0x%x]",
466  NameOfCPURegister(index),
467  1 << scale,
468  disp < 0 ? "-" : "+",
469  disp < 0 ? -disp : disp);
470  return 6;
471  } else if (index != 4 && base != 5) {
472  // [base+index*scale]
473  AppendToBuffer("[%s+%s*%d]",
474  NameOfCPURegister(base),
475  NameOfCPURegister(index),
476  1 << scale);
477  return 2;
478  } else {
479  UnimplementedInstruction();
480  return 1;
481  }
482  } else {
483  AppendToBuffer("[%s]", NameOfCPURegister(rm));
484  return 1;
485  }
486  break;
487  case 1: // fall through
488  case 2:
489  if ((rm & 7) == 4) {
490  byte sib = *(modrmp + 1);
491  int scale, index, base;
492  get_sib(sib, &scale, &index, &base);
493  int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 2)
494  : *reinterpret_cast<int8_t*>(modrmp + 2);
495  if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
496  AppendToBuffer("[%s%s0x%x]",
497  NameOfCPURegister(base),
498  disp < 0 ? "-" : "+",
499  disp < 0 ? -disp : disp);
500  } else {
501  AppendToBuffer("[%s+%s*%d%s0x%x]",
502  NameOfCPURegister(base),
503  NameOfCPURegister(index),
504  1 << scale,
505  disp < 0 ? "-" : "+",
506  disp < 0 ? -disp : disp);
507  }
508  return mod == 2 ? 6 : 3;
509  } else {
510  // No sib.
511  int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 1)
512  : *reinterpret_cast<int8_t*>(modrmp + 1);
513  AppendToBuffer("[%s%s0x%x]",
514  NameOfCPURegister(rm),
515  disp < 0 ? "-" : "+",
516  disp < 0 ? -disp : disp);
517  return (mod == 2) ? 5 : 2;
518  }
519  break;
520  case 3:
521  AppendToBuffer("%s", (this->*register_name)(rm));
522  return 1;
523  default:
524  UnimplementedInstruction();
525  return 1;
526  }
527  UNREACHABLE();
528 }
529 
530 
531 int DisassemblerX64::PrintImmediate(byte* data, OperandSize size) {
532  int64_t value;
533  int count;
534  switch (size) {
535  case OPERAND_BYTE_SIZE:
536  value = *data;
537  count = 1;
538  break;
539  case OPERAND_WORD_SIZE:
540  value = *reinterpret_cast<int16_t*>(data);
541  count = 2;
542  break;
543  case OPERAND_DOUBLEWORD_SIZE:
544  value = *reinterpret_cast<uint32_t*>(data);
545  count = 4;
546  break;
547  case OPERAND_QUADWORD_SIZE:
548  value = *reinterpret_cast<int32_t*>(data);
549  count = 4;
550  break;
551  default:
552  UNREACHABLE();
553  value = 0; // Initialize variables on all paths to satisfy the compiler.
554  count = 0;
555  }
556  AppendToBuffer("%" V8_PTR_PREFIX "x", value);
557  return count;
558 }
559 
560 
561 int DisassemblerX64::PrintRightOperand(byte* modrmp) {
562  return PrintRightOperandHelper(modrmp,
563  &DisassemblerX64::NameOfCPURegister);
564 }
565 
566 
567 int DisassemblerX64::PrintRightByteOperand(byte* modrmp) {
568  return PrintRightOperandHelper(modrmp,
569  &DisassemblerX64::NameOfByteCPURegister);
570 }
571 
572 
573 int DisassemblerX64::PrintRightXMMOperand(byte* modrmp) {
574  return PrintRightOperandHelper(modrmp,
575  &DisassemblerX64::NameOfXMMRegister);
576 }
577 
578 
579 // Returns number of bytes used including the current *data.
580 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
581 int DisassemblerX64::PrintOperands(const char* mnem,
582  OperandType op_order,
583  byte* data) {
584  byte modrm = *data;
585  int mod, regop, rm;
586  get_modrm(modrm, &mod, &regop, &rm);
587  int advance = 0;
588  const char* register_name =
589  byte_size_operand_ ? NameOfByteCPURegister(regop)
590  : NameOfCPURegister(regop);
591  switch (op_order) {
592  case REG_OPER_OP_ORDER: {
593  AppendToBuffer("%s%c %s,",
594  mnem,
595  operand_size_code(),
596  register_name);
597  advance = byte_size_operand_ ? PrintRightByteOperand(data)
598  : PrintRightOperand(data);
599  break;
600  }
601  case OPER_REG_OP_ORDER: {
602  AppendToBuffer("%s%c ", mnem, operand_size_code());
603  advance = byte_size_operand_ ? PrintRightByteOperand(data)
604  : PrintRightOperand(data);
605  AppendToBuffer(",%s", register_name);
606  break;
607  }
608  default:
609  UNREACHABLE();
610  break;
611  }
612  return advance;
613 }
614 
615 
616 // Returns number of bytes used by machine instruction, including *data byte.
617 // Writes immediate instructions to 'tmp_buffer_'.
618 int DisassemblerX64::PrintImmediateOp(byte* data) {
619  bool byte_size_immediate = (*data & 0x02) != 0;
620  byte modrm = *(data + 1);
621  int mod, regop, rm;
622  get_modrm(modrm, &mod, &regop, &rm);
623  const char* mnem = "Imm???";
624  switch (regop) {
625  case 0:
626  mnem = "add";
627  break;
628  case 1:
629  mnem = "or";
630  break;
631  case 2:
632  mnem = "adc";
633  break;
634  case 3:
635  mnem = "sbb";
636  break;
637  case 4:
638  mnem = "and";
639  break;
640  case 5:
641  mnem = "sub";
642  break;
643  case 6:
644  mnem = "xor";
645  break;
646  case 7:
647  mnem = "cmp";
648  break;
649  default:
650  UnimplementedInstruction();
651  }
652  AppendToBuffer("%s%c ", mnem, operand_size_code());
653  int count = PrintRightOperand(data + 1);
654  AppendToBuffer(",0x");
655  OperandSize immediate_size =
656  byte_size_immediate ? OPERAND_BYTE_SIZE : operand_size();
657  count += PrintImmediate(data + 1 + count, immediate_size);
658  return 1 + count;
659 }
660 
661 
662 // Returns number of bytes used, including *data.
663 int DisassemblerX64::F6F7Instruction(byte* data) {
664  DCHECK(*data == 0xF7 || *data == 0xF6);
665  byte modrm = *(data + 1);
666  int mod, regop, rm;
667  get_modrm(modrm, &mod, &regop, &rm);
668  if (mod == 3 && regop != 0) {
669  const char* mnem = NULL;
670  switch (regop) {
671  case 2:
672  mnem = "not";
673  break;
674  case 3:
675  mnem = "neg";
676  break;
677  case 4:
678  mnem = "mul";
679  break;
680  case 5:
681  mnem = "imul";
682  break;
683  case 6:
684  mnem = "div";
685  break;
686  case 7:
687  mnem = "idiv";
688  break;
689  default:
690  UnimplementedInstruction();
691  }
692  AppendToBuffer("%s%c %s",
693  mnem,
694  operand_size_code(),
695  NameOfCPURegister(rm));
696  return 2;
697  } else if (regop == 0) {
698  AppendToBuffer("test%c ", operand_size_code());
699  int count = PrintRightOperand(data + 1); // Use name of 64-bit register.
700  AppendToBuffer(",0x");
701  count += PrintImmediate(data + 1 + count, operand_size());
702  return 1 + count;
703  } else {
704  UnimplementedInstruction();
705  return 2;
706  }
707 }
708 
709 
710 int DisassemblerX64::ShiftInstruction(byte* data) {
711  byte op = *data & (~1);
712  if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
713  UnimplementedInstruction();
714  return 1;
715  }
716  byte modrm = *(data + 1);
717  int mod, regop, rm;
718  get_modrm(modrm, &mod, &regop, &rm);
719  regop &= 0x7; // The REX.R bit does not affect the operation.
720  int imm8 = -1;
721  int num_bytes = 2;
722  if (mod != 3) {
723  UnimplementedInstruction();
724  return num_bytes;
725  }
726  const char* mnem = NULL;
727  switch (regop) {
728  case 0:
729  mnem = "rol";
730  break;
731  case 1:
732  mnem = "ror";
733  break;
734  case 2:
735  mnem = "rcl";
736  break;
737  case 3:
738  mnem = "rcr";
739  break;
740  case 4:
741  mnem = "shl";
742  break;
743  case 5:
744  mnem = "shr";
745  break;
746  case 7:
747  mnem = "sar";
748  break;
749  default:
750  UnimplementedInstruction();
751  return num_bytes;
752  }
753  DCHECK_NE(NULL, mnem);
754  if (op == 0xD0) {
755  imm8 = 1;
756  } else if (op == 0xC0) {
757  imm8 = *(data + 2);
758  num_bytes = 3;
759  }
760  AppendToBuffer("%s%c %s,",
761  mnem,
762  operand_size_code(),
763  byte_size_operand_ ? NameOfByteCPURegister(rm)
764  : NameOfCPURegister(rm));
765  if (op == 0xD2) {
766  AppendToBuffer("cl");
767  } else {
768  AppendToBuffer("%d", imm8);
769  }
770  return num_bytes;
771 }
772 
773 
774 // Returns number of bytes used, including *data.
775 int DisassemblerX64::JumpShort(byte* data) {
776  DCHECK_EQ(0xEB, *data);
777  byte b = *(data + 1);
778  byte* dest = data + static_cast<int8_t>(b) + 2;
779  AppendToBuffer("jmp %s", NameOfAddress(dest));
780  return 2;
781 }
782 
783 
784 // Returns number of bytes used, including *data.
785 int DisassemblerX64::JumpConditional(byte* data) {
786  DCHECK_EQ(0x0F, *data);
787  byte cond = *(data + 1) & 0x0F;
788  byte* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6;
789  const char* mnem = conditional_code_suffix[cond];
790  AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
791  return 6; // includes 0x0F
792 }
793 
794 
795 // Returns number of bytes used, including *data.
796 int DisassemblerX64::JumpConditionalShort(byte* data) {
797  byte cond = *data & 0x0F;
798  byte b = *(data + 1);
799  byte* dest = data + static_cast<int8_t>(b) + 2;
800  const char* mnem = conditional_code_suffix[cond];
801  AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
802  return 2;
803 }
804 
805 
806 // Returns number of bytes used, including *data.
807 int DisassemblerX64::SetCC(byte* data) {
808  DCHECK_EQ(0x0F, *data);
809  byte cond = *(data + 1) & 0x0F;
810  const char* mnem = conditional_code_suffix[cond];
811  AppendToBuffer("set%s%c ", mnem, operand_size_code());
812  PrintRightByteOperand(data + 2);
813  return 3; // includes 0x0F
814 }
815 
816 
817 // Returns number of bytes used, including *data.
818 int DisassemblerX64::FPUInstruction(byte* data) {
819  byte escape_opcode = *data;
820  DCHECK_EQ(0xD8, escape_opcode & 0xF8);
821  byte modrm_byte = *(data+1);
822 
823  if (modrm_byte >= 0xC0) {
824  return RegisterFPUInstruction(escape_opcode, modrm_byte);
825  } else {
826  return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
827  }
828 }
829 
830 int DisassemblerX64::MemoryFPUInstruction(int escape_opcode,
831  int modrm_byte,
832  byte* modrm_start) {
833  const char* mnem = "?";
834  int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
835  switch (escape_opcode) {
836  case 0xD9: switch (regop) {
837  case 0: mnem = "fld_s"; break;
838  case 3: mnem = "fstp_s"; break;
839  case 7: mnem = "fstcw"; break;
840  default: UnimplementedInstruction();
841  }
842  break;
843 
844  case 0xDB: switch (regop) {
845  case 0: mnem = "fild_s"; break;
846  case 1: mnem = "fisttp_s"; break;
847  case 2: mnem = "fist_s"; break;
848  case 3: mnem = "fistp_s"; break;
849  default: UnimplementedInstruction();
850  }
851  break;
852 
853  case 0xDD: switch (regop) {
854  case 0: mnem = "fld_d"; break;
855  case 3: mnem = "fstp_d"; break;
856  default: UnimplementedInstruction();
857  }
858  break;
859 
860  case 0xDF: switch (regop) {
861  case 5: mnem = "fild_d"; break;
862  case 7: mnem = "fistp_d"; break;
863  default: UnimplementedInstruction();
864  }
865  break;
866 
867  default: UnimplementedInstruction();
868  }
869  AppendToBuffer("%s ", mnem);
870  int count = PrintRightOperand(modrm_start);
871  return count + 1;
872 }
873 
874 int DisassemblerX64::RegisterFPUInstruction(int escape_opcode,
875  byte modrm_byte) {
876  bool has_register = false; // Is the FPU register encoded in modrm_byte?
877  const char* mnem = "?";
878 
879  switch (escape_opcode) {
880  case 0xD8:
881  UnimplementedInstruction();
882  break;
883 
884  case 0xD9:
885  switch (modrm_byte & 0xF8) {
886  case 0xC0:
887  mnem = "fld";
888  has_register = true;
889  break;
890  case 0xC8:
891  mnem = "fxch";
892  has_register = true;
893  break;
894  default:
895  switch (modrm_byte) {
896  case 0xE0: mnem = "fchs"; break;
897  case 0xE1: mnem = "fabs"; break;
898  case 0xE3: mnem = "fninit"; break;
899  case 0xE4: mnem = "ftst"; break;
900  case 0xE8: mnem = "fld1"; break;
901  case 0xEB: mnem = "fldpi"; break;
902  case 0xED: mnem = "fldln2"; break;
903  case 0xEE: mnem = "fldz"; break;
904  case 0xF0: mnem = "f2xm1"; break;
905  case 0xF1: mnem = "fyl2x"; break;
906  case 0xF2: mnem = "fptan"; break;
907  case 0xF5: mnem = "fprem1"; break;
908  case 0xF7: mnem = "fincstp"; break;
909  case 0xF8: mnem = "fprem"; break;
910  case 0xFC: mnem = "frndint"; break;
911  case 0xFD: mnem = "fscale"; break;
912  case 0xFE: mnem = "fsin"; break;
913  case 0xFF: mnem = "fcos"; break;
914  default: UnimplementedInstruction();
915  }
916  }
917  break;
918 
919  case 0xDA:
920  if (modrm_byte == 0xE9) {
921  mnem = "fucompp";
922  } else {
923  UnimplementedInstruction();
924  }
925  break;
926 
927  case 0xDB:
928  if ((modrm_byte & 0xF8) == 0xE8) {
929  mnem = "fucomi";
930  has_register = true;
931  } else if (modrm_byte == 0xE2) {
932  mnem = "fclex";
933  } else if (modrm_byte == 0xE3) {
934  mnem = "fninit";
935  } else {
936  UnimplementedInstruction();
937  }
938  break;
939 
940  case 0xDC:
941  has_register = true;
942  switch (modrm_byte & 0xF8) {
943  case 0xC0: mnem = "fadd"; break;
944  case 0xE8: mnem = "fsub"; break;
945  case 0xC8: mnem = "fmul"; break;
946  case 0xF8: mnem = "fdiv"; break;
947  default: UnimplementedInstruction();
948  }
949  break;
950 
951  case 0xDD:
952  has_register = true;
953  switch (modrm_byte & 0xF8) {
954  case 0xC0: mnem = "ffree"; break;
955  case 0xD8: mnem = "fstp"; break;
956  default: UnimplementedInstruction();
957  }
958  break;
959 
960  case 0xDE:
961  if (modrm_byte == 0xD9) {
962  mnem = "fcompp";
963  } else {
964  has_register = true;
965  switch (modrm_byte & 0xF8) {
966  case 0xC0: mnem = "faddp"; break;
967  case 0xE8: mnem = "fsubp"; break;
968  case 0xC8: mnem = "fmulp"; break;
969  case 0xF8: mnem = "fdivp"; break;
970  default: UnimplementedInstruction();
971  }
972  }
973  break;
974 
975  case 0xDF:
976  if (modrm_byte == 0xE0) {
977  mnem = "fnstsw_ax";
978  } else if ((modrm_byte & 0xF8) == 0xE8) {
979  mnem = "fucomip";
980  has_register = true;
981  }
982  break;
983 
984  default: UnimplementedInstruction();
985  }
986 
987  if (has_register) {
988  AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
989  } else {
990  AppendToBuffer("%s", mnem);
991  }
992  return 2;
993 }
994 
995 
996 
997 // Handle all two-byte opcodes, which start with 0x0F.
998 // These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix.
999 // We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A.
1000 int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
1001  byte opcode = *(data + 1);
1002  byte* current = data + 2;
1003  // At return, "current" points to the start of the next instruction.
1004  const char* mnemonic = TwoByteMnemonic(opcode);
1005  if (operand_size_ == 0x66) {
1006  // 0x66 0x0F prefix.
1007  int mod, regop, rm;
1008  if (opcode == 0x3A) {
1009  byte third_byte = *current;
1010  current = data + 3;
1011  if (third_byte == 0x17) {
1012  get_modrm(*current, &mod, &regop, &rm);
1013  AppendToBuffer("extractps "); // reg/m32, xmm, imm8
1014  current += PrintRightOperand(current);
1015  AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
1016  current += 1;
1017  } else if (third_byte == 0x0b) {
1018  get_modrm(*current, &mod, &regop, &rm);
1019  // roundsd xmm, xmm/m64, imm8
1020  AppendToBuffer("roundsd %s,", NameOfXMMRegister(regop));
1021  current += PrintRightXMMOperand(current);
1022  AppendToBuffer(",%d", (*current) & 3);
1023  current += 1;
1024  } else {
1025  UnimplementedInstruction();
1026  }
1027  } else {
1028  get_modrm(*current, &mod, &regop, &rm);
1029  if (opcode == 0x1f) {
1030  current++;
1031  if (rm == 4) { // SIB byte present.
1032  current++;
1033  }
1034  if (mod == 1) { // Byte displacement.
1035  current += 1;
1036  } else if (mod == 2) { // 32-bit displacement.
1037  current += 4;
1038  } // else no immediate displacement.
1039  AppendToBuffer("nop");
1040  } else if (opcode == 0x28) {
1041  AppendToBuffer("movapd %s,", NameOfXMMRegister(regop));
1042  current += PrintRightXMMOperand(current);
1043  } else if (opcode == 0x29) {
1044  AppendToBuffer("movapd ");
1045  current += PrintRightXMMOperand(current);
1046  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1047  } else if (opcode == 0x6E) {
1048  AppendToBuffer("mov%c %s,",
1049  rex_w() ? 'q' : 'd',
1050  NameOfXMMRegister(regop));
1051  current += PrintRightOperand(current);
1052  } else if (opcode == 0x6F) {
1053  AppendToBuffer("movdqa %s,",
1054  NameOfXMMRegister(regop));
1055  current += PrintRightXMMOperand(current);
1056  } else if (opcode == 0x7E) {
1057  AppendToBuffer("mov%c ",
1058  rex_w() ? 'q' : 'd');
1059  current += PrintRightOperand(current);
1060  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1061  } else if (opcode == 0x7F) {
1062  AppendToBuffer("movdqa ");
1063  current += PrintRightXMMOperand(current);
1064  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1065  } else if (opcode == 0xD6) {
1066  AppendToBuffer("movq ");
1067  current += PrintRightXMMOperand(current);
1068  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1069  } else if (opcode == 0x50) {
1070  AppendToBuffer("movmskpd %s,", NameOfCPURegister(regop));
1071  current += PrintRightXMMOperand(current);
1072  } else if (opcode == 0x73) {
1073  current += 1;
1074  DCHECK(regop == 6);
1075  AppendToBuffer("psllq,%s,%d", NameOfXMMRegister(rm), *current & 0x7f);
1076  current += 1;
1077  } else {
1078  const char* mnemonic = "?";
1079  if (opcode == 0x54) {
1080  mnemonic = "andpd";
1081  } else if (opcode == 0x56) {
1082  mnemonic = "orpd";
1083  } else if (opcode == 0x57) {
1084  mnemonic = "xorpd";
1085  } else if (opcode == 0x2E) {
1086  mnemonic = "ucomisd";
1087  } else if (opcode == 0x2F) {
1088  mnemonic = "comisd";
1089  } else {
1090  UnimplementedInstruction();
1091  }
1092  AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1093  current += PrintRightXMMOperand(current);
1094  }
1095  }
1096  } else if (group_1_prefix_ == 0xF2) {
1097  // Beginning of instructions with prefix 0xF2.
1098 
1099  if (opcode == 0x11 || opcode == 0x10) {
1100  // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
1101  AppendToBuffer("movsd ");
1102  int mod, regop, rm;
1103  get_modrm(*current, &mod, &regop, &rm);
1104  if (opcode == 0x11) {
1105  current += PrintRightXMMOperand(current);
1106  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1107  } else {
1108  AppendToBuffer("%s,", NameOfXMMRegister(regop));
1109  current += PrintRightXMMOperand(current);
1110  }
1111  } else if (opcode == 0x2A) {
1112  // CVTSI2SD: integer to XMM double conversion.
1113  int mod, regop, rm;
1114  get_modrm(*current, &mod, &regop, &rm);
1115  AppendToBuffer("%sd %s,", mnemonic, NameOfXMMRegister(regop));
1116  current += PrintRightOperand(current);
1117  } else if (opcode == 0x2C) {
1118  // CVTTSD2SI:
1119  // Convert with truncation scalar double-precision FP to integer.
1120  int mod, regop, rm;
1121  get_modrm(*current, &mod, &regop, &rm);
1122  AppendToBuffer("cvttsd2si%c %s,",
1123  operand_size_code(), NameOfCPURegister(regop));
1124  current += PrintRightXMMOperand(current);
1125  } else if (opcode == 0x2D) {
1126  // CVTSD2SI: Convert scalar double-precision FP to integer.
1127  int mod, regop, rm;
1128  get_modrm(*current, &mod, &regop, &rm);
1129  AppendToBuffer("cvtsd2si%c %s,",
1130  operand_size_code(), NameOfCPURegister(regop));
1131  current += PrintRightXMMOperand(current);
1132  } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
1133  // XMM arithmetic. Mnemonic was retrieved at the start of this function.
1134  int mod, regop, rm;
1135  get_modrm(*current, &mod, &regop, &rm);
1136  AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1137  current += PrintRightXMMOperand(current);
1138  } else if (opcode == 0xC2) {
1139  // Intel manual 2A, Table 3-18.
1140  int mod, regop, rm;
1141  get_modrm(*current, &mod, &regop, &rm);
1142  const char* const pseudo_op[] = {
1143  "cmpeqsd",
1144  "cmpltsd",
1145  "cmplesd",
1146  "cmpunordsd",
1147  "cmpneqsd",
1148  "cmpnltsd",
1149  "cmpnlesd",
1150  "cmpordsd"
1151  };
1152  AppendToBuffer("%s %s,%s",
1153  pseudo_op[current[1]],
1154  NameOfXMMRegister(regop),
1155  NameOfXMMRegister(rm));
1156  current += 2;
1157  } else {
1158  UnimplementedInstruction();
1159  }
1160  } else if (group_1_prefix_ == 0xF3) {
1161  // Instructions with prefix 0xF3.
1162  if (opcode == 0x11 || opcode == 0x10) {
1163  // MOVSS: Move scalar double-precision fp to/from/between XMM registers.
1164  AppendToBuffer("movss ");
1165  int mod, regop, rm;
1166  get_modrm(*current, &mod, &regop, &rm);
1167  if (opcode == 0x11) {
1168  current += PrintRightOperand(current);
1169  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1170  } else {
1171  AppendToBuffer("%s,", NameOfXMMRegister(regop));
1172  current += PrintRightOperand(current);
1173  }
1174  } else if (opcode == 0x2A) {
1175  // CVTSI2SS: integer to XMM single conversion.
1176  int mod, regop, rm;
1177  get_modrm(*current, &mod, &regop, &rm);
1178  AppendToBuffer("%ss %s,", mnemonic, NameOfXMMRegister(regop));
1179  current += PrintRightOperand(current);
1180  } else if (opcode == 0x2C) {
1181  // CVTTSS2SI:
1182  // Convert with truncation scalar single-precision FP to dword integer.
1183  int mod, regop, rm;
1184  get_modrm(*current, &mod, &regop, &rm);
1185  AppendToBuffer("cvttss2si%c %s,",
1186  operand_size_code(), NameOfCPURegister(regop));
1187  current += PrintRightXMMOperand(current);
1188  } else if (opcode == 0x5A) {
1189  // CVTSS2SD:
1190  // Convert scalar single-precision FP to scalar double-precision FP.
1191  int mod, regop, rm;
1192  get_modrm(*current, &mod, &regop, &rm);
1193  AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1194  current += PrintRightXMMOperand(current);
1195  } else if (opcode == 0x7E) {
1196  int mod, regop, rm;
1197  get_modrm(*current, &mod, &regop, &rm);
1198  AppendToBuffer("movq %s,", NameOfXMMRegister(regop));
1199  current += PrintRightXMMOperand(current);
1200  } else {
1201  UnimplementedInstruction();
1202  }
1203  } else if (opcode == 0x1F) {
1204  // NOP
1205  int mod, regop, rm;
1206  get_modrm(*current, &mod, &regop, &rm);
1207  current++;
1208  if (rm == 4) { // SIB byte present.
1209  current++;
1210  }
1211  if (mod == 1) { // Byte displacement.
1212  current += 1;
1213  } else if (mod == 2) { // 32-bit displacement.
1214  current += 4;
1215  } // else no immediate displacement.
1216  AppendToBuffer("nop");
1217 
1218  } else if (opcode == 0x28) {
1219  // movaps xmm, xmm/m128
1220  int mod, regop, rm;
1221  get_modrm(*current, &mod, &regop, &rm);
1222  AppendToBuffer("movaps %s,", NameOfXMMRegister(regop));
1223  current += PrintRightXMMOperand(current);
1224 
1225  } else if (opcode == 0x29) {
1226  // movaps xmm/m128, xmm
1227  int mod, regop, rm;
1228  get_modrm(*current, &mod, &regop, &rm);
1229  AppendToBuffer("movaps ");
1230  current += PrintRightXMMOperand(current);
1231  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1232 
1233  } else if (opcode == 0xA2) {
1234  // CPUID
1235  AppendToBuffer("%s", mnemonic);
1236 
1237  } else if ((opcode & 0xF0) == 0x40) {
1238  // CMOVcc: conditional move.
1239  int condition = opcode & 0x0F;
1240  const InstructionDesc& idesc = cmov_instructions[condition];
1241  byte_size_operand_ = idesc.byte_size_operation;
1242  current += PrintOperands(idesc.mnem, idesc.op_order_, current);
1243 
1244  } else if (opcode >= 0x53 && opcode <= 0x5F) {
1245  const char* const pseudo_op[] = {
1246  "rcpps",
1247  "andps",
1248  "andnps",
1249  "orps",
1250  "xorps",
1251  "addps",
1252  "mulps",
1253  "cvtps2pd",
1254  "cvtdq2ps",
1255  "subps",
1256  "minps",
1257  "divps",
1258  "maxps",
1259  };
1260  int mod, regop, rm;
1261  get_modrm(*current, &mod, &regop, &rm);
1262  AppendToBuffer("%s %s,",
1263  pseudo_op[opcode - 0x53],
1264  NameOfXMMRegister(regop));
1265  current += PrintRightXMMOperand(current);
1266 
1267  } else if (opcode == 0xC6) {
1268  // shufps xmm, xmm/m128, imm8
1269  int mod, regop, rm;
1270  get_modrm(*current, &mod, &regop, &rm);
1271  AppendToBuffer("shufps %s, ", NameOfXMMRegister(regop));
1272  current += PrintRightXMMOperand(current);
1273  AppendToBuffer(", %d", (*current) & 3);
1274  current += 1;
1275 
1276  } else if (opcode == 0x50) {
1277  // movmskps reg, xmm
1278  int mod, regop, rm;
1279  get_modrm(*current, &mod, &regop, &rm);
1280  AppendToBuffer("movmskps %s,", NameOfCPURegister(regop));
1281  current += PrintRightXMMOperand(current);
1282 
1283  } else if ((opcode & 0xF0) == 0x80) {
1284  // Jcc: Conditional jump (branch).
1285  current = data + JumpConditional(data);
1286 
1287  } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
1288  opcode == 0xB7 || opcode == 0xAF) {
1289  // Size-extending moves, IMUL.
1290  current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1291 
1292  } else if ((opcode & 0xF0) == 0x90) {
1293  // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
1294  current = data + SetCC(data);
1295 
1296  } else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
1297  // SHLD, SHRD (double-precision shift), BTS (bit set).
1298  AppendToBuffer("%s ", mnemonic);
1299  int mod, regop, rm;
1300  get_modrm(*current, &mod, &regop, &rm);
1301  current += PrintRightOperand(current);
1302  if (opcode == 0xAB) {
1303  AppendToBuffer(",%s", NameOfCPURegister(regop));
1304  } else {
1305  AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1306  }
1307  } else if (opcode == 0xBD) {
1308  AppendToBuffer("%s%c ", mnemonic, operand_size_code());
1309  int mod, regop, rm;
1310  get_modrm(*current, &mod, &regop, &rm);
1311  AppendToBuffer("%s,", NameOfCPURegister(regop));
1312  current += PrintRightOperand(current);
1313  } else {
1314  UnimplementedInstruction();
1315  }
1316  return static_cast<int>(current - data);
1317 }
1318 
1319 
1320 // Mnemonics for two-byte opcode instructions starting with 0x0F.
1321 // The argument is the second byte of the two-byte opcode.
1322 // Returns NULL if the instruction is not handled here.
1323 const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
1324  switch (opcode) {
1325  case 0x1F:
1326  return "nop";
1327  case 0x2A: // F2/F3 prefix.
1328  return "cvtsi2s";
1329  case 0x51: // F2 prefix.
1330  return "sqrtsd";
1331  case 0x58: // F2 prefix.
1332  return "addsd";
1333  case 0x59: // F2 prefix.
1334  return "mulsd";
1335  case 0x5A: // F2 prefix.
1336  return "cvtsd2ss";
1337  case 0x5C: // F2 prefix.
1338  return "subsd";
1339  case 0x5E: // F2 prefix.
1340  return "divsd";
1341  case 0xA2:
1342  return "cpuid";
1343  case 0xA5:
1344  return "shld";
1345  case 0xAB:
1346  return "bts";
1347  case 0xAD:
1348  return "shrd";
1349  case 0xAF:
1350  return "imul";
1351  case 0xB6:
1352  return "movzxb";
1353  case 0xB7:
1354  return "movzxw";
1355  case 0xBD:
1356  return "bsr";
1357  case 0xBE:
1358  return "movsxb";
1359  case 0xBF:
1360  return "movsxw";
1361  default:
1362  return NULL;
1363  }
1364 }
1365 
1366 
1367 // Disassembles the instruction at instr, and writes it into out_buffer.
1368 int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
1369  byte* instr) {
1370  tmp_buffer_pos_ = 0; // starting to write as position 0
1371  byte* data = instr;
1372  bool processed = true; // Will be set to false if the current instruction
1373  // is not in 'instructions' table.
1374  byte current;
1375 
1376  // Scan for prefixes.
1377  while (true) {
1378  current = *data;
1379  if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix.
1380  operand_size_ = current;
1381  } else if ((current & 0xF0) == 0x40) { // REX prefix.
1382  setRex(current);
1383  if (rex_w()) AppendToBuffer("REX.W ");
1384  } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3).
1385  group_1_prefix_ = current;
1386  } else { // Not a prefix - an opcode.
1387  break;
1388  }
1389  data++;
1390  }
1391 
1392  const InstructionDesc& idesc = instruction_table_->Get(current);
1393  byte_size_operand_ = idesc.byte_size_operation;
1394  switch (idesc.type) {
1395  case ZERO_OPERANDS_INSTR:
1396  if (current >= 0xA4 && current <= 0xA7) {
1397  // String move or compare operations.
1398  if (group_1_prefix_ == REP_PREFIX) {
1399  // REP.
1400  AppendToBuffer("rep ");
1401  }
1402  if (rex_w()) AppendToBuffer("REX.W ");
1403  AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
1404  } else {
1405  AppendToBuffer("%s", idesc.mnem, operand_size_code());
1406  }
1407  data++;
1408  break;
1409 
1410  case TWO_OPERANDS_INSTR:
1411  data++;
1412  data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1413  break;
1414 
1415  case JUMP_CONDITIONAL_SHORT_INSTR:
1416  data += JumpConditionalShort(data);
1417  break;
1418 
1419  case REGISTER_INSTR:
1420  AppendToBuffer("%s%c %s",
1421  idesc.mnem,
1422  operand_size_code(),
1423  NameOfCPURegister(base_reg(current & 0x07)));
1424  data++;
1425  break;
1426  case PUSHPOP_INSTR:
1427  AppendToBuffer("%s %s",
1428  idesc.mnem,
1429  NameOfCPURegister(base_reg(current & 0x07)));
1430  data++;
1431  break;
1432  case MOVE_REG_INSTR: {
1433  byte* addr = NULL;
1434  switch (operand_size()) {
1435  case OPERAND_WORD_SIZE:
1436  addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
1437  data += 3;
1438  break;
1439  case OPERAND_DOUBLEWORD_SIZE:
1440  addr =
1441  reinterpret_cast<byte*>(*reinterpret_cast<uint32_t*>(data + 1));
1442  data += 5;
1443  break;
1444  case OPERAND_QUADWORD_SIZE:
1445  addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
1446  data += 9;
1447  break;
1448  default:
1449  UNREACHABLE();
1450  }
1451  AppendToBuffer("mov%c %s,%s",
1452  operand_size_code(),
1453  NameOfCPURegister(base_reg(current & 0x07)),
1454  NameOfAddress(addr));
1455  break;
1456  }
1457 
1458  case CALL_JUMP_INSTR: {
1459  byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
1460  AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
1461  data += 5;
1462  break;
1463  }
1464 
1465  case SHORT_IMMEDIATE_INSTR: {
1466  byte* addr =
1467  reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1468  AppendToBuffer("%s rax,%s", idesc.mnem, NameOfAddress(addr));
1469  data += 5;
1470  break;
1471  }
1472 
1473  case NO_INSTR:
1474  processed = false;
1475  break;
1476 
1477  default:
1478  UNIMPLEMENTED(); // This type is not implemented.
1479  }
1480 
1481  // The first byte didn't match any of the simple opcodes, so we
1482  // need to do special processing on it.
1483  if (!processed) {
1484  switch (*data) {
1485  case 0xC2:
1486  AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1));
1487  data += 3;
1488  break;
1489 
1490  case 0x69: // fall through
1491  case 0x6B: {
1492  int mod, regop, rm;
1493  get_modrm(*(data + 1), &mod, &regop, &rm);
1494  int32_t imm = *data == 0x6B ? *(data + 2)
1495  : *reinterpret_cast<int32_t*>(data + 2);
1496  AppendToBuffer("imul%c %s,%s,0x%x",
1497  operand_size_code(),
1498  NameOfCPURegister(regop),
1499  NameOfCPURegister(rm), imm);
1500  data += 2 + (*data == 0x6B ? 1 : 4);
1501  break;
1502  }
1503 
1504  case 0x81: // fall through
1505  case 0x83: // 0x81 with sign extension bit set
1506  data += PrintImmediateOp(data);
1507  break;
1508 
1509  case 0x0F:
1510  data += TwoByteOpcodeInstruction(data);
1511  break;
1512 
1513  case 0x8F: {
1514  data++;
1515  int mod, regop, rm;
1516  get_modrm(*data, &mod, &regop, &rm);
1517  if (regop == 0) {
1518  AppendToBuffer("pop ");
1519  data += PrintRightOperand(data);
1520  }
1521  }
1522  break;
1523 
1524  case 0xFF: {
1525  data++;
1526  int mod, regop, rm;
1527  get_modrm(*data, &mod, &regop, &rm);
1528  const char* mnem = NULL;
1529  switch (regop) {
1530  case 0:
1531  mnem = "inc";
1532  break;
1533  case 1:
1534  mnem = "dec";
1535  break;
1536  case 2:
1537  mnem = "call";
1538  break;
1539  case 4:
1540  mnem = "jmp";
1541  break;
1542  case 6:
1543  mnem = "push";
1544  break;
1545  default:
1546  mnem = "???";
1547  }
1548  AppendToBuffer(((regop <= 1) ? "%s%c " : "%s "),
1549  mnem,
1550  operand_size_code());
1551  data += PrintRightOperand(data);
1552  }
1553  break;
1554 
1555  case 0xC7: // imm32, fall through
1556  case 0xC6: // imm8
1557  {
1558  bool is_byte = *data == 0xC6;
1559  data++;
1560  if (is_byte) {
1561  AppendToBuffer("movb ");
1562  data += PrintRightByteOperand(data);
1563  int32_t imm = *data;
1564  AppendToBuffer(",0x%x", imm);
1565  data++;
1566  } else {
1567  AppendToBuffer("mov%c ", operand_size_code());
1568  data += PrintRightOperand(data);
1569  if (operand_size() == OPERAND_WORD_SIZE) {
1570  int16_t imm = *reinterpret_cast<int16_t*>(data);
1571  AppendToBuffer(",0x%x", imm);
1572  data += 2;
1573  } else {
1574  int32_t imm = *reinterpret_cast<int32_t*>(data);
1575  AppendToBuffer(",0x%x", imm);
1576  data += 4;
1577  }
1578  }
1579  }
1580  break;
1581 
1582  case 0x80: {
1583  data++;
1584  AppendToBuffer("cmpb ");
1585  data += PrintRightByteOperand(data);
1586  int32_t imm = *data;
1587  AppendToBuffer(",0x%x", imm);
1588  data++;
1589  }
1590  break;
1591 
1592  case 0x88: // 8bit, fall through
1593  case 0x89: // 32bit
1594  {
1595  bool is_byte = *data == 0x88;
1596  int mod, regop, rm;
1597  data++;
1598  get_modrm(*data, &mod, &regop, &rm);
1599  if (is_byte) {
1600  AppendToBuffer("movb ");
1601  data += PrintRightByteOperand(data);
1602  AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1603  } else {
1604  AppendToBuffer("mov%c ", operand_size_code());
1605  data += PrintRightOperand(data);
1606  AppendToBuffer(",%s", NameOfCPURegister(regop));
1607  }
1608  }
1609  break;
1610 
1611  case 0x90:
1612  case 0x91:
1613  case 0x92:
1614  case 0x93:
1615  case 0x94:
1616  case 0x95:
1617  case 0x96:
1618  case 0x97: {
1619  int reg = (*data & 0x7) | (rex_b() ? 8 : 0);
1620  if (reg == 0) {
1621  AppendToBuffer("nop"); // Common name for xchg rax,rax.
1622  } else {
1623  AppendToBuffer("xchg%c rax,%s",
1624  operand_size_code(),
1625  NameOfCPURegister(reg));
1626  }
1627  data++;
1628  }
1629  break;
1630  case 0xB0:
1631  case 0xB1:
1632  case 0xB2:
1633  case 0xB3:
1634  case 0xB4:
1635  case 0xB5:
1636  case 0xB6:
1637  case 0xB7:
1638  case 0xB8:
1639  case 0xB9:
1640  case 0xBA:
1641  case 0xBB:
1642  case 0xBC:
1643  case 0xBD:
1644  case 0xBE:
1645  case 0xBF: {
1646  // mov reg8,imm8 or mov reg32,imm32
1647  byte opcode = *data;
1648  data++;
1649  bool is_32bit = (opcode >= 0xB8);
1650  int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
1651  if (is_32bit) {
1652  AppendToBuffer("mov%c %s,",
1653  operand_size_code(),
1654  NameOfCPURegister(reg));
1655  data += PrintImmediate(data, OPERAND_DOUBLEWORD_SIZE);
1656  } else {
1657  AppendToBuffer("movb %s,",
1658  NameOfByteCPURegister(reg));
1659  data += PrintImmediate(data, OPERAND_BYTE_SIZE);
1660  }
1661  break;
1662  }
1663  case 0xFE: {
1664  data++;
1665  int mod, regop, rm;
1666  get_modrm(*data, &mod, &regop, &rm);
1667  if (regop == 1) {
1668  AppendToBuffer("decb ");
1669  data += PrintRightByteOperand(data);
1670  } else {
1671  UnimplementedInstruction();
1672  }
1673  break;
1674  }
1675  case 0x68:
1676  AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data + 1));
1677  data += 5;
1678  break;
1679 
1680  case 0x6A:
1681  AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1682  data += 2;
1683  break;
1684 
1685  case 0xA1: // Fall through.
1686  case 0xA3:
1687  switch (operand_size()) {
1688  case OPERAND_DOUBLEWORD_SIZE: {
1689  const char* memory_location = NameOfAddress(
1690  reinterpret_cast<byte*>(
1691  *reinterpret_cast<int32_t*>(data + 1)));
1692  if (*data == 0xA1) { // Opcode 0xA1
1693  AppendToBuffer("movzxlq rax,(%s)", memory_location);
1694  } else { // Opcode 0xA3
1695  AppendToBuffer("movzxlq (%s),rax", memory_location);
1696  }
1697  data += 5;
1698  break;
1699  }
1700  case OPERAND_QUADWORD_SIZE: {
1701  // New x64 instruction mov rax,(imm_64).
1702  const char* memory_location = NameOfAddress(
1703  *reinterpret_cast<byte**>(data + 1));
1704  if (*data == 0xA1) { // Opcode 0xA1
1705  AppendToBuffer("movq rax,(%s)", memory_location);
1706  } else { // Opcode 0xA3
1707  AppendToBuffer("movq (%s),rax", memory_location);
1708  }
1709  data += 9;
1710  break;
1711  }
1712  default:
1713  UnimplementedInstruction();
1714  data += 2;
1715  }
1716  break;
1717 
1718  case 0xA8:
1719  AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1));
1720  data += 2;
1721  break;
1722 
1723  case 0xA9: {
1724  int64_t value = 0;
1725  switch (operand_size()) {
1726  case OPERAND_WORD_SIZE:
1727  value = *reinterpret_cast<uint16_t*>(data + 1);
1728  data += 3;
1729  break;
1730  case OPERAND_DOUBLEWORD_SIZE:
1731  value = *reinterpret_cast<uint32_t*>(data + 1);
1732  data += 5;
1733  break;
1734  case OPERAND_QUADWORD_SIZE:
1735  value = *reinterpret_cast<int32_t*>(data + 1);
1736  data += 5;
1737  break;
1738  default:
1739  UNREACHABLE();
1740  }
1741  AppendToBuffer("test%c rax,0x%" V8_PTR_PREFIX "x",
1742  operand_size_code(),
1743  value);
1744  break;
1745  }
1746  case 0xD1: // fall through
1747  case 0xD3: // fall through
1748  case 0xC1:
1749  data += ShiftInstruction(data);
1750  break;
1751  case 0xD0: // fall through
1752  case 0xD2: // fall through
1753  case 0xC0:
1754  byte_size_operand_ = true;
1755  data += ShiftInstruction(data);
1756  break;
1757 
1758  case 0xD9: // fall through
1759  case 0xDA: // fall through
1760  case 0xDB: // fall through
1761  case 0xDC: // fall through
1762  case 0xDD: // fall through
1763  case 0xDE: // fall through
1764  case 0xDF:
1765  data += FPUInstruction(data);
1766  break;
1767 
1768  case 0xEB:
1769  data += JumpShort(data);
1770  break;
1771 
1772  case 0xF6:
1773  byte_size_operand_ = true; // fall through
1774  case 0xF7:
1775  data += F6F7Instruction(data);
1776  break;
1777 
1778  case 0x3C:
1779  AppendToBuffer("cmp al,0x%x", *reinterpret_cast<int8_t*>(data + 1));
1780  data +=2;
1781  break;
1782 
1783  default:
1784  UnimplementedInstruction();
1785  data += 1;
1786  }
1787  } // !processed
1788 
1789  if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1790  tmp_buffer_[tmp_buffer_pos_] = '\0';
1791  }
1792 
1793  int instr_len = static_cast<int>(data - instr);
1794  DCHECK(instr_len > 0); // Ensure progress.
1795 
1796  int outp = 0;
1797  // Instruction bytes.
1798  for (byte* bp = instr; bp < data; bp++) {
1799  outp += v8::internal::SNPrintF(out_buffer + outp, "%02x", *bp);
1800  }
1801  for (int i = 6 - instr_len; i >= 0; i--) {
1802  outp += v8::internal::SNPrintF(out_buffer + outp, " ");
1803  }
1804 
1805  outp += v8::internal::SNPrintF(out_buffer + outp, " %s",
1806  tmp_buffer_.start());
1807  return instr_len;
1808 }
1809 
1810 
1811 //------------------------------------------------------------------------------
1812 
1813 
1814 static const char* cpu_regs[16] = {
1815  "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
1816  "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
1817 };
1818 
1819 
1820 static const char* byte_cpu_regs[16] = {
1821  "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
1822  "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"
1823 };
1824 
1825 
1826 static const char* xmm_regs[16] = {
1827  "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
1828  "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
1829 };
1830 
1831 
1832 const char* NameConverter::NameOfAddress(byte* addr) const {
1833  v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
1834  return tmp_buffer_.start();
1835 }
1836 
1837 
1838 const char* NameConverter::NameOfConstant(byte* addr) const {
1839  return NameOfAddress(addr);
1840 }
1841 
1842 
1843 const char* NameConverter::NameOfCPURegister(int reg) const {
1844  if (0 <= reg && reg < 16)
1845  return cpu_regs[reg];
1846  return "noreg";
1847 }
1848 
1849 
1850 const char* NameConverter::NameOfByteCPURegister(int reg) const {
1851  if (0 <= reg && reg < 16)
1852  return byte_cpu_regs[reg];
1853  return "noreg";
1854 }
1855 
1856 
1857 const char* NameConverter::NameOfXMMRegister(int reg) const {
1858  if (0 <= reg && reg < 16)
1859  return xmm_regs[reg];
1860  return "noxmmreg";
1861 }
1862 
1863 
1864 const char* NameConverter::NameInCode(byte* addr) const {
1865  // X64 does not embed debug strings at the moment.
1866  UNREACHABLE();
1867  return "";
1868 }
1869 
1870 
1871 //------------------------------------------------------------------------------
1872 
1873 Disassembler::Disassembler(const NameConverter& converter)
1874  : converter_(converter) { }
1875 
1876 Disassembler::~Disassembler() { }
1877 
1878 
1879 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1880  byte* instruction) {
1881  DisassemblerX64 d(converter_, CONTINUE_ON_UNIMPLEMENTED_OPCODE);
1882  return d.InstructionDecode(buffer, instruction);
1883 }
1884 
1885 
1886 // The X64 assembler does not use constant pools.
1887 int Disassembler::ConstantPoolSizeAt(byte* instruction) {
1888  return -1;
1889 }
1890 
1891 
1892 void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1893  NameConverter converter;
1894  Disassembler d(converter);
1895  for (byte* pc = begin; pc < end;) {
1897  buffer[0] = '\0';
1898  byte* prev_pc = pc;
1899  pc += d.InstructionDecode(buffer, pc);
1900  fprintf(f, "%p", prev_pc);
1901  fprintf(f, " ");
1902 
1903  for (byte* bp = prev_pc; bp < pc; bp++) {
1904  fprintf(f, "%02x", *bp);
1905  }
1906  for (int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) {
1907  fprintf(f, " ");
1908  }
1909  fprintf(f, " %s\n", buffer.start());
1910  }
1911 }
1912 
1913 } // namespace disasm
1914 
1915 #endif // V8_TARGET_ARCH_X64
Disassembler(const NameConverter &converter)
v8::internal::EmbeddedVector< char, 128 > tmp_buffer_
Definition: disasm.h:26
virtual const char * NameInCode(byte *addr) const
virtual const char * NameOfByteCPURegister(int reg) const
virtual const char * NameOfXMMRegister(int reg) const
virtual const char * NameOfAddress(byte *addr) const
virtual const char * NameOfCPURegister(int reg) const
virtual const char * NameOfConstant(byte *addr) const
T * start() const
Definition: vector.h:47
enable harmony numeric enable harmony object literal extensions Optimize object size
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define LAZY_INSTANCE_INITIALIZER
Definition: lazy-instance.h:81
#define UNREACHABLE()
Definition: logging.h:30
#define CHECK(condition)
Definition: logging.h:36
#define DCHECK_NE(v1, v2)
Definition: logging.h:207
#define UNIMPLEMENTED()
Definition: logging.h:28
#define DCHECK(condition)
Definition: logging.h:205
#define DCHECK_EQ(v1, v2)
Definition: logging.h:206
#define V8_PTR_PREFIX
Definition: macros.h:360
Definition: disasm.h:8
unsigned short uint16_t
Definition: unicode.cc:23
signed short int16_t
Definition: unicode.cc:22
int int32_t
Definition: unicode.cc:24
int SNPrintF(Vector< char > str, const char *format,...)
Definition: utils.cc:105
const Register pc
int VSNPrintF(Vector< char > str, const char *format, va_list args)
Definition: utils.cc:114