v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
disasm-ia32.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#if V8_TARGET_ARCH_IA32
10
12#include "src/base/strings.h"
16
17namespace disasm {
18
19enum OperandOrder { UNSET_OP_ORDER = 0, REG_OPER_OP_ORDER, OPER_REG_OP_ORDER };
20
21//------------------------------------------------------------------
22// Tables
23//------------------------------------------------------------------
24struct ByteMnemonic {
25 int b; // -1 terminates, otherwise must be in range (0..255)
26 const char* mnem;
27 OperandOrder op_order_;
28};
29
30static const ByteMnemonic two_operands_instr[] = {
31 {0x01, "add", OPER_REG_OP_ORDER}, {0x03, "add", REG_OPER_OP_ORDER},
32 {0x09, "or", OPER_REG_OP_ORDER}, {0x0B, "or", REG_OPER_OP_ORDER},
33 {0x13, "adc", REG_OPER_OP_ORDER}, {0x1B, "sbb", REG_OPER_OP_ORDER},
34 {0x21, "and", OPER_REG_OP_ORDER}, {0x23, "and", REG_OPER_OP_ORDER},
35 {0x29, "sub", OPER_REG_OP_ORDER}, {0x2A, "subb", REG_OPER_OP_ORDER},
36 {0x2B, "sub", REG_OPER_OP_ORDER}, {0x31, "xor", OPER_REG_OP_ORDER},
37 {0x33, "xor", REG_OPER_OP_ORDER}, {0x38, "cmpb", OPER_REG_OP_ORDER},
38 {0x39, "cmp", OPER_REG_OP_ORDER}, {0x3A, "cmpb", REG_OPER_OP_ORDER},
39 {0x3B, "cmp", REG_OPER_OP_ORDER}, {0x84, "test_b", REG_OPER_OP_ORDER},
40 {0x85, "test", REG_OPER_OP_ORDER}, {0x86, "xchg_b", REG_OPER_OP_ORDER},
41 {0x87, "xchg", REG_OPER_OP_ORDER}, {0x8A, "mov_b", REG_OPER_OP_ORDER},
42 {0x8B, "mov", REG_OPER_OP_ORDER}, {0x8D, "lea", REG_OPER_OP_ORDER},
43 {-1, "", UNSET_OP_ORDER}};
44
45static const ByteMnemonic zero_operands_instr[] = {
46 {0xC3, "ret", UNSET_OP_ORDER}, {0xC9, "leave", UNSET_OP_ORDER},
47 {0x90, "nop", UNSET_OP_ORDER}, {0xF4, "hlt", UNSET_OP_ORDER},
48 {0xCC, "int3", UNSET_OP_ORDER}, {0x60, "pushad", UNSET_OP_ORDER},
49 {0x61, "popad", UNSET_OP_ORDER}, {0x9C, "pushfd", UNSET_OP_ORDER},
50 {0x9D, "popfd", UNSET_OP_ORDER}, {0x9E, "sahf", UNSET_OP_ORDER},
51 {0x99, "cdq", UNSET_OP_ORDER}, {0x9B, "fwait", UNSET_OP_ORDER},
52 {0xFC, "cld", UNSET_OP_ORDER}, {0xAB, "stos", UNSET_OP_ORDER},
53 {-1, "", UNSET_OP_ORDER}};
54
55static const ByteMnemonic call_jump_instr[] = {{0xE8, "call", UNSET_OP_ORDER},
56 {0xE9, "jmp", UNSET_OP_ORDER},
57 {-1, "", UNSET_OP_ORDER}};
58
59static const ByteMnemonic short_immediate_instr[] = {
60 {0x05, "add", UNSET_OP_ORDER}, {0x0D, "or", UNSET_OP_ORDER},
61 {0x15, "adc", UNSET_OP_ORDER}, {0x25, "and", UNSET_OP_ORDER},
62 {0x2D, "sub", UNSET_OP_ORDER}, {0x35, "xor", UNSET_OP_ORDER},
63 {0x3D, "cmp", UNSET_OP_ORDER}, {-1, "", UNSET_OP_ORDER}};
64
65// Generally we don't want to generate these because they are subject to partial
66// register stalls. They are included for completeness and because the cmp
67// variant is used by the RecordWrite stub. Because it does not update the
68// register it is not subject to partial register stalls.
69static ByteMnemonic byte_immediate_instr[] = {{0x0C, "or", UNSET_OP_ORDER},
70 {0x24, "and", UNSET_OP_ORDER},
71 {0x34, "xor", UNSET_OP_ORDER},
72 {0x3C, "cmp", UNSET_OP_ORDER},
73 {-1, "", UNSET_OP_ORDER}};
74
75static const char* const jump_conditional_mnem[] = {
76 /*0*/ "jo", "jno", "jc", "jnc",
77 /*4*/ "jz", "jnz", "jna", "ja",
78 /*8*/ "js", "jns", "jpe", "jpo",
79 /*12*/ "jl", "jnl", "jng", "jg"};
80
81static const char* const set_conditional_mnem[] = {
82 /*0*/ "seto", "setno", "setc", "setnc",
83 /*4*/ "setz", "setnz", "setna", "seta",
84 /*8*/ "sets", "setns", "setpe", "setpo",
85 /*12*/ "setl", "setnl", "setng", "setg"};
86
87static const char* const conditional_move_mnem[] = {
88 /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc",
89 /*4*/ "cmovz", "cmovnz", "cmovna", "cmova",
90 /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo",
91 /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg"};
92
93static const char* const cmp_pseudo_op[16] = {
94 "eq", "lt", "le", "unord", "neq", "nlt", "nle", "ord",
95 "eq_uq", "nge", "ngt", "false", "neq_oq", "ge", "gt", "true"};
96
97enum InstructionType {
98 NO_INSTR,
99 ZERO_OPERANDS_INSTR,
100 TWO_OPERANDS_INSTR,
101 JUMP_CONDITIONAL_SHORT_INSTR,
102 REGISTER_INSTR,
103 MOVE_REG_INSTR,
104 CALL_JUMP_INSTR,
105 SHORT_IMMEDIATE_INSTR,
106 BYTE_IMMEDIATE_INSTR
107};
108
109struct InstructionDesc {
110 const char* mnem;
111 InstructionType type;
112 OperandOrder op_order_;
113};
114
115class InstructionTable {
116 public:
117 InstructionTable();
118 const InstructionDesc& Get(uint8_t x) const { return instructions_[x]; }
119 static InstructionTable* get_instance() {
120 static InstructionTable table;
121 return &table;
122 }
123
124 private:
125 InstructionDesc instructions_[256];
126 void Clear();
127 void Init();
128 void CopyTable(const ByteMnemonic bm[], InstructionType type);
129 void SetTableRange(InstructionType type, uint8_t start, uint8_t end,
130 const char* mnem);
131 void AddJumpConditionalShort();
132};
133
134InstructionTable::InstructionTable() {
135 Clear();
136 Init();
137}
138
139void InstructionTable::Clear() {
140 for (int i = 0; i < 256; i++) {
141 instructions_[i].mnem = "";
142 instructions_[i].type = NO_INSTR;
143 instructions_[i].op_order_ = UNSET_OP_ORDER;
144 }
145}
146
147void InstructionTable::Init() {
148 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
149 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
150 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
151 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
152 CopyTable(byte_immediate_instr, BYTE_IMMEDIATE_INSTR);
153 AddJumpConditionalShort();
154 SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc");
155 SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec");
156 SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push");
157 SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop");
158 SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop.
159 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
160}
161
162void InstructionTable::CopyTable(const ByteMnemonic bm[],
163 InstructionType type) {
164 for (int i = 0; bm[i].b >= 0; i++) {
165 InstructionDesc* id = &instructions_[bm[i].b];
166 id->mnem = bm[i].mnem;
167 id->op_order_ = bm[i].op_order_;
168 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
169 id->type = type;
170 }
171}
172
173void InstructionTable::SetTableRange(InstructionType type, uint8_t start,
174 uint8_t end, const char* mnem) {
175 for (uint8_t b = start; b <= end; b++) {
176 InstructionDesc* id = &instructions_[b];
177 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
178 id->mnem = mnem;
179 id->type = type;
180 }
181}
182
183void InstructionTable::AddJumpConditionalShort() {
184 for (uint8_t b = 0x70; b <= 0x7F; b++) {
185 InstructionDesc* id = &instructions_[b];
186 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
187 id->mnem = jump_conditional_mnem[b & 0x0F];
188 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
189 }
190}
191
192namespace {
193int8_t Imm8(const uint8_t* data) {
194 return *reinterpret_cast<const int8_t*>(data);
195}
196uint8_t Imm8_U(const uint8_t* data) {
197 return *reinterpret_cast<const uint8_t*>(data);
198}
199int16_t Imm16(const uint8_t* data) {
200 return *reinterpret_cast<const int16_t*>(data);
201}
202uint16_t Imm16_U(const uint8_t* data) {
203 return *reinterpret_cast<const uint16_t*>(data);
204}
205int32_t Imm32(const uint8_t* data) {
206 return *reinterpret_cast<const int32_t*>(data);
207}
208} // namespace
209
210// The IA32 disassembler implementation.
211class DisassemblerIA32 {
212 public:
213 DisassemblerIA32(
214 const NameConverter& converter,
215 Disassembler::UnimplementedOpcodeAction unimplemented_opcode_action)
216 : converter_(converter),
217 vex_byte0_(0),
218 vex_byte1_(0),
219 vex_byte2_(0),
220 instruction_table_(InstructionTable::get_instance()),
221 tmp_buffer_pos_(0),
222 unimplemented_opcode_action_(unimplemented_opcode_action) {
223 tmp_buffer_[0] = '\0';
224 }
225
226 virtual ~DisassemblerIA32() {}
227
228 // Writes one disassembled instruction into 'buffer' (0-terminated).
229 // Returns the length of the disassembled machine instruction in bytes.
230 int InstructionDecode(v8::base::Vector<char> buffer, uint8_t* instruction);
231
232 private:
233 const NameConverter& converter_;
234 uint8_t vex_byte0_; // 0xC4 or 0xC5
235 uint8_t vex_byte1_;
236 uint8_t vex_byte2_; // only for 3 bytes vex prefix
237 InstructionTable* instruction_table_;
239 unsigned int tmp_buffer_pos_;
240 Disassembler::UnimplementedOpcodeAction unimplemented_opcode_action_;
241
242 enum {
243 eax = 0,
244 ecx = 1,
245 edx = 2,
246 ebx = 3,
247 esp = 4,
248 ebp = 5,
249 esi = 6,
250 edi = 7
251 };
252
253 enum ShiftOpcodeExtension {
254 kROL = 0,
255 kROR = 1,
256 kRCL = 2,
257 kRCR = 3,
258 kSHL = 4,
259 KSHR = 5,
260 kSAR = 7
261 };
262
263 bool vex_128() {
264 DCHECK(vex_byte0_ == 0xC4 || vex_byte0_ == 0xC5);
265 uint8_t checked = vex_byte0_ == 0xC4 ? vex_byte2_ : vex_byte1_;
266 return (checked & 4) == 0;
267 }
268
269 bool vex_none() {
270 DCHECK(vex_byte0_ == 0xC4 || vex_byte0_ == 0xC5);
271 uint8_t checked = vex_byte0_ == 0xC4 ? vex_byte2_ : vex_byte1_;
272 return (checked & 3) == 0;
273 }
274
275 bool vex_66() {
276 DCHECK(vex_byte0_ == 0xC4 || vex_byte0_ == 0xC5);
277 uint8_t checked = vex_byte0_ == 0xC4 ? vex_byte2_ : vex_byte1_;
278 return (checked & 3) == 1;
279 }
280
281 bool vex_f3() {
282 DCHECK(vex_byte0_ == 0xC4 || vex_byte0_ == 0xC5);
283 uint8_t checked = vex_byte0_ == 0xC4 ? vex_byte2_ : vex_byte1_;
284 return (checked & 3) == 2;
285 }
286
287 bool vex_f2() {
288 DCHECK(vex_byte0_ == 0xC4 || vex_byte0_ == 0xC5);
289 uint8_t checked = vex_byte0_ == 0xC4 ? vex_byte2_ : vex_byte1_;
290 return (checked & 3) == 3;
291 }
292
293 bool vex_w() {
294 if (vex_byte0_ == 0xC5) return false;
295 return (vex_byte2_ & 0x80) != 0;
296 }
297
298 bool vex_0f() {
299 if (vex_byte0_ == 0xC5) return true;
300 return (vex_byte1_ & 3) == 1;
301 }
302
303 bool vex_0f38() {
304 if (vex_byte0_ == 0xC5) return false;
305 return (vex_byte1_ & 3) == 2;
306 }
307
308 bool vex_0f3a() {
309 if (vex_byte0_ == 0xC5) return false;
310 return (vex_byte1_ & 3) == 3;
311 }
312
313 int vex_vreg() {
314 DCHECK(vex_byte0_ == 0xC4 || vex_byte0_ == 0xC5);
315 uint8_t checked = vex_byte0_ == 0xC4 ? vex_byte2_ : vex_byte1_;
316 return ~(checked >> 3) & 0xF;
317 }
318
319 char float_size_code() { return "sd"[vex_w()]; }
320
321 const char* NameOfCPURegister(int reg) const {
322 return converter_.NameOfCPURegister(reg);
323 }
324
325 const char* NameOfByteCPURegister(int reg) const {
326 return converter_.NameOfByteCPURegister(reg);
327 }
328
329 const char* NameOfXMMRegister(int reg) const {
330 return converter_.NameOfXMMRegister(reg);
331 }
332
333 const char* NameOfAddress(uint8_t* addr) const {
334 return converter_.NameOfAddress(addr);
335 }
336
337 // Disassembler helper functions.
338 static void get_modrm(uint8_t data, int* mod, int* regop, int* rm) {
339 *mod = (data >> 6) & 3;
340 *regop = (data & 0x38) >> 3;
341 *rm = data & 7;
342 }
343
344 static void get_sib(uint8_t data, int* scale, int* index, int* base) {
345 *scale = (data >> 6) & 3;
346 *index = (data >> 3) & 7;
347 *base = data & 7;
348 }
349
350 using RegisterNameMapping = const char* (DisassemblerIA32::*)(int reg) const;
351
352 int PrintRightOperandHelper(uint8_t* modrmp,
353 RegisterNameMapping register_name);
354 int PrintRightOperand(uint8_t* modrmp);
355 int PrintRightByteOperand(uint8_t* modrmp);
356 int PrintRightXMMOperand(uint8_t* modrmp);
357 int PrintOperands(const char* mnem, OperandOrder op_order, uint8_t* data);
358 int PrintImmediateOp(uint8_t* data);
359 int F7Instruction(uint8_t* data);
360 int D1D3C1Instruction(uint8_t* data);
361 int JumpShort(uint8_t* data);
362 int JumpConditional(uint8_t* data, const char* comment);
363 int JumpConditionalShort(uint8_t* data, const char* comment);
364 int SetCC(uint8_t* data);
365 int CMov(uint8_t* data);
366 int FPUInstruction(uint8_t* data);
367 int MemoryFPUInstruction(int escape_opcode, int regop, uint8_t* modrm_start);
368 int RegisterFPUInstruction(int escape_opcode, uint8_t modrm_byte);
369 int AVXInstruction(uint8_t* data);
370 PRINTF_FORMAT(2, 3) void AppendToBuffer(const char* format, ...);
371
372 void UnimplementedInstruction() {
373 if (unimplemented_opcode_action_ ==
374 Disassembler::kAbortOnUnimplementedOpcode) {
375 FATAL("Unimplemented instruction in disassembler");
376 } else {
377 AppendToBuffer("'Unimplemented instruction'");
378 }
379 }
380};
381
382void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
383 v8::base::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
384 va_list args;
385 va_start(args, format);
386 int result = v8::base::VSNPrintF(buf, format, args);
387 va_end(args);
388 tmp_buffer_pos_ += result;
389}
390
391int DisassemblerIA32::PrintRightOperandHelper(
392 uint8_t* modrmp, RegisterNameMapping direct_register_name) {
393 int mod, regop, rm;
394 get_modrm(*modrmp, &mod, &regop, &rm);
395 RegisterNameMapping register_name =
396 (mod == 3) ? direct_register_name : &DisassemblerIA32::NameOfCPURegister;
397 switch (mod) {
398 case 0:
399 if (rm == ebp) {
400 AppendToBuffer("[0x%x]", Imm32(modrmp + 1));
401 return 5;
402 } else if (rm == esp) {
403 uint8_t sib = *(modrmp + 1);
404 int scale, index, base;
405 get_sib(sib, &scale, &index, &base);
406 if (index == esp && base == esp && scale == 0 /*times_1*/) {
407 AppendToBuffer("[%s]", (this->*register_name)(rm));
408 return 2;
409 } else if (base == ebp) {
410 int32_t disp = Imm32(modrmp + 2);
411 AppendToBuffer("[%s*%d%s0x%x]", (this->*register_name)(index),
412 1 << scale, disp < 0 ? "-" : "+",
413 disp < 0 ? -disp : disp);
414 return 6;
415 } else if (index != esp && base != ebp) {
416 // [base+index*scale]
417 AppendToBuffer("[%s+%s*%d]", (this->*register_name)(base),
418 (this->*register_name)(index), 1 << scale);
419 return 2;
420 } else {
421 UnimplementedInstruction();
422 return 1;
423 }
424 }
425 AppendToBuffer("[%s]", (this->*register_name)(rm));
426 return 1;
427 case 1: // fall through
428 case 2: {
429 if (rm == esp) {
430 uint8_t sib = *(modrmp + 1);
431 int scale, index, base;
432 get_sib(sib, &scale, &index, &base);
433 int disp = mod == 2 ? Imm32(modrmp + 2) : Imm8(modrmp + 2);
434 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
435 AppendToBuffer("[%s%s0x%x]", (this->*register_name)(rm),
436 disp < 0 ? "-" : "+", disp < 0 ? -disp : disp);
437 } else {
438 AppendToBuffer("[%s+%s*%d%s0x%x]", (this->*register_name)(base),
439 (this->*register_name)(index), 1 << scale,
440 disp < 0 ? "-" : "+", disp < 0 ? -disp : disp);
441 }
442 return mod == 2 ? 6 : 3;
443 }
444 // No sib.
445 int disp = mod == 2 ? Imm32(modrmp + 1) : Imm8(modrmp + 1);
446 AppendToBuffer("[%s%s0x%x]", (this->*register_name)(rm),
447 disp < 0 ? "-" : "+", disp < 0 ? -disp : disp);
448 return mod == 2 ? 5 : 2;
449 }
450 case 3:
451 AppendToBuffer("%s", (this->*register_name)(rm));
452 return 1;
453 default:
454 UnimplementedInstruction();
455 return 1;
456 }
457 UNREACHABLE();
458}
459
460int DisassemblerIA32::PrintRightOperand(uint8_t* modrmp) {
461 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
462}
463
464int DisassemblerIA32::PrintRightByteOperand(uint8_t* modrmp) {
465 return PrintRightOperandHelper(modrmp,
466 &DisassemblerIA32::NameOfByteCPURegister);
467}
468
469int DisassemblerIA32::PrintRightXMMOperand(uint8_t* modrmp) {
470 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfXMMRegister);
471}
472
473// Returns number of bytes used including the current *data.
474// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
475int DisassemblerIA32::PrintOperands(const char* mnem, OperandOrder op_order,
476 uint8_t* data) {
477 uint8_t modrm = *data;
478 int mod, regop, rm;
479 get_modrm(modrm, &mod, &regop, &rm);
480 int advance = 0;
481 switch (op_order) {
482 case REG_OPER_OP_ORDER: {
483 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
484 advance = PrintRightOperand(data);
485 break;
486 }
487 case OPER_REG_OP_ORDER: {
488 AppendToBuffer("%s ", mnem);
489 advance = PrintRightOperand(data);
490 AppendToBuffer(",%s", NameOfCPURegister(regop));
491 break;
492 }
493 default:
494 UNREACHABLE();
495 }
496 return advance;
497}
498
499// Returns number of bytes used by machine instruction, including *data byte.
500// Writes immediate instructions to 'tmp_buffer_'.
501int DisassemblerIA32::PrintImmediateOp(uint8_t* data) {
502 bool sign_extension_bit = (*data & 0x02) != 0;
503 uint8_t modrm = *(data + 1);
504 int mod, regop, rm;
505 get_modrm(modrm, &mod, &regop, &rm);
506 const char* mnem = "Imm???";
507 switch (regop) {
508 case 0:
509 mnem = "add";
510 break;
511 case 1:
512 mnem = "or";
513 break;
514 case 2:
515 mnem = "adc";
516 break;
517 case 4:
518 mnem = "and";
519 break;
520 case 5:
521 mnem = "sub";
522 break;
523 case 6:
524 mnem = "xor";
525 break;
526 case 7:
527 mnem = "cmp";
528 break;
529 default:
530 UnimplementedInstruction();
531 }
532 AppendToBuffer("%s ", mnem);
533 int count = PrintRightOperand(data + 1);
534 if (sign_extension_bit) {
535 AppendToBuffer(",0x%x", *(data + 1 + count));
536 return 1 + count + 1 /*int8*/;
537 } else {
538 AppendToBuffer(",0x%x", Imm32(data + 1 + count));
539 return 1 + count + 4 /*int32_t*/;
540 }
541}
542
543// Returns number of bytes used, including *data.
544int DisassemblerIA32::F7Instruction(uint8_t* data) {
545 DCHECK_EQ(0xF7, *data);
546 uint8_t modrm = *++data;
547 int mod, regop, rm;
548 get_modrm(modrm, &mod, &regop, &rm);
549 const char* mnem = "";
550 switch (regop) {
551 case 0:
552 mnem = "test";
553 break;
554 case 2:
555 mnem = "not";
556 break;
557 case 3:
558 mnem = "neg";
559 break;
560 case 4:
561 mnem = "mul";
562 break;
563 case 5:
564 mnem = "imul";
565 break;
566 case 6:
567 mnem = "div";
568 break;
569 case 7:
570 mnem = "idiv";
571 break;
572 default:
573 UnimplementedInstruction();
574 }
575 AppendToBuffer("%s ", mnem);
576 int count = PrintRightOperand(data);
577 if (regop == 0) {
578 AppendToBuffer(",0x%x", Imm32(data + count));
579 count += 4;
580 }
581 return 1 + count;
582}
583
584int DisassemblerIA32::D1D3C1Instruction(uint8_t* data) {
585 uint8_t op = *data;
586 DCHECK(op == 0xD1 || op == 0xD3 || op == 0xC1);
587 uint8_t modrm = *++data;
588 int mod, regop, rm;
589 get_modrm(modrm, &mod, &regop, &rm);
590 int imm8 = -1;
591 const char* mnem = "";
592 switch (regop) {
593 case kROL:
594 mnem = "rol";
595 break;
596 case kROR:
597 mnem = "ror";
598 break;
599 case kRCL:
600 mnem = "rcl";
601 break;
602 case kRCR:
603 mnem = "rcr";
604 break;
605 case kSHL:
606 mnem = "shl";
607 break;
608 case KSHR:
609 mnem = "shr";
610 break;
611 case kSAR:
612 mnem = "sar";
613 break;
614 default:
615 UnimplementedInstruction();
616 }
617 AppendToBuffer("%s ", mnem);
618 int count = PrintRightOperand(data);
619 if (op == 0xD1) {
620 imm8 = 1;
621 } else if (op == 0xC1) {
622 imm8 = *(data + 1);
623 count++;
624 } else if (op == 0xD3) {
625 // Shift/rotate by cl.
626 }
627 if (imm8 >= 0) {
628 AppendToBuffer(",%d", imm8);
629 } else {
630 AppendToBuffer(",cl");
631 }
632 return 1 + count;
633}
634
635// Returns number of bytes used, including *data.
636int DisassemblerIA32::JumpShort(uint8_t* data) {
637 DCHECK_EQ(0xEB, *data);
638 uint8_t b = *(data + 1);
639 uint8_t* dest = data + static_cast<int8_t>(b) + 2;
640 AppendToBuffer("jmp %s", NameOfAddress(dest));
641 return 2;
642}
643
644// Returns number of bytes used, including *data.
645int DisassemblerIA32::JumpConditional(uint8_t* data, const char* comment) {
646 DCHECK_EQ(0x0F, *data);
647 uint8_t cond = *(data + 1) & 0x0F;
648 uint8_t* dest = data + Imm32(data + 2) + 6;
649 const char* mnem = jump_conditional_mnem[cond];
650 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
651 if (comment != nullptr) {
652 AppendToBuffer(", %s", comment);
653 }
654 return 6; // includes 0x0F
655}
656
657// Returns number of bytes used, including *data.
658int DisassemblerIA32::JumpConditionalShort(uint8_t* data, const char* comment) {
659 uint8_t cond = *data & 0x0F;
660 uint8_t b = *(data + 1);
661 uint8_t* dest = data + static_cast<int8_t>(b) + 2;
662 const char* mnem = jump_conditional_mnem[cond];
663 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
664 if (comment != nullptr) {
665 AppendToBuffer(", %s", comment);
666 }
667 return 2;
668}
669
670// Returns number of bytes used, including *data.
671int DisassemblerIA32::SetCC(uint8_t* data) {
672 DCHECK_EQ(0x0F, *data);
673 uint8_t cond = *(data + 1) & 0x0F;
674 const char* mnem = set_conditional_mnem[cond];
675 AppendToBuffer("%s ", mnem);
676 PrintRightByteOperand(data + 2);
677 return 3; // Includes 0x0F.
678}
679
680// Returns number of bytes used, including *data.
681int DisassemblerIA32::CMov(uint8_t* data) {
682 DCHECK_EQ(0x0F, *data);
683 uint8_t cond = *(data + 1) & 0x0F;
684 const char* mnem = conditional_move_mnem[cond];
685 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
686 return 2 + op_size; // includes 0x0F
687}
688
689const char* sf_str[4] = {"", "rl", "ra", "ll"};
690
691int DisassemblerIA32::AVXInstruction(uint8_t* data) {
692 uint8_t opcode = *data;
693 uint8_t* current = data + 1;
694 if (vex_66() && vex_0f38()) {
695 int mod, regop, rm, vvvv = vex_vreg();
696 get_modrm(*current, &mod, &regop, &rm);
697 switch (opcode) {
698 case 0x18:
699 AppendToBuffer("vbroadcastss %s,", NameOfXMMRegister(regop));
700 current += PrintRightXMMOperand(current);
701 break;
702 case 0x37:
703 AppendToBuffer("vpcmpgtq %s,%s,", NameOfXMMRegister(regop),
704 NameOfXMMRegister(vvvv));
705 current += PrintRightXMMOperand(current);
706 break;
707 case 0xF7:
708 AppendToBuffer("shlx %s,", NameOfCPURegister(regop));
709 current += PrintRightOperand(current);
710 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
711 break;
712#define DECLARE_SSE_AVX_DIS_CASE(instruction, notUsed1, notUsed2, notUsed3, \
713 opcode) \
714 case 0x##opcode: { \
715 AppendToBuffer("v" #instruction " %s,%s,", NameOfXMMRegister(regop), \
716 NameOfXMMRegister(vvvv)); \
717 current += PrintRightXMMOperand(current); \
718 break; \
719 }
720
721 SSSE3_INSTRUCTION_LIST(DECLARE_SSE_AVX_DIS_CASE)
722 SSE4_INSTRUCTION_LIST(DECLARE_SSE_AVX_DIS_CASE)
723#undef DECLARE_SSE_AVX_DIS_CASE
724#define DECLARE_SSE_AVX_RM_DIS_CASE(instruction, notUsed1, notUsed2, notUsed3, \
725 opcode) \
726 case 0x##opcode: { \
727 AppendToBuffer("v" #instruction " %s,", NameOfXMMRegister(regop)); \
728 current += PrintRightXMMOperand(current); \
729 break; \
730 }
731
732 SSSE3_UNOP_INSTRUCTION_LIST(DECLARE_SSE_AVX_RM_DIS_CASE)
733 SSE4_RM_INSTRUCTION_LIST(DECLARE_SSE_AVX_RM_DIS_CASE)
734#undef DECLARE_SSE_AVX_RM_DIS_CASE
735
736#define DISASSEMBLE_AVX2_BROADCAST(instruction, _1, _2, _3, code) \
737 case 0x##code: \
738 AppendToBuffer("" #instruction " %s,", NameOfXMMRegister(regop)); \
739 current += PrintRightXMMOperand(current); \
740 break;
741 AVX2_BROADCAST_LIST(DISASSEMBLE_AVX2_BROADCAST)
742#undef DISASSEMBLE_AVX2_BROADCAST
743
744 default: {
745#define DECLARE_FMA_DISASM(instruction, _1, _2, _3, _4, _5, code) \
746 case 0x##code: { \
747 AppendToBuffer(#instruction " %s,%s,", NameOfXMMRegister(regop), \
748 NameOfXMMRegister(vvvv)); \
749 current += PrintRightXMMOperand(current); \
750 break; \
751 }
752 // Handle all the fma instructions here in the default branch since they
753 // have the same opcodes but differ by rex_w.
754 if (vex_w()) {
755 switch (opcode) {
756 FMA_SD_INSTRUCTION_LIST(DECLARE_FMA_DISASM)
757 FMA_PD_INSTRUCTION_LIST(DECLARE_FMA_DISASM)
758 default: {
759 UnimplementedInstruction();
760 }
761 }
762 } else {
763 switch (opcode) {
764 FMA_SS_INSTRUCTION_LIST(DECLARE_FMA_DISASM)
765 FMA_PS_INSTRUCTION_LIST(DECLARE_FMA_DISASM)
766 default: {
767 UnimplementedInstruction();
768 }
769 }
770 }
771#undef DECLARE_FMA_DISASM
772 }
773 }
774 } else if (vex_66() && vex_0f3a()) {
775 int mod, regop, rm, vvvv = vex_vreg();
776 get_modrm(*current, &mod, &regop, &rm);
777 switch (opcode) {
778 case 0x08:
779 AppendToBuffer("vroundps %s,", NameOfXMMRegister(regop));
780 current += PrintRightXMMOperand(current);
781 AppendToBuffer(",%d", Imm8_U(current));
782 current++;
783 break;
784 case 0x09:
785 AppendToBuffer("vroundpd %s,", NameOfXMMRegister(regop));
786 current += PrintRightXMMOperand(current);
787 AppendToBuffer(",%d", Imm8_U(current));
788 current++;
789 break;
790 case 0x0a:
791 AppendToBuffer("vroundss %s,%s,", NameOfXMMRegister(regop),
792 NameOfXMMRegister(vvvv));
793 current += PrintRightXMMOperand(current);
794 AppendToBuffer(",%d", Imm8_U(current));
795 current++;
796 break;
797 case 0x0b:
798 AppendToBuffer("vroundsd %s,%s,", NameOfXMMRegister(regop),
799 NameOfXMMRegister(vvvv));
800 current += PrintRightXMMOperand(current);
801 AppendToBuffer(",%d", Imm8_U(current));
802 current++;
803 break;
804 case 0x0E:
805 AppendToBuffer("vpblendw %s,%s,", NameOfXMMRegister(regop),
806 NameOfXMMRegister(vvvv));
807 current += PrintRightXMMOperand(current);
808 AppendToBuffer(",%d", Imm8_U(current));
809 current++;
810 break;
811 case 0x0F:
812 AppendToBuffer("vpalignr %s,%s,", NameOfXMMRegister(regop),
813 NameOfXMMRegister(vvvv));
814 current += PrintRightXMMOperand(current);
815 AppendToBuffer(",%d", Imm8_U(current));
816 current++;
817 break;
818 case 0x14:
819 AppendToBuffer("vpextrb ");
820 current += PrintRightOperand(current);
821 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(current));
822 current++;
823 break;
824 case 0x15:
825 AppendToBuffer("vpextrw ");
826 current += PrintRightOperand(current);
827 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(current));
828 current++;
829 break;
830 case 0x16:
831 AppendToBuffer("vpextrd ");
832 current += PrintRightOperand(current);
833 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(current));
834 current++;
835 break;
836 case 0x20:
837 AppendToBuffer("vpinsrb %s,%s,", NameOfXMMRegister(regop),
838 NameOfXMMRegister(vvvv));
839 current += PrintRightOperand(current);
840 AppendToBuffer(",%d", Imm8(current));
841 current++;
842 break;
843 case 0x21:
844 AppendToBuffer("vinsertps %s,%s,", NameOfXMMRegister(regop),
845 NameOfXMMRegister(vvvv));
846 current += PrintRightXMMOperand(current);
847 AppendToBuffer(",%d", Imm8(current));
848 current++;
849 break;
850 case 0x22:
851 AppendToBuffer("vpinsrd %s,%s,", NameOfXMMRegister(regop),
852 NameOfXMMRegister(vvvv));
853 current += PrintRightOperand(current);
854 AppendToBuffer(",%d", Imm8(current));
855 current++;
856 break;
857 case 0x4A:
858 AppendToBuffer("vblendvps %s,%s,", NameOfXMMRegister(regop),
859 NameOfXMMRegister(vvvv));
860 current += PrintRightXMMOperand(current);
861 AppendToBuffer(",%s", NameOfXMMRegister(*current >> 4));
862 break;
863 case 0x4B:
864 AppendToBuffer("vblendvps %s,%s,", NameOfXMMRegister(regop),
865 NameOfXMMRegister(vvvv));
866 current += PrintRightXMMOperand(current);
867 AppendToBuffer(",%s", NameOfXMMRegister(*current >> 4));
868 break;
869 case 0x4C:
870 AppendToBuffer("vpblendvb %s,%s,", NameOfXMMRegister(regop),
871 NameOfXMMRegister(vvvv));
872 current += PrintRightXMMOperand(current);
873 AppendToBuffer(",%s", NameOfXMMRegister(*current >> 4));
874 break;
875 default:
876 UnimplementedInstruction();
877 }
878 } else if (vex_f2() && vex_0f()) {
879 int mod, regop, rm, vvvv = vex_vreg();
880 get_modrm(*current, &mod, &regop, &rm);
881 switch (opcode) {
882 case 0x10:
883 AppendToBuffer("vmovsd %s,%s,", NameOfXMMRegister(regop),
884 NameOfXMMRegister(vvvv));
885 current += PrintRightXMMOperand(current);
886 break;
887 case 0x11:
888 AppendToBuffer("vmovsd ");
889 current += PrintRightXMMOperand(current);
890 AppendToBuffer(",%s", NameOfXMMRegister(regop));
891 break;
892 case 0x12:
893 AppendToBuffer("vmovddup %s,", NameOfXMMRegister(regop));
894 current += PrintRightXMMOperand(current);
895 break;
896 case 0x2c:
897 AppendToBuffer("vcvttsd2si %s,", NameOfXMMRegister(regop));
898 current += PrintRightXMMOperand(current);
899 break;
900 case 0x70:
901 AppendToBuffer("vpshuflw %s,", NameOfXMMRegister(regop));
902 current += PrintRightXMMOperand(current);
903 AppendToBuffer(",%d", Imm8(current));
904 current++;
905 break;
906 case 0x7C:
907 AppendToBuffer("vhaddps %s,%s,", NameOfXMMRegister(regop),
908 NameOfXMMRegister(vvvv));
909 current += PrintRightXMMOperand(current);
910 break;
911#define DISASM_SSE2_INSTRUCTION_LIST_SD(instruction, _1, _2, opcode) \
912 case 0x##opcode: \
913 AppendToBuffer("v" #instruction " %s,%s,", NameOfXMMRegister(regop), \
914 NameOfXMMRegister(vvvv)); \
915 current += PrintRightXMMOperand(current); \
916 break;
917 SSE2_INSTRUCTION_LIST_SD(DISASM_SSE2_INSTRUCTION_LIST_SD)
918#undef DISASM_SSE2_INSTRUCTION_LIST_SD
919 default:
920 UnimplementedInstruction();
921 }
922 } else if (vex_f3() && vex_0f()) {
923 int mod, regop, rm, vvvv = vex_vreg();
924 get_modrm(*current, &mod, &regop, &rm);
925 switch (opcode) {
926 case 0x10:
927 AppendToBuffer("vmovss %s,%s,", NameOfXMMRegister(regop),
928 NameOfXMMRegister(vvvv));
929 current += PrintRightXMMOperand(current);
930 break;
931 case 0x11:
932 AppendToBuffer("vmovss ");
933 current += PrintRightXMMOperand(current);
934 AppendToBuffer(",%s", NameOfXMMRegister(regop));
935 break;
936 case 0x16:
937 AppendToBuffer("vmovshdup %s,", NameOfXMMRegister(regop));
938 current += PrintRightXMMOperand(current);
939 break;
940 case 0x2c:
941 AppendToBuffer("vcvttss2si %s,", NameOfXMMRegister(regop));
942 current += PrintRightXMMOperand(current);
943 break;
944 case 0x51:
945 AppendToBuffer("vsqrtss %s,%s,", NameOfXMMRegister(regop),
946 NameOfXMMRegister(vvvv));
947 current += PrintRightXMMOperand(current);
948 break;
949 case 0x58:
950 AppendToBuffer("vaddss %s,%s,", NameOfXMMRegister(regop),
951 NameOfXMMRegister(vvvv));
952 current += PrintRightXMMOperand(current);
953 break;
954 case 0x59:
955 AppendToBuffer("vmulss %s,%s,", NameOfXMMRegister(regop),
956 NameOfXMMRegister(vvvv));
957 current += PrintRightXMMOperand(current);
958 break;
959 case 0x5a:
960 AppendToBuffer("vcvtss2sd %s,%s,", NameOfXMMRegister(regop),
961 NameOfXMMRegister(vvvv));
962 current += PrintRightXMMOperand(current);
963 break;
964 case 0x5B:
965 AppendToBuffer("vcvttps2dq %s,", NameOfXMMRegister(regop));
966 current += PrintRightXMMOperand(current);
967 break;
968 case 0x5C:
969 AppendToBuffer("vsubss %s,%s,", NameOfXMMRegister(regop),
970 NameOfXMMRegister(vvvv));
971 current += PrintRightXMMOperand(current);
972 break;
973 case 0x5D:
974 AppendToBuffer("vminss %s,%s,", NameOfXMMRegister(regop),
975 NameOfXMMRegister(vvvv));
976 current += PrintRightXMMOperand(current);
977 break;
978 case 0x5E:
979 AppendToBuffer("vdivss %s,%s,", NameOfXMMRegister(regop),
980 NameOfXMMRegister(vvvv));
981 current += PrintRightXMMOperand(current);
982 break;
983 case 0x5F:
984 AppendToBuffer("vmaxss %s,%s,", NameOfXMMRegister(regop),
985 NameOfXMMRegister(vvvv));
986 current += PrintRightXMMOperand(current);
987 break;
988 case 0x6f:
989 AppendToBuffer("vmovdqu %s,", NameOfXMMRegister(regop));
990 current += PrintRightOperand(current);
991 break;
992 case 0x70:
993 AppendToBuffer("vpshufhw %s,", NameOfXMMRegister(regop));
994 current += PrintRightXMMOperand(current);
995 AppendToBuffer(",%d", Imm8(current));
996 current++;
997 break;
998 case 0x7f:
999 AppendToBuffer("vmovdqu ");
1000 current += PrintRightOperand(current);
1001 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1002 break;
1003 case 0xE6:
1004 AppendToBuffer("vcvtdq2pd %s,", NameOfXMMRegister(regop));
1005 current += PrintRightXMMOperand(current);
1006 break;
1007 default:
1008 UnimplementedInstruction();
1009 }
1010 } else if (vex_none() && vex_0f38()) {
1011 int mod, regop, rm, vvvv = vex_vreg();
1012 get_modrm(*current, &mod, &regop, &rm);
1013 const char* mnem = "?";
1014 switch (opcode) {
1015 case 0xF2:
1016 AppendToBuffer("andn %s,%s,", NameOfCPURegister(regop),
1017 NameOfCPURegister(vvvv));
1018 current += PrintRightOperand(current);
1019 break;
1020 case 0xF5:
1021 AppendToBuffer("bzhi %s,", NameOfCPURegister(regop));
1022 current += PrintRightOperand(current);
1023 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1024 break;
1025 case 0xF7:
1026 AppendToBuffer("bextr %s,", NameOfCPURegister(regop));
1027 current += PrintRightOperand(current);
1028 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1029 break;
1030 case 0xF3:
1031 switch (regop) {
1032 case 1:
1033 mnem = "blsr";
1034 break;
1035 case 2:
1036 mnem = "blsmsk";
1037 break;
1038 case 3:
1039 mnem = "blsi";
1040 break;
1041 default:
1042 UnimplementedInstruction();
1043 }
1044 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(vvvv));
1045 current += PrintRightOperand(current);
1046 mnem = "?";
1047 break;
1048 default:
1049 UnimplementedInstruction();
1050 }
1051 } else if (vex_f2() && vex_0f38()) {
1052 int mod, regop, rm, vvvv = vex_vreg();
1053 get_modrm(*current, &mod, &regop, &rm);
1054 switch (opcode) {
1055 case 0xF5:
1056 AppendToBuffer("pdep %s,%s,", NameOfCPURegister(regop),
1057 NameOfCPURegister(vvvv));
1058 current += PrintRightOperand(current);
1059 break;
1060 case 0xF6:
1061 AppendToBuffer("mulx %s,%s,", NameOfCPURegister(regop),
1062 NameOfCPURegister(vvvv));
1063 current += PrintRightOperand(current);
1064 break;
1065 case 0xF7:
1066 AppendToBuffer("shrx %s,", NameOfCPURegister(regop));
1067 current += PrintRightOperand(current);
1068 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1069 break;
1070 default:
1071 UnimplementedInstruction();
1072 }
1073 } else if (vex_f3() && vex_0f38()) {
1074 int mod, regop, rm, vvvv = vex_vreg();
1075 get_modrm(*current, &mod, &regop, &rm);
1076 switch (opcode) {
1077 case 0xF5:
1078 AppendToBuffer("pext %s,%s,", NameOfCPURegister(regop),
1079 NameOfCPURegister(vvvv));
1080 current += PrintRightOperand(current);
1081 break;
1082 case 0xF7:
1083 AppendToBuffer("sarx %s,", NameOfCPURegister(regop));
1084 current += PrintRightOperand(current);
1085 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1086 break;
1087 default:
1088 UnimplementedInstruction();
1089 }
1090 } else if (vex_f2() && vex_0f3a()) {
1091 int mod, regop, rm;
1092 get_modrm(*current, &mod, &regop, &rm);
1093 switch (opcode) {
1094 case 0xF0:
1095 AppendToBuffer("rorx %s,", NameOfCPURegister(regop));
1096 current += PrintRightOperand(current);
1097 AppendToBuffer(",%d", *current & 0x1F);
1098 current += 1;
1099 break;
1100 default:
1101 UnimplementedInstruction();
1102 }
1103 } else if (vex_none() && vex_0f()) {
1104 int mod, regop, rm, vvvv = vex_vreg();
1105 get_modrm(*current, &mod, &regop, &rm);
1106 switch (opcode) {
1107 case 0x10:
1108 AppendToBuffer("vmovups %s,", NameOfXMMRegister(regop));
1109 current += PrintRightXMMOperand(current);
1110 break;
1111 case 0x11:
1112 AppendToBuffer("vmovups ");
1113 current += PrintRightXMMOperand(current);
1114 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1115 break;
1116 case 0x12:
1117 if (mod == 0b11) {
1118 AppendToBuffer("vmovhlps %s,%s,", NameOfXMMRegister(regop),
1119 NameOfXMMRegister(vvvv));
1120 } else {
1121 AppendToBuffer("vmovlps %s,%s,", NameOfXMMRegister(regop),
1122 NameOfXMMRegister(vvvv));
1123 }
1124 current += PrintRightXMMOperand(current);
1125 break;
1126 case 0x13:
1127 AppendToBuffer("vmovlps ");
1128 current += PrintRightXMMOperand(current);
1129 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1130 break;
1131 case 0x14:
1132 AppendToBuffer("vunpcklps %s,%s,", NameOfXMMRegister(regop),
1133 NameOfXMMRegister(vvvv));
1134 current += PrintRightXMMOperand(current);
1135 break;
1136 case 0x16:
1137 AppendToBuffer("vmovhps %s,", NameOfXMMRegister(regop));
1138 current += PrintRightXMMOperand(current);
1139 break;
1140 case 0x17:
1141 AppendToBuffer("vmovhps ");
1142 current += PrintRightXMMOperand(current);
1143 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1144 break;
1145 case 0x28:
1146 AppendToBuffer("vmovaps %s,", NameOfXMMRegister(regop));
1147 current += PrintRightXMMOperand(current);
1148 break;
1149 case 0x2e:
1150 AppendToBuffer("vucomiss %s,", NameOfXMMRegister(regop));
1151 current += PrintRightXMMOperand(current);
1152 break;
1153 case 0x50:
1154 AppendToBuffer("vmovmskps %s,%s", NameOfCPURegister(regop),
1155 NameOfXMMRegister(rm));
1156 current++;
1157 break;
1158 case 0x51:
1159 AppendToBuffer("vsqrtps %s,", NameOfXMMRegister(regop));
1160 current += PrintRightXMMOperand(current);
1161 break;
1162 case 0x52:
1163 AppendToBuffer("vrsqrtps %s,", NameOfXMMRegister(regop));
1164 current += PrintRightXMMOperand(current);
1165 break;
1166 case 0x53:
1167 AppendToBuffer("vrcpps %s,", NameOfXMMRegister(regop));
1168 current += PrintRightXMMOperand(current);
1169 break;
1170 case 0x54:
1171 AppendToBuffer("vandps %s,%s,", NameOfXMMRegister(regop),
1172 NameOfXMMRegister(vvvv));
1173 current += PrintRightXMMOperand(current);
1174 break;
1175 case 0x55:
1176 AppendToBuffer("vandnps %s,%s,", NameOfXMMRegister(regop),
1177 NameOfXMMRegister(vvvv));
1178 current += PrintRightXMMOperand(current);
1179 break;
1180 case 0x56:
1181 AppendToBuffer("vorps %s,%s,", NameOfXMMRegister(regop),
1182 NameOfXMMRegister(vvvv));
1183 current += PrintRightXMMOperand(current);
1184 break;
1185 case 0x57:
1186 AppendToBuffer("vxorps %s,%s,", NameOfXMMRegister(regop),
1187 NameOfXMMRegister(vvvv));
1188 current += PrintRightXMMOperand(current);
1189 break;
1190 case 0x58:
1191 AppendToBuffer("vaddps %s,%s,", NameOfXMMRegister(regop),
1192 NameOfXMMRegister(vvvv));
1193 current += PrintRightXMMOperand(current);
1194 break;
1195 case 0x59:
1196 AppendToBuffer("vmulps %s,%s,", NameOfXMMRegister(regop),
1197 NameOfXMMRegister(vvvv));
1198 current += PrintRightXMMOperand(current);
1199 break;
1200 case 0x5A:
1201 AppendToBuffer("vcvtps2pd %s,", NameOfXMMRegister(regop));
1202 current += PrintRightXMMOperand(current);
1203 break;
1204 case 0x5B:
1205 AppendToBuffer("vcvtdq2ps %s,", NameOfXMMRegister(regop));
1206 current += PrintRightXMMOperand(current);
1207 break;
1208 case 0x5C:
1209 AppendToBuffer("vsubps %s,%s,", NameOfXMMRegister(regop),
1210 NameOfXMMRegister(vvvv));
1211 current += PrintRightXMMOperand(current);
1212 break;
1213 case 0x5D:
1214 AppendToBuffer("vminps %s,%s,", NameOfXMMRegister(regop),
1215 NameOfXMMRegister(vvvv));
1216 current += PrintRightXMMOperand(current);
1217 break;
1218 case 0x5E:
1219 AppendToBuffer("vdivps %s,%s,", NameOfXMMRegister(regop),
1220 NameOfXMMRegister(vvvv));
1221 current += PrintRightXMMOperand(current);
1222 break;
1223 case 0x5F:
1224 AppendToBuffer("vmaxps %s,%s,", NameOfXMMRegister(regop),
1225 NameOfXMMRegister(vvvv));
1226 current += PrintRightXMMOperand(current);
1227 break;
1228 case 0xC2: {
1229 AppendToBuffer("vcmpps %s,%s,", NameOfXMMRegister(regop),
1230 NameOfXMMRegister(vvvv));
1231 current += PrintRightXMMOperand(current);
1232 AppendToBuffer(", (%s)", cmp_pseudo_op[*current]);
1233 current++;
1234 break;
1235 }
1236 case 0xC6:
1237 AppendToBuffer("vshufps %s,%s,", NameOfXMMRegister(regop),
1238 NameOfXMMRegister(vvvv));
1239 current += PrintRightXMMOperand(current);
1240 AppendToBuffer(", %d", (*current) & 3);
1241 current += 1;
1242 break;
1243 default:
1244 UnimplementedInstruction();
1245 }
1246 } else if (vex_66() && vex_0f()) {
1247 int mod, regop, rm, vvvv = vex_vreg();
1248 get_modrm(*current, &mod, &regop, &rm);
1249 switch (opcode) {
1250 case 0x10:
1251 AppendToBuffer("vmovupd %s,", NameOfXMMRegister(regop));
1252 current += PrintRightXMMOperand(current);
1253 break;
1254 case 0x28:
1255 AppendToBuffer("vmovapd %s,", NameOfXMMRegister(regop));
1256 current += PrintRightXMMOperand(current);
1257 break;
1258 case 0x2e:
1259 AppendToBuffer("vucomisd %s,", NameOfXMMRegister(regop));
1260 current += PrintRightXMMOperand(current);
1261 break;
1262 case 0x50:
1263 AppendToBuffer("vmovmskpd %s,%s", NameOfCPURegister(regop),
1264 NameOfXMMRegister(rm));
1265 current++;
1266 break;
1267 case 0x54:
1268 AppendToBuffer("vandpd %s,%s,", NameOfXMMRegister(regop),
1269 NameOfXMMRegister(vvvv));
1270 current += PrintRightXMMOperand(current);
1271 break;
1272 case 0x55:
1273 AppendToBuffer("vandnpd %s,%s,", NameOfXMMRegister(regop),
1274 NameOfXMMRegister(vvvv));
1275 current += PrintRightXMMOperand(current);
1276 break;
1277 case 0x56:
1278 AppendToBuffer("vorpd %s,%s,", NameOfXMMRegister(regop),
1279 NameOfXMMRegister(vvvv));
1280 current += PrintRightXMMOperand(current);
1281 break;
1282 case 0x57:
1283 AppendToBuffer("vxorpd %s,%s,", NameOfXMMRegister(regop),
1284 NameOfXMMRegister(vvvv));
1285 current += PrintRightXMMOperand(current);
1286 break;
1287 case 0x58:
1288 AppendToBuffer("vaddpd %s,%s,", NameOfXMMRegister(regop),
1289 NameOfXMMRegister(vvvv));
1290 current += PrintRightXMMOperand(current);
1291 break;
1292 case 0x59:
1293 AppendToBuffer("vmulpd %s,%s,", NameOfXMMRegister(regop),
1294 NameOfXMMRegister(vvvv));
1295 current += PrintRightXMMOperand(current);
1296 break;
1297 case 0x5A:
1298 AppendToBuffer("vcvtpd2ps %s,", NameOfXMMRegister(regop));
1299 current += PrintRightXMMOperand(current);
1300 break;
1301 case 0x5C:
1302 AppendToBuffer("vsubpd %s,%s,", NameOfXMMRegister(regop),
1303 NameOfXMMRegister(vvvv));
1304 current += PrintRightXMMOperand(current);
1305 break;
1306 case 0x5D:
1307 AppendToBuffer("vminpd %s,%s,", NameOfXMMRegister(regop),
1308 NameOfXMMRegister(vvvv));
1309 current += PrintRightXMMOperand(current);
1310 break;
1311 case 0x5E:
1312 AppendToBuffer("vdivpd %s,%s,", NameOfXMMRegister(regop),
1313 NameOfXMMRegister(vvvv));
1314 current += PrintRightXMMOperand(current);
1315 break;
1316 case 0x5F:
1317 AppendToBuffer("vmaxpd %s,%s,", NameOfXMMRegister(regop),
1318 NameOfXMMRegister(vvvv));
1319 current += PrintRightXMMOperand(current);
1320 break;
1321 case 0x6E:
1322 AppendToBuffer("vmovd %s,", NameOfXMMRegister(regop));
1323 current += PrintRightOperand(current);
1324 break;
1325 case 0x6f:
1326 AppendToBuffer("vmovdqa %s,", NameOfXMMRegister(regop));
1327 current += PrintRightOperand(current);
1328 break;
1329 case 0x70:
1330 AppendToBuffer("vpshufd %s,", NameOfXMMRegister(regop));
1331 current += PrintRightXMMOperand(current);
1332 AppendToBuffer(",%d", Imm8(current));
1333 current++;
1334 break;
1335 case 0x71:
1336 AppendToBuffer("vps%sw %s,%s", sf_str[regop / 2],
1337 NameOfXMMRegister(vvvv), NameOfXMMRegister(rm));
1338 current++;
1339 AppendToBuffer(",%u", *current++);
1340 break;
1341 case 0x72:
1342 AppendToBuffer("vps%sd %s,%s", sf_str[regop / 2],
1343 NameOfXMMRegister(vvvv), NameOfXMMRegister(rm));
1344 current++;
1345 AppendToBuffer(",%u", *current++);
1346 break;
1347 case 0x73:
1348 AppendToBuffer("vps%sq %s,%s", sf_str[regop / 2],
1349 NameOfXMMRegister(vvvv), NameOfXMMRegister(rm));
1350 current++;
1351 AppendToBuffer(",%u", *current++);
1352 break;
1353 case 0x7E:
1354 AppendToBuffer("vmovd ");
1355 current += PrintRightOperand(current);
1356 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1357 break;
1358 case 0xC2: {
1359 AppendToBuffer("vcmppd %s,%s,", NameOfXMMRegister(regop),
1360 NameOfXMMRegister(vvvv));
1361 current += PrintRightXMMOperand(current);
1362 AppendToBuffer(", (%s)", cmp_pseudo_op[*current]);
1363 current++;
1364 break;
1365 }
1366 case 0xC4:
1367 AppendToBuffer("vpinsrw %s,%s,", NameOfXMMRegister(regop),
1368 NameOfXMMRegister(vvvv));
1369 current += PrintRightOperand(current);
1370 AppendToBuffer(",%d", Imm8(current));
1371 current++;
1372 break;
1373 case 0xC6:
1374 AppendToBuffer("vshufpd %s,%s,", NameOfXMMRegister(regop),
1375 NameOfXMMRegister(vvvv));
1376 current += PrintRightXMMOperand(current);
1377 AppendToBuffer(",%d", Imm8(current));
1378 current++;
1379 break;
1380 case 0xD7:
1381 AppendToBuffer("vpmovmskb %s,%s", NameOfCPURegister(regop),
1382 NameOfXMMRegister(rm));
1383 current++;
1384 break;
1385 case 0xE6:
1386 AppendToBuffer("vcvttpd2dq %s,", NameOfXMMRegister(regop));
1387 current += PrintRightXMMOperand(current);
1388 break;
1389#define DECLARE_SSE_AVX_DIS_CASE(instruction, notUsed1, notUsed2, opcode) \
1390 case 0x##opcode: { \
1391 AppendToBuffer("v" #instruction " %s,%s,", NameOfXMMRegister(regop), \
1392 NameOfXMMRegister(vvvv)); \
1393 current += PrintRightXMMOperand(current); \
1394 break; \
1395 }
1396
1397 SSE2_INSTRUCTION_LIST(DECLARE_SSE_AVX_DIS_CASE)
1398#undef DECLARE_SSE_AVX_DIS_CASE
1399 default:
1400 UnimplementedInstruction();
1401 }
1402 } else {
1403 UnimplementedInstruction();
1404 }
1405
1406 return static_cast<int>(current - data);
1407}
1408
1409// Returns number of bytes used, including *data.
1410int DisassemblerIA32::FPUInstruction(uint8_t* data) {
1411 uint8_t escape_opcode = *data;
1412 DCHECK_EQ(0xD8, escape_opcode & 0xF8);
1413 uint8_t modrm_byte = *(data + 1);
1414
1415 if (modrm_byte >= 0xC0) {
1416 return RegisterFPUInstruction(escape_opcode, modrm_byte);
1417 } else {
1418 return MemoryFPUInstruction(escape_opcode, modrm_byte, data + 1);
1419 }
1420}
1421
1422int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode, int modrm_byte,
1423 uint8_t* modrm_start) {
1424 const char* mnem = "?";
1425 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
1426 switch (escape_opcode) {
1427 case 0xD9:
1428 switch (regop) {
1429 case 0:
1430 mnem = "fld_s";
1431 break;
1432 case 2:
1433 mnem = "fst_s";
1434 break;
1435 case 3:
1436 mnem = "fstp_s";
1437 break;
1438 case 7:
1439 mnem = "fstcw";
1440 break;
1441 default:
1442 UnimplementedInstruction();
1443 }
1444 break;
1445
1446 case 0xDB:
1447 switch (regop) {
1448 case 0:
1449 mnem = "fild_s";
1450 break;
1451 case 1:
1452 mnem = "fisttp_s";
1453 break;
1454 case 2:
1455 mnem = "fist_s";
1456 break;
1457 case 3:
1458 mnem = "fistp_s";
1459 break;
1460 default:
1461 UnimplementedInstruction();
1462 }
1463 break;
1464
1465 case 0xDD:
1466 switch (regop) {
1467 case 0:
1468 mnem = "fld_d";
1469 break;
1470 case 1:
1471 mnem = "fisttp_d";
1472 break;
1473 case 2:
1474 mnem = "fst_d";
1475 break;
1476 case 3:
1477 mnem = "fstp_d";
1478 break;
1479 default:
1480 UnimplementedInstruction();
1481 }
1482 break;
1483
1484 case 0xDF:
1485 switch (regop) {
1486 case 5:
1487 mnem = "fild_d";
1488 break;
1489 case 7:
1490 mnem = "fistp_d";
1491 break;
1492 default:
1493 UnimplementedInstruction();
1494 }
1495 break;
1496
1497 default:
1498 UnimplementedInstruction();
1499 }
1500 AppendToBuffer("%s ", mnem);
1501 int count = PrintRightOperand(modrm_start);
1502 return count + 1;
1503}
1504
1505int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
1506 uint8_t modrm_byte) {
1507 bool has_register = false; // Is the FPU register encoded in modrm_byte?
1508 const char* mnem = "?";
1509
1510 switch (escape_opcode) {
1511 case 0xD8:
1512 has_register = true;
1513 switch (modrm_byte & 0xF8) {
1514 case 0xC0:
1515 mnem = "fadd_i";
1516 break;
1517 case 0xE0:
1518 mnem = "fsub_i";
1519 break;
1520 case 0xC8:
1521 mnem = "fmul_i";
1522 break;
1523 case 0xF0:
1524 mnem = "fdiv_i";
1525 break;
1526 default:
1527 UnimplementedInstruction();
1528 }
1529 break;
1530
1531 case 0xD9:
1532 switch (modrm_byte & 0xF8) {
1533 case 0xC0:
1534 mnem = "fld";
1535 has_register = true;
1536 break;
1537 case 0xC8:
1538 mnem = "fxch";
1539 has_register = true;
1540 break;
1541 default:
1542 switch (modrm_byte) {
1543 case 0xE0:
1544 mnem = "fchs";
1545 break;
1546 case 0xE1:
1547 mnem = "fabs";
1548 break;
1549 case 0xE4:
1550 mnem = "ftst";
1551 break;
1552 case 0xE8:
1553 mnem = "fld1";
1554 break;
1555 case 0xEB:
1556 mnem = "fldpi";
1557 break;
1558 case 0xED:
1559 mnem = "fldln2";
1560 break;
1561 case 0xEE:
1562 mnem = "fldz";
1563 break;
1564 case 0xF0:
1565 mnem = "f2xm1";
1566 break;
1567 case 0xF1:
1568 mnem = "fyl2x";
1569 break;
1570 case 0xF4:
1571 mnem = "fxtract";
1572 break;
1573 case 0xF5:
1574 mnem = "fprem1";
1575 break;
1576 case 0xF7:
1577 mnem = "fincstp";
1578 break;
1579 case 0xF8:
1580 mnem = "fprem";
1581 break;
1582 case 0xFC:
1583 mnem = "frndint";
1584 break;
1585 case 0xFD:
1586 mnem = "fscale";
1587 break;
1588 case 0xFE:
1589 mnem = "fsin";
1590 break;
1591 case 0xFF:
1592 mnem = "fcos";
1593 break;
1594 default:
1595 UnimplementedInstruction();
1596 }
1597 }
1598 break;
1599
1600 case 0xDA:
1601 if (modrm_byte == 0xE9) {
1602 mnem = "fucompp";
1603 } else {
1604 UnimplementedInstruction();
1605 }
1606 break;
1607
1608 case 0xDB:
1609 if ((modrm_byte & 0xF8) == 0xE8) {
1610 mnem = "fucomi";
1611 has_register = true;
1612 } else if (modrm_byte == 0xE2) {
1613 mnem = "fclex";
1614 } else if (modrm_byte == 0xE3) {
1615 mnem = "fninit";
1616 } else {
1617 UnimplementedInstruction();
1618 }
1619 break;
1620
1621 case 0xDC:
1622 has_register = true;
1623 switch (modrm_byte & 0xF8) {
1624 case 0xC0:
1625 mnem = "fadd";
1626 break;
1627 case 0xE8:
1628 mnem = "fsub";
1629 break;
1630 case 0xC8:
1631 mnem = "fmul";
1632 break;
1633 case 0xF8:
1634 mnem = "fdiv";
1635 break;
1636 default:
1637 UnimplementedInstruction();
1638 }
1639 break;
1640
1641 case 0xDD:
1642 has_register = true;
1643 switch (modrm_byte & 0xF8) {
1644 case 0xC0:
1645 mnem = "ffree";
1646 break;
1647 case 0xD0:
1648 mnem = "fst";
1649 break;
1650 case 0xD8:
1651 mnem = "fstp";
1652 break;
1653 default:
1654 UnimplementedInstruction();
1655 }
1656 break;
1657
1658 case 0xDE:
1659 if (modrm_byte == 0xD9) {
1660 mnem = "fcompp";
1661 } else {
1662 has_register = true;
1663 switch (modrm_byte & 0xF8) {
1664 case 0xC0:
1665 mnem = "faddp";
1666 break;
1667 case 0xE8:
1668 mnem = "fsubp";
1669 break;
1670 case 0xC8:
1671 mnem = "fmulp";
1672 break;
1673 case 0xF8:
1674 mnem = "fdivp";
1675 break;
1676 default:
1677 UnimplementedInstruction();
1678 }
1679 }
1680 break;
1681
1682 case 0xDF:
1683 if (modrm_byte == 0xE0) {
1684 mnem = "fnstsw_ax";
1685 } else if ((modrm_byte & 0xF8) == 0xE8) {
1686 mnem = "fucomip";
1687 has_register = true;
1688 }
1689 break;
1690
1691 default:
1692 UnimplementedInstruction();
1693 }
1694
1695 if (has_register) {
1696 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1697 } else {
1698 AppendToBuffer("%s", mnem);
1699 }
1700 return 2;
1701}
1702
1703// Mnemonics for instructions 0xF0 byte.
1704// Returns nullptr if the instruction is not handled here.
1705static const char* F0Mnem(uint8_t f0byte) {
1706 switch (f0byte) {
1707 case 0x0B:
1708 return "ud2";
1709 case 0x18:
1710 return "prefetch";
1711 case 0xA2:
1712 return "cpuid";
1713 case 0xBE:
1714 return "movsx_b";
1715 case 0xBF:
1716 return "movsx_w";
1717 case 0xB6:
1718 return "movzx_b";
1719 case 0xB7:
1720 return "movzx_w";
1721 case 0xAF:
1722 return "imul";
1723 case 0xA4:
1724 return "shld";
1725 case 0xA5:
1726 return "shld";
1727 case 0xAD:
1728 return "shrd";
1729 case 0xAC:
1730 return "shrd"; // 3-operand version.
1731 case 0xAB:
1732 return "bts";
1733 case 0xB0:
1734 return "cmpxchg_b";
1735 case 0xB1:
1736 return "cmpxchg";
1737 case 0xBC:
1738 return "bsf";
1739 case 0xBD:
1740 return "bsr";
1741 case 0xC7:
1742 return "cmpxchg8b";
1743 default:
1744 return nullptr;
1745 }
1746}
1747
1748// Disassembled instruction '*instr' and writes it into 'out_buffer'.
1749int DisassemblerIA32::InstructionDecode(v8::base::Vector<char> out_buffer,
1750 uint8_t* instr) {
1751 tmp_buffer_pos_ = 0; // starting to write as position 0
1752 uint8_t* data = instr;
1753 // Check for hints.
1754 const char* branch_hint = nullptr;
1755 // We use these two prefixes only with branch prediction
1756 if (*data == 0x3E /*ds*/) {
1757 branch_hint = "predicted taken";
1758 data++;
1759 } else if (*data == 0x2E /*cs*/) {
1760 branch_hint = "predicted not taken";
1761 data++;
1762 } else if (*data == 0xC4 && *(data + 1) >= 0xC0) {
1763 vex_byte0_ = *data;
1764 vex_byte1_ = *(data + 1);
1765 vex_byte2_ = *(data + 2);
1766 data += 3;
1767 } else if (*data == 0xC5 && *(data + 1) >= 0xC0) {
1768 vex_byte0_ = *data;
1769 vex_byte1_ = *(data + 1);
1770 data += 2;
1771 } else if (*data == 0xF0 /*lock*/) {
1772 AppendToBuffer("lock ");
1773 data++;
1774 }
1775
1776 bool processed = true; // Will be set to false if the current instruction
1777 // is not in 'instructions' table.
1778 // Decode AVX instructions.
1779 if (vex_byte0_ != 0) {
1780 data += AVXInstruction(data);
1781 } else {
1782 const InstructionDesc& idesc = instruction_table_->Get(*data);
1783 switch (idesc.type) {
1784 case ZERO_OPERANDS_INSTR:
1785 AppendToBuffer("%s", idesc.mnem);
1786 data++;
1787 break;
1788
1789 case TWO_OPERANDS_INSTR:
1790 data++;
1791 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1792 break;
1793
1794 case JUMP_CONDITIONAL_SHORT_INSTR:
1795 data += JumpConditionalShort(data, branch_hint);
1796 break;
1797
1798 case REGISTER_INSTR:
1799 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
1800 data++;
1801 break;
1802
1803 case MOVE_REG_INSTR: {
1804 uint8_t* addr = reinterpret_cast<uint8_t*>(Imm32(data + 1));
1805 AppendToBuffer("mov %s,%s", NameOfCPURegister(*data & 0x07),
1806 NameOfAddress(addr));
1807 data += 5;
1808 break;
1809 }
1810
1811 case CALL_JUMP_INSTR: {
1812 uint8_t* addr = data + Imm32(data + 1) + 5;
1813 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
1814 data += 5;
1815 break;
1816 }
1817
1818 case SHORT_IMMEDIATE_INSTR: {
1819 uint8_t* addr = reinterpret_cast<uint8_t*>(Imm32(data + 1));
1820 AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
1821 data += 5;
1822 break;
1823 }
1824
1825 case BYTE_IMMEDIATE_INSTR: {
1826 AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
1827 data += 2;
1828 break;
1829 }
1830
1831 case NO_INSTR:
1832 processed = false;
1833 break;
1834
1835 default:
1836 UNIMPLEMENTED(); // This type is not implemented.
1837 }
1838 }
1839 //----------------------------
1840 if (!processed) {
1841 switch (*data) {
1842 case 0xC2:
1843 AppendToBuffer("ret 0x%x", Imm16_U(data + 1));
1844 data += 3;
1845 break;
1846
1847 case 0x6B: {
1848 data++;
1849 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1850 AppendToBuffer(",%d", *data);
1851 data++;
1852 } break;
1853
1854 case 0x69: {
1855 data++;
1856 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1857 AppendToBuffer(",%d", Imm32(data));
1858 data += 4;
1859 } break;
1860
1861 case 0xF6: {
1862 data++;
1863 int mod, regop, rm;
1864 get_modrm(*data, &mod, &regop, &rm);
1865 if (regop == eax) {
1866 AppendToBuffer("test_b ");
1867 data += PrintRightByteOperand(data);
1868 int32_t imm = *data;
1869 AppendToBuffer(",0x%x", imm);
1870 data++;
1871 } else {
1872 UnimplementedInstruction();
1873 }
1874 } break;
1875
1876 case 0x81: // fall through
1877 case 0x83: // 0x81 with sign extension bit set
1878 data += PrintImmediateOp(data);
1879 break;
1880
1881 case 0x0F: {
1882 uint8_t f0byte = data[1];
1883 const char* f0mnem = F0Mnem(f0byte);
1884 int mod, regop, rm;
1885 // Not every instruction use this, and it is safe to index data+2 as all
1886 // instructions are at least 3 bytes with operands.
1887 get_modrm(*(data + 2), &mod, &regop, &rm);
1888 if (f0byte == 0x12) {
1889 data += 2;
1890 if (mod == 0b11) {
1891 AppendToBuffer("movhlps %s,", NameOfXMMRegister(regop));
1892 } else {
1893 AppendToBuffer("movlps %s,", NameOfXMMRegister(regop));
1894 }
1895 data += PrintRightXMMOperand(data);
1896 } else if (f0byte == 0x13) {
1897 data += 2;
1898 AppendToBuffer("movlps ");
1899 data += PrintRightXMMOperand(data);
1900 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1901 } else if (f0byte == 0x14) {
1902 data += 2;
1903 AppendToBuffer("unpcklps %s,", NameOfXMMRegister(regop));
1904 data += PrintRightXMMOperand(data);
1905 } else if (f0byte == 0x16) {
1906 data += 2;
1907 AppendToBuffer("movhps %s,", NameOfXMMRegister(regop));
1908 data += PrintRightXMMOperand(data);
1909 } else if (f0byte == 0x17) {
1910 data += 2;
1911 AppendToBuffer("movhps ");
1912 data += PrintRightXMMOperand(data);
1913 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1914 } else if (f0byte == 0x18) {
1915 data += 2;
1916 const char* suffix[] = {"nta", "1", "2", "3"};
1917 AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
1918 data += PrintRightOperand(data);
1919 } else if (f0byte == 0x1F && data[2] == 0) {
1920 AppendToBuffer("nop"); // 3 byte nop.
1921 data += 3;
1922 } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1923 AppendToBuffer("nop"); // 4 byte nop.
1924 data += 4;
1925 } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1926 data[4] == 0) {
1927 AppendToBuffer("nop"); // 5 byte nop.
1928 data += 5;
1929 } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1930 data[4] == 0 && data[5] == 0 && data[6] == 0) {
1931 AppendToBuffer("nop"); // 7 byte nop.
1932 data += 7;
1933 } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1934 data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1935 data[7] == 0) {
1936 AppendToBuffer("nop"); // 8 byte nop.
1937 data += 8;
1938 } else if (f0byte == 0x0B || f0byte == 0xA2 || f0byte == 0x31) {
1939 AppendToBuffer("%s", f0mnem);
1940 data += 2;
1941 } else if (f0byte == 0x28) {
1942 data += 2;
1943 AppendToBuffer("movaps %s,%s", NameOfXMMRegister(regop),
1944 NameOfXMMRegister(rm));
1945 data++;
1946 } else if (f0byte == 0x10 || f0byte == 0x11) {
1947 data += 2;
1948 // movups xmm, xmm/m128
1949 // movups xmm/m128, xmm
1950 AppendToBuffer("movups ");
1951 if (f0byte == 0x11) {
1952 data += PrintRightXMMOperand(data);
1953 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1954 } else {
1955 AppendToBuffer("%s,", NameOfXMMRegister(regop));
1956 data += PrintRightXMMOperand(data);
1957 }
1958 } else if (f0byte == 0x2E) {
1959 data += 2;
1960 AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
1961 data += PrintRightXMMOperand(data);
1962 } else if (f0byte >= 0x51 && f0byte <= 0x5F) {
1963 const char* const pseudo_op[] = {
1964 "sqrtps", "rsqrtps", "rcpps", "andps", "andnps",
1965 "orps", "xorps", "addps", "mulps", "cvtps2pd",
1966 "cvtdq2ps", "subps", "minps", "divps", "maxps",
1967 };
1968
1969 data += 2;
1970 AppendToBuffer("%s %s,", pseudo_op[f0byte - 0x51],
1971 NameOfXMMRegister(regop));
1972 data += PrintRightXMMOperand(data);
1973 } else if (f0byte == 0x50) {
1974 data += 2;
1975 AppendToBuffer("movmskps %s,%s", NameOfCPURegister(regop),
1976 NameOfXMMRegister(rm));
1977 data++;
1978 } else if (f0byte == 0xC0) {
1979 data += 2;
1980 data += PrintOperands("xadd_b", OPER_REG_OP_ORDER, data);
1981 } else if (f0byte == 0xC1) {
1982 data += 2;
1983 data += PrintOperands("xadd", OPER_REG_OP_ORDER, data);
1984 } else if (f0byte == 0xC2) {
1985 data += 2;
1986 AppendToBuffer("cmpps %s, ", NameOfXMMRegister(regop));
1987 data += PrintRightXMMOperand(data);
1988 AppendToBuffer(", (%s)", cmp_pseudo_op[*data]);
1989 data++;
1990 } else if (f0byte == 0xC6) {
1991 // shufps xmm, xmm/m128, imm8
1992 data += 2;
1993 int8_t imm8 = static_cast<int8_t>(data[1]);
1994 AppendToBuffer("shufps %s,%s,%d", NameOfXMMRegister(rm),
1995 NameOfXMMRegister(regop), static_cast<int>(imm8));
1996 data += 2;
1997 } else if (f0byte >= 0xC8 && f0byte <= 0xCF) {
1998 // bswap
1999 data += 2;
2000 int reg = f0byte - 0xC8;
2001 AppendToBuffer("bswap %s", NameOfCPURegister(reg));
2002 } else if ((f0byte & 0xF0) == 0x80) {
2003 data += JumpConditional(data, branch_hint);
2004 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
2005 f0byte == 0xB7 || f0byte == 0xAF) {
2006 data += 2;
2007 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
2008 } else if ((f0byte & 0xF0) == 0x90) {
2009 data += SetCC(data);
2010 } else if ((f0byte & 0xF0) == 0x40) {
2011 data += CMov(data);
2012 } else if (f0byte == 0xA4 || f0byte == 0xAC) {
2013 // shld, shrd
2014 data += 2;
2015 AppendToBuffer("%s ", f0mnem);
2016 int8_t imm8 = static_cast<int8_t>(data[1]);
2017 data += 2;
2018 AppendToBuffer("%s,%s,%d", NameOfCPURegister(rm),
2019 NameOfCPURegister(regop), static_cast<int>(imm8));
2020 } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
2021 // shrd_cl, shld_cl, bts
2022 data += 2;
2023 AppendToBuffer("%s ", f0mnem);
2024 data += PrintRightOperand(data);
2025 if (f0byte == 0xAB) {
2026 AppendToBuffer(",%s", NameOfCPURegister(regop));
2027 } else {
2028 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
2029 }
2030 } else if (f0byte == 0xB0) {
2031 // cmpxchg_b
2032 data += 2;
2033 AppendToBuffer("%s ", f0mnem);
2034 data += PrintRightOperand(data);
2035 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
2036 } else if (f0byte == 0xB1) {
2037 // cmpxchg
2038 data += 2;
2039 data += PrintOperands(f0mnem, OPER_REG_OP_ORDER, data);
2040 } else if (f0byte == 0xBC) {
2041 data += 2;
2042 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
2043 data += PrintRightOperand(data);
2044 } else if (f0byte == 0xBD) {
2045 data += 2;
2046 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
2047 data += PrintRightOperand(data);
2048 } else if (f0byte == 0xC7) {
2049 // cmpxchg8b
2050 data += 2;
2051 AppendToBuffer("%s ", f0mnem);
2052 data += PrintRightOperand(data);
2053 } else if (f0byte == 0xAE && (data[2] & 0xF8) == 0xF0) {
2054 AppendToBuffer("mfence");
2055 data += 3;
2056 } else if (f0byte == 0xAE && (data[2] & 0xF8) == 0xE8) {
2057 AppendToBuffer("lfence");
2058 data += 3;
2059 } else {
2060 UnimplementedInstruction();
2061 data += 1;
2062 }
2063 } break;
2064
2065 case 0x8F: {
2066 data++;
2067 int mod, regop, rm;
2068 get_modrm(*data, &mod, &regop, &rm);
2069 if (regop == eax) {
2070 AppendToBuffer("pop ");
2071 data += PrintRightOperand(data);
2072 }
2073 } break;
2074
2075 case 0xFF: {
2076 data++;
2077 int mod, regop, rm;
2078 get_modrm(*data, &mod, &regop, &rm);
2079 const char* mnem = "";
2080 switch (regop) {
2081 case esi:
2082 mnem = "push";
2083 break;
2084 case eax:
2085 mnem = "inc";
2086 break;
2087 case ecx:
2088 mnem = "dec";
2089 break;
2090 case edx:
2091 mnem = "call";
2092 break;
2093 case esp:
2094 mnem = "jmp";
2095 break;
2096 default:
2097 mnem = "???";
2098 }
2099 AppendToBuffer("%s ", mnem);
2100 data += PrintRightOperand(data);
2101 } break;
2102
2103 case 0xC7: // imm32, fall through
2104 case 0xC6: // imm8
2105 {
2106 bool is_byte = *data == 0xC6;
2107 data++;
2108 if (is_byte) {
2109 AppendToBuffer("%s ", "mov_b");
2110 data += PrintRightByteOperand(data);
2111 int32_t imm = *data;
2112 AppendToBuffer(",0x%x", imm);
2113 data++;
2114 } else {
2115 AppendToBuffer("%s ", "mov");
2116 data += PrintRightOperand(data);
2117 AppendToBuffer(",0x%x", Imm32(data));
2118 data += 4;
2119 }
2120 } break;
2121
2122 case 0x80: {
2123 data++;
2124 int mod, regop, rm;
2125 get_modrm(*data, &mod, &regop, &rm);
2126 const char* mnem = "";
2127 switch (regop) {
2128 case 5:
2129 mnem = "subb";
2130 break;
2131 case 7:
2132 mnem = "cmpb";
2133 break;
2134 default:
2135 UnimplementedInstruction();
2136 }
2137 AppendToBuffer("%s ", mnem);
2138 data += PrintRightByteOperand(data);
2139 int32_t imm = *data;
2140 AppendToBuffer(",0x%x", imm);
2141 data++;
2142 } break;
2143
2144 case 0x88: // 8bit, fall through
2145 case 0x89: // 32bit
2146 {
2147 bool is_byte = *data == 0x88;
2148 int mod, regop, rm;
2149 data++;
2150 get_modrm(*data, &mod, &regop, &rm);
2151 if (is_byte) {
2152 AppendToBuffer("%s ", "mov_b");
2153 data += PrintRightByteOperand(data);
2154 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
2155 } else {
2156 AppendToBuffer("%s ", "mov");
2157 data += PrintRightOperand(data);
2158 AppendToBuffer(",%s", NameOfCPURegister(regop));
2159 }
2160 } break;
2161
2162 case 0x66: // prefix
2163 while (*data == 0x66) data++;
2164 if (*data == 0xF && data[1] == 0x1F) {
2165 AppendToBuffer("nop"); // 0x66 prefix
2166 } else if (*data == 0x39) {
2167 data++;
2168 data += PrintOperands("cmpw", OPER_REG_OP_ORDER, data);
2169 } else if (*data == 0x3B) {
2170 data++;
2171 data += PrintOperands("cmpw", REG_OPER_OP_ORDER, data);
2172 } else if (*data == 0x81) {
2173 data++;
2174 AppendToBuffer("cmpw ");
2175 data += PrintRightOperand(data);
2176 AppendToBuffer(",0x%x", Imm16(data));
2177 data += 2;
2178 } else if (*data == 0x87) {
2179 data++;
2180 int mod, regop, rm;
2181 get_modrm(*data, &mod, &regop, &rm);
2182 AppendToBuffer("xchg_w %s,", NameOfCPURegister(regop));
2183 data += PrintRightOperand(data);
2184 } else if (*data == 0x89) {
2185 data++;
2186 int mod, regop, rm;
2187 get_modrm(*data, &mod, &regop, &rm);
2188 AppendToBuffer("mov_w ");
2189 data += PrintRightOperand(data);
2190 AppendToBuffer(",%s", NameOfCPURegister(regop));
2191 } else if (*data == 0x8B) {
2192 data++;
2193 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
2194 } else if (*data == 0x90) {
2195 AppendToBuffer("nop"); // 0x66 prefix
2196 } else if (*data == 0xC7) {
2197 data++;
2198 AppendToBuffer("%s ", "mov_w");
2199 data += PrintRightOperand(data);
2200 AppendToBuffer(",0x%x", Imm16(data));
2201 data += 2;
2202 } else if (*data == 0xF7) {
2203 data++;
2204 AppendToBuffer("%s ", "test_w");
2205 data += PrintRightOperand(data);
2206 AppendToBuffer(",0x%x", Imm16(data));
2207 data += 2;
2208 } else if (*data == 0x0F) {
2209 data++;
2210 if (*data == 0x10) {
2211 data++;
2212 int mod, regop, rm;
2213 get_modrm(*data, &mod, &regop, &rm);
2214 AppendToBuffer("movupd %s,", NameOfXMMRegister(regop));
2215 data += PrintRightXMMOperand(data);
2216 } else if (*data == 0x28) {
2217 data++;
2218 int mod, regop, rm;
2219 get_modrm(*data, &mod, &regop, &rm);
2220 AppendToBuffer("movapd %s,", NameOfXMMRegister(regop));
2221 data += PrintRightXMMOperand(data);
2222 } else if (*data == 0x38) {
2223 data++;
2224 uint8_t op = *data;
2225 data++;
2226 int mod, regop, rm;
2227 get_modrm(*data, &mod, &regop, &rm);
2228 switch (op) {
2229#define SSE34_DIS_CASE(instruction, notUsed1, notUsed2, notUsed3, opcode) \
2230 case 0x##opcode: { \
2231 AppendToBuffer(#instruction " %s,", NameOfXMMRegister(regop)); \
2232 data += PrintRightXMMOperand(data); \
2233 break; \
2234 }
2235
2236 SSSE3_INSTRUCTION_LIST(SSE34_DIS_CASE)
2237 SSSE3_UNOP_INSTRUCTION_LIST(SSE34_DIS_CASE)
2238 SSE4_INSTRUCTION_LIST(SSE34_DIS_CASE)
2239 SSE4_RM_INSTRUCTION_LIST(SSE34_DIS_CASE)
2240#undef SSE34_DIS_CASE
2241 case 0x10:
2242 AppendToBuffer("pblendvb %s,", NameOfXMMRegister(regop));
2243 data += PrintRightXMMOperand(data);
2244 AppendToBuffer(",xmm0");
2245 break;
2246 case 0x14:
2247 AppendToBuffer("blendvps %s,", NameOfXMMRegister(regop));
2248 data += PrintRightXMMOperand(data);
2249 AppendToBuffer(",xmm0");
2250 break;
2251 case 0x15:
2252 AppendToBuffer("blendvps %s,", NameOfXMMRegister(regop));
2253 data += PrintRightXMMOperand(data);
2254 AppendToBuffer(",xmm0");
2255 break;
2256 case 0x37:
2257 AppendToBuffer("pcmpgtq %s,", NameOfXMMRegister(regop));
2258 data += PrintRightXMMOperand(data);
2259 break;
2260 default:
2261 UnimplementedInstruction();
2262 }
2263 } else if (*data == 0x3A) {
2264 data++;
2265 if (*data >= 0x08 && *data <= 0x0B) {
2266 const char* const pseudo_op[] = {
2267 "roundps",
2268 "roundpd",
2269 "roundss",
2270 "roundsd",
2271 };
2272 uint8_t op = *data;
2273 data++;
2274 int mod, regop, rm;
2275 get_modrm(*data, &mod, &regop, &rm);
2276 int8_t imm8 = static_cast<int8_t>(data[1]);
2277 AppendToBuffer("%s %s,%s,%d", pseudo_op[op - 0x08],
2278 NameOfXMMRegister(regop), NameOfXMMRegister(rm),
2279 static_cast<int>(imm8));
2280 data += 2;
2281 } else if (*data == 0x0E) {
2282 data++;
2283 int mod, regop, rm;
2284 get_modrm(*data, &mod, &regop, &rm);
2285 AppendToBuffer("pblendw %s,", NameOfXMMRegister(regop));
2286 data += PrintRightXMMOperand(data);
2287 AppendToBuffer(",%d", Imm8_U(data));
2288 data++;
2289 } else if (*data == 0x0F) {
2290 data++;
2291 int mod, regop, rm;
2292 get_modrm(*data, &mod, &regop, &rm);
2293 AppendToBuffer("palignr %s,", NameOfXMMRegister(regop));
2294 data += PrintRightXMMOperand(data);
2295 AppendToBuffer(",%d", Imm8_U(data));
2296 data++;
2297 } else if (*data == 0x14) {
2298 data++;
2299 int mod, regop, rm;
2300 get_modrm(*data, &mod, &regop, &rm);
2301 AppendToBuffer("pextrb ");
2302 data += PrintRightOperand(data);
2303 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(data));
2304 data++;
2305 } else if (*data == 0x15) {
2306 data++;
2307 int mod, regop, rm;
2308 get_modrm(*data, &mod, &regop, &rm);
2309 AppendToBuffer("pextrw ");
2310 data += PrintRightOperand(data);
2311 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(data));
2312 data++;
2313 } else if (*data == 0x16) {
2314 data++;
2315 int mod, regop, rm;
2316 get_modrm(*data, &mod, &regop, &rm);
2317 AppendToBuffer("pextrd ");
2318 data += PrintRightOperand(data);
2319 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(data));
2320 data++;
2321 } else if (*data == 0x17) {
2322 data++;
2323 int mod, regop, rm;
2324 get_modrm(*data, &mod, &regop, &rm);
2325 int8_t imm8 = static_cast<int8_t>(data[1]);
2326 AppendToBuffer("extractps %s,%s,%d", NameOfCPURegister(rm),
2327 NameOfXMMRegister(regop), static_cast<int>(imm8));
2328 data += 2;
2329 } else if (*data == 0x20) {
2330 data++;
2331 int mod, regop, rm;
2332 get_modrm(*data, &mod, &regop, &rm);
2333 AppendToBuffer("pinsrb %s,", NameOfXMMRegister(regop));
2334 data += PrintRightOperand(data);
2335 AppendToBuffer(",%d", Imm8(data));
2336 data++;
2337 } else if (*data == 0x21) {
2338 data++;
2339 int mod, regop, rm;
2340 get_modrm(*data, &mod, &regop, &rm);
2341 AppendToBuffer("insertps %s,", NameOfXMMRegister(regop));
2342 data += PrintRightXMMOperand(data);
2343 AppendToBuffer(",%d", Imm8(data));
2344 data++;
2345 } else if (*data == 0x22) {
2346 data++;
2347 int mod, regop, rm;
2348 get_modrm(*data, &mod, &regop, &rm);
2349 AppendToBuffer("pinsrd %s,", NameOfXMMRegister(regop));
2350 data += PrintRightOperand(data);
2351 AppendToBuffer(",%d", Imm8(data));
2352 data++;
2353 } else {
2354 UnimplementedInstruction();
2355 }
2356 } else if (*data == 0x2E || *data == 0x2F) {
2357 const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
2358 data++;
2359 int mod, regop, rm;
2360 get_modrm(*data, &mod, &regop, &rm);
2361 if (mod == 0x3) {
2362 AppendToBuffer("%s %s,%s", mnem, NameOfXMMRegister(regop),
2363 NameOfXMMRegister(rm));
2364 data++;
2365 } else {
2366 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2367 data += PrintRightOperand(data);
2368 }
2369 } else if (*data == 0x50) {
2370 data++;
2371 int mod, regop, rm;
2372 get_modrm(*data, &mod, &regop, &rm);
2373 AppendToBuffer("movmskpd %s,%s", NameOfCPURegister(regop),
2374 NameOfXMMRegister(rm));
2375 data++;
2376 } else if (*data >= 0x54 && *data <= 0x5A) {
2377 const char* const pseudo_op[] = {"andpd", "andnpd", "orpd",
2378 "xorpd", "addpd", "mulpd",
2379 "cvtpd2ps"};
2380 uint8_t op = *data;
2381 data++;
2382 int mod, regop, rm;
2383 get_modrm(*data, &mod, &regop, &rm);
2384 AppendToBuffer("%s %s,", pseudo_op[op - 0x54],
2385 NameOfXMMRegister(regop));
2386 data += PrintRightXMMOperand(data);
2387 } else if (*data >= 0x5c && *data <= 0x5f) {
2388 const char* const pseudo_op[] = {
2389 "subpd",
2390 "minpd",
2391 "divpd",
2392 "maxpd",
2393 };
2394 uint8_t op = *data;
2395 data++;
2396 int mod, regop, rm;
2397 get_modrm(*data, &mod, &regop, &rm);
2398 AppendToBuffer("%s %s,", pseudo_op[op - 0x5c],
2399 NameOfXMMRegister(regop));
2400 data += PrintRightXMMOperand(data);
2401 } else if (*data == 0x6E) {
2402 data++;
2403 int mod, regop, rm;
2404 get_modrm(*data, &mod, &regop, &rm);
2405 AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
2406 data += PrintRightOperand(data);
2407 } else if (*data == 0x6F) {
2408 data++;
2409 int mod, regop, rm;
2410 get_modrm(*data, &mod, &regop, &rm);
2411 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
2412 data += PrintRightXMMOperand(data);
2413 } else if (*data == 0x70) {
2414 data++;
2415 int mod, regop, rm;
2416 get_modrm(*data, &mod, &regop, &rm);
2417 AppendToBuffer("pshufd %s,", NameOfXMMRegister(regop));
2418 data += PrintRightXMMOperand(data);
2419 AppendToBuffer(",%d", Imm8(data));
2420 data++;
2421 } else if (*data == 0x90) {
2422 data++;
2423 AppendToBuffer("nop"); // 2 byte nop.
2424 } else if (*data == 0x71) {
2425 data++;
2426 int mod, regop, rm;
2427 get_modrm(*data, &mod, &regop, &rm);
2428 int8_t imm8 = static_cast<int8_t>(data[1]);
2429 AppendToBuffer("ps%sw %s,%d", sf_str[regop / 2],
2430 NameOfXMMRegister(rm), static_cast<int>(imm8));
2431 data += 2;
2432 } else if (*data == 0x72) {
2433 data++;
2434 int mod, regop, rm;
2435 get_modrm(*data, &mod, &regop, &rm);
2436 int8_t imm8 = static_cast<int8_t>(data[1]);
2437 AppendToBuffer("ps%sd %s,%d", sf_str[regop / 2],
2438 NameOfXMMRegister(rm), static_cast<int>(imm8));
2439 data += 2;
2440 } else if (*data == 0x73) {
2441 data++;
2442 int mod, regop, rm;
2443 get_modrm(*data, &mod, &regop, &rm);
2444 int8_t imm8 = static_cast<int8_t>(data[1]);
2445 DCHECK(regop == esi || regop == edx);
2446 AppendToBuffer("ps%sq %s,%d", sf_str[regop / 2],
2447 NameOfXMMRegister(rm), static_cast<int>(imm8));
2448 data += 2;
2449 } else if (*data == 0x7F) {
2450 AppendToBuffer("movdqa ");
2451 data++;
2452 int mod, regop, rm;
2453 get_modrm(*data, &mod, &regop, &rm);
2454 data += PrintRightXMMOperand(data);
2455 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2456 } else if (*data == 0x7E) {
2457 data++;
2458 int mod, regop, rm;
2459 get_modrm(*data, &mod, &regop, &rm);
2460 AppendToBuffer("movd ");
2461 data += PrintRightOperand(data);
2462 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2463 } else if (*data == 0xC1) {
2464 data += 2;
2465 data += PrintOperands("xadd_w", OPER_REG_OP_ORDER, data);
2466 } else if (*data == 0xC2) {
2467 data++;
2468 int mod, regop, rm;
2469 get_modrm(*data, &mod, &regop, &rm);
2470 AppendToBuffer("cmppd %s, ", NameOfXMMRegister(regop));
2471 data += PrintRightXMMOperand(data);
2472 AppendToBuffer(", (%s)", cmp_pseudo_op[*data]);
2473 data++;
2474 } else if (*data == 0xC4) {
2475 data++;
2476 int mod, regop, rm;
2477 get_modrm(*data, &mod, &regop, &rm);
2478 AppendToBuffer("pinsrw %s,", NameOfXMMRegister(regop));
2479 data += PrintRightOperand(data);
2480 AppendToBuffer(",%d", Imm8(data));
2481 data++;
2482 } else if (*data == 0xC6) {
2483 // shufpd xmm, xmm/m128, imm8
2484 data++;
2485 int mod, regop, rm;
2486 get_modrm(*data, &mod, &regop, &rm);
2487 AppendToBuffer("shufpd %s,", NameOfXMMRegister(regop));
2488 data += PrintRightXMMOperand(data);
2489 AppendToBuffer(",%d", Imm8(data));
2490 data++;
2491 } else if (*data == 0xE6) {
2492 data++;
2493 int mod, regop, rm;
2494 get_modrm(*data, &mod, &regop, &rm);
2495 AppendToBuffer("cvttpd2dq %s,", NameOfXMMRegister(regop));
2496 data += PrintRightXMMOperand(data);
2497 } else if (*data == 0xE7) {
2498 data++;
2499 int mod, regop, rm;
2500 get_modrm(*data, &mod, &regop, &rm);
2501 if (mod == 3) {
2502 // movntdq
2503 UnimplementedInstruction();
2504 } else {
2505 UnimplementedInstruction();
2506 }
2507 } else if (*data == 0xB1) {
2508 data++;
2509 data += PrintOperands("cmpxchg_w", OPER_REG_OP_ORDER, data);
2510 } else if (*data == 0xD7) {
2511 data++;
2512 int mod, regop, rm;
2513 get_modrm(*data, &mod, &regop, &rm);
2514 AppendToBuffer("pmovmskb %s,%s", NameOfCPURegister(regop),
2515 NameOfXMMRegister(rm));
2516 data++;
2517 } else {
2518 uint8_t op = *data;
2519 data++;
2520 int mod, regop, rm;
2521 get_modrm(*data, &mod, &regop, &rm);
2522 switch (op) {
2523#define SSE2_DIS_CASE(instruction, notUsed1, notUsed2, opcode) \
2524 case 0x##opcode: { \
2525 AppendToBuffer(#instruction " %s,", NameOfXMMRegister(regop)); \
2526 data += PrintRightXMMOperand(data); \
2527 break; \
2528 }
2529
2530 SSE2_INSTRUCTION_LIST(SSE2_DIS_CASE)
2531#undef SSE2_DIS_CASE
2532 default:
2533 UnimplementedInstruction();
2534 }
2535 }
2536 } else {
2537 UnimplementedInstruction();
2538 }
2539 break;
2540
2541 case 0xFE: {
2542 data++;
2543 int mod, regop, rm;
2544 get_modrm(*data, &mod, &regop, &rm);
2545 if (regop == ecx) {
2546 AppendToBuffer("dec_b ");
2547 data += PrintRightOperand(data);
2548 } else {
2549 UnimplementedInstruction();
2550 }
2551 } break;
2552
2553 case 0x68:
2554 AppendToBuffer("push 0x%x", Imm32(data + 1));
2555 data += 5;
2556 break;
2557
2558 case 0x6A:
2559 AppendToBuffer("push 0x%x", Imm8(data + 1));
2560 data += 2;
2561 break;
2562
2563 case 0xA8:
2564 AppendToBuffer("test al,0x%x", Imm8_U(data + 1));
2565 data += 2;
2566 break;
2567
2568 case 0xA9:
2569 AppendToBuffer("test eax,0x%x", Imm32(data + 1));
2570 data += 5;
2571 break;
2572
2573 case 0xD1: // fall through
2574 case 0xD3: // fall through
2575 case 0xC1:
2576 data += D1D3C1Instruction(data);
2577 break;
2578
2579 case 0xD8: // fall through
2580 case 0xD9: // fall through
2581 case 0xDA: // fall through
2582 case 0xDB: // fall through
2583 case 0xDC: // fall through
2584 case 0xDD: // fall through
2585 case 0xDE: // fall through
2586 case 0xDF:
2587 data += FPUInstruction(data);
2588 break;
2589
2590 case 0xEB:
2591 data += JumpShort(data);
2592 break;
2593
2594 case 0xF2:
2595 if (*(data + 1) == 0x0F) {
2596 uint8_t b2 = *(data + 2);
2597 if (b2 == 0x11) {
2598 AppendToBuffer("movsd ");
2599 data += 3;
2600 int mod, regop, rm;
2601 get_modrm(*data, &mod, &regop, &rm);
2602 data += PrintRightXMMOperand(data);
2603 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2604 } else if (b2 == 0x10) {
2605 data += 3;
2606 int mod, regop, rm;
2607 get_modrm(*data, &mod, &regop, &rm);
2608 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
2609 data += PrintRightXMMOperand(data);
2610 } else if (b2 == 0x12) {
2611 data += 3;
2612 int mod, regop, rm;
2613 get_modrm(*data, &mod, &regop, &rm);
2614 AppendToBuffer("movddup %s,", NameOfXMMRegister(regop));
2615 data += PrintRightXMMOperand(data);
2616 } else if (b2 == 0x5A) {
2617 data += 3;
2618 int mod, regop, rm;
2619 get_modrm(*data, &mod, &regop, &rm);
2620 AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
2621 data += PrintRightXMMOperand(data);
2622 } else if (b2 == 0x70) {
2623 data += 3;
2624 int mod, regop, rm;
2625 get_modrm(*data, &mod, &regop, &rm);
2626 AppendToBuffer("pshuflw %s,", NameOfXMMRegister(regop));
2627 data += PrintRightXMMOperand(data);
2628 AppendToBuffer(",%d", Imm8(data));
2629 data++;
2630 } else {
2631 const char* mnem = "?";
2632 switch (b2) {
2633 case 0x2A:
2634 mnem = "cvtsi2sd";
2635 break;
2636 case 0x2C:
2637 mnem = "cvttsd2si";
2638 break;
2639 case 0x2D:
2640 mnem = "cvtsd2si";
2641 break;
2642 case 0x7C:
2643 mnem = "haddps";
2644 break;
2645#define MNEM_FOR_SSE2_INSTRUCTION_LSIT_SD(instruction, _1, _2, opcode) \
2646 case 0x##opcode: \
2647 mnem = "" #instruction; \
2648 break;
2649 SSE2_INSTRUCTION_LIST_SD(MNEM_FOR_SSE2_INSTRUCTION_LSIT_SD)
2650#undef MNEM_FOR_SSE2_INSTRUCTION_LSIT_SD
2651 }
2652 data += 3;
2653 int mod, regop, rm;
2654 get_modrm(*data, &mod, &regop, &rm);
2655 if (b2 == 0x2A) {
2656 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2657 data += PrintRightOperand(data);
2658 } else if (b2 == 0x2C || b2 == 0x2D) {
2659 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
2660 data += PrintRightXMMOperand(data);
2661 } else if (b2 == 0xC2) {
2662 // Intel manual 2A, Table 3-18.
2663 AppendToBuffer("cmp%ssd %s,%s", cmp_pseudo_op[data[1]],
2664 NameOfXMMRegister(regop), NameOfXMMRegister(rm));
2665 data += 2;
2666 } else {
2667 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2668 data += PrintRightXMMOperand(data);
2669 }
2670 }
2671 } else {
2672 UnimplementedInstruction();
2673 data++;
2674 }
2675 break;
2676
2677 case 0xF3:
2678 if (*(data + 1) == 0x0F) {
2679 uint8_t b2 = *(data + 2);
2680 if (b2 == 0x11) {
2681 AppendToBuffer("movss ");
2682 data += 3;
2683 int mod, regop, rm;
2684 get_modrm(*data, &mod, &regop, &rm);
2685 data += PrintRightXMMOperand(data);
2686 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2687 } else if (b2 == 0x10) {
2688 data += 3;
2689 int mod, regop, rm;
2690 get_modrm(*data, &mod, &regop, &rm);
2691 AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
2692 data += PrintRightXMMOperand(data);
2693 } else if (b2 == 0x16) {
2694 data += 3;
2695 int mod, regop, rm;
2696 get_modrm(*data, &mod, &regop, &rm);
2697 AppendToBuffer("movshdup %s,", NameOfXMMRegister(regop));
2698 data += PrintRightXMMOperand(data);
2699 } else if (b2 == 0x5A) {
2700 data += 3;
2701 int mod, regop, rm;
2702 get_modrm(*data, &mod, &regop, &rm);
2703 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
2704 data += PrintRightXMMOperand(data);
2705 } else if (b2 == 0x6F) {
2706 data += 3;
2707 int mod, regop, rm;
2708 get_modrm(*data, &mod, &regop, &rm);
2709 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
2710 data += PrintRightXMMOperand(data);
2711 } else if (b2 == 0x70) {
2712 data += 3;
2713 int mod, regop, rm;
2714 get_modrm(*data, &mod, &regop, &rm);
2715 AppendToBuffer("pshufhw %s,", NameOfXMMRegister(regop));
2716 data += PrintRightXMMOperand(data);
2717 AppendToBuffer(",%d", Imm8(data));
2718 data++;
2719 } else if (b2 == 0x7F) {
2720 AppendToBuffer("movdqu ");
2721 data += 3;
2722 int mod, regop, rm;
2723 get_modrm(*data, &mod, &regop, &rm);
2724 data += PrintRightXMMOperand(data);
2725 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2726 } else if (b2 == 0xB8) {
2727 data += 3;
2728 int mod, regop, rm;
2729 get_modrm(*data, &mod, &regop, &rm);
2730 AppendToBuffer("popcnt %s,", NameOfCPURegister(regop));
2731 data += PrintRightOperand(data);
2732 } else if (b2 == 0xBC) {
2733 data += 3;
2734 int mod, regop, rm;
2735 get_modrm(*data, &mod, &regop, &rm);
2736 AppendToBuffer("tzcnt %s,", NameOfCPURegister(regop));
2737 data += PrintRightOperand(data);
2738 } else if (b2 == 0xBD) {
2739 data += 3;
2740 int mod, regop, rm;
2741 get_modrm(*data, &mod, &regop, &rm);
2742 AppendToBuffer("lzcnt %s,", NameOfCPURegister(regop));
2743 data += PrintRightOperand(data);
2744 } else if (b2 == 0xE6) {
2745 data += 3;
2746 int mod, regop, rm;
2747 get_modrm(*data, &mod, &regop, &rm);
2748 AppendToBuffer("cvtdq2pd %s", NameOfXMMRegister(regop));
2749 data += PrintRightXMMOperand(data);
2750 } else {
2751 const char* mnem = "?";
2752 switch (b2) {
2753 case 0x2A:
2754 mnem = "cvtsi2ss";
2755 break;
2756 case 0x2C:
2757 mnem = "cvttss2si";
2758 break;
2759 case 0x2D:
2760 mnem = "cvtss2si";
2761 break;
2762 case 0x51:
2763 mnem = "sqrtss";
2764 break;
2765 case 0x58:
2766 mnem = "addss";
2767 break;
2768 case 0x59:
2769 mnem = "mulss";
2770 break;
2771 case 0x5B:
2772 mnem = "cvttps2dq";
2773 break;
2774 case 0x5C:
2775 mnem = "subss";
2776 break;
2777 case 0x5D:
2778 mnem = "minss";
2779 break;
2780 case 0x5E:
2781 mnem = "divss";
2782 break;
2783 case 0x5F:
2784 mnem = "maxss";
2785 break;
2786 case 0x7E:
2787 mnem = "movq";
2788 break;
2789 }
2790 data += 3;
2791 int mod, regop, rm;
2792 get_modrm(*data, &mod, &regop, &rm);
2793 if (b2 == 0x2A) {
2794 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2795 data += PrintRightOperand(data);
2796 } else if (b2 == 0x2C || b2 == 0x2D) {
2797 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
2798 data += PrintRightXMMOperand(data);
2799 } else if (b2 == 0xC2) {
2800 // Intel manual 2A, Table 3-18.
2801 AppendToBuffer("cmp%sss %s,%s", cmp_pseudo_op[data[1]],
2802 NameOfXMMRegister(regop), NameOfXMMRegister(rm));
2803 data += 2;
2804 } else {
2805 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2806 data += PrintRightXMMOperand(data);
2807 }
2808 }
2809 } else if (*(data + 1) == 0xA5) {
2810 data += 2;
2811 AppendToBuffer("rep_movs");
2812 } else if (*(data + 1) == 0xAB) {
2813 data += 2;
2814 AppendToBuffer("rep_stos");
2815 } else if (*(data + 1) == 0x90) {
2816 data += 2;
2817 AppendToBuffer("pause");
2818 } else {
2819 UnimplementedInstruction();
2820 }
2821 break;
2822
2823 case 0xF7:
2824 data += F7Instruction(data);
2825 break;
2826
2827 default:
2828 UnimplementedInstruction();
2829 data++;
2830 }
2831 }
2832
2833 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
2834 tmp_buffer_[tmp_buffer_pos_] = '\0';
2835 }
2836
2837 int instr_len = data - instr;
2838 if (instr_len == 0) {
2839 printf("%02x", *data);
2840 }
2841 DCHECK_GT(instr_len, 0); // Ensure progress.
2842
2843 int outp = 0;
2844 // Instruction bytes.
2845 for (uint8_t* bp = instr; bp < data; bp++) {
2846 outp += v8::base::SNPrintF(out_buffer + outp, "%02x", *bp);
2847 }
2848 // Indent instruction, leaving space for 6 bytes, i.e. 12 characters in hex.
2849 while (outp < 12) {
2850 outp += v8::base::SNPrintF(out_buffer + outp, " ");
2851 }
2852
2853 outp += v8::base::SNPrintF(out_buffer + outp, " %s", tmp_buffer_.begin());
2854 return instr_len;
2855}
2856
2857//------------------------------------------------------------------------------
2858
2859static const char* const cpu_regs[8] = {"eax", "ecx", "edx", "ebx",
2860 "esp", "ebp", "esi", "edi"};
2861
2862static const char* const byte_cpu_regs[8] = {"al", "cl", "dl", "bl",
2863 "ah", "ch", "dh", "bh"};
2864
2865static const char* const xmm_regs[8] = {"xmm0", "xmm1", "xmm2", "xmm3",
2866 "xmm4", "xmm5", "xmm6", "xmm7"};
2867
2868const char* NameConverter::NameOfAddress(uint8_t* addr) const {
2869 v8::base::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr));
2870 return tmp_buffer_.begin();
2871}
2872
2873const char* NameConverter::NameOfConstant(uint8_t* addr) const {
2874 return NameOfAddress(addr);
2875}
2876
2877const char* NameConverter::NameOfCPURegister(int reg) const {
2878 if (0 <= reg && reg < 8) return cpu_regs[reg];
2879 return "noreg";
2880}
2881
2882const char* NameConverter::NameOfByteCPURegister(int reg) const {
2883 if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
2884 return "noreg";
2885}
2886
2887const char* NameConverter::NameOfXMMRegister(int reg) const {
2888 if (0 <= reg && reg < 8) return xmm_regs[reg];
2889 return "noxmmreg";
2890}
2891
2892const char* NameConverter::NameInCode(uint8_t* addr) const {
2893 // IA32 does not embed debug strings at the moment.
2894 UNREACHABLE();
2895}
2896
2897//------------------------------------------------------------------------------
2898
2900 uint8_t* instruction) {
2901 DisassemblerIA32 d(converter_, unimplemented_opcode_action());
2902 return d.InstructionDecode(buffer, instruction);
2903}
2904
2905// The IA-32 assembler does not currently use constant pools.
2906int Disassembler::ConstantPoolSizeAt(uint8_t* instruction) { return -1; }
2907
2908// static
2909void Disassembler::Disassemble(FILE* f, uint8_t* begin, uint8_t* end,
2910 UnimplementedOpcodeAction unimplemented_action) {
2911 NameConverter converter;
2912 Disassembler d(converter, unimplemented_action);
2913 for (uint8_t* pc = begin; pc < end;) {
2915 buffer[0] = '\0';
2916 uint8_t* prev_pc = pc;
2917 pc += d.InstructionDecode(buffer, pc);
2918 fprintf(f, "%p", static_cast<void*>(prev_pc));
2919 fprintf(f, " ");
2920
2921 for (uint8_t* bp = prev_pc; bp < pc; bp++) {
2922 fprintf(f, "%02x", *bp);
2923 }
2924 for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
2925 fprintf(f, " ");
2926 }
2927 fprintf(f, " %s\n", buffer.begin());
2928 }
2929}
2930
2931} // namespace disasm
2932
2933#endif // V8_TARGET_ARCH_IA32
interpreter::OperandScale scale
Definition builtins.cc:44
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
static V8_EXPORT_PRIVATE void Disassemble(FILE *f, uint8_t *begin, uint8_t *end, UnimplementedOpcodeAction unimplemented_action=kAbortOnUnimplementedOpcode)
V8_EXPORT_PRIVATE int InstructionDecode(v8::base::Vector< char > buffer, uint8_t *instruction)
int ConstantPoolSizeAt(uint8_t *instruction)
Disassembler(const NameConverter &converter, UnimplementedOpcodeAction unimplemented_opcode_action=kAbortOnUnimplementedOpcode)
Definition disasm.h:44
UnimplementedOpcodeAction unimplemented_opcode_action() const
Definition disasm.h:50
const NameConverter & converter_
Definition disasm.h:71
virtual const char * NameOfAddress(uint8_t *addr) const
virtual const char * NameOfXMMRegister(int reg) const
virtual const char * NameInCode(uint8_t *addr) const
virtual const char * NameOfConstant(uint8_t *addr) const
v8::base::EmbeddedVector< char, 128 > tmp_buffer_
Definition disasm.h:32
virtual const char * NameOfByteCPURegister(int reg) const
virtual const char * NameOfCPURegister(int reg) const
constexpr T * begin() const
Definition vector.h:96
int start
uint32_t count
int end
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
#define FMA_SD_INSTRUCTION_LIST(V)
Definition fma-instr.h:8
#define FMA_PD_INSTRUCTION_LIST(V)
Definition fma-instr.h:44
#define FMA_SS_INSTRUCTION_LIST(V)
Definition fma-instr.h:22
#define FMA_PS_INSTRUCTION_LIST(V)
Definition fma-instr.h:36
#define SSSE3_UNOP_INSTRUCTION_LIST(V)
Definition sse-instr.h:96
#define SSE4_INSTRUCTION_LIST(V)
Definition sse-instr.h:101
#define SSE4_RM_INSTRUCTION_LIST(V)
Definition sse-instr.h:115
#define SSE2_INSTRUCTION_LIST(V)
Definition sse-instr.h:16
#define SSE2_INSTRUCTION_LIST_SD(V)
Definition sse-instr.h:75
#define SSSE3_INSTRUCTION_LIST(V)
Definition sse-instr.h:85
#define AVX2_BROADCAST_LIST(V)
Definition sse-instr.h:126
OptionalOpIndex index
Instruction * instr
ZoneVector< RpoNumber > & result
LiftoffRegister reg
int x
int int32_t
Definition unicode.cc:40
unsigned short uint16_t
Definition unicode.cc:39
signed short int16_t
Definition unicode.cc:38
int SNPrintF(Vector< char > str, const char *format,...)
Definition strings.cc:20
int VSNPrintF(Vector< char > str, const char *format, va_list args)
Definition strings.cc:16
V8_INLINE const Operation & Get(const Graph &graph, OpIndex index)
Definition graph.h:1231
constexpr SBit SetCC
#define PRINTF_FORMAT(format_param, dots_param)
#define UNREACHABLE()
Definition logging.h:67
#define FATAL(...)
Definition logging.h:47
#define UNIMPLEMENTED()
Definition logging.h:66
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
wasm::ValueType type