From 4185d7b2d6044273d728e7230c56b2d8c8fda4bd Mon Sep 17 00:00:00 2001 From: Alexis Engelke Date: Fri, 2 Apr 2021 11:26:12 +0200 Subject: [PATCH] encode: Support FD/TD encodings --- encode.c | 17 +++++++++++------ parseinstrs.py | 2 +- tests/test_encode.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/encode.c b/encode.c index 85ffd17..53888cc 100644 --- a/encode.c +++ b/encode.c @@ -291,8 +291,8 @@ const struct EncodingInfo encoding_infos[ENC_MAX] = { [ENC_S] = { 0 }, [ENC_A] = { .zregidx = 0^3, .zregval = 0 }, [ENC_D] = { .immctl = 6, .immidx = 0 }, - [ENC_FD] = { .immctl = 2, .immidx = 1 }, - [ENC_TD] = { .immctl = 2, .immidx = 0 }, + [ENC_FD] = { .zregidx = 0^3, .zregval = 0, .immctl = 2, .immidx = 1 }, + [ENC_TD] = { .zregidx = 1^3, .zregval = 0, .immctl = 2, .immidx = 0 }, [ENC_RVM] = { .modrm = 2^3, .modreg = 0^3, .vexreg = 1^3 }, [ENC_RVMI] = { .modrm = 2^3, .modreg = 0^3, .vexreg = 1^3, .immctl = 4, .immidx = 3 }, [ENC_RVMR] = { .modrm = 2^3, .modreg = 0^3, .vexreg = 1^3, .immctl = 3, .immidx = 3 }, @@ -330,6 +330,7 @@ fe_enc64_impl(uint8_t** restrict buf, uint64_t mnem, FeOp op0, FeOp op1, const struct EncodingInfo* ei = &encoding_infos[desc->enc]; uint64_t opc = desc->opc; int64_t imm = 0xcc; + unsigned immsz = desc->immsz; if (UNLIKELY(desc->enc == ENC_INVALID)) goto fail; @@ -362,14 +363,18 @@ fe_enc64_impl(uint8_t** restrict buf, uint64_t mnem, FeOp op0, FeOp op1, if (ei->immctl > 0) { imm = ops[ei->immidx]; + if (ei->immctl == 2) { + immsz = UNLIKELY(mnem & FE_ADDR32) ? 4 : 8; + if (immsz == 4) imm = (int32_t) imm; // address are zero-extended + } if (ei->immctl == 3) imm = op_reg_idx(imm) << 4; if (ei->immctl == 6) { if (UNLIKELY(mnem & FE_JMPL) && desc->alt) goto next; - imm -= (int64_t) *buf + opc_size(opc) + desc->immsz; + imm -= (int64_t) *buf + opc_size(opc) + immsz; } if (UNLIKELY(ei->immctl == 1) && imm != 1) goto next; - if (ei->immctl >= 4 && !op_imm_n(imm, desc->immsz)) goto next; + if (ei->immctl >= 2 && !op_imm_n(imm, immsz)) goto next; } // NOP has no operands, so this must be the 32-bit OA XCHG @@ -380,7 +385,7 @@ fe_enc64_impl(uint8_t** restrict buf, uint64_t mnem, FeOp op0, FeOp op1, if (ei->modrm) { FeOp modreg = ei->modreg ? ops[ei->modreg^3] : (opc & 0xff00) >> 8; - if (enc_mr(buf, opc, ops[ei->modrm^3], modreg, desc->immsz)) goto fail; + if (enc_mr(buf, opc, ops[ei->modrm^3], modreg, immsz)) goto fail; } else if (ei->modreg) { if (enc_o(buf, opc, ops[ei->modreg^3])) goto fail; } else { @@ -388,7 +393,7 @@ fe_enc64_impl(uint8_t** restrict buf, uint64_t mnem, FeOp op0, FeOp op1, } if (ei->immctl >= 2) - if (enc_imm(buf, imm, desc->immsz)) goto fail; + if (enc_imm(buf, imm, immsz)) goto fail; return 0; diff --git a/parseinstrs.py b/parseinstrs.py index 104c021..dddd54a 100644 --- a/parseinstrs.py +++ b/parseinstrs.py @@ -154,7 +154,7 @@ class InstrDesc(NamedTuple): for ot, op in zip(ots, self.operands): if ot == "m": tys.append(0xf) - elif ot in "io": + elif ot in "ioa": tys.append(0) elif op.kind == "GP": if (self.mnemonic == "MOVSX" or self.mnemonic == "MOVZX" or diff --git a/tests/test_encode.c b/tests/test_encode.c index d7ee42a..ed29288 100644 --- a/tests/test_encode.c +++ b/tests/test_encode.c @@ -159,6 +159,48 @@ main(int argc, char** argv) TEST("\x66\x0f\x3a\x14\xc1\x02", FE_SSE_PEXTRBrri, FE_CX, FE_XMM0, 2); TEST("", FE_SSE_PEXTRBrri, FE_CH, FE_XMM0, 2); + // Test FD/TD encodings + TEST("\xa0\x00\x00\x00\x00\x00\x00\x00\x00", FE_MOV8ra, FE_AX, 0); + TEST("\x67\xa0\x00\x00\x00\x00", FE_MOV8ra|FE_ADDR32, FE_AX, 0); + TEST("\x66\xa1\x00\x00\x00\x00\x00\x00\x00\x00", FE_MOV16ra, FE_AX, 0); + TEST("\x67\x66\xa1\x00\x00\x00\x00", FE_MOV16ra|FE_ADDR32, FE_AX, 0); + TEST("\x66\xa1\x10\x32\x54\x76\x98\xba\xdc\xfe", FE_MOV16ra, FE_AX, 0xfedcba9876543210); + TEST("\x67\x66\xa1\x98\xba\xdc\xfe", FE_MOV16ra|FE_ADDR32, FE_AX, 0xfedcba98); + TEST("\xa1\x10\x32\x54\x76\x98\xba\xdc\xfe", FE_MOV32ra, FE_AX, 0xfedcba9876543210); + TEST("\x67\xa1\x98\xba\xdc\xfe", FE_MOV32ra|FE_ADDR32, FE_AX, 0xfedcba98); + TEST("\x48\xa1\x10\x32\x54\x76\x98\xba\xdc\xfe", FE_MOV64ra, FE_AX, 0xfedcba9876543210); + TEST("\x67\x48\xa1\x98\xba\xdc\xfe", FE_MOV64ra|FE_ADDR32, FE_AX, 0xfedcba98); + TEST("\xa2\x00\x00\x00\x00\x00\x00\x00\x00", FE_MOV8ar, 0, FE_AX); + TEST("\x67\xa2\x00\x00\x00\x00", FE_MOV8ar|FE_ADDR32, 0, FE_AX); + TEST("\x66\xa3\x00\x00\x00\x00\x00\x00\x00\x00", FE_MOV16ar, 0, FE_AX); + TEST("\x67\x66\xa3\x00\x00\x00\x00", FE_MOV16ar|FE_ADDR32, 0, FE_AX); + TEST("\x66\xa3\x10\x32\x54\x76\x98\xba\xdc\xfe", FE_MOV16ar, 0xfedcba9876543210, FE_AX); + TEST("\x67\x66\xa3\x98\xba\xdc\xfe", FE_MOV16ar|FE_ADDR32, 0xfedcba98, FE_AX); + TEST("\xa3\x10\x32\x54\x76\x98\xba\xdc\xfe", FE_MOV32ar, 0xfedcba9876543210, FE_AX); + TEST("\x67\xa3\x98\xba\xdc\xfe", FE_MOV32ar|FE_ADDR32, 0xfedcba98, FE_AX); + TEST("\x48\xa3\x10\x32\x54\x76\x98\xba\xdc\xfe", FE_MOV64ar, 0xfedcba9876543210, FE_AX); + TEST("\x67\x48\xa3\x98\xba\xdc\xfe", FE_MOV64ar|FE_ADDR32, 0xfedcba98, FE_AX); + TEST("", FE_MOV8ra, FE_CX, 0); + TEST("", FE_MOV8ra|FE_ADDR32, FE_CX, 0); + TEST("", FE_MOV16ra, FE_CX, 0); + TEST("", FE_MOV16ra|FE_ADDR32, FE_CX, 0); + TEST("", FE_MOV16ra, FE_CX, 0xfedcba9876543210); + TEST("", FE_MOV16ra|FE_ADDR32, FE_CX, 0xfedcba98); + TEST("", FE_MOV32ra, FE_CX, 0xfedcba9876543210); + TEST("", FE_MOV32ra|FE_ADDR32, FE_CX, 0xfedcba98); + TEST("", FE_MOV64ra, FE_CX, 0xfedcba9876543210); + TEST("", FE_MOV64ra|FE_ADDR32, FE_CX, 0xfedcba98); + TEST("", FE_MOV8ar, 0, FE_CX); + TEST("", FE_MOV8ar|FE_ADDR32, 0, FE_CX); + TEST("", FE_MOV16ar, 0, FE_CX); + TEST("", FE_MOV16ar|FE_ADDR32, 0, FE_CX); + TEST("", FE_MOV16ar, 0xfedcba9876543210, FE_CX); + TEST("", FE_MOV16ar|FE_ADDR32, 0xfedcba98, FE_CX); + TEST("", FE_MOV32ar, 0xfedcba9876543210, FE_CX); + TEST("", FE_MOV32ar|FE_ADDR32, 0xfedcba98, FE_CX); + TEST("", FE_MOV64ar, 0xfedcba9876543210, FE_CX); + TEST("", FE_MOV64ar|FE_ADDR32, 0xfedcba98, FE_CX); + // Test VEX encoding TEST("\xc5\xfc\x77", FE_VZEROALL); TEST("\xc5\xf8\x77", FE_VZEROUPPER);