Add cmpxchg and lock instructions to x64 and ia32 {dis,}assemblers

Review-Url: https://codereview.chromium.org/1986113004
Cr-Commit-Position: refs/heads/master@{#36341}
This commit is contained in:
binji 2016-05-18 17:55:08 -07:00 committed by Commit bot
parent 04aa9436ce
commit 5c22cf5ae7
8 changed files with 155 additions and 6 deletions

View File

@ -730,6 +730,33 @@ void Assembler::xchg_w(Register reg, const Operand& op) {
emit_operand(reg, op); emit_operand(reg, op);
} }
void Assembler::lock() {
EnsureSpace ensure_space(this);
EMIT(0xF0);
}
void Assembler::cmpxchg(const Operand& dst, Register src) {
EnsureSpace ensure_space(this);
EMIT(0x0F);
EMIT(0xB1);
emit_operand(src, dst);
}
void Assembler::cmpxchg_b(const Operand& dst, Register src) {
EnsureSpace ensure_space(this);
EMIT(0x0F);
EMIT(0xB0);
emit_operand(src, dst);
}
void Assembler::cmpxchg_w(const Operand& dst, Register src) {
EnsureSpace ensure_space(this);
EMIT(0x66);
EMIT(0x0F);
EMIT(0xB1);
emit_operand(src, dst);
}
void Assembler::adc(Register dst, int32_t imm32) { void Assembler::adc(Register dst, int32_t imm32) {
EnsureSpace ensure_space(this); EnsureSpace ensure_space(this);
emit_arith(2, Operand(dst), Immediate(imm32)); emit_arith(2, Operand(dst), Immediate(imm32));

View File

@ -662,6 +662,14 @@ class Assembler : public AssemblerBase {
void xchg_b(Register reg, const Operand& op); void xchg_b(Register reg, const Operand& op);
void xchg_w(Register reg, const Operand& op); void xchg_w(Register reg, const Operand& op);
// Lock prefix
void lock();
// CompareExchange
void cmpxchg(const Operand& dst, Register src);
void cmpxchg_b(const Operand& dst, Register src);
void cmpxchg_w(const Operand& dst, Register src);
// Arithmetics // Arithmetics
void adc(Register dst, int32_t imm32); void adc(Register dst, int32_t imm32);
void adc(Register dst, const Operand& src); void adc(Register dst, const Operand& src);

View File

@ -1232,6 +1232,10 @@ static const char* F0Mnem(byte f0byte) {
return "shrd"; // 3-operand version. return "shrd"; // 3-operand version.
case 0xAB: case 0xAB:
return "bts"; return "bts";
case 0xB0:
return "cmpxchg_b";
case 0xB1:
return "cmpxchg";
case 0xBC: case 0xBC:
return "bsf"; return "bsf";
case 0xBD: case 0xBD:
@ -1264,6 +1268,9 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
vex_byte0_ = *data; vex_byte0_ = *data;
vex_byte1_ = *(data + 1); vex_byte1_ = *(data + 1);
data += 2; data += 2;
} else if (*data == 0xF0 /*lock*/) {
AppendToBuffer("lock ");
data++;
} }
bool processed = true; // Will be set to false if the current instruction bool processed = true; // Will be set to false if the current instruction
@ -1496,6 +1503,18 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
} else { } else {
AppendToBuffer(",%s,cl", NameOfCPURegister(regop)); AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
} }
} else if (f0byte == 0xB0) {
// cmpxchg_b
data += 2;
AppendToBuffer("%s ", f0mnem);
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
data += PrintRightOperand(data);
AppendToBuffer(",%s", NameOfByteCPURegister(regop));
} else if (f0byte == 0xB1) {
// cmpxchg
data += 2;
data += PrintOperands(f0mnem, OPER_REG_OP_ORDER, data);
} else if (f0byte == 0xBC) { } else if (f0byte == 0xBC) {
data += 2; data += 2;
int mod, regop, rm; int mod, regop, rm;
@ -1612,9 +1631,8 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
data++; data++;
int mod, regop, rm; int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm); get_modrm(*data, &mod, &regop, &rm);
AppendToBuffer("xchg_w "); AppendToBuffer("xchg_w %s,", NameOfCPURegister(regop));
data += PrintRightOperand(data); data += PrintRightOperand(data);
AppendToBuffer(",%s", NameOfCPURegister(regop));
} else if (*data == 0x89) { } else if (*data == 0x89) {
data++; data++;
int mod, regop, rm; int mod, regop, rm;
@ -1884,6 +1902,9 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
NameOfXMMRegister(regop), NameOfXMMRegister(regop),
NameOfXMMRegister(rm)); NameOfXMMRegister(rm));
data++; data++;
} else if (*data == 0xB1) {
data++;
data += PrintOperands("cmpxchg_w", OPER_REG_OP_ORDER, data);
} else { } else {
UnimplementedInstruction(); UnimplementedInstruction();
} }

View File

@ -1016,6 +1016,40 @@ void Assembler::cmpb_al(Immediate imm8) {
emit(imm8.value_); emit(imm8.value_);
} }
void Assembler::lock() {
EnsureSpace ensure_space(this);
emit(0xf0);
}
void Assembler::cmpxchgb(const Operand& dst, Register src) {
EnsureSpace ensure_space(this);
if (!src.is_byte_register()) {
// Register is not one of al, bl, cl, dl. Its encoding needs REX.
emit_rex_32(src, dst);
} else {
emit_optional_rex_32(src, dst);
}
emit(0x0f);
emit(0xb0);
emit_operand(src, dst);
}
void Assembler::cmpxchgw(const Operand& dst, Register src) {
EnsureSpace ensure_space(this);
emit(0x66);
emit_optional_rex_32(src, dst);
emit(0x0f);
emit(0xb1);
emit_operand(src, dst);
}
void Assembler::emit_cmpxchg(const Operand& dst, Register src, int size) {
EnsureSpace ensure_space(this);
emit_rex(src, dst, size);
emit(0x0f);
emit(0xb1);
emit_operand(src, dst);
}
void Assembler::cpuid() { void Assembler::cpuid() {
EnsureSpace ensure_space(this); EnsureSpace ensure_space(this);

View File

@ -421,11 +421,11 @@ class Operand BASE_EMBEDDED {
friend class Assembler; friend class Assembler;
}; };
#define ASSEMBLER_INSTRUCTION_LIST(V) \ #define ASSEMBLER_INSTRUCTION_LIST(V) \
V(add) \ V(add) \
V(and) \ V(and) \
V(cmp) \ V(cmp) \
V(cmpxchg) \
V(dec) \ V(dec) \
V(idiv) \ V(idiv) \
V(div) \ V(div) \
@ -445,7 +445,6 @@ class Operand BASE_EMBEDDED {
V(xchg) \ V(xchg) \
V(xor) V(xor)
// Shift instructions on operands/registers with kPointerSize, kInt32Size and // Shift instructions on operands/registers with kPointerSize, kInt32Size and
// kInt64Size. // kInt64Size.
#define SHIFT_INSTRUCTION_LIST(V) \ #define SHIFT_INSTRUCTION_LIST(V) \
@ -788,9 +787,15 @@ class Assembler : public AssemblerBase {
void decb(Register dst); void decb(Register dst);
void decb(const Operand& dst); void decb(const Operand& dst);
// Lock prefix.
void lock();
void xchgb(Register reg, const Operand& op); void xchgb(Register reg, const Operand& op);
void xchgw(Register reg, const Operand& op); void xchgw(Register reg, const Operand& op);
void cmpxchgb(const Operand& dst, Register src);
void cmpxchgw(const Operand& dst, Register src);
// Sign-extends rax into rdx:rax. // Sign-extends rax into rdx:rax.
void cqo(); void cqo();
// Sign-extends eax into edx:eax. // Sign-extends eax into edx:eax.
@ -2054,6 +2059,11 @@ class Assembler : public AssemblerBase {
immediate_arithmetic_op(0x7, dst, src, size); immediate_arithmetic_op(0x7, dst, src, size);
} }
// Compare {al,ax,eax,rax} with src. If equal, set ZF and write dst into
// src. Otherwise clear ZF and write src into {al,ax,eax,rax}. This
// operation is only atomic if prefixed by the lock instruction.
void emit_cmpxchg(const Operand& dst, Register src, int size);
void emit_dec(Register dst, int size); void emit_dec(Register dst, int size);
void emit_dec(const Operand& dst, int size); void emit_dec(const Operand& dst, int size);

View File

@ -142,19 +142,18 @@ enum InstructionType {
SHORT_IMMEDIATE_INSTR SHORT_IMMEDIATE_INSTR
}; };
enum Prefixes { enum Prefixes {
ESCAPE_PREFIX = 0x0F, ESCAPE_PREFIX = 0x0F,
OPERAND_SIZE_OVERRIDE_PREFIX = 0x66, OPERAND_SIZE_OVERRIDE_PREFIX = 0x66,
ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67, ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67,
VEX3_PREFIX = 0xC4, VEX3_PREFIX = 0xC4,
VEX2_PREFIX = 0xC5, VEX2_PREFIX = 0xC5,
LOCK_PREFIX = 0xF0,
REPNE_PREFIX = 0xF2, REPNE_PREFIX = 0xF2,
REP_PREFIX = 0xF3, REP_PREFIX = 0xF3,
REPEQ_PREFIX = REP_PREFIX REPEQ_PREFIX = REP_PREFIX
}; };
struct InstructionDesc { struct InstructionDesc {
const char* mnem; const char* mnem;
InstructionType type; InstructionType type;
@ -1607,6 +1606,8 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
AppendToBuffer("%s %s,%d", (regop == 6) ? "psllq" : "psrlq", AppendToBuffer("%s %s,%d", (regop == 6) ? "psllq" : "psrlq",
NameOfXMMRegister(rm), *current & 0x7f); NameOfXMMRegister(rm), *current & 0x7f);
current += 1; current += 1;
} else if (opcode == 0xB1) {
current += PrintOperands("cmpxchg", OPER_REG_OP_ORDER, current);
} else { } else {
const char* mnemonic = "?"; const char* mnemonic = "?";
if (opcode == 0x54) { if (opcode == 0x54) {
@ -1884,6 +1885,12 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
current += PrintRightOperand(current); current += PrintRightOperand(current);
} else if (opcode == 0x0B) { } else if (opcode == 0x0B) {
AppendToBuffer("ud2"); AppendToBuffer("ud2");
} else if (opcode == 0xB0 || opcode == 0xB1) {
// CMPXCHG.
if (opcode == 0xB0) {
byte_size_operand_ = true;
}
current += PrintOperands(mnemonic, OPER_REG_OP_ORDER, current);
} else { } else {
UnimplementedInstruction(); UnimplementedInstruction();
} }
@ -1926,6 +1933,9 @@ const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
return "shrd"; return "shrd";
case 0xAF: case 0xAF:
return "imul"; return "imul";
case 0xB0:
case 0xB1:
return "cmpxchg";
case 0xB6: case 0xB6:
return "movzxb"; return "movzxb";
case 0xB7: case 0xB7:
@ -1963,6 +1973,8 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
if (rex_w()) AppendToBuffer("REX.W "); if (rex_w()) AppendToBuffer("REX.W ");
} else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3). } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3).
group_1_prefix_ = current; group_1_prefix_ = current;
} else if (current == LOCK_PREFIX) {
AppendToBuffer("lock ");
} else if (current == VEX3_PREFIX) { } else if (current == VEX3_PREFIX) {
vex_byte0_ = current; vex_byte0_ = current;
vex_byte1_ = *(data + 1); vex_byte1_ = *(data + 1);

View File

@ -665,12 +665,30 @@ TEST(DisasmIa320) {
// xchg. // xchg.
{ {
__ xchg_b(eax, Operand(eax, 8));
__ xchg_w(eax, Operand(ebx, 8));
__ xchg(eax, eax); __ xchg(eax, eax);
__ xchg(eax, ebx); __ xchg(eax, ebx);
__ xchg(ebx, ebx); __ xchg(ebx, ebx);
__ xchg(ebx, Operand(esp, 12)); __ xchg(ebx, Operand(esp, 12));
} }
// cmpxchg.
{
__ cmpxchg_b(Operand(esp, 12), eax);
__ cmpxchg_w(Operand(ebx, ecx, times_4, 10000), eax);
__ cmpxchg(Operand(ebx, ecx, times_4, 10000), eax);
}
// lock prefix.
{
__ lock();
__ cmpxchg(Operand(esp, 12), ebx);
__ lock();
__ xchg_w(eax, Operand(ecx, 8));
}
// Nop instructions // Nop instructions
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
__ Nop(i); __ Nop(i);

View File

@ -745,12 +745,31 @@ TEST(DisasmX64) {
// xchg. // xchg.
{ {
__ xchgb(rax, Operand(rax, 8));
__ xchgw(rax, Operand(rbx, 8));
__ xchgq(rax, rax); __ xchgq(rax, rax);
__ xchgq(rax, rbx); __ xchgq(rax, rbx);
__ xchgq(rbx, rbx); __ xchgq(rbx, rbx);
__ xchgq(rbx, Operand(rsp, 12)); __ xchgq(rbx, Operand(rsp, 12));
} }
// cmpxchg.
{
__ cmpxchgb(Operand(rsp, 12), rax);
__ cmpxchgw(Operand(rbx, rcx, times_4, 10000), rax);
__ cmpxchgl(Operand(rbx, rcx, times_4, 10000), rax);
__ cmpxchgq(Operand(rbx, rcx, times_4, 10000), rax);
}
// lock prefix.
{
__ lock();
__ cmpxchgl(Operand(rsp, 12), rbx);
__ lock();
__ xchgw(rax, Operand(rcx, 8));
}
// Nop instructions // Nop instructions
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
__ Nop(i); __ Nop(i);