OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <assert.h> | 5 #include <assert.h> |
6 #include <stdarg.h> | 6 #include <stdarg.h> |
7 #include <stdio.h> | 7 #include <stdio.h> |
8 | 8 |
9 #include "src/v8.h" | 9 #include "src/v8.h" |
10 | 10 |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
141 MOVE_REG_INSTR, | 141 MOVE_REG_INSTR, |
142 CALL_JUMP_INSTR, | 142 CALL_JUMP_INSTR, |
143 SHORT_IMMEDIATE_INSTR | 143 SHORT_IMMEDIATE_INSTR |
144 }; | 144 }; |
145 | 145 |
146 | 146 |
147 enum Prefixes { | 147 enum Prefixes { |
148 ESCAPE_PREFIX = 0x0F, | 148 ESCAPE_PREFIX = 0x0F, |
149 OPERAND_SIZE_OVERRIDE_PREFIX = 0x66, | 149 OPERAND_SIZE_OVERRIDE_PREFIX = 0x66, |
150 ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67, | 150 ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67, |
| 151 VEX3_PREFIX = 0xC4, |
| 152 VEX2_PREFIX = 0xC5, |
151 REPNE_PREFIX = 0xF2, | 153 REPNE_PREFIX = 0xF2, |
152 REP_PREFIX = 0xF3, | 154 REP_PREFIX = 0xF3, |
153 REPEQ_PREFIX = REP_PREFIX | 155 REPEQ_PREFIX = REP_PREFIX |
154 }; | 156 }; |
155 | 157 |
156 | 158 |
157 struct InstructionDesc { | 159 struct InstructionDesc { |
158 const char* mnem; | 160 const char* mnem; |
159 InstructionType type; | 161 InstructionType type; |
160 OperandType op_order_; | 162 OperandType op_order_; |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
283 | 285 |
284 // A new DisassemblerX64 object is created to disassemble each instruction. | 286 // A new DisassemblerX64 object is created to disassemble each instruction. |
285 // The object can only disassemble a single instruction. | 287 // The object can only disassemble a single instruction. |
286 class DisassemblerX64 { | 288 class DisassemblerX64 { |
287 public: | 289 public: |
288 DisassemblerX64(const NameConverter& converter, | 290 DisassemblerX64(const NameConverter& converter, |
289 UnimplementedOpcodeAction unimplemented_action = | 291 UnimplementedOpcodeAction unimplemented_action = |
290 ABORT_ON_UNIMPLEMENTED_OPCODE) | 292 ABORT_ON_UNIMPLEMENTED_OPCODE) |
291 : converter_(converter), | 293 : converter_(converter), |
292 tmp_buffer_pos_(0), | 294 tmp_buffer_pos_(0), |
293 abort_on_unimplemented_( | 295 abort_on_unimplemented_(unimplemented_action == |
294 unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE), | 296 ABORT_ON_UNIMPLEMENTED_OPCODE), |
295 rex_(0), | 297 rex_(0), |
296 operand_size_(0), | 298 operand_size_(0), |
297 group_1_prefix_(0), | 299 group_1_prefix_(0), |
| 300 vex_byte0_(0), |
| 301 vex_byte1_(0), |
| 302 vex_byte2_(0), |
298 byte_size_operand_(false), | 303 byte_size_operand_(false), |
299 instruction_table_(instruction_table.Pointer()) { | 304 instruction_table_(instruction_table.Pointer()) { |
300 tmp_buffer_[0] = '\0'; | 305 tmp_buffer_[0] = '\0'; |
301 } | 306 } |
302 | 307 |
303 virtual ~DisassemblerX64() { | 308 virtual ~DisassemblerX64() { |
304 } | 309 } |
305 | 310 |
306 // Writes one disassembled instruction into 'buffer' (0-terminated). | 311 // Writes one disassembled instruction into 'buffer' (0-terminated). |
307 // Returns the length of the disassembled machine instruction in bytes. | 312 // Returns the length of the disassembled machine instruction in bytes. |
308 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction); | 313 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction); |
309 | 314 |
310 private: | 315 private: |
311 enum OperandSize { | 316 enum OperandSize { |
312 OPERAND_BYTE_SIZE = 0, | 317 OPERAND_BYTE_SIZE = 0, |
313 OPERAND_WORD_SIZE = 1, | 318 OPERAND_WORD_SIZE = 1, |
314 OPERAND_DOUBLEWORD_SIZE = 2, | 319 OPERAND_DOUBLEWORD_SIZE = 2, |
315 OPERAND_QUADWORD_SIZE = 3 | 320 OPERAND_QUADWORD_SIZE = 3 |
316 }; | 321 }; |
317 | 322 |
318 const NameConverter& converter_; | 323 const NameConverter& converter_; |
319 v8::internal::EmbeddedVector<char, 128> tmp_buffer_; | 324 v8::internal::EmbeddedVector<char, 128> tmp_buffer_; |
320 unsigned int tmp_buffer_pos_; | 325 unsigned int tmp_buffer_pos_; |
321 bool abort_on_unimplemented_; | 326 bool abort_on_unimplemented_; |
322 // Prefixes parsed | 327 // Prefixes parsed |
323 byte rex_; | 328 byte rex_; |
324 byte operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0. | 329 byte operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0. |
325 byte group_1_prefix_; // 0xF2, 0xF3, or (if no group 1 prefix is present) 0. | 330 byte group_1_prefix_; // 0xF2, 0xF3, or (if no group 1 prefix is present) 0. |
| 331 byte vex_byte0_; // 0xc4 or 0xc5 |
| 332 byte vex_byte1_; |
| 333 byte vex_byte2_; // only for 3 bytes vex prefix |
326 // Byte size operand override. | 334 // Byte size operand override. |
327 bool byte_size_operand_; | 335 bool byte_size_operand_; |
328 const InstructionTable* const instruction_table_; | 336 const InstructionTable* const instruction_table_; |
329 | 337 |
330 void setRex(byte rex) { | 338 void setRex(byte rex) { |
331 DCHECK_EQ(0x40, rex & 0xF0); | 339 DCHECK_EQ(0x40, rex & 0xF0); |
332 rex_ = rex; | 340 rex_ = rex; |
333 } | 341 } |
334 | 342 |
335 bool rex() { return rex_ != 0; } | 343 bool rex() { return rex_ != 0; } |
336 | 344 |
337 bool rex_b() { return (rex_ & 0x01) != 0; } | 345 bool rex_b() { return (rex_ & 0x01) != 0; } |
338 | 346 |
339 // Actual number of base register given the low bits and the rex.b state. | 347 // Actual number of base register given the low bits and the rex.b state. |
340 int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); } | 348 int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); } |
341 | 349 |
342 bool rex_x() { return (rex_ & 0x02) != 0; } | 350 bool rex_x() { return (rex_ & 0x02) != 0; } |
343 | 351 |
344 bool rex_r() { return (rex_ & 0x04) != 0; } | 352 bool rex_r() { return (rex_ & 0x04) != 0; } |
345 | 353 |
346 bool rex_w() { return (rex_ & 0x08) != 0; } | 354 bool rex_w() { return (rex_ & 0x08) != 0; } |
347 | 355 |
| 356 bool vex_128() { |
| 357 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX); |
| 358 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_; |
| 359 return (checked & 4) != 1; |
| 360 } |
| 361 |
| 362 bool vex_66() { |
| 363 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX); |
| 364 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_; |
| 365 return (checked & 3) == 1; |
| 366 } |
| 367 |
| 368 bool vex_f3() { |
| 369 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX); |
| 370 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_; |
| 371 return (checked & 3) == 2; |
| 372 } |
| 373 |
| 374 bool vex_f2() { |
| 375 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX); |
| 376 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_; |
| 377 return (checked & 3) == 3; |
| 378 } |
| 379 |
| 380 bool vex_0f() { |
| 381 if (vex_byte0_ == VEX2_PREFIX) return true; |
| 382 return (vex_byte1_ & 3) == 1; |
| 383 } |
| 384 |
| 385 bool vex_0f38() { |
| 386 DCHECK(vex_byte0_ == VEX3_PREFIX); |
| 387 return (vex_byte1_ & 3) == 2; |
| 388 } |
| 389 |
| 390 bool vex_0f3a() { |
| 391 DCHECK(vex_byte0_ == VEX3_PREFIX); |
| 392 return (vex_byte1_ & 3) == 3; |
| 393 } |
| 394 |
| 395 int vex_vreg() { |
| 396 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX); |
| 397 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_; |
| 398 return ~(checked >> 3) & 0xf; |
| 399 } |
| 400 |
348 OperandSize operand_size() { | 401 OperandSize operand_size() { |
349 if (byte_size_operand_) return OPERAND_BYTE_SIZE; | 402 if (byte_size_operand_) return OPERAND_BYTE_SIZE; |
350 if (rex_w()) return OPERAND_QUADWORD_SIZE; | 403 if (rex_w()) return OPERAND_QUADWORD_SIZE; |
351 if (operand_size_ != 0) return OPERAND_WORD_SIZE; | 404 if (operand_size_ != 0) return OPERAND_WORD_SIZE; |
352 return OPERAND_DOUBLEWORD_SIZE; | 405 return OPERAND_DOUBLEWORD_SIZE; |
353 } | 406 } |
354 | 407 |
355 char operand_size_code() { | 408 char operand_size_code() { |
356 return "bwlq"[operand_size()]; | 409 return "bwlq"[operand_size()]; |
357 } | 410 } |
358 | 411 |
| 412 char float_size_code() { return "sd"[rex_w()]; } |
| 413 |
359 const char* NameOfCPURegister(int reg) const { | 414 const char* NameOfCPURegister(int reg) const { |
360 return converter_.NameOfCPURegister(reg); | 415 return converter_.NameOfCPURegister(reg); |
361 } | 416 } |
362 | 417 |
363 const char* NameOfByteCPURegister(int reg) const { | 418 const char* NameOfByteCPURegister(int reg) const { |
364 return converter_.NameOfByteCPURegister(reg); | 419 return converter_.NameOfByteCPURegister(reg); |
365 } | 420 } |
366 | 421 |
367 const char* NameOfXMMRegister(int reg) const { | 422 const char* NameOfXMMRegister(int reg) const { |
368 return converter_.NameOfXMMRegister(reg); | 423 return converter_.NameOfXMMRegister(reg); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
407 int TwoByteOpcodeInstruction(byte* data); | 462 int TwoByteOpcodeInstruction(byte* data); |
408 int F6F7Instruction(byte* data); | 463 int F6F7Instruction(byte* data); |
409 int ShiftInstruction(byte* data); | 464 int ShiftInstruction(byte* data); |
410 int JumpShort(byte* data); | 465 int JumpShort(byte* data); |
411 int JumpConditional(byte* data); | 466 int JumpConditional(byte* data); |
412 int JumpConditionalShort(byte* data); | 467 int JumpConditionalShort(byte* data); |
413 int SetCC(byte* data); | 468 int SetCC(byte* data); |
414 int FPUInstruction(byte* data); | 469 int FPUInstruction(byte* data); |
415 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start); | 470 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start); |
416 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte); | 471 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte); |
| 472 int AVXInstruction(byte* data); |
417 void AppendToBuffer(const char* format, ...); | 473 void AppendToBuffer(const char* format, ...); |
418 | 474 |
419 void UnimplementedInstruction() { | 475 void UnimplementedInstruction() { |
420 if (abort_on_unimplemented_) { | 476 if (abort_on_unimplemented_) { |
421 CHECK(false); | 477 CHECK(false); |
422 } else { | 478 } else { |
423 AppendToBuffer("'Unimplemented Instruction'"); | 479 AppendToBuffer("'Unimplemented Instruction'"); |
424 } | 480 } |
425 } | 481 } |
426 }; | 482 }; |
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
804 int DisassemblerX64::SetCC(byte* data) { | 860 int DisassemblerX64::SetCC(byte* data) { |
805 DCHECK_EQ(0x0F, *data); | 861 DCHECK_EQ(0x0F, *data); |
806 byte cond = *(data + 1) & 0x0F; | 862 byte cond = *(data + 1) & 0x0F; |
807 const char* mnem = conditional_code_suffix[cond]; | 863 const char* mnem = conditional_code_suffix[cond]; |
808 AppendToBuffer("set%s%c ", mnem, operand_size_code()); | 864 AppendToBuffer("set%s%c ", mnem, operand_size_code()); |
809 PrintRightByteOperand(data + 2); | 865 PrintRightByteOperand(data + 2); |
810 return 3; // includes 0x0F | 866 return 3; // includes 0x0F |
811 } | 867 } |
812 | 868 |
813 | 869 |
| 870 int DisassemblerX64::AVXInstruction(byte* data) { |
| 871 byte opcode = *data; |
| 872 byte* current = data + 1; |
| 873 if (vex_byte0_ == VEX3_PREFIX) { |
| 874 if (vex_128()) { |
| 875 if (vex_66() && vex_0f38()) { |
| 876 int mod, regop, rm, vvvv = vex_vreg(); |
| 877 get_modrm(*current, &mod, ®op, &rm); |
| 878 switch (opcode) { |
| 879 case 0x99: |
| 880 AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(), |
| 881 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); |
| 882 current += PrintRightXMMOperand(current); |
| 883 break; |
| 884 case 0xa9: |
| 885 AppendToBuffer("vfmadd213s%c %s,%s,", float_size_code(), |
| 886 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); |
| 887 current += PrintRightXMMOperand(current); |
| 888 break; |
| 889 case 0xb9: |
| 890 AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(), |
| 891 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); |
| 892 current += PrintRightXMMOperand(current); |
| 893 break; |
| 894 case 0x9b: |
| 895 AppendToBuffer("vfmsub132s%c %s,%s,", float_size_code(), |
| 896 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); |
| 897 current += PrintRightXMMOperand(current); |
| 898 break; |
| 899 case 0xab: |
| 900 AppendToBuffer("vfmsub213s%c %s,%s,", float_size_code(), |
| 901 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); |
| 902 current += PrintRightXMMOperand(current); |
| 903 break; |
| 904 case 0xbb: |
| 905 AppendToBuffer("vfmsub231s%c %s,%s,", float_size_code(), |
| 906 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); |
| 907 current += PrintRightXMMOperand(current); |
| 908 break; |
| 909 case 0x9d: |
| 910 AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(), |
| 911 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); |
| 912 current += PrintRightXMMOperand(current); |
| 913 break; |
| 914 case 0xad: |
| 915 AppendToBuffer("vfnmadd213s%c %s,%s,", float_size_code(), |
| 916 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); |
| 917 current += PrintRightXMMOperand(current); |
| 918 break; |
| 919 case 0xbd: |
| 920 AppendToBuffer("vfnmadd231s%c %s,%s,", float_size_code(), |
| 921 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); |
| 922 current += PrintRightXMMOperand(current); |
| 923 break; |
| 924 case 0x9f: |
| 925 AppendToBuffer("vfnmsub132s%c %s,%s,", float_size_code(), |
| 926 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); |
| 927 current += PrintRightXMMOperand(current); |
| 928 break; |
| 929 case 0xaf: |
| 930 AppendToBuffer("vfnmsub213s%c %s,%s,", float_size_code(), |
| 931 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); |
| 932 current += PrintRightXMMOperand(current); |
| 933 break; |
| 934 case 0xbf: |
| 935 AppendToBuffer("vfnmsub231s%c %s,%s,", float_size_code(), |
| 936 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); |
| 937 current += PrintRightXMMOperand(current); |
| 938 break; |
| 939 default: |
| 940 UnimplementedInstruction(); |
| 941 } |
| 942 } |
| 943 } else { |
| 944 UnimplementedInstruction(); |
| 945 } |
| 946 } else if (vex_byte0_ == VEX2_PREFIX) { |
| 947 UnimplementedInstruction(); |
| 948 } else { |
| 949 UNREACHABLE(); |
| 950 } |
| 951 |
| 952 return static_cast<int>(current - data); |
| 953 } |
| 954 |
| 955 |
814 // Returns number of bytes used, including *data. | 956 // Returns number of bytes used, including *data. |
815 int DisassemblerX64::FPUInstruction(byte* data) { | 957 int DisassemblerX64::FPUInstruction(byte* data) { |
816 byte escape_opcode = *data; | 958 byte escape_opcode = *data; |
817 DCHECK_EQ(0xD8, escape_opcode & 0xF8); | 959 DCHECK_EQ(0xD8, escape_opcode & 0xF8); |
818 byte modrm_byte = *(data+1); | 960 byte modrm_byte = *(data+1); |
819 | 961 |
820 if (modrm_byte >= 0xC0) { | 962 if (modrm_byte >= 0xC0) { |
821 return RegisterFPUInstruction(escape_opcode, modrm_byte); | 963 return RegisterFPUInstruction(escape_opcode, modrm_byte); |
822 } else { | 964 } else { |
823 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1); | 965 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1); |
(...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1182 AppendToBuffer("%ss %s,", mnemonic, NameOfXMMRegister(regop)); | 1324 AppendToBuffer("%ss %s,", mnemonic, NameOfXMMRegister(regop)); |
1183 current += PrintRightOperand(current); | 1325 current += PrintRightOperand(current); |
1184 } else if (opcode == 0x2C) { | 1326 } else if (opcode == 0x2C) { |
1185 // CVTTSS2SI: | 1327 // CVTTSS2SI: |
1186 // Convert with truncation scalar single-precision FP to dword integer. | 1328 // Convert with truncation scalar single-precision FP to dword integer. |
1187 int mod, regop, rm; | 1329 int mod, regop, rm; |
1188 get_modrm(*current, &mod, ®op, &rm); | 1330 get_modrm(*current, &mod, ®op, &rm); |
1189 AppendToBuffer("cvttss2si%c %s,", | 1331 AppendToBuffer("cvttss2si%c %s,", |
1190 operand_size_code(), NameOfCPURegister(regop)); | 1332 operand_size_code(), NameOfCPURegister(regop)); |
1191 current += PrintRightXMMOperand(current); | 1333 current += PrintRightXMMOperand(current); |
| 1334 } else if (opcode == 0x58) { |
| 1335 int mod, regop, rm; |
| 1336 get_modrm(*current, &mod, ®op, &rm); |
| 1337 AppendToBuffer("addss %s,", NameOfXMMRegister(regop)); |
| 1338 current += PrintRightXMMOperand(current); |
| 1339 } else if (opcode == 0x59) { |
| 1340 int mod, regop, rm; |
| 1341 get_modrm(*current, &mod, ®op, &rm); |
| 1342 AppendToBuffer("mulss %s,", NameOfXMMRegister(regop)); |
| 1343 current += PrintRightXMMOperand(current); |
1192 } else if (opcode == 0x5A) { | 1344 } else if (opcode == 0x5A) { |
1193 // CVTSS2SD: | 1345 // CVTSS2SD: |
1194 // Convert scalar single-precision FP to scalar double-precision FP. | 1346 // Convert scalar single-precision FP to scalar double-precision FP. |
1195 int mod, regop, rm; | 1347 int mod, regop, rm; |
1196 get_modrm(*current, &mod, ®op, &rm); | 1348 get_modrm(*current, &mod, ®op, &rm); |
1197 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop)); | 1349 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop)); |
1198 current += PrintRightXMMOperand(current); | 1350 current += PrintRightXMMOperand(current); |
| 1351 } else if (opcode == 0x5c) { |
| 1352 int mod, regop, rm; |
| 1353 get_modrm(*current, &mod, ®op, &rm); |
| 1354 AppendToBuffer("subss %s,", NameOfXMMRegister(regop)); |
| 1355 current += PrintRightXMMOperand(current); |
| 1356 } else if (opcode == 0x5e) { |
| 1357 int mod, regop, rm; |
| 1358 get_modrm(*current, &mod, ®op, &rm); |
| 1359 AppendToBuffer("divss %s,", NameOfXMMRegister(regop)); |
| 1360 current += PrintRightXMMOperand(current); |
1199 } else if (opcode == 0x7E) { | 1361 } else if (opcode == 0x7E) { |
1200 int mod, regop, rm; | 1362 int mod, regop, rm; |
1201 get_modrm(*current, &mod, ®op, &rm); | 1363 get_modrm(*current, &mod, ®op, &rm); |
1202 AppendToBuffer("movq %s,", NameOfXMMRegister(regop)); | 1364 AppendToBuffer("movq %s,", NameOfXMMRegister(regop)); |
1203 current += PrintRightXMMOperand(current); | 1365 current += PrintRightXMMOperand(current); |
1204 } else { | 1366 } else { |
1205 UnimplementedInstruction(); | 1367 UnimplementedInstruction(); |
1206 } | 1368 } |
1207 } else if (opcode == 0x1F) { | 1369 } else if (opcode == 0x1F) { |
1208 // NOP | 1370 // NOP |
(...skipping 18 matching lines...) Expand all Loading... |
1227 current += PrintRightXMMOperand(current); | 1389 current += PrintRightXMMOperand(current); |
1228 | 1390 |
1229 } else if (opcode == 0x29) { | 1391 } else if (opcode == 0x29) { |
1230 // movaps xmm/m128, xmm | 1392 // movaps xmm/m128, xmm |
1231 int mod, regop, rm; | 1393 int mod, regop, rm; |
1232 get_modrm(*current, &mod, ®op, &rm); | 1394 get_modrm(*current, &mod, ®op, &rm); |
1233 AppendToBuffer("movaps "); | 1395 AppendToBuffer("movaps "); |
1234 current += PrintRightXMMOperand(current); | 1396 current += PrintRightXMMOperand(current); |
1235 AppendToBuffer(",%s", NameOfXMMRegister(regop)); | 1397 AppendToBuffer(",%s", NameOfXMMRegister(regop)); |
1236 | 1398 |
| 1399 } else if (opcode == 0x2e) { |
| 1400 int mod, regop, rm; |
| 1401 get_modrm(*current, &mod, ®op, &rm); |
| 1402 AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop)); |
| 1403 current += PrintRightXMMOperand(current); |
1237 } else if (opcode == 0xA2) { | 1404 } else if (opcode == 0xA2) { |
1238 // CPUID | 1405 // CPUID |
1239 AppendToBuffer("%s", mnemonic); | 1406 AppendToBuffer("%s", mnemonic); |
1240 | 1407 |
1241 } else if ((opcode & 0xF0) == 0x40) { | 1408 } else if ((opcode & 0xF0) == 0x40) { |
1242 // CMOVcc: conditional move. | 1409 // CMOVcc: conditional move. |
1243 int condition = opcode & 0x0F; | 1410 int condition = opcode & 0x0F; |
1244 const InstructionDesc& idesc = cmov_instructions[condition]; | 1411 const InstructionDesc& idesc = cmov_instructions[condition]; |
1245 byte_size_operand_ = idesc.byte_size_operation; | 1412 byte_size_operand_ = idesc.byte_size_operation; |
1246 current += PrintOperands(idesc.mnem, idesc.op_order_, current); | 1413 current += PrintOperands(idesc.mnem, idesc.op_order_, current); |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1380 // Scan for prefixes. | 1547 // Scan for prefixes. |
1381 while (true) { | 1548 while (true) { |
1382 current = *data; | 1549 current = *data; |
1383 if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix. | 1550 if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix. |
1384 operand_size_ = current; | 1551 operand_size_ = current; |
1385 } else if ((current & 0xF0) == 0x40) { // REX prefix. | 1552 } else if ((current & 0xF0) == 0x40) { // REX prefix. |
1386 setRex(current); | 1553 setRex(current); |
1387 if (rex_w()) AppendToBuffer("REX.W "); | 1554 if (rex_w()) AppendToBuffer("REX.W "); |
1388 } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3). | 1555 } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3). |
1389 group_1_prefix_ = current; | 1556 group_1_prefix_ = current; |
| 1557 } else if (current == VEX3_PREFIX) { |
| 1558 vex_byte0_ = current; |
| 1559 vex_byte1_ = *(data + 1); |
| 1560 vex_byte2_ = *(data + 2); |
| 1561 setRex(0x40 | (~(vex_byte1_ >> 5) & 7) | ((vex_byte2_ >> 4) & 8)); |
| 1562 data += 2; |
| 1563 } else if (current == VEX2_PREFIX) { |
| 1564 vex_byte0_ = current; |
| 1565 vex_byte1_ = *(data + 1); |
| 1566 setRex(0x40 | (~(vex_byte1_ >> 5) & 4)); |
| 1567 data++; |
1390 } else { // Not a prefix - an opcode. | 1568 } else { // Not a prefix - an opcode. |
1391 break; | 1569 break; |
1392 } | 1570 } |
1393 data++; | 1571 data++; |
1394 } | 1572 } |
1395 | 1573 |
1396 const InstructionDesc& idesc = instruction_table_->Get(current); | 1574 // Decode AVX instructions. |
1397 byte_size_operand_ = idesc.byte_size_operation; | 1575 if (vex_byte0_ != 0) { |
1398 switch (idesc.type) { | 1576 processed = true; |
1399 case ZERO_OPERANDS_INSTR: | 1577 data += AVXInstruction(data); |
1400 if (current >= 0xA4 && current <= 0xA7) { | 1578 } else { |
1401 // String move or compare operations. | 1579 const InstructionDesc& idesc = instruction_table_->Get(current); |
1402 if (group_1_prefix_ == REP_PREFIX) { | 1580 byte_size_operand_ = idesc.byte_size_operation; |
1403 // REP. | 1581 switch (idesc.type) { |
1404 AppendToBuffer("rep "); | 1582 case ZERO_OPERANDS_INSTR: |
| 1583 if (current >= 0xA4 && current <= 0xA7) { |
| 1584 // String move or compare operations. |
| 1585 if (group_1_prefix_ == REP_PREFIX) { |
| 1586 // REP. |
| 1587 AppendToBuffer("rep "); |
| 1588 } |
| 1589 if (rex_w()) AppendToBuffer("REX.W "); |
| 1590 AppendToBuffer("%s%c", idesc.mnem, operand_size_code()); |
| 1591 } else { |
| 1592 AppendToBuffer("%s", idesc.mnem, operand_size_code()); |
1405 } | 1593 } |
1406 if (rex_w()) AppendToBuffer("REX.W "); | 1594 data++; |
1407 AppendToBuffer("%s%c", idesc.mnem, operand_size_code()); | 1595 break; |
1408 } else { | 1596 |
1409 AppendToBuffer("%s", idesc.mnem, operand_size_code()); | 1597 case TWO_OPERANDS_INSTR: |
| 1598 data++; |
| 1599 data += PrintOperands(idesc.mnem, idesc.op_order_, data); |
| 1600 break; |
| 1601 |
| 1602 case JUMP_CONDITIONAL_SHORT_INSTR: |
| 1603 data += JumpConditionalShort(data); |
| 1604 break; |
| 1605 |
| 1606 case REGISTER_INSTR: |
| 1607 AppendToBuffer("%s%c %s", idesc.mnem, operand_size_code(), |
| 1608 NameOfCPURegister(base_reg(current & 0x07))); |
| 1609 data++; |
| 1610 break; |
| 1611 case PUSHPOP_INSTR: |
| 1612 AppendToBuffer("%s %s", idesc.mnem, |
| 1613 NameOfCPURegister(base_reg(current & 0x07))); |
| 1614 data++; |
| 1615 break; |
| 1616 case MOVE_REG_INSTR: { |
| 1617 byte* addr = NULL; |
| 1618 switch (operand_size()) { |
| 1619 case OPERAND_WORD_SIZE: |
| 1620 addr = |
| 1621 reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1)); |
| 1622 data += 3; |
| 1623 break; |
| 1624 case OPERAND_DOUBLEWORD_SIZE: |
| 1625 addr = |
| 1626 reinterpret_cast<byte*>(*reinterpret_cast<uint32_t*>(data + 1)); |
| 1627 data += 5; |
| 1628 break; |
| 1629 case OPERAND_QUADWORD_SIZE: |
| 1630 addr = |
| 1631 reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1)); |
| 1632 data += 9; |
| 1633 break; |
| 1634 default: |
| 1635 UNREACHABLE(); |
| 1636 } |
| 1637 AppendToBuffer("mov%c %s,%s", operand_size_code(), |
| 1638 NameOfCPURegister(base_reg(current & 0x07)), |
| 1639 NameOfAddress(addr)); |
| 1640 break; |
1410 } | 1641 } |
1411 data++; | |
1412 break; | |
1413 | 1642 |
1414 case TWO_OPERANDS_INSTR: | 1643 case CALL_JUMP_INSTR: { |
1415 data++; | 1644 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5; |
1416 data += PrintOperands(idesc.mnem, idesc.op_order_, data); | 1645 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr)); |
1417 break; | 1646 data += 5; |
| 1647 break; |
| 1648 } |
1418 | 1649 |
1419 case JUMP_CONDITIONAL_SHORT_INSTR: | 1650 case SHORT_IMMEDIATE_INSTR: { |
1420 data += JumpConditionalShort(data); | 1651 byte* addr = |
1421 break; | 1652 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1)); |
| 1653 AppendToBuffer("%s rax,%s", idesc.mnem, NameOfAddress(addr)); |
| 1654 data += 5; |
| 1655 break; |
| 1656 } |
1422 | 1657 |
1423 case REGISTER_INSTR: | 1658 case NO_INSTR: |
1424 AppendToBuffer("%s%c %s", | 1659 processed = false; |
1425 idesc.mnem, | 1660 break; |
1426 operand_size_code(), | 1661 |
1427 NameOfCPURegister(base_reg(current & 0x07))); | 1662 default: |
1428 data++; | 1663 UNIMPLEMENTED(); // This type is not implemented. |
1429 break; | |
1430 case PUSHPOP_INSTR: | |
1431 AppendToBuffer("%s %s", | |
1432 idesc.mnem, | |
1433 NameOfCPURegister(base_reg(current & 0x07))); | |
1434 data++; | |
1435 break; | |
1436 case MOVE_REG_INSTR: { | |
1437 byte* addr = NULL; | |
1438 switch (operand_size()) { | |
1439 case OPERAND_WORD_SIZE: | |
1440 addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1)); | |
1441 data += 3; | |
1442 break; | |
1443 case OPERAND_DOUBLEWORD_SIZE: | |
1444 addr = | |
1445 reinterpret_cast<byte*>(*reinterpret_cast<uint32_t*>(data + 1)); | |
1446 data += 5; | |
1447 break; | |
1448 case OPERAND_QUADWORD_SIZE: | |
1449 addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1)); | |
1450 data += 9; | |
1451 break; | |
1452 default: | |
1453 UNREACHABLE(); | |
1454 } | |
1455 AppendToBuffer("mov%c %s,%s", | |
1456 operand_size_code(), | |
1457 NameOfCPURegister(base_reg(current & 0x07)), | |
1458 NameOfAddress(addr)); | |
1459 break; | |
1460 } | 1664 } |
1461 | |
1462 case CALL_JUMP_INSTR: { | |
1463 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5; | |
1464 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr)); | |
1465 data += 5; | |
1466 break; | |
1467 } | |
1468 | |
1469 case SHORT_IMMEDIATE_INSTR: { | |
1470 byte* addr = | |
1471 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1)); | |
1472 AppendToBuffer("%s rax,%s", idesc.mnem, NameOfAddress(addr)); | |
1473 data += 5; | |
1474 break; | |
1475 } | |
1476 | |
1477 case NO_INSTR: | |
1478 processed = false; | |
1479 break; | |
1480 | |
1481 default: | |
1482 UNIMPLEMENTED(); // This type is not implemented. | |
1483 } | 1665 } |
1484 | 1666 |
1485 // The first byte didn't match any of the simple opcodes, so we | 1667 // The first byte didn't match any of the simple opcodes, so we |
1486 // need to do special processing on it. | 1668 // need to do special processing on it. |
1487 if (!processed) { | 1669 if (!processed) { |
1488 switch (*data) { | 1670 switch (*data) { |
1489 case 0xC2: | 1671 case 0xC2: |
1490 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1)); | 1672 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1)); |
1491 data += 3; | 1673 data += 3; |
1492 break; | 1674 break; |
(...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1910 for (int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) { | 2092 for (int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) { |
1911 fprintf(f, " "); | 2093 fprintf(f, " "); |
1912 } | 2094 } |
1913 fprintf(f, " %s\n", buffer.start()); | 2095 fprintf(f, " %s\n", buffer.start()); |
1914 } | 2096 } |
1915 } | 2097 } |
1916 | 2098 |
1917 } // namespace disasm | 2099 } // namespace disasm |
1918 | 2100 |
1919 #endif // V8_TARGET_ARCH_X64 | 2101 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |