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