encode: Support FD/TD encodings

This commit is contained in:
Alexis Engelke
2021-04-02 11:26:12 +02:00
parent fa52782e76
commit 4185d7b2d6
3 changed files with 54 additions and 7 deletions

View File

@@ -291,8 +291,8 @@ const struct EncodingInfo encoding_infos[ENC_MAX] = {
[ENC_S] = { 0 }, [ENC_S] = { 0 },
[ENC_A] = { .zregidx = 0^3, .zregval = 0 }, [ENC_A] = { .zregidx = 0^3, .zregval = 0 },
[ENC_D] = { .immctl = 6, .immidx = 0 }, [ENC_D] = { .immctl = 6, .immidx = 0 },
[ENC_FD] = { .immctl = 2, .immidx = 1 }, [ENC_FD] = { .zregidx = 0^3, .zregval = 0, .immctl = 2, .immidx = 1 },
[ENC_TD] = { .immctl = 2, .immidx = 0 }, [ENC_TD] = { .zregidx = 1^3, .zregval = 0, .immctl = 2, .immidx = 0 },
[ENC_RVM] = { .modrm = 2^3, .modreg = 0^3, .vexreg = 1^3 }, [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_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 }, [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]; const struct EncodingInfo* ei = &encoding_infos[desc->enc];
uint64_t opc = desc->opc; uint64_t opc = desc->opc;
int64_t imm = 0xcc; int64_t imm = 0xcc;
unsigned immsz = desc->immsz;
if (UNLIKELY(desc->enc == ENC_INVALID)) goto fail; 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) { if (ei->immctl > 0) {
imm = ops[ei->immidx]; 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) if (ei->immctl == 3)
imm = op_reg_idx(imm) << 4; imm = op_reg_idx(imm) << 4;
if (ei->immctl == 6) { if (ei->immctl == 6) {
if (UNLIKELY(mnem & FE_JMPL) && desc->alt) goto next; 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 (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 // 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) { if (ei->modrm) {
FeOp modreg = ei->modreg ? ops[ei->modreg^3] : (opc & 0xff00) >> 8; 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) { } else if (ei->modreg) {
if (enc_o(buf, opc, ops[ei->modreg^3])) goto fail; if (enc_o(buf, opc, ops[ei->modreg^3])) goto fail;
} else { } else {
@@ -388,7 +393,7 @@ fe_enc64_impl(uint8_t** restrict buf, uint64_t mnem, FeOp op0, FeOp op1,
} }
if (ei->immctl >= 2) if (ei->immctl >= 2)
if (enc_imm(buf, imm, desc->immsz)) goto fail; if (enc_imm(buf, imm, immsz)) goto fail;
return 0; return 0;

View File

@@ -154,7 +154,7 @@ class InstrDesc(NamedTuple):
for ot, op in zip(ots, self.operands): for ot, op in zip(ots, self.operands):
if ot == "m": if ot == "m":
tys.append(0xf) tys.append(0xf)
elif ot in "io": elif ot in "ioa":
tys.append(0) tys.append(0)
elif op.kind == "GP": elif op.kind == "GP":
if (self.mnemonic == "MOVSX" or self.mnemonic == "MOVZX" or if (self.mnemonic == "MOVSX" or self.mnemonic == "MOVZX" or

View File

@@ -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("\x66\x0f\x3a\x14\xc1\x02", FE_SSE_PEXTRBrri, FE_CX, FE_XMM0, 2);
TEST("", FE_SSE_PEXTRBrri, FE_CH, 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 VEX encoding
TEST("\xc5\xfc\x77", FE_VZEROALL); TEST("\xc5\xfc\x77", FE_VZEROALL);
TEST("\xc5\xf8\x77", FE_VZEROUPPER); TEST("\xc5\xf8\x77", FE_VZEROUPPER);