Skip to content

Commit

Permalink
Add decode/encode support for additional Intel cache management instr…
Browse files Browse the repository at this point in the history
…uctions. (#7109)

This covers the CLWB/CLDEMOTE extensions and the previously omitted
CLFLUSHOPT instruction.

Because these instructions explicitly forbid modrm.mod == 3 a sequence
from the binutils tests that previously decoded as a nop but now would
decode as a CLDEMOTE with modrm.mod == 3 is removed.
  • Loading branch information
khuey authored Dec 10, 2024
1 parent 2fe63a0 commit e24dbb0
Show file tree
Hide file tree
Showing 11 changed files with 382 additions and 310 deletions.
47 changes: 43 additions & 4 deletions core/ir/x86/decode_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ const instr_info_t * const op_instr[] =
/* OP_stmxcsr */ &e_vex_extensions[62][0],
/* OP_lfence */ &mod_extensions[6][1],
/* OP_mfence */ &mod_extensions[7][1],
/* OP_clflush */ &mod_extensions[3][0],
/* OP_clflush */ &prefix_extensions[194][0],
/* OP_sfence */ &mod_extensions[3][1],
/* OP_prefetchnta */ &base_extensions[23][0],
/* OP_prefetcht0 */ &base_extensions[23][1],
Expand Down Expand Up @@ -1655,6 +1655,15 @@ const instr_info_t * const op_instr[] =

/* RDPID */
/* OP_rdpid */ &prefix_extensions[193][1],

/* Not really part of CLWB but never got added earlier. */
/* OP_clflushopt */ &prefix_extensions[194][2],

/* CLWB */
/* OP_clwb */ &mod_extensions[123][0],

/* CLDEMOTE */
/* OP_cldemote */ &second_byte[0x1c],
};


Expand Down Expand Up @@ -2517,7 +2526,7 @@ const instr_info_t second_byte[] = {
{OP_nop_modrm, 0x0f1910, catSIMD, "nop", xx, xx, Ed, xx, xx, mrm, x, END_LIST},
{PREFIX_EXT, 0x0f1a10, catUncategorized, "(prefix ext 186)", xx, xx, xx, xx, xx, mrm, x, 186},
{PREFIX_EXT, 0x0f1b10, catUncategorized, "(prefix ext 187)", xx, xx, xx, xx, xx, mrm, x, 187},
{OP_nop_modrm, 0x0f1c10, catSIMD, "nop", xx, xx, Ed, xx, xx, mrm, x, END_LIST},
{OP_cldemote, 0x0f1c30, catOther, "cldemote", xx, xx, Mb, xx, xx, mrm|reqp, x, END_LIST},
{OP_nop_modrm, 0x0f1d10, catSIMD, "nop", xx, xx, Ed, xx, xx, mrm, x, END_LIST},
{OP_nop_modrm, 0x0f1e10, catSIMD, "nop", xx, xx, Ed, xx, xx, mrm, x, END_LIST},
{OP_nop_modrm, 0x0f1f10, catSIMD, "nop", xx, xx, Ed, xx, xx, mrm, x, END_LIST},
Expand Down Expand Up @@ -5946,6 +5955,32 @@ const instr_info_t prefix_extensions[][12] = {
{INVALID, 0xf30fc737, catUncategorized, "(bad)" , xx, xx, xx, xx, xx, no, x, NA},
{INVALID, 0x660fc737, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
{INVALID, 0xf20fc737, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
},{ /* prefix extension 194 */
{OP_clflush, 0x0fae37, catSIMD, "clflush", xx, xx, Mb, xx, xx, mrm, x, END_LIST},
{INVALID, 0xf30fae37, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
{OP_clflushopt, 0x660fae37, catOther, "clflushopt", xx, xx, Mb, xx, xx, mrm, x, END_LIST},
{INVALID, 0xf20fae37, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
{INVALID, 0x0fae37, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
{INVALID, 0xf30fae37, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
{INVALID, 0x660fae37, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
{INVALID, 0xf20fae37, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
{INVALID, 0x0fae37, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
{INVALID, 0xf30fae37, catUncategorized, "(bad)" , xx, xx, xx, xx, xx, no, x, NA},
{INVALID, 0x660fae37, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
{INVALID, 0xf20fae37, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
},{ /* prefix extension 195 */
{REX_W_EXT, 0x0fae36, catUncategorized, "(rex.w ext 4)", xx, xx, xx, xx, xx, mrm, x, 4},
{INVALID, 0xf30fae36, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
{MOD_EXT, 0x660fae36, catUncategorized, "(mod ext 123)", xx, xx, xx, xx, xx, mrm, x, 123},
{INVALID, 0xf20fae36, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
{INVALID, 0x0fae36, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
{INVALID, 0xf30fae36, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
{INVALID, 0x660fae36, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
{INVALID, 0xf20fae36, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
{INVALID, 0x0fae36, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
{INVALID, 0xf30fae36, catUncategorized, "(bad)" , xx, xx, xx, xx, xx, no, x, NA},
{INVALID, 0x660fae36, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
{INVALID, 0xf20fae36, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
}
};
/****************************************************************************
Expand Down Expand Up @@ -6596,7 +6631,7 @@ const instr_info_t mod_extensions[][2] = {
{RM_EXT, 0x0f0177, catUncategorized, "(group 7 mod + rm ext 2)", xx, xx, xx, xx, xx, mrm, x, 2},
},
{ /* mod extension 3 */
{OP_clflush, 0x0fae37, catSIMD, "clflush", xx, xx, Mb, xx, xx, mrm, x, END_LIST},
{PREFIX_EXT, 0x0fae37, catUncategorized, "(prefix ext 194)", xx, xx, xx, xx, xx, no, x, 194},
// If we add an "atomic" category we'd put this there.
// Without it, "state" might best be interpreted as a barrier, so we use it for
// all the OP_*fence opcodes.
Expand All @@ -6616,7 +6651,7 @@ const instr_info_t mod_extensions[][2] = {
{OP_lfence, 0xe80fae75, catState, "lfence", xx, xx, xx, xx, xx, mrm, x, END_LIST},
},
{ /* mod extension 7 */
{REX_W_EXT, 0x0fae36, catUncategorized, "(rex.w ext 4)", xx, xx, xx, xx, xx, mrm, x, 4},
{PREFIX_EXT, 0x0fae36, catUncategorized, "(prefix ext 195)", xx, xx, xx, xx, xx, no, x, 195},
{OP_mfence, 0xf00fae76, catState, "mfence", xx, xx, xx, xx, xx, mrm, x, END_LIST},
},
{ /* mod extension 8 */
Expand Down Expand Up @@ -7087,6 +7122,10 @@ const instr_info_t mod_extensions[][2] = {
{OP_enqcmd, 0xf238f808, catMove | catOther, "enqcmd", GesvS_oq, xx, Moq, xx, xx, mrm, fW6, END_LIST},
{INVALID, 0xf238f808, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, END_LIST},
},
{ /* mod extension 123 */
{OP_clwb, 0x660fae36, catOther, "clwb", xx, xx, Mb, xx, xx, mrm, no, END_LIST},
{INVALID, 0x660fae36, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, END_LIST},
},
};

/* Naturally all of these have modrm bytes even if they have no explicit operands */
Expand Down
24 changes: 24 additions & 0 deletions core/ir/x86/instr_create_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,30 @@
* created with OPND_CREATE_MEM_clflush() to get the appropriate operand size.
*/
#define INSTR_CREATE_clflush(dc, s) instr_create_0dst_1src((dc), OP_clflush, (s))
/**
* This INSTR_CREATE_xxx macro creates an instr_t with opcode OP_xxx and
* the given explicit operands, automatically supplying any implicit operands.
* \param dc The void * dcontext used to allocate memory for the instr_t.
* \param s The opnd_t explicit source operand for the instruction, which can be
* created with OPND_CREATE_MEM_clflush() to get the appropriate operand size.
*/
#define INSTR_CREATE_clflushopt(dc, s) instr_create_0dst_1src((dc), OP_clflushopt, (s))
/**
* This INSTR_CREATE_xxx macro creates an instr_t with opcode OP_xxx and
* the given explicit operands, automatically supplying any implicit operands.
* \param dc The void * dcontext used to allocate memory for the instr_t.
* \param s The opnd_t explicit source operand for the instruction, which can be
* created with OPND_CREATE_MEM_clflush() to get the appropriate operand size.
*/
#define INSTR_CREATE_clwb(dc, s) instr_create_0dst_1src((dc), OP_clwb, (s))
/**
* This INSTR_CREATE_xxx macro creates an instr_t with opcode OP_xxx and
* the given explicit operands, automatically supplying any implicit operands.
* \param dc The void * dcontext used to allocate memory for the instr_t.
* \param s The opnd_t explicit source operand for the instruction, which can be
* created with OPND_CREATE_MEM_clflush() to get the appropriate operand size.
*/
#define INSTR_CREATE_cldemote(dc, s) instr_create_0dst_1src((dc), OP_cldemote, (s))
/**
* This INSTR_CREATE_xxx macro creates an instr_t with opcode OP_xxx and the
* given explicit operands, automatically supplying any implicit operands.
Expand Down
9 changes: 9 additions & 0 deletions core/ir/x86/opcode_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -1642,6 +1642,15 @@ enum {
/* RDPID */
/* 1448 */ OP_rdpid, /**< IA-32/AMD64 rdpid opcode. */

/* Not really part of CLWB but never got added earlier. */
/* 1449 */ OP_clflushopt, /**< IA-32/AMD64 clflushopt opcode. */

/* CLWB */
/* 1450 */ OP_clwb, /**< IA-32/AMD64 clwb opcode. */

/* CLDEMOTE */
/* 1451 */ OP_cldemote, /**< IA-32/AMD64 cldemote opcode. */

OP_AFTER_LAST,
OP_FIRST = OP_add, /**< First real opcode. */
OP_LAST = OP_AFTER_LAST - 1, /**< Last real opcode. */
Expand Down
2 changes: 1 addition & 1 deletion suite/tests/api/dis-x64.expect
Original file line number Diff line number Diff line change
Expand Up @@ -2897,7 +2897,7 @@
+0x1ca0 3a f5 cmp dh, ch
+0x1ca2 48 bf 79 0f c9 63 6d mov rdi, 0x77705d6d63c90f79
5d 70 77
+0x1cac 0f 1c 4f 65 nop dword ptr [rdi+0x65]
+0x1cac 0f 1c 4f 65 cldemote byte ptr [rdi+0x65]
+0x1cb0 74 2a jz 0x0000000010001cdc
+0x1cb2 12 cc adc cl, ah
+0x1cb4 37...?? <INVALID>
Expand Down
2 changes: 1 addition & 1 deletion suite/tests/api/dis-x86.expect
Original file line number Diff line number Diff line change
Expand Up @@ -2960,7 +2960,7 @@
+0x1ca8 6d insd
+0x1ca9 5d pop ebp
+0x1caa 70 77 jo 0x10001d23
+0x1cac 0f 1c 4f 65 nop dword ptr [edi+0x65]
+0x1cac 0f 1c 4f 65 cldemote byte ptr [edi+0x65]
+0x1cb0 74 2a jz 0x10001cdc
+0x1cb2 12 cc adc cl, ah
+0x1cb4 37 aaa
Expand Down
5 changes: 3 additions & 2 deletions suite/tests/api/ir_x86.c
Original file line number Diff line number Diff line change
Expand Up @@ -1293,9 +1293,10 @@ test_hint_nops(void *dc)
/* other types of hintable nop [eax] */
buf[2] = 0x00;
for (buf[1] = 0x19; buf[1] <= 0x1f; buf[1]++) {
/* Intel is using these encodings now for the MPX instructions bndldx and bndstx.
/* Intel is using these encodings now for the MPX instructions bndldx and bndstx,
* and cldemote.
*/
if (buf[1] == 0x1a || buf[1] == 0x1b)
if (buf[1] == 0x1a || buf[1] == 0x1b || buf[1] == 0x1c)
continue;
pc = decode(dc, buf, instr);
ASSERT(instr_get_opcode(instr) == OP_nop_modrm);
Expand Down
3 changes: 3 additions & 0 deletions suite/tests/api/ir_x86_1args.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ OPCODE(xsaveopt32, xsaveopt32, xsaveopt32, 0, MEMARG(OPSZ_xsave))
OPCODE(xsaveopt64, xsaveopt64, xsaveopt64, X64_ONLY, MEMARG(OPSZ_xsave))
OPCODE(xsavec32, xsavec32, xsavec32, 0, MEMARG(OPSZ_xsave))
OPCODE(xsavec64, xsavec64, xsavec64, X64_ONLY, MEMARG(OPSZ_xsave))
OPCODE(clflushopt, clflushopt, clflushopt, 0, MEMARG(OPSZ_clflush))
OPCODE(clwb, clwb, clwb, 0, MEMARG(OPSZ_clflush))
OPCODE(cldemote, cldemote, cldemote, 0, MEMARG(OPSZ_clflush))

/****************************************************************************/
/* single immed argument */
Expand Down
Loading

0 comments on commit e24dbb0

Please sign in to comment.