encode: Enforce 15-byte limit

This commit is contained in:
Alexis Engelke
2021-04-02 11:00:24 +02:00
parent d9183228d0
commit fa52782e76

View File

@@ -49,10 +49,13 @@ static unsigned op_mem_idx(FeOp op) { return (op >> 44) & 0xfff; }
static unsigned op_mem_scale(FeOp op) { return (op >> 56) & 0xf; } static unsigned op_mem_scale(FeOp op) { return (op >> 56) & 0xf; }
static unsigned op_reg_idx(FeOp op) { return op & 0xff; } static unsigned op_reg_idx(FeOp op) { return op & 0xff; }
static bool op_imm_n(FeOp imm, unsigned immsz) { static bool op_imm_n(FeOp imm, unsigned immsz) {
if (immsz == 1 && (int8_t) imm != imm) return false; if (immsz == 0 && !imm) return true;
if (immsz == 2 && (int16_t) imm != imm) return false; if (immsz == 1 && (int8_t) imm == imm) return true;
if (immsz == 4 && (int32_t) imm != imm) return false; if (immsz == 2 && (int16_t) imm == imm) return true;
return true; if (immsz == 3 && (imm&0xffffff) == imm) return true;
if (immsz == 4 && (int32_t) imm == imm) return true;
if (immsz == 8 && (int64_t) imm == imm) return true;
return false;
} }
static static
@@ -167,6 +170,7 @@ enc_mr(uint8_t** restrict buf, uint64_t opc, uint64_t op0, uint64_t op1,
bool has_rex = !!(opc & (OPC_REX|OPC_REXW|OPC_REXR|OPC_REXX|OPC_REXB)); bool has_rex = !!(opc & (OPC_REX|OPC_REXW|OPC_REXR|OPC_REXX|OPC_REXB));
if (has_rex && (op_reg_gph(op0) || op_reg_gph(op1))) return -1; if (has_rex && (op_reg_gph(op0) || op_reg_gph(op1))) return -1;
unsigned opcsz = opc_size(opc);
int mod = 0, reg = op1 & 7, rm; int mod = 0, reg = op1 & 7, rm;
int scale = 0, idx = 4, base = 0; int scale = 0, idx = 4, base = 0;
@@ -212,7 +216,7 @@ enc_mr(uint8_t** restrict buf, uint64_t opc, uint64_t op0, uint64_t op1,
rm = 5; rm = 5;
mod0off = true; mod0off = true;
// Adjust offset, caller doesn't know instruction length. // Adjust offset, caller doesn't know instruction length.
off -= opc_size(opc) + 5 + immsz; off -= opcsz + 5 + immsz;
if (withsib) return -1; if (withsib) return -1;
} }
else else
@@ -234,13 +238,14 @@ enc_mr(uint8_t** restrict buf, uint64_t opc, uint64_t op0, uint64_t op1,
} }
} }
unsigned dispsz = mod == 1 ? 1 : (mod == 2 || mod0off) ? 4 : 0;
if (opcsz + 1 + (mod != 3 && rm == 4) + dispsz + immsz > 15) return -1;
if (enc_opc(buf, opc)) return -1; if (enc_opc(buf, opc)) return -1;
*(*buf)++ = (mod << 6) | (reg << 3) | rm; *(*buf)++ = (mod << 6) | (reg << 3) | rm;
if (mod != 3 && rm == 4) if (mod != 3 && rm == 4)
*(*buf)++ = (scale << 6) | (idx << 3) | base; *(*buf)++ = (scale << 6) | (idx << 3) | base;
if (mod == 1) return enc_imm(buf, off, 1); return enc_imm(buf, off, dispsz);
if (mod == 2 || mod0off) return enc_imm(buf, off, 4);
return 0;
} }
typedef enum { typedef enum {