feat(disasm): name the amd64 encodings x86asm refuses
The toolchain's assembler corpus carries 195 amd64 encodings the x/arch decoder rejects or degenerates: the BMI1/BMI2 VEX families (ANDN, BEXTR, BLSI, BLSMSK, BLSR, BZHI, MULX, PDEP, PEXT, RORX, SARX, SHLX, SHRX), the 0F 01 quartet CLAC, STAC, RDPKRU and WRPKRU, the bare and REX-only RDSEED forms, and UD1. The supplementary naming table decodes the VEX prefix and the ModR/M shape and renders the toolchain's own spellings; every corpus row is pinned in the unlisted fixture and round-trips byte for byte through the encoder, and the boundary test pins the prefix shapes no family carries. Assisted-by: GLM 5.3
This commit is contained in:
1 parent
d98aadbbbf
commit
2c70359ad0
3 files changed
+419
-16
No files matched your search
@@ -80,6 +80,46 @@ func TestDegenerateNaming(t *testing.T) {
|
||||
// rejects the encoding outright; the table names it from the
|
||||
// bytes.
|
||||
{[]byte{0x0f, 0x1c, 0x03}, "CLDEMOTE 0(BX)"},
|
||||
// amd64enc.s: the BMI1/BMI2 VEX families the decoder refuses
|
||||
// with "unknown AVX Opcode". One row per family and operand
|
||||
// shape; every corpus row is pinned in the unlisted fixture.
|
||||
{[]byte{0xc4, 0xe2, 0x30, 0xf2, 0x13}, "ANDNL 0(BX), R9, DX"},
|
||||
{[]byte{0xc4, 0xe2, 0x88, 0xf2, 0xd2}, "ANDNQ DX, R14, DX"},
|
||||
{[]byte{0xc4, 0xe2, 0x30, 0xf7, 0x13}, "BEXTRL R9, 0(BX), DX"},
|
||||
{[]byte{0xc4, 0x62, 0x88, 0xf7, 0xda}, "BEXTRQ R14, DX, R11"},
|
||||
{[]byte{0xc4, 0xe2, 0x30, 0xf3, 0x1b}, "BLSIL 0(BX), R9"},
|
||||
{[]byte{0xc4, 0xe2, 0x30, 0xf3, 0x13}, "BLSMSKL 0(BX), R9"},
|
||||
{[]byte{0xc4, 0xe2, 0x30, 0xf3, 0x0b}, "BLSRL 0(BX), R9"},
|
||||
{[]byte{0xc4, 0xe2, 0x88, 0xf3, 0xca}, "BLSRQ DX, R14"},
|
||||
{[]byte{0xc4, 0xe2, 0x30, 0xf5, 0x13}, "BZHIL R9, 0(BX), DX"},
|
||||
{[]byte{0xc4, 0x42, 0x88, 0xf5, 0xdb}, "BZHIQ R14, R11, R11"},
|
||||
{[]byte{0xc4, 0xe2, 0x33, 0xf6, 0x13}, "MULXL 0(BX), R9, DX"},
|
||||
{[]byte{0xc4, 0x62, 0x8b, 0xf6, 0xda}, "MULXQ DX, R14, R11"},
|
||||
{[]byte{0xc4, 0xe2, 0x33, 0xf5, 0x13}, "PDEPL 0(BX), R9, DX"},
|
||||
{[]byte{0xc4, 0xe2, 0x32, 0xf5, 0x13}, "PEXTL 0(BX), R9, DX"},
|
||||
{[]byte{0xc4, 0xe3, 0x7b, 0xf0, 0x13, 0x07}, "RORXL $7, 0(BX), DX"},
|
||||
{[]byte{0xc4, 0xe3, 0xfb, 0xf0, 0x10, 0xff}, "RORXQ $-1, 0(AX), DX"},
|
||||
{[]byte{0xc4, 0xe2, 0x32, 0xf7, 0x13}, "SARXL R9, 0(BX), DX"},
|
||||
{[]byte{0xc4, 0xe2, 0x31, 0xf7, 0x13}, "SHLXL R9, 0(BX), DX"},
|
||||
{[]byte{0xc4, 0xe2, 0x33, 0xf7, 0x13}, "SHRXL R9, 0(BX), DX"},
|
||||
{[]byte{0xc4, 0x42, 0x89, 0xf7, 0xdb}, "SHLXQ R14, R11, R11"},
|
||||
// amd64enc.s: CLAC // 0f01ca, STAC // 0f01cb, RDPKRU // 0f01ee
|
||||
// and WRPKRU // 0f01ef; the decoder rejects the encodings.
|
||||
{[]byte{0x0f, 0x01, 0xca}, "CLAC"},
|
||||
{[]byte{0x0f, 0x01, 0xcb}, "STAC"},
|
||||
{[]byte{0x0f, 0x01, 0xee}, "RDPKRU"},
|
||||
{[]byte{0x0f, 0x01, 0xef}, "WRPKRU"},
|
||||
// amd64enc.s: RDSEEDL DX // 0fc7fa and RDSEEDQ DX // 480fc7fa.
|
||||
// The bare and REX-only forms are refused outright (the 66 and
|
||||
// f3 forms above come back degenerate), so they are named in
|
||||
// the rejected-encoding table.
|
||||
{[]byte{0x0f, 0xc7, 0xfa}, "RDSEEDL DX"},
|
||||
{[]byte{0x41, 0x0f, 0xc7, 0xfb}, "RDSEEDL R11"},
|
||||
{[]byte{0x48, 0x0f, 0xc7, 0xfa}, "RDSEEDQ DX"},
|
||||
{[]byte{0x49, 0x0f, 0xc7, 0xfb}, "RDSEEDQ R11"},
|
||||
// amd64enc.s: UD1 // 0fb9, decoded with no error but the
|
||||
// degenerate zero instruction.
|
||||
{[]byte{0x0f, 0xb9}, "UD1"},
|
||||
} {
|
||||
ins, err := Decode(arch.AMD64, tt.code, 0)
|
||||
if err != nil {
|
||||
@@ -105,14 +145,27 @@ func TestDegenerateNamingBoundaries(t *testing.T) {
|
||||
code []byte
|
||||
text string
|
||||
}{
|
||||
// Rejected outright: RDSEED without the operand-size override
|
||||
// (the bare 0F C7 /7 register form), MONITORX and MWAITX, and
|
||||
// the register form of the hint NOP opcode, which the corpus
|
||||
// does not spell.
|
||||
{[]byte{0x0f, 0xc7, 0xfa}, "???"},
|
||||
// Rejected outright: MONITORX and MWAITX, and the register
|
||||
// form of the hint NOP opcode, which the corpus does not
|
||||
// spell.
|
||||
{[]byte{0x0f, 0x01, 0xfa}, "???"},
|
||||
{[]byte{0x0f, 0x01, 0xfb}, "???"},
|
||||
{[]byte{0x0f, 0x1c, 0xc3}, "???"},
|
||||
// The 0F 01 family keeps its fixed three bytes: a REX prefix
|
||||
// extends nothing the instructions carry.
|
||||
{[]byte{0x41, 0x0f, 0x01, 0xca}, "???"},
|
||||
// The VEX families stay pinned to the corpus prefix shapes:
|
||||
// the vector-length bit set (a reserved encoding in every GPR
|
||||
// family), the operand-size selector on the ANDN opcode (the
|
||||
// selector belongs to no F2 family), RORX with a live vvvv
|
||||
// field (the toolchain keeps it dead), the BLS* selector
|
||||
// outside its three defined reg fields, and the one-byte-map
|
||||
// escape, which no family here uses.
|
||||
{[]byte{0xc4, 0xe3, 0x34, 0xf2, 0x13}, "???"},
|
||||
{[]byte{0xc4, 0xe2, 0x31, 0xf2, 0x13}, "???"},
|
||||
{[]byte{0xc4, 0xe3, 0x63, 0xf0, 0x13, 0x07}, "???"},
|
||||
{[]byte{0xc4, 0xe2, 0x30, 0xf3, 0x03}, "???"},
|
||||
{[]byte{0xc4, 0xe1, 0x70, 0xf2, 0x13}, "???"},
|
||||
// Degenerate but outside the table's prefix gates: repne ADCX is
|
||||
// no instruction the corpus names.
|
||||
{[]byte{0xf2, 0x0f, 0x38, 0xf6, 0xd2}, "REPNE; Op(0)"},
|
||||
|
||||
Reference in new issue
Block a user