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:
parent
04aa9436ce
commit
5c22cf5ae7
@ -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));
|
||||||
|
@ -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);
|
||||||
|
@ -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, ®op, &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, ®op, &rm);
|
get_modrm(*data, &mod, ®op, &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();
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user