OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
246 assert(id->type == NO_INSTR); // Information already entered | 246 assert(id->type == NO_INSTR); // Information already entered |
247 id->mnem = NULL; // Computed depending on condition code. | 247 id->mnem = NULL; // Computed depending on condition code. |
248 id->type = JUMP_CONDITIONAL_SHORT_INSTR; | 248 id->type = JUMP_CONDITIONAL_SHORT_INSTR; |
249 } | 249 } |
250 } | 250 } |
251 | 251 |
252 | 252 |
253 static InstructionTable instruction_table; | 253 static InstructionTable instruction_table; |
254 | 254 |
255 | 255 |
256 // The X64 disassembler implementation. | 256 //------------------------------------------------------------------------------ |
| 257 // DisassemblerX64 implementation. |
| 258 |
257 enum UnimplementedOpcodeAction { | 259 enum UnimplementedOpcodeAction { |
258 CONTINUE_ON_UNIMPLEMENTED_OPCODE, | 260 CONTINUE_ON_UNIMPLEMENTED_OPCODE, |
259 ABORT_ON_UNIMPLEMENTED_OPCODE | 261 ABORT_ON_UNIMPLEMENTED_OPCODE |
260 }; | 262 }; |
261 | 263 |
262 | 264 // A new DisassemblerX64 object is created to disassemble each instruction. |
| 265 // The object can only disassemble a single instruction. |
263 class DisassemblerX64 { | 266 class DisassemblerX64 { |
264 public: | 267 public: |
265 DisassemblerX64(const NameConverter& converter, | 268 DisassemblerX64(const NameConverter& converter, |
266 UnimplementedOpcodeAction unimplemented_action = | 269 UnimplementedOpcodeAction unimplemented_action = |
267 ABORT_ON_UNIMPLEMENTED_OPCODE) | 270 ABORT_ON_UNIMPLEMENTED_OPCODE) |
268 : converter_(converter), | 271 : converter_(converter), |
269 tmp_buffer_pos_(0), | 272 tmp_buffer_pos_(0), |
270 abort_on_unimplemented_( | 273 abort_on_unimplemented_( |
271 unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE), | 274 unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE), |
272 rex_(0), | 275 rex_(0), |
273 operand_size_(0), | 276 operand_size_(0), |
| 277 group_1_prefix_(0), |
274 byte_size_operand_(false) { | 278 byte_size_operand_(false) { |
275 tmp_buffer_[0] = '\0'; | 279 tmp_buffer_[0] = '\0'; |
276 } | 280 } |
277 | 281 |
278 virtual ~DisassemblerX64() { | 282 virtual ~DisassemblerX64() { |
279 } | 283 } |
280 | 284 |
281 // Writes one disassembled instruction into 'buffer' (0-terminated). | 285 // Writes one disassembled instruction into 'buffer' (0-terminated). |
282 // Returns the length of the disassembled machine instruction in bytes. | 286 // Returns the length of the disassembled machine instruction in bytes. |
283 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction); | 287 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction); |
284 | 288 |
285 private: | 289 private: |
286 enum OperandSize { | 290 enum OperandSize { |
287 BYTE_SIZE = 0, | 291 BYTE_SIZE = 0, |
288 WORD_SIZE = 1, | 292 WORD_SIZE = 1, |
289 DOUBLEWORD_SIZE = 2, | 293 DOUBLEWORD_SIZE = 2, |
290 QUADWORD_SIZE = 3 | 294 QUADWORD_SIZE = 3 |
291 }; | 295 }; |
292 | 296 |
293 const NameConverter& converter_; | 297 const NameConverter& converter_; |
294 v8::internal::EmbeddedVector<char, 128> tmp_buffer_; | 298 v8::internal::EmbeddedVector<char, 128> tmp_buffer_; |
295 unsigned int tmp_buffer_pos_; | 299 unsigned int tmp_buffer_pos_; |
296 bool abort_on_unimplemented_; | 300 bool abort_on_unimplemented_; |
297 // Prefixes parsed | 301 // Prefixes parsed |
298 byte rex_; | 302 byte rex_; |
299 byte operand_size_; | 303 byte operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0. |
| 304 byte group_1_prefix_; // 0xF2, 0xF3, or (if no group 1 prefix is present) 0. |
300 // Byte size operand override. | 305 // Byte size operand override. |
301 bool byte_size_operand_; | 306 bool byte_size_operand_; |
302 | 307 |
303 void setOperandSizePrefix(byte prefix) { | |
304 ASSERT_EQ(0x66, prefix); | |
305 operand_size_ = prefix; | |
306 } | |
307 | |
308 void setRex(byte rex) { | 308 void setRex(byte rex) { |
309 ASSERT_EQ(0x40, rex & 0xF0); | 309 ASSERT_EQ(0x40, rex & 0xF0); |
310 rex_ = rex; | 310 rex_ = rex; |
311 } | 311 } |
312 | 312 |
313 bool rex() { return rex_ != 0; } | 313 bool rex() { return rex_ != 0; } |
314 | 314 |
315 bool rex_b() { return (rex_ & 0x01) != 0; } | 315 bool rex_b() { return (rex_ & 0x01) != 0; } |
316 | 316 |
317 // Actual number of base register given the low bits and the rex.b state. | 317 // Actual number of base register given the low bits and the rex.b state. |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
373 | 373 |
374 int PrintRightOperandHelper(byte* modrmp, | 374 int PrintRightOperandHelper(byte* modrmp, |
375 RegisterNameMapping register_name); | 375 RegisterNameMapping register_name); |
376 int PrintRightOperand(byte* modrmp); | 376 int PrintRightOperand(byte* modrmp); |
377 int PrintRightByteOperand(byte* modrmp); | 377 int PrintRightByteOperand(byte* modrmp); |
378 int PrintOperands(const char* mnem, | 378 int PrintOperands(const char* mnem, |
379 OperandType op_order, | 379 OperandType op_order, |
380 byte* data); | 380 byte* data); |
381 int PrintImmediate(byte* data, OperandSize size); | 381 int PrintImmediate(byte* data, OperandSize size); |
382 int PrintImmediateOp(byte* data); | 382 int PrintImmediateOp(byte* data); |
| 383 const char* TwoByteMnemonic(byte opcode); |
| 384 int TwoByteOpcodeInstruction(byte* data); |
383 int F7Instruction(byte* data); | 385 int F7Instruction(byte* data); |
384 int ShiftInstruction(byte* data); | 386 int ShiftInstruction(byte* data); |
385 int JumpShort(byte* data); | 387 int JumpShort(byte* data); |
386 int JumpConditional(byte* data); | 388 int JumpConditional(byte* data); |
387 int JumpConditionalShort(byte* data); | 389 int JumpConditionalShort(byte* data); |
388 int SetCC(byte* data); | 390 int SetCC(byte* data); |
389 int FPUInstruction(byte* data); | 391 int FPUInstruction(byte* data); |
390 void AppendToBuffer(const char* format, ...); | 392 void AppendToBuffer(const char* format, ...); |
391 | 393 |
392 void UnimplementedInstruction() { | 394 void UnimplementedInstruction() { |
393 if (abort_on_unimplemented_) { | 395 if (abort_on_unimplemented_) { |
394 UNIMPLEMENTED(); | 396 CHECK(false); |
395 } else { | 397 } else { |
396 AppendToBuffer("'Unimplemented Instruction'"); | 398 AppendToBuffer("'Unimplemented Instruction'"); |
397 } | 399 } |
398 } | 400 } |
399 }; | 401 }; |
400 | 402 |
401 | 403 |
402 void DisassemblerX64::AppendToBuffer(const char* format, ...) { | 404 void DisassemblerX64::AppendToBuffer(const char* format, ...) { |
403 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_; | 405 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_; |
404 va_list args; | 406 va_list args; |
(...skipping 524 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
929 return 2; | 931 return 2; |
930 } else if (b1 == 0xDA && b2 == 0xE9) { | 932 } else if (b1 == 0xDA && b2 == 0xE9) { |
931 const char* mnem = "fucompp"; | 933 const char* mnem = "fucompp"; |
932 AppendToBuffer("%s", mnem); | 934 AppendToBuffer("%s", mnem); |
933 return 2; | 935 return 2; |
934 } | 936 } |
935 AppendToBuffer("Unknown FP instruction"); | 937 AppendToBuffer("Unknown FP instruction"); |
936 return 2; | 938 return 2; |
937 } | 939 } |
938 | 940 |
939 // Mnemonics for instructions 0xF0 byte. | 941 |
| 942 // Handle all two-byte opcodes, which start with 0x0F. |
| 943 // These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix. |
| 944 // We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A. |
| 945 int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { |
| 946 byte opcode = *(data + 1); |
| 947 byte* current = data + 2; |
| 948 // At return, "current" points to the start of the next instruction. |
| 949 const char* mnemonic = TwoByteMnemonic(opcode); |
| 950 if (opcode == 0x1F) { |
| 951 // NOP |
| 952 int mod, regop, rm; |
| 953 get_modrm(*current, &mod, ®op, &rm); |
| 954 current++; |
| 955 if (regop == 4) { // SIB byte present. |
| 956 current++; |
| 957 } |
| 958 if (mod == 1) { // Byte displacement. |
| 959 current += 1; |
| 960 } else if (mod == 2) { // 32-bit displacement. |
| 961 current += 4; |
| 962 } // else no immediate displacement. |
| 963 AppendToBuffer("nop"); |
| 964 |
| 965 } else if (opcode == 0xA2 || opcode == 0x31) { |
| 966 // RDTSC or CPUID |
| 967 AppendToBuffer("%s", mnemonic); |
| 968 |
| 969 } else if ((opcode & 0xF0) == 0x80) { |
| 970 // Jcc: Conditional jump (branch). |
| 971 current = data + JumpConditional(data); |
| 972 |
| 973 } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 || |
| 974 opcode == 0xB7 || opcode == 0xAF) { |
| 975 // Size-extending moves, IMUL. |
| 976 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current); |
| 977 |
| 978 } else if ((opcode & 0xF0) == 0x90) { |
| 979 // SETcc: Set byte on condition. Needs pointer to beginning of instruction. |
| 980 current = data + SetCC(data); |
| 981 |
| 982 } else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) { |
| 983 // SHLD, SHRD (double-precision shift), BTS (bit set). |
| 984 AppendToBuffer("%s ", mnemonic); |
| 985 int mod, regop, rm; |
| 986 get_modrm(*current, &mod, ®op, &rm); |
| 987 current += PrintRightOperand(current); |
| 988 if (opcode == 0xAB) { |
| 989 AppendToBuffer(",%s", NameOfCPURegister(regop)); |
| 990 } else { |
| 991 AppendToBuffer(",%s,cl", NameOfCPURegister(regop)); |
| 992 } |
| 993 } else if (group_1_prefix_ == 0xF2) { |
| 994 // Beginning of instructions with prefix 0xF2. |
| 995 |
| 996 if (opcode == 0x11 || opcode == 0x10) { |
| 997 // MOVSD: Move scalar double-precision fp to/from/between XMM registers. |
| 998 AppendToBuffer("movsd "); |
| 999 int mod, regop, rm; |
| 1000 get_modrm(*current, &mod, ®op, &rm); |
| 1001 if (opcode == 0x11) { |
| 1002 current += PrintRightOperand(current); |
| 1003 AppendToBuffer(",%s", NameOfXMMRegister(regop)); |
| 1004 } else { |
| 1005 AppendToBuffer("%s,", NameOfXMMRegister(regop)); |
| 1006 current += PrintRightOperand(current); |
| 1007 } |
| 1008 } else if (opcode == 0x2A) { |
| 1009 // CVTSI2SD: integer to XMM double conversion. |
| 1010 int mod, regop, rm; |
| 1011 get_modrm(*current, &mod, ®op, &rm); |
| 1012 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop)); |
| 1013 data += PrintRightOperand(data); |
| 1014 } else if ((opcode & 0xF8) == 0x58) { |
| 1015 // XMM arithmetic. Mnemonic was retrieved at the start of this function. |
| 1016 int mod, regop, rm; |
| 1017 get_modrm(*current, &mod, ®op, &rm); |
| 1018 AppendToBuffer("%s %s,%s", mnemonic, NameOfXMMRegister(regop), |
| 1019 NameOfXMMRegister(rm)); |
| 1020 } else { |
| 1021 UnimplementedInstruction(); |
| 1022 } |
| 1023 } else if (opcode == 0x2C && group_1_prefix_ == 0xF3) { |
| 1024 // Instruction with prefix 0xF3. |
| 1025 |
| 1026 // CVTTSS2SI: Convert scalar single-precision FP to dword integer. |
| 1027 // Assert that mod is not 3, so source is memory, not an XMM register. |
| 1028 ASSERT((*current & 0xC0) != 0xC0); |
| 1029 current += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, current); |
| 1030 } else { |
| 1031 UnimplementedInstruction(); |
| 1032 } |
| 1033 return current - data; |
| 1034 } |
| 1035 |
| 1036 |
| 1037 // Mnemonics for two-byte opcode instructions starting with 0x0F. |
| 1038 // The argument is the second byte of the two-byte opcode. |
940 // Returns NULL if the instruction is not handled here. | 1039 // Returns NULL if the instruction is not handled here. |
941 static const char* F0Mnem(byte f0byte) { | 1040 const char* DisassemblerX64::TwoByteMnemonic(byte opcode) { |
942 switch (f0byte) { | 1041 switch (opcode) { |
943 case 0x1F: | 1042 case 0x1F: |
944 return "nop"; | 1043 return "nop"; |
| 1044 case 0x2A: // F2 prefix. |
| 1045 return "cvtsi2sd"; |
945 case 0x31: | 1046 case 0x31: |
946 return "rdtsc"; | 1047 return "rdtsc"; |
| 1048 case 0x58: // F2 prefix. |
| 1049 return "addsd"; |
| 1050 case 0x59: // F2 prefix. |
| 1051 return "mulsd"; |
| 1052 case 0x5C: // F2 prefix. |
| 1053 return "subsd"; |
| 1054 case 0x5E: // F2 prefix. |
| 1055 return "divsd"; |
947 case 0xA2: | 1056 case 0xA2: |
948 return "cpuid"; | 1057 return "cpuid"; |
| 1058 case 0xA5: |
| 1059 return "shld"; |
| 1060 case 0xAB: |
| 1061 return "bts"; |
| 1062 case 0xAD: |
| 1063 return "shrd"; |
| 1064 case 0xAF: |
| 1065 return "imul"; |
| 1066 case 0xB6: |
| 1067 return "movzxb"; |
| 1068 case 0xB7: |
| 1069 return "movzxw"; |
949 case 0xBE: | 1070 case 0xBE: |
950 return "movsxb"; | 1071 return "movsxb"; |
951 case 0xBF: | 1072 case 0xBF: |
952 return "movsxw"; | 1073 return "movsxw"; |
953 case 0xB6: | |
954 return "movzxb"; | |
955 case 0xB7: | |
956 return "movzxw"; | |
957 case 0xAF: | |
958 return "imul"; | |
959 case 0xA5: | |
960 return "shld"; | |
961 case 0xAD: | |
962 return "shrd"; | |
963 case 0xAB: | |
964 return "bts"; | |
965 default: | 1074 default: |
966 return NULL; | 1075 return NULL; |
967 } | 1076 } |
968 } | 1077 } |
969 | 1078 |
970 // Disassembled instruction '*instr' and writes it into 'out_buffer'. | 1079 |
| 1080 // Disassembles the instruction at instr, and writes it into out_buffer. |
971 int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer, | 1081 int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer, |
972 byte* instr) { | 1082 byte* instr) { |
973 tmp_buffer_pos_ = 0; // starting to write as position 0 | 1083 tmp_buffer_pos_ = 0; // starting to write as position 0 |
974 byte* data = instr; | 1084 byte* data = instr; |
975 bool processed = true; // Will be set to false if the current instruction | 1085 bool processed = true; // Will be set to false if the current instruction |
976 // is not in 'instructions' table. | 1086 // is not in 'instructions' table. |
977 byte current; | 1087 byte current; |
978 | 1088 |
979 // Scan for prefixes. | 1089 // Scan for prefixes. |
980 while (true) { | 1090 while (true) { |
981 current = *data; | 1091 current = *data; |
982 if (current == 0x66) { | 1092 if (current == 0x66) { // Group 3 prefix. |
983 // If the sequence is 66 0f, it's not a prefix, but a SSE escape. | 1093 operand_size_ = current; |
984 if (*(data + 1) == 0x0F) break; | 1094 } else if ((current & 0xF0) == 0x40) { // REX prefix. |
985 data++; | |
986 } else if ((current & 0xF0) == 0x40) { | |
987 setRex(current); | 1095 setRex(current); |
988 if (rex_w()) AppendToBuffer("REX.W "); | 1096 if (rex_w()) AppendToBuffer("REX.W "); |
989 data++; | 1097 } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix. |
990 } else { | 1098 group_1_prefix_ = current; |
| 1099 } else { // Not a prefix - an opcode. |
991 break; | 1100 break; |
992 } | 1101 } |
| 1102 data++; |
993 } | 1103 } |
994 | 1104 |
995 const InstructionDesc& idesc = instruction_table.Get(current); | 1105 const InstructionDesc& idesc = instruction_table.Get(current); |
996 byte_size_operand_ = idesc.byte_size_operation; | 1106 byte_size_operand_ = idesc.byte_size_operation; |
997 switch (idesc.type) { | 1107 switch (idesc.type) { |
998 case ZERO_OPERANDS_INSTR: | 1108 case ZERO_OPERANDS_INSTR: |
999 AppendToBuffer(idesc.mnem); | 1109 AppendToBuffer(idesc.mnem); |
1000 data++; | 1110 data++; |
1001 break; | 1111 break; |
1002 | 1112 |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1101 } | 1211 } |
1102 data += 3; | 1212 data += 3; |
1103 break; | 1213 break; |
1104 } | 1214 } |
1105 | 1215 |
1106 case 0x81: // fall through | 1216 case 0x81: // fall through |
1107 case 0x83: // 0x81 with sign extension bit set | 1217 case 0x83: // 0x81 with sign extension bit set |
1108 data += PrintImmediateOp(data); | 1218 data += PrintImmediateOp(data); |
1109 break; | 1219 break; |
1110 | 1220 |
1111 case 0x0F: { | 1221 case 0x0F: |
1112 byte f0byte = *(data + 1); | 1222 data += TwoByteOpcodeInstruction(data); |
1113 const char* f0mnem = F0Mnem(f0byte); | |
1114 if (f0byte == 0x1F) { | |
1115 data += 1; | |
1116 byte modrm = *data; | |
1117 data += 1; | |
1118 if (((modrm >> 3) & 7) == 4) { | |
1119 // SIB byte present. | |
1120 data += 1; | |
1121 } | |
1122 int mod = modrm >> 6; | |
1123 if (mod == 1) { | |
1124 // Byte displacement. | |
1125 data += 1; | |
1126 } else if (mod == 2) { | |
1127 // 32-bit displacement. | |
1128 data += 4; | |
1129 } | |
1130 AppendToBuffer("nop"); | |
1131 } else if (f0byte == 0xA2 || f0byte == 0x31) { | |
1132 AppendToBuffer("%s", f0mnem); | |
1133 data += 2; | |
1134 } else if ((f0byte & 0xF0) == 0x80) { | |
1135 data += JumpConditional(data); | |
1136 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 || f0byte | |
1137 == 0xB7 || f0byte == 0xAF) { | |
1138 data += 2; | |
1139 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data); | |
1140 } else if ((f0byte & 0xF0) == 0x90) { | |
1141 data += SetCC(data); | |
1142 } else { | |
1143 data += 2; | |
1144 if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) { | |
1145 // shrd, shld, bts | |
1146 AppendToBuffer("%s ", f0mnem); | |
1147 int mod, regop, rm; | |
1148 get_modrm(*data, &mod, ®op, &rm); | |
1149 data += PrintRightOperand(data); | |
1150 if (f0byte == 0xAB) { | |
1151 AppendToBuffer(",%s", NameOfCPURegister(regop)); | |
1152 } else { | |
1153 AppendToBuffer(",%s,cl", NameOfCPURegister(regop)); | |
1154 } | |
1155 } else { | |
1156 UnimplementedInstruction(); | |
1157 } | |
1158 } | |
1159 } | |
1160 break; | 1223 break; |
1161 | 1224 |
1162 case 0x8F: { | 1225 case 0x8F: { |
1163 data++; | 1226 data++; |
1164 int mod, regop, rm; | 1227 int mod, regop, rm; |
1165 get_modrm(*data, &mod, ®op, &rm); | 1228 get_modrm(*data, &mod, ®op, &rm); |
1166 if (regop == 0) { | 1229 if (regop == 0) { |
1167 AppendToBuffer("pop "); | 1230 AppendToBuffer("pop "); |
1168 data += PrintRightOperand(data); | 1231 data += PrintRightOperand(data); |
1169 } | 1232 } |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1296 value = *reinterpret_cast<uint32_t*>(data + 1); | 1359 value = *reinterpret_cast<uint32_t*>(data + 1); |
1297 data += 5; | 1360 data += 5; |
1298 break; | 1361 break; |
1299 case QUADWORD_SIZE: | 1362 case QUADWORD_SIZE: |
1300 value = *reinterpret_cast<int32_t*>(data + 1); | 1363 value = *reinterpret_cast<int32_t*>(data + 1); |
1301 data += 5; | 1364 data += 5; |
1302 break; | 1365 break; |
1303 default: | 1366 default: |
1304 UNREACHABLE(); | 1367 UNREACHABLE(); |
1305 } | 1368 } |
1306 break; | |
1307 AppendToBuffer("test%c rax,0x%"V8_PTR_PREFIX"ux", | 1369 AppendToBuffer("test%c rax,0x%"V8_PTR_PREFIX"ux", |
1308 operand_size_code(), | 1370 operand_size_code(), |
1309 value); | 1371 value); |
| 1372 break; |
1310 } | 1373 } |
1311 case 0xD1: // fall through | 1374 case 0xD1: // fall through |
1312 case 0xD3: // fall through | 1375 case 0xD3: // fall through |
1313 case 0xC1: | 1376 case 0xC1: |
1314 data += ShiftInstruction(data); | 1377 data += ShiftInstruction(data); |
1315 break; | 1378 break; |
1316 case 0xD0: // fall through | 1379 case 0xD0: // fall through |
1317 case 0xD2: // fall through | 1380 case 0xD2: // fall through |
1318 case 0xC0: | 1381 case 0xC0: |
1319 byte_size_operand_ = true; | 1382 byte_size_operand_ = true; |
1320 data += ShiftInstruction(data); | 1383 data += ShiftInstruction(data); |
1321 break; | 1384 break; |
1322 | 1385 |
1323 case 0xD9: // fall through | 1386 case 0xD9: // fall through |
1324 case 0xDA: // fall through | 1387 case 0xDA: // fall through |
1325 case 0xDB: // fall through | 1388 case 0xDB: // fall through |
1326 case 0xDC: // fall through | 1389 case 0xDC: // fall through |
1327 case 0xDD: // fall through | 1390 case 0xDD: // fall through |
1328 case 0xDE: // fall through | 1391 case 0xDE: // fall through |
1329 case 0xDF: | 1392 case 0xDF: |
1330 data += FPUInstruction(data); | 1393 data += FPUInstruction(data); |
1331 break; | 1394 break; |
1332 | 1395 |
1333 case 0xEB: | 1396 case 0xEB: |
1334 data += JumpShort(data); | 1397 data += JumpShort(data); |
1335 break; | 1398 break; |
1336 | 1399 |
1337 case 0xF2: | |
1338 if (*(data + 1) == 0x0F) { | |
1339 byte b2 = *(data + 2); | |
1340 if (b2 == 0x11) { | |
1341 AppendToBuffer("movsd "); | |
1342 data += 3; | |
1343 int mod, regop, rm; | |
1344 get_modrm(*data, &mod, ®op, &rm); | |
1345 data += PrintRightOperand(data); | |
1346 AppendToBuffer(",%s", NameOfXMMRegister(regop)); | |
1347 } else if (b2 == 0x10) { | |
1348 data += 3; | |
1349 int mod, regop, rm; | |
1350 get_modrm(*data, &mod, ®op, &rm); | |
1351 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop)); | |
1352 data += PrintRightOperand(data); | |
1353 } else { | |
1354 const char* mnem = "?"; | |
1355 switch (b2) { | |
1356 case 0x2A: | |
1357 mnem = "cvtsi2sd"; | |
1358 break; | |
1359 case 0x58: | |
1360 mnem = "addsd"; | |
1361 break; | |
1362 case 0x59: | |
1363 mnem = "mulsd"; | |
1364 break; | |
1365 case 0x5C: | |
1366 mnem = "subsd"; | |
1367 break; | |
1368 case 0x5E: | |
1369 mnem = "divsd"; | |
1370 break; | |
1371 } | |
1372 data += 3; | |
1373 int mod, regop, rm; | |
1374 get_modrm(*data, &mod, ®op, &rm); | |
1375 if (b2 == 0x2A) { | |
1376 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); | |
1377 data += PrintRightOperand(data); | |
1378 } else { | |
1379 AppendToBuffer("%s %s,%s", mnem, NameOfXMMRegister(regop), | |
1380 NameOfXMMRegister(rm)); | |
1381 data++; | |
1382 } | |
1383 } | |
1384 } else { | |
1385 UnimplementedInstruction(); | |
1386 } | |
1387 break; | |
1388 | |
1389 case 0xF3: | |
1390 if (*(data + 1) == 0x0F) { | |
1391 if (*(data + 2) == 0x2C) { | |
1392 data += 3; | |
1393 data += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, data); | |
1394 } else { | |
1395 UnimplementedInstruction(); | |
1396 data += 1; | |
1397 } | |
1398 } else { | |
1399 UnimplementedInstruction(); | |
1400 data += 1; | |
1401 } | |
1402 break; | |
1403 | |
1404 case 0xF7: | 1400 case 0xF7: |
1405 data += F7Instruction(data); | 1401 data += F7Instruction(data); |
1406 break; | 1402 break; |
1407 | 1403 |
1408 default: | 1404 default: |
1409 UnimplementedInstruction(); | 1405 UnimplementedInstruction(); |
1410 data += 1; | 1406 data += 1; |
1411 } | 1407 } |
1412 } // !processed | 1408 } // !processed |
1413 | 1409 |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1528 fprintf(f, "%02x", *bp); | 1524 fprintf(f, "%02x", *bp); |
1529 } | 1525 } |
1530 for (int i = 6 - (pc - prev_pc); i >= 0; i--) { | 1526 for (int i = 6 - (pc - prev_pc); i >= 0; i--) { |
1531 fprintf(f, " "); | 1527 fprintf(f, " "); |
1532 } | 1528 } |
1533 fprintf(f, " %s\n", buffer.start()); | 1529 fprintf(f, " %s\n", buffer.start()); |
1534 } | 1530 } |
1535 } | 1531 } |
1536 | 1532 |
1537 } // namespace disasm | 1533 } // namespace disasm |
OLD | NEW |