| Index: src/x64/disasm-x64.cc
|
| ===================================================================
|
| --- src/x64/disasm-x64.cc (revision 2455)
|
| +++ src/x64/disasm-x64.cc (working copy)
|
| @@ -34,8 +34,15 @@
|
|
|
| namespace disasm {
|
|
|
| -enum OperandOrder {
|
| - UNSET_OP_ORDER = 0, REG_OPER_OP_ORDER, OPER_REG_OP_ORDER
|
| +enum OperandType {
|
| + UNSET_OP_ORDER = 0,
|
| + // Operand size decides between 16, 32 and 64 bit operands.
|
| + REG_OPER_OP_ORDER = 1, // Register destination, operand source.
|
| + OPER_REG_OP_ORDER = 2, // Operand destination, register source.
|
| + // Fixed 8-bit operands.
|
| + BYTE_SIZE_OPERAND_FLAG = 4,
|
| + BYTE_REG_OPER_OP_ORDER = REG_OPER_OP_ORDER | BYTE_SIZE_OPERAND_FLAG,
|
| + BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG
|
| };
|
|
|
| //------------------------------------------------------------------
|
| @@ -43,28 +50,53 @@
|
| //------------------------------------------------------------------
|
| struct ByteMnemonic {
|
| int b; // -1 terminates, otherwise must be in range (0..255)
|
| - OperandOrder op_order_;
|
| + OperandType op_order_;
|
| const char* mnem;
|
| };
|
|
|
|
|
| static ByteMnemonic two_operands_instr[] = {
|
| - { 0x03, REG_OPER_OP_ORDER, "add" },
|
| - { 0x21, OPER_REG_OP_ORDER, "and" },
|
| - { 0x23, REG_OPER_OP_ORDER, "and" },
|
| - { 0x3B, REG_OPER_OP_ORDER, "cmp" },
|
| - { 0x8D, REG_OPER_OP_ORDER, "lea" },
|
| - { 0x09, OPER_REG_OP_ORDER, "or" },
|
| - { 0x0B, REG_OPER_OP_ORDER, "or" },
|
| - { 0x1B, REG_OPER_OP_ORDER, "sbb" },
|
| - { 0x29, OPER_REG_OP_ORDER, "sub" },
|
| - { 0x2B, REG_OPER_OP_ORDER, "sub" },
|
| - { 0x85, REG_OPER_OP_ORDER, "test" },
|
| - { 0x31, OPER_REG_OP_ORDER, "xor" },
|
| - { 0x33, REG_OPER_OP_ORDER, "xor" },
|
| - { 0x87, REG_OPER_OP_ORDER, "xchg" },
|
| - { 0x8A, REG_OPER_OP_ORDER, "movb" },
|
| - { 0x8B, REG_OPER_OP_ORDER, "mov" },
|
| + { 0x00, BYTE_OPER_REG_OP_ORDER, "add" },
|
| + { 0x01, OPER_REG_OP_ORDER, "add" },
|
| + { 0x02, BYTE_REG_OPER_OP_ORDER, "add" },
|
| + { 0x03, REG_OPER_OP_ORDER, "add" },
|
| + { 0x08, BYTE_OPER_REG_OP_ORDER, "or" },
|
| + { 0x09, OPER_REG_OP_ORDER, "or" },
|
| + { 0x0A, BYTE_REG_OPER_OP_ORDER, "or" },
|
| + { 0x0B, REG_OPER_OP_ORDER, "or" },
|
| + { 0x10, BYTE_OPER_REG_OP_ORDER, "adc" },
|
| + { 0x11, OPER_REG_OP_ORDER, "adc" },
|
| + { 0x12, BYTE_REG_OPER_OP_ORDER, "adc" },
|
| + { 0x13, REG_OPER_OP_ORDER, "adc" },
|
| + { 0x18, BYTE_OPER_REG_OP_ORDER, "sbb" },
|
| + { 0x19, OPER_REG_OP_ORDER, "sbb" },
|
| + { 0x1A, BYTE_REG_OPER_OP_ORDER, "sbb" },
|
| + { 0x1B, REG_OPER_OP_ORDER, "sbb" },
|
| + { 0x20, BYTE_OPER_REG_OP_ORDER, "and" },
|
| + { 0x21, OPER_REG_OP_ORDER, "and" },
|
| + { 0x22, BYTE_REG_OPER_OP_ORDER, "and" },
|
| + { 0x23, REG_OPER_OP_ORDER, "and" },
|
| + { 0x28, BYTE_OPER_REG_OP_ORDER, "sub" },
|
| + { 0x29, OPER_REG_OP_ORDER, "sub" },
|
| + { 0x2A, BYTE_REG_OPER_OP_ORDER, "sub" },
|
| + { 0x2B, REG_OPER_OP_ORDER, "sub" },
|
| + { 0x30, BYTE_OPER_REG_OP_ORDER, "xor" },
|
| + { 0x31, OPER_REG_OP_ORDER, "xor" },
|
| + { 0x32, BYTE_REG_OPER_OP_ORDER, "xor" },
|
| + { 0x33, REG_OPER_OP_ORDER, "xor" },
|
| + { 0x38, BYTE_OPER_REG_OP_ORDER, "cmp" },
|
| + { 0x39, OPER_REG_OP_ORDER, "cmp" },
|
| + { 0x3A, BYTE_REG_OPER_OP_ORDER, "cmp" },
|
| + { 0x3B, REG_OPER_OP_ORDER, "cmp" },
|
| + { 0x8D, REG_OPER_OP_ORDER, "lea" },
|
| + { 0x84, BYTE_REG_OPER_OP_ORDER, "test" },
|
| + { 0x85, REG_OPER_OP_ORDER, "test" },
|
| + { 0x86, BYTE_REG_OPER_OP_ORDER, "xchg" },
|
| + { 0x87, REG_OPER_OP_ORDER, "xchg" },
|
| + { 0x88, BYTE_OPER_REG_OP_ORDER, "mov" },
|
| + { 0x89, OPER_REG_OP_ORDER, "mov" },
|
| + { 0x8A, BYTE_REG_OPER_OP_ORDER, "mov" },
|
| + { 0x8B, REG_OPER_OP_ORDER, "mov" },
|
| { -1, UNSET_OP_ORDER, "" }
|
| };
|
|
|
| @@ -97,6 +129,7 @@
|
| { 0x05, UNSET_OP_ORDER, "add" },
|
| { 0x0D, UNSET_OP_ORDER, "or" },
|
| { 0x15, UNSET_OP_ORDER, "adc" },
|
| + { 0x1D, UNSET_OP_ORDER, "sbb" },
|
| { 0x25, UNSET_OP_ORDER, "and" },
|
| { 0x2D, UNSET_OP_ORDER, "sub" },
|
| { 0x35, UNSET_OP_ORDER, "xor" },
|
| @@ -127,7 +160,8 @@
|
| struct InstructionDesc {
|
| const char* mnem;
|
| InstructionType type;
|
| - OperandOrder op_order_;
|
| + OperandType op_order_;
|
| + bool byte_size_operation; // Fixed 8-bit operation.
|
| };
|
|
|
|
|
| @@ -143,7 +177,7 @@
|
| void Clear();
|
| void Init();
|
| void CopyTable(ByteMnemonic bm[], InstructionType type);
|
| - void SetTableRange(InstructionType type, byte start, byte end,
|
| + void SetTableRange(InstructionType type, byte start, byte end, bool byte_size,
|
| const char* mnem);
|
| void AddJumpConditionalShort();
|
| };
|
| @@ -157,9 +191,10 @@
|
|
|
| void InstructionTable::Clear() {
|
| for (int i = 0; i < 256; i++) {
|
| - instructions_[i].mnem = "";
|
| + instructions_[i].mnem = "(bad)";
|
| instructions_[i].type = NO_INSTR;
|
| instructions_[i].op_order_ = UNSET_OP_ORDER;
|
| + instructions_[i].byte_size_operation = false;
|
| }
|
| }
|
|
|
| @@ -170,9 +205,9 @@
|
| CopyTable(call_jump_instr, CALL_JUMP_INSTR);
|
| CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
|
| AddJumpConditionalShort();
|
| - SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, "push");
|
| - SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, "pop");
|
| - SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
|
| + SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push");
|
| + SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop");
|
| + SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov");
|
| }
|
|
|
|
|
| @@ -180,20 +215,27 @@
|
| for (int i = 0; bm[i].b >= 0; i++) {
|
| InstructionDesc* id = &instructions_[bm[i].b];
|
| id->mnem = bm[i].mnem;
|
| - id->op_order_ = bm[i].op_order_;
|
| - assert(id->type == NO_INSTR); // Information already entered
|
| + OperandType op_order = bm[i].op_order_;
|
| + id->op_order_ =
|
| + static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG);
|
| + assert(id->type == NO_INSTR); // Information not already entered
|
| id->type = type;
|
| + id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0);
|
| }
|
| }
|
|
|
|
|
| -void InstructionTable::SetTableRange(InstructionType type, byte start,
|
| - byte end, const char* mnem) {
|
| +void InstructionTable::SetTableRange(InstructionType type,
|
| + byte start,
|
| + byte end,
|
| + bool byte_size,
|
| + const char* mnem) {
|
| for (byte b = start; b <= end; b++) {
|
| InstructionDesc* id = &instructions_[b];
|
| assert(id->type == NO_INSTR); // Information already entered
|
| id->mnem = mnem;
|
| id->type = type;
|
| + id->byte_size_operation = byte_size;
|
| }
|
| }
|
|
|
| @@ -228,7 +270,8 @@
|
| abort_on_unimplemented_(
|
| unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE),
|
| rex_(0),
|
| - operand_size_(0) {
|
| + operand_size_(0),
|
| + byte_size_operand_(false) {
|
| tmp_buffer_[0] = '\0';
|
| }
|
|
|
| @@ -240,6 +283,12 @@
|
| int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
|
|
|
| private:
|
| + enum OperandSize {
|
| + BYTE_SIZE = 0,
|
| + WORD_SIZE = 1,
|
| + DOUBLEWORD_SIZE = 2,
|
| + QUADWORD_SIZE = 3
|
| + };
|
|
|
| const NameConverter& converter_;
|
| v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
|
| @@ -248,6 +297,8 @@
|
| // Prefixes parsed
|
| byte rex_;
|
| byte operand_size_;
|
| + // Byte size operand override.
|
| + bool byte_size_operand_;
|
|
|
| void setOperandSizePrefix(byte prefix) {
|
| ASSERT_EQ(0x66, prefix);
|
| @@ -272,12 +323,15 @@
|
|
|
| bool rex_w() { return (rex_ & 0x08) != 0; }
|
|
|
| - int operand_size() {
|
| - return rex_w() ? 64 : (operand_size_ != 0) ? 16 : 32;
|
| + OperandSize operand_size() {
|
| + if (byte_size_operand_) return BYTE_SIZE;
|
| + if (rex_w()) return QUADWORD_SIZE;
|
| + if (operand_size_ != 0) return WORD_SIZE;
|
| + return DOUBLEWORD_SIZE;
|
| }
|
|
|
| char operand_size_code() {
|
| - return rex_w() ? 'q' : (operand_size_ != 0) ? 'w' : 'l';
|
| + return "bwlq"[operand_size()];
|
| }
|
|
|
| const char* NameOfCPURegister(int reg) const {
|
| @@ -312,7 +366,7 @@
|
| int* base) {
|
| *scale = (data >> 6) & 3;
|
| *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0);
|
| - *base = data & 7 | (rex_b() ? 8 : 0);
|
| + *base = (data & 7) | (rex_b() ? 8 : 0);
|
| }
|
|
|
| typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const;
|
| @@ -322,11 +376,12 @@
|
| int PrintRightOperand(byte* modrmp);
|
| int PrintRightByteOperand(byte* modrmp);
|
| int PrintOperands(const char* mnem,
|
| - OperandOrder op_order,
|
| + OperandType op_order,
|
| byte* data);
|
| + int PrintImmediate(byte* data, OperandSize size);
|
| int PrintImmediateOp(byte* data);
|
| int F7Instruction(byte* data);
|
| - int D1D3C1Instruction(byte* data);
|
| + int ShiftInstruction(byte* data);
|
| int JumpShort(byte* data);
|
| int JumpConditional(byte* data);
|
| int JumpConditionalShort(byte* data);
|
| @@ -451,6 +506,36 @@
|
| }
|
|
|
|
|
| +int DisassemblerX64::PrintImmediate(byte* data, OperandSize size) {
|
| + int64_t value;
|
| + int count;
|
| + switch (size) {
|
| + case BYTE_SIZE:
|
| + value = *data;
|
| + count = 1;
|
| + break;
|
| + case WORD_SIZE:
|
| + value = *reinterpret_cast<int16_t*>(data);
|
| + count = 2;
|
| + break;
|
| + case DOUBLEWORD_SIZE:
|
| + value = *reinterpret_cast<uint32_t*>(data);
|
| + count = 4;
|
| + break;
|
| + case QUADWORD_SIZE:
|
| + value = *reinterpret_cast<int32_t*>(data);
|
| + count = 4;
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + value = 0; // Initialize variables on all paths to satisfy the compiler.
|
| + count = 0;
|
| + }
|
| + AppendToBuffer(V8_PTR_PREFIX"x", value);
|
| + return count;
|
| +}
|
| +
|
| +
|
| int DisassemblerX64::PrintRightOperand(byte* modrmp) {
|
| return PrintRightOperandHelper(modrmp,
|
| &DisassemblerX64::NameOfCPURegister);
|
| @@ -466,25 +551,30 @@
|
| // Returns number of bytes used including the current *data.
|
| // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
|
| int DisassemblerX64::PrintOperands(const char* mnem,
|
| - OperandOrder op_order,
|
| + OperandType op_order,
|
| byte* data) {
|
| byte modrm = *data;
|
| int mod, regop, rm;
|
| get_modrm(modrm, &mod, ®op, &rm);
|
| int advance = 0;
|
| + const char* register_name =
|
| + byte_size_operand_ ? NameOfByteCPURegister(regop)
|
| + : NameOfCPURegister(regop);
|
| switch (op_order) {
|
| case REG_OPER_OP_ORDER: {
|
| AppendToBuffer("%s%c %s,",
|
| mnem,
|
| operand_size_code(),
|
| - NameOfCPURegister(regop));
|
| - advance = PrintRightOperand(data);
|
| + register_name);
|
| + advance = byte_size_operand_ ? PrintRightByteOperand(data)
|
| + : PrintRightOperand(data);
|
| break;
|
| }
|
| case OPER_REG_OP_ORDER: {
|
| AppendToBuffer("%s%c ", mnem, operand_size_code());
|
| - advance = PrintRightOperand(data);
|
| - AppendToBuffer(",%s", NameOfCPURegister(regop));
|
| + advance = byte_size_operand_ ? PrintRightByteOperand(data)
|
| + : PrintRightOperand(data);
|
| + AppendToBuffer(",%s", register_name);
|
| break;
|
| }
|
| default:
|
| @@ -498,7 +588,7 @@
|
| // Returns number of bytes used by machine instruction, including *data byte.
|
| // Writes immediate instructions to 'tmp_buffer_'.
|
| int DisassemblerX64::PrintImmediateOp(byte* data) {
|
| - bool sign_extension_bit = (*data & 0x02) != 0;
|
| + bool byte_size_immediate = (*data & 0x02) != 0;
|
| byte modrm = *(data + 1);
|
| int mod, regop, rm;
|
| get_modrm(modrm, &mod, ®op, &rm);
|
| @@ -528,15 +618,12 @@
|
| default:
|
| UnimplementedInstruction();
|
| }
|
| - AppendToBuffer("%s ", mnem);
|
| + AppendToBuffer("%s%c ", mnem, operand_size_code());
|
| int count = PrintRightOperand(data + 1);
|
| - if (sign_extension_bit) {
|
| - AppendToBuffer(",0x%x", *(data + 1 + count));
|
| - return 1 + count + 1 /*int8*/;
|
| - } else {
|
| - AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
|
| - return 1 + count + 4 /*int32_t*/;
|
| - }
|
| + AppendToBuffer(",0x");
|
| + OperandSize immediate_size = byte_size_immediate ? BYTE_SIZE : operand_size();
|
| + count += PrintImmediate(data + 1 + count, immediate_size);
|
| + return 1 + count;
|
| }
|
|
|
|
|
| @@ -589,79 +676,66 @@
|
| }
|
|
|
|
|
| -int DisassemblerX64::D1D3C1Instruction(byte* data) {
|
| - byte op = *data;
|
| - assert(op == 0xD1 || op == 0xD3 || op == 0xC1);
|
| +int DisassemblerX64::ShiftInstruction(byte* data) {
|
| + byte op = *data & (~1);
|
| + if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
|
| + UnimplementedInstruction();
|
| + return 1;
|
| + }
|
| byte modrm = *(data + 1);
|
| int mod, regop, rm;
|
| get_modrm(modrm, &mod, ®op, &rm);
|
| ASSERT(regop < 8);
|
| int imm8 = -1;
|
| int num_bytes = 2;
|
| - if (mod == 3) {
|
| - const char* mnem = NULL;
|
| - if (op == 0xD1) {
|
| - imm8 = 1;
|
| - switch (regop) {
|
| - case 2:
|
| - mnem = "rcl";
|
| - break;
|
| - case 7:
|
| - mnem = "sar";
|
| - break;
|
| - case 4:
|
| - mnem = "shl";
|
| - break;
|
| - default:
|
| - UnimplementedInstruction();
|
| - }
|
| - } else if (op == 0xC1) {
|
| - imm8 = *(data + 2);
|
| - num_bytes = 3;
|
| - switch (regop) {
|
| - case 2:
|
| - mnem = "rcl";
|
| - break;
|
| - case 4:
|
| - mnem = "shl";
|
| - break;
|
| - case 5:
|
| - mnem = "shr";
|
| - break;
|
| - case 7:
|
| - mnem = "sar";
|
| - break;
|
| - default:
|
| - UnimplementedInstruction();
|
| - }
|
| - } else if (op == 0xD3) {
|
| - switch (regop) {
|
| - case 4:
|
| - mnem = "shl";
|
| - break;
|
| - case 5:
|
| - mnem = "shr";
|
| - break;
|
| - case 7:
|
| - mnem = "sar";
|
| - break;
|
| - default:
|
| - UnimplementedInstruction();
|
| - }
|
| - }
|
| - assert(mnem != NULL);
|
| - AppendToBuffer("%s%c %s,",
|
| - mnem,
|
| - operand_size_code(),
|
| - NameOfCPURegister(rm));
|
| - if (imm8 > 0) {
|
| - AppendToBuffer("%d", imm8);
|
| - } else {
|
| - AppendToBuffer("cl");
|
| - }
|
| - } else {
|
| + if (mod != 3) {
|
| UnimplementedInstruction();
|
| + return num_bytes;
|
| }
|
| + const char* mnem = NULL;
|
| + switch (regop) {
|
| + case 0:
|
| + mnem = "rol";
|
| + break;
|
| + case 1:
|
| + mnem = "ror";
|
| + break;
|
| + case 2:
|
| + mnem = "rcl";
|
| + break;
|
| + case 3:
|
| + mnem = "rcr";
|
| + break;
|
| + case 4:
|
| + mnem = "shl";
|
| + break;
|
| + case 5:
|
| + mnem = "shr";
|
| + break;
|
| + case 7:
|
| + mnem = "sar";
|
| + break;
|
| + default:
|
| + UnimplementedInstruction();
|
| + return num_bytes;
|
| + }
|
| + assert(mnem != NULL);
|
| + if (op == 0xD0) {
|
| + imm8 = 1;
|
| + } else if (op == 0xC0) {
|
| + imm8 = *(data + 2);
|
| + num_bytes = 3;
|
| + }
|
| + AppendToBuffer("%s%c %s,",
|
| + mnem,
|
| + operand_size_code(),
|
| + byte_size_operand_ ? NameOfByteCPURegister(rm)
|
| + : NameOfCPURegister(rm));
|
| + if (op == 0xD2) {
|
| + AppendToBuffer("cl");
|
| + } else {
|
| + AppendToBuffer("%d", imm8);
|
| + }
|
| return num_bytes;
|
| }
|
|
|
| @@ -716,30 +790,30 @@
|
| if (b1 == 0xD9) {
|
| const char* mnem = NULL;
|
| switch (b2) {
|
| - case 0xE8:
|
| - mnem = "fld1";
|
| + case 0xE0:
|
| + mnem = "fchs";
|
| break;
|
| - case 0xEE:
|
| - mnem = "fldz";
|
| - break;
|
| case 0xE1:
|
| mnem = "fabs";
|
| break;
|
| - case 0xE0:
|
| - mnem = "fchs";
|
| + case 0xE4:
|
| + mnem = "ftst";
|
| break;
|
| - case 0xF8:
|
| - mnem = "fprem";
|
| - break;
|
| case 0xF5:
|
| mnem = "fprem1";
|
| break;
|
| case 0xF7:
|
| mnem = "fincstp";
|
| break;
|
| - case 0xE4:
|
| - mnem = "ftst";
|
| + case 0xE8:
|
| + mnem = "fld1";
|
| break;
|
| + case 0xEE:
|
| + mnem = "fldz";
|
| + break;
|
| + case 0xF8:
|
| + mnem = "fprem";
|
| + break;
|
| }
|
| if (mnem != NULL) {
|
| AppendToBuffer("%s", mnem);
|
| @@ -906,7 +980,8 @@
|
| while (true) {
|
| current = *data;
|
| if (current == 0x66) {
|
| - setOperandSizePrefix(current);
|
| + // If the sequence is 66 0f, it's not a prefix, but a SSE escape.
|
| + if (*(data + 1) == 0x0F) break;
|
| data++;
|
| } else if ((current & 0xF0) == 0x40) {
|
| setRex(current);
|
| @@ -918,6 +993,7 @@
|
| }
|
|
|
| const InstructionDesc& idesc = instruction_table.Get(current);
|
| + byte_size_operand_ = idesc.byte_size_operation;
|
| switch (idesc.type) {
|
| case ZERO_OPERANDS_INSTR:
|
| AppendToBuffer(idesc.mnem);
|
| @@ -949,15 +1025,15 @@
|
| case MOVE_REG_INSTR: {
|
| byte* addr = NULL;
|
| switch (operand_size()) {
|
| - case 16:
|
| + case WORD_SIZE:
|
| addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
|
| data += 3;
|
| break;
|
| - case 32:
|
| + case DOUBLEWORD_SIZE:
|
| addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
|
| data += 5;
|
| break;
|
| - case 64:
|
| + case QUADWORD_SIZE:
|
| addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
|
| data += 9;
|
| break;
|
| @@ -1012,8 +1088,8 @@
|
| AppendToBuffer("imul %s,%s,0x%x", NameOfCPURegister(regop),
|
| NameOfCPURegister(rm), imm);
|
| data += 2 + (*data == 0x6B ? 1 : 4);
|
| + break;
|
| }
|
| - break;
|
|
|
| case 0xF6: {
|
| int mod, regop, rm;
|
| @@ -1024,8 +1100,8 @@
|
| UnimplementedInstruction();
|
| }
|
| data += 3;
|
| + break;
|
| }
|
| - break;
|
|
|
| case 0x81: // fall through
|
| case 0x83: // 0x81 with sign extension bit set
|
| @@ -1170,13 +1246,13 @@
|
| case 0x95:
|
| case 0x96:
|
| case 0x97: {
|
| - int reg = current & 0x7 | (rex_b() ? 8 : 0);
|
| + int reg = (current & 0x7) | (rex_b() ? 8 : 0);
|
| if (reg == 0) {
|
| AppendToBuffer("nop"); // Common name for xchg rax,rax.
|
| } else {
|
| AppendToBuffer("xchg%c rax, %s",
|
| operand_size_code(),
|
| - NameOfByteCPURegister(reg));
|
| + NameOfCPURegister(reg));
|
| }
|
| }
|
|
|
| @@ -1209,18 +1285,40 @@
|
| data += 2;
|
| break;
|
|
|
| - case 0xA9:
|
| - AppendToBuffer("test%c rax,0x%x", // CHECKME!
|
| + case 0xA9: {
|
| + int64_t value;
|
| + switch (operand_size()) {
|
| + case WORD_SIZE:
|
| + value = *reinterpret_cast<uint16_t*>(data + 1);
|
| + data += 3;
|
| + break;
|
| + case DOUBLEWORD_SIZE:
|
| + value = *reinterpret_cast<uint32_t*>(data + 1);
|
| + data += 5;
|
| + break;
|
| + case QUADWORD_SIZE:
|
| + value = *reinterpret_cast<int32_t*>(data + 1);
|
| + data += 5;
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| + break;
|
| + AppendToBuffer("test%c rax,0x%"V8_PTR_PREFIX"ux",
|
| operand_size_code(),
|
| - *reinterpret_cast<int32_t*>(data + 1));
|
| - data += 5;
|
| - break;
|
| -
|
| + value);
|
| + }
|
| case 0xD1: // fall through
|
| case 0xD3: // fall through
|
| case 0xC1:
|
| - data += D1D3C1Instruction(data);
|
| + data += ShiftInstruction(data);
|
| break;
|
| + case 0xD0: // fall through
|
| + case 0xD2: // fall through
|
| + case 0xC0:
|
| + byte_size_operand_ = true;
|
| + data += ShiftInstruction(data);
|
| + break;
|
|
|
| case 0xD9: // fall through
|
| case 0xDA: // fall through
|
| @@ -1289,11 +1387,17 @@
|
| break;
|
|
|
| case 0xF3:
|
| - if (*(data + 1) == 0x0F && *(data + 2) == 0x2C) {
|
| - data += 3;
|
| - data += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, data);
|
| + if (*(data + 1) == 0x0F) {
|
| + if (*(data + 2) == 0x2C) {
|
| + data += 3;
|
| + data += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, data);
|
| + } else {
|
| + UnimplementedInstruction();
|
| + data += 1;
|
| + }
|
| } else {
|
| UnimplementedInstruction();
|
| + data += 1;
|
| }
|
| break;
|
|
|
| @@ -1303,6 +1407,7 @@
|
|
|
| default:
|
| UnimplementedInstruction();
|
| + data += 1;
|
| }
|
| } // !processed
|
|
|
|
|