diff --git a/decode.c b/decode.c index 3c8cc35..ccba6f3 100644 --- a/decode.c +++ b/decode.c @@ -244,7 +244,6 @@ prefix_end: // there is a REP prefix, then the 66h prefix is ignored here. uint8_t mandatory_prefix = prefix_rep ? prefix_rep : !!prefix_66; table_idx = table_walk(table_idx, mandatory_prefix, &kind); - prefix_rep = 0; // Don't include REP/REPNZ in instr flags } // Then, walk through ModR/M-encoded opcode extensions. diff --git a/format.c b/format.c index a719492..e844c4a 100644 --- a/format.c +++ b/format.c @@ -125,6 +125,7 @@ fd_format_abs(const FdInstr* instr, uint64_t addr, char* buffer, size_t len) const char* mnemonic = fdi_name(FD_TYPE(instr)); bool prefix_rep = false; + bool prefix_xacq_xrel = false; bool prefix_addrsize = false; bool prefix_segment = false; @@ -183,6 +184,16 @@ fd_format_abs(const FdInstr* instr, uint64_t addr, char* buffer, size_t len) FD_OP_REG_TYPE(instr, 0) == FD_RT_SEG) sizesuffix[0] = 'w'; break; + case FDI_XCHG: + if (FD_OP_TYPE(instr, 0) == FD_OT_MEM) + prefix_xacq_xrel = true; + break; + case FDI_MOV: + // MOV C6h/C7h can have XRELEASE prefix. + if (FD_HAS_REP(instr) && FD_OP_TYPE(instr, 0) == FD_OT_MEM && + FD_OP_TYPE(instr, 1) == FD_OT_IMM) + prefix_xacq_xrel = true; + break; case FDI_FXSAVE: case FDI_FXRSTOR: case FDI_XSAVE: @@ -217,7 +228,12 @@ fd_format_abs(const FdInstr* instr, uint64_t addr, char* buffer, size_t len) default: break; } - if (prefix_rep) { + if (prefix_xacq_xrel || FD_HAS_LOCK(instr)) { + if (FD_HAS_REP(instr)) + buf = fd_strplcpy(buf, "xrelease ", end-buf); + if (FD_HAS_REPNZ(instr)) + buf = fd_strplcpy(buf, "xacquire ", end-buf); + } else if (prefix_rep) { if (FD_HAS_REP(instr)) buf = fd_strplcpy(buf, "rep ", end-buf); if (FD_HAS_REPNZ(instr)) diff --git a/tests/test_decode.c b/tests/test_decode.c index 0c574b4..548f418 100644 --- a/tests/test_decode.c +++ b/tests/test_decode.c @@ -90,6 +90,32 @@ main(int argc, char** argv) TEST64("\xf2\x0f\xc7\x0f", "cmpxchg8b qword ptr [rdi]"); TEST32("\xf3\x0f\xc7\x0f", "cmpxchg8b qword ptr [edi]"); TEST64("\xf3\x0f\xc7\x0f", "cmpxchg8b qword ptr [rdi]"); + TEST32("\xf2\xf0\x0f\xc7\x0f", "xacquire lock cmpxchg8b qword ptr [edi]"); + TEST64("\xf2\xf0\x0f\xc7\x0f", "xacquire lock cmpxchg8b qword ptr [rdi]"); + TEST32("\xf3\xf0\x0f\xc7\x0f", "xrelease lock cmpxchg8b qword ptr [edi]"); + TEST64("\xf3\xf0\x0f\xc7\x0f", "xrelease lock cmpxchg8b qword ptr [rdi]"); + TEST32("\x87\x0f", "xchg dword ptr [edi], ecx"); + TEST64("\x87\x0f", "xchg dword ptr [rdi], ecx"); + TEST32("\xf2\x87\x0f", "xacquire xchg dword ptr [edi], ecx"); + TEST64("\xf2\x87\x0f", "xacquire xchg dword ptr [rdi], ecx"); + TEST32("\xf3\x87\x0f", "xrelease xchg dword ptr [edi], ecx"); + TEST64("\xf3\x87\x0f", "xrelease xchg dword ptr [rdi], ecx"); + TEST32("\xf2\xf0\x87\x0f", "xacquire lock xchg dword ptr [edi], ecx"); + TEST64("\xf2\xf0\x87\x0f", "xacquire lock xchg dword ptr [rdi], ecx"); + TEST32("\xf3\xf0\x87\x0f", "xrelease lock xchg dword ptr [edi], ecx"); + TEST64("\xf3\xf0\x87\x0f", "xrelease lock xchg dword ptr [rdi], ecx"); + TEST32("\xc6\x07\x12", "mov byte ptr [edi], 0x12"); + TEST64("\xc6\x07\x12", "mov byte ptr [rdi], 0x12"); + TEST32("\xf2\xc6\x07\x12", "mov byte ptr [edi], 0x12"); // no xacquire + TEST64("\xf2\xc6\x07\x12", "mov byte ptr [rdi], 0x12"); // no xacquire + TEST32("\xf3\xc6\x07\x12", "xrelease mov byte ptr [edi], 0x12"); + TEST64("\xf3\xc6\x07\x12", "xrelease mov byte ptr [rdi], 0x12"); + TEST32("\x66\xc7\x07\x34\x12", "mov word ptr [edi], 0x1234"); + TEST64("\x66\xc7\x07\x34\x12", "mov word ptr [rdi], 0x1234"); + TEST32("\x66\xf2\xc7\x07\x34\x12", "mov word ptr [edi], 0x1234"); // no xacquire + TEST64("\x66\xf2\xc7\x07\x34\x12", "mov word ptr [rdi], 0x1234"); // no xacquire + TEST32("\x66\xf3\xc7\x07\x34\x12", "xrelease mov word ptr [edi], 0x1234"); + TEST64("\x66\xf3\xc7\x07\x34\x12", "xrelease mov word ptr [rdi], 0x1234"); TEST("\x66", "PARTIAL"); TEST("\xf0", "PARTIAL"); TEST("\x0f", "PARTIAL");