mirror of
https://github.com/netwide-assembler/nasm.git
synced 2025-10-10 00:25:06 -04:00
disasm: Add basic AVX512 support
Disassembler can translate EVEX prefix, count up to 32 vector registers and recognize new ZMM / opmask registers. Signed-off-by: Jin Kyu Song <jin.kyu.song@intel.com>
This commit is contained in:
97
disasm.c
97
disasm.c
@@ -81,6 +81,7 @@ struct prefix_info {
|
|||||||
uint8_t vex_v;
|
uint8_t vex_v;
|
||||||
uint8_t vex_lp; /* VEX.LP fields */
|
uint8_t vex_lp; /* VEX.LP fields */
|
||||||
uint32_t rex; /* REX prefix present */
|
uint32_t rex; /* REX prefix present */
|
||||||
|
uint8_t evex[3]; /* EVEX prefix present */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define getu8(x) (*(uint8_t *)(x))
|
#define getu8(x) (*(uint8_t *)(x))
|
||||||
@@ -133,12 +134,14 @@ static enum reg_enum whichreg(opflags_t regflags, int regval, int rex)
|
|||||||
{FPU0, R_ST0},
|
{FPU0, R_ST0},
|
||||||
{XMM0, R_XMM0},
|
{XMM0, R_XMM0},
|
||||||
{YMM0, R_YMM0},
|
{YMM0, R_YMM0},
|
||||||
|
{ZMM0, R_ZMM0},
|
||||||
{REG_ES, R_ES},
|
{REG_ES, R_ES},
|
||||||
{REG_CS, R_CS},
|
{REG_CS, R_CS},
|
||||||
{REG_SS, R_SS},
|
{REG_SS, R_SS},
|
||||||
{REG_DS, R_DS},
|
{REG_DS, R_DS},
|
||||||
{REG_FS, R_FS},
|
{REG_FS, R_FS},
|
||||||
{REG_GS, R_GS}
|
{REG_GS, R_GS},
|
||||||
|
{OPMASK0, R_K0},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!(regflags & (REGISTER|REGMEM)))
|
if (!(regflags & (REGISTER|REGMEM)))
|
||||||
@@ -151,7 +154,7 @@ static enum reg_enum whichreg(opflags_t regflags, int regval, int rex)
|
|||||||
return specific_registers[i].reg;
|
return specific_registers[i].reg;
|
||||||
|
|
||||||
/* All the entries below look up regval in an 16-entry array */
|
/* All the entries below look up regval in an 16-entry array */
|
||||||
if (regval < 0 || regval > 15)
|
if (regval < 0 || regval > (rex & REX_EV ? 31 : 15))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!(REG8 & ~regflags)) {
|
if (!(REG8 & ~regflags)) {
|
||||||
@@ -185,6 +188,10 @@ static enum reg_enum whichreg(opflags_t regflags, int regval, int rex)
|
|||||||
return nasm_rd_xmmreg[regval];
|
return nasm_rd_xmmreg[regval];
|
||||||
if (!(YMMREG & ~regflags))
|
if (!(YMMREG & ~regflags))
|
||||||
return nasm_rd_ymmreg[regval];
|
return nasm_rd_ymmreg[regval];
|
||||||
|
if (!(ZMMREG & ~regflags))
|
||||||
|
return nasm_rd_zmmreg[regval];
|
||||||
|
if (!(OPMASKREG & ~regflags))
|
||||||
|
return nasm_rd_opmaskreg[regval];
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -198,7 +205,9 @@ static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
|
|||||||
{
|
{
|
||||||
int mod, rm, scale, index, base;
|
int mod, rm, scale, index, base;
|
||||||
int rex;
|
int rex;
|
||||||
|
uint8_t *evex;
|
||||||
uint8_t sib = 0;
|
uint8_t sib = 0;
|
||||||
|
bool is_evex = !!(ins->rex & REX_EV);
|
||||||
|
|
||||||
mod = (modrm >> 6) & 03;
|
mod = (modrm >> 6) & 03;
|
||||||
rm = modrm & 07;
|
rm = modrm & 07;
|
||||||
@@ -206,11 +215,15 @@ static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
|
|||||||
if (mod != 3 && asize != 16 && rm == 4)
|
if (mod != 3 && asize != 16 && rm == 4)
|
||||||
sib = *data++;
|
sib = *data++;
|
||||||
|
|
||||||
rex = ins->rex;
|
rex = ins->rex;
|
||||||
|
evex = ins->evex_p;
|
||||||
|
|
||||||
if (mod == 3) { /* pure register version */
|
if (mod == 3) { /* pure register version */
|
||||||
op->basereg = rm+(rex & REX_B ? 8 : 0);
|
op->basereg = rm+(rex & REX_B ? 8 : 0);
|
||||||
op->segment |= SEG_RMREG;
|
op->segment |= SEG_RMREG;
|
||||||
|
if (is_evex && segsize == 64) {
|
||||||
|
op->basereg += (evex[0] & EVEX_P0X ? 0 : 16);
|
||||||
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -564,6 +577,8 @@ static int matches(const struct itemplate *t, uint8_t *data,
|
|||||||
if (!data)
|
if (!data)
|
||||||
return false;
|
return false;
|
||||||
opx->basereg = ((modrm >> 3) & 7) + (ins->rex & REX_R ? 8 : 0);
|
opx->basereg = ((modrm >> 3) & 7) + (ins->rex & REX_R ? 8 : 0);
|
||||||
|
if ((ins->rex & REX_EV) && (segsize == 64))
|
||||||
|
opx->basereg += (ins->evex_p[0] & EVEX_P0RP ? 0 : 16);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -617,6 +632,55 @@ static int matches(const struct itemplate *t, uint8_t *data,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case4(0240):
|
||||||
|
case 0250:
|
||||||
|
{
|
||||||
|
uint8_t evexm = *r++;
|
||||||
|
uint8_t evexwlp = *r++;
|
||||||
|
ins->evex_tuple = *r++ - 0300;
|
||||||
|
|
||||||
|
ins->rex |= REX_EV;
|
||||||
|
if ((prefix->rex & (REX_EV|REX_V|REX_P)) != REX_EV)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((evexm & 0x1f) != prefix->vex_m)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (evexwlp & 060) {
|
||||||
|
case 000:
|
||||||
|
if (prefix->rex & REX_W)
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case 020:
|
||||||
|
if (!(prefix->rex & REX_W))
|
||||||
|
return false;
|
||||||
|
ins->rex |= REX_W;
|
||||||
|
break;
|
||||||
|
case 040: /* VEX.W is a don't care */
|
||||||
|
ins->rex &= ~REX_W;
|
||||||
|
break;
|
||||||
|
case 060:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If EVEX.b is set, EVEX.L'L can be rounding control bits */
|
||||||
|
if ((evexwlp ^ prefix->vex_lp) &
|
||||||
|
((prefix->evex[2] & EVEX_P2B) ? 0x03 : 0x0f))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (c == 0250) {
|
||||||
|
if ((prefix->vex_v != 0) || !(prefix->evex[2] & EVEX_P2VP))
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
opx->segment |= SEG_RMREG;
|
||||||
|
opx->basereg = ((~prefix->evex[2] & EVEX_P2VP) << (4 - 3) ) |
|
||||||
|
prefix->vex_v;
|
||||||
|
}
|
||||||
|
vex_ok = true;
|
||||||
|
memcpy(ins->evex_p, prefix->evex, 3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case4(0260):
|
case4(0260):
|
||||||
case 0270:
|
case 0270:
|
||||||
{
|
{
|
||||||
@@ -879,7 +943,7 @@ static int matches(const struct itemplate *t, uint8_t *data,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vex_ok && (ins->rex & REX_V))
|
if (!vex_ok && (ins->rex & (REX_V | REX_EV)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* REX cannot be combined with VEX */
|
/* REX cannot be combined with VEX */
|
||||||
@@ -1045,6 +1109,31 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
|
|||||||
end_prefix = true;
|
end_prefix = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 0x62:
|
||||||
|
{
|
||||||
|
uint8_t evex_p0 = data[1] & 0x0f;
|
||||||
|
if (segsize == 64 ||
|
||||||
|
((evex_p0 >= 0x01) && (evex_p0 <= 0x03))) {
|
||||||
|
data++; /* 62h EVEX prefix */
|
||||||
|
prefix.evex[0] = *data++;
|
||||||
|
prefix.evex[1] = *data++;
|
||||||
|
prefix.evex[2] = *data++;
|
||||||
|
|
||||||
|
prefix.rex = REX_EV;
|
||||||
|
prefix.vex_c = RV_EVEX;
|
||||||
|
prefix.rex |= (~prefix.evex[0] >> 5) & 7; /* REX_RXB */
|
||||||
|
prefix.rex |= (prefix.evex[1] >> (7-3)) & REX_W;
|
||||||
|
prefix.vex_m = prefix.evex[0] & EVEX_P0MM;
|
||||||
|
prefix.vex_v = (~prefix.evex[1] & EVEX_P1VVVV) >> 3;
|
||||||
|
prefix.vex_lp = ((prefix.evex[2] & EVEX_P2LL) >> (5-2)) |
|
||||||
|
(prefix.evex[1] & EVEX_P1PP);
|
||||||
|
|
||||||
|
ix = itable_vex[prefix.vex_c][prefix.vex_m][prefix.vex_lp & 3];
|
||||||
|
}
|
||||||
|
end_prefix = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 0x8F:
|
case 0x8F:
|
||||||
if ((data[1] & 030) != 0 &&
|
if ((data[1] & 030) != 0 &&
|
||||||
(segsize == 64 || (data[1] & 0xc0) == 0xc0)) {
|
(segsize == 64 || (data[1] & 0xc0) == 0xc0)) {
|
||||||
|
|||||||
@@ -3730,8 +3730,8 @@ VEXTRACTI32X4 mem128|mask,zmmreg,imm8 [mri:t4: e
|
|||||||
VEXTRACTI32X4 xmmreg|mask|z,zmmreg,imm8 [mri: evex.512.66.0f3a.w0 39 /r ib ] AVX512,FUTURE
|
VEXTRACTI32X4 xmmreg|mask|z,zmmreg,imm8 [mri: evex.512.66.0f3a.w0 39 /r ib ] AVX512,FUTURE
|
||||||
VEXTRACTI64X4 ymmreg|mask|z,zmmreg,imm8 [mri: evex.512.66.0f3a.w1 3b /r ib ] AVX512,FUTURE
|
VEXTRACTI64X4 ymmreg|mask|z,zmmreg,imm8 [mri: evex.512.66.0f3a.w1 3b /r ib ] AVX512,FUTURE
|
||||||
VEXTRACTI64X4 mem256|mask,zmmreg,imm8 [mri:t4: evex.512.66.0f3a.w1 3b /r ib ] AVX512,FUTURE
|
VEXTRACTI64X4 mem256|mask,zmmreg,imm8 [mri:t4: evex.512.66.0f3a.w1 3b /r ib ] AVX512,FUTURE
|
||||||
VEXTRACTPS rm32,xmmreg,imm8 [mri:t1s: evex.128.66.0f3a.wig 17 /r ib ] AVX512,FUTURE
|
|
||||||
VEXTRACTPS rm64,xmmreg,imm8 [mri:t1s: evex.128.66.0f3a.w1 17 /r ib ] AVX512,FUTURE
|
VEXTRACTPS rm64,xmmreg,imm8 [mri:t1s: evex.128.66.0f3a.w1 17 /r ib ] AVX512,FUTURE
|
||||||
|
VEXTRACTPS rm32,xmmreg,imm8 [mri:t1s: evex.128.66.0f3a.wig 17 /r ib ] AVX512,FUTURE
|
||||||
VFIXUPIMMPD zmmreg|mask|z,zmmreg,zmmrm512|b64|sae,imm8 [rvmi:fv: evex.nds.512.66.0f3a.w1 54 /r ib ] AVX512,FUTURE
|
VFIXUPIMMPD zmmreg|mask|z,zmmreg,zmmrm512|b64|sae,imm8 [rvmi:fv: evex.nds.512.66.0f3a.w1 54 /r ib ] AVX512,FUTURE
|
||||||
VFIXUPIMMPS zmmreg|mask|z,zmmreg,zmmrm512|b32|sae,imm8 [rvmi:fv: evex.nds.512.66.0f3a.w0 54 /r ib ] AVX512,FUTURE
|
VFIXUPIMMPS zmmreg|mask|z,zmmreg,zmmrm512|b32|sae,imm8 [rvmi:fv: evex.nds.512.66.0f3a.w0 54 /r ib ] AVX512,FUTURE
|
||||||
VFIXUPIMMSD xmmreg|mask|z,xmmreg,xmmrm64|sae,imm8 [rvmi:t1s: evex.nds.lig.66.0f3a.w1 55 /r ib ] AVX512,FUTURE
|
VFIXUPIMMSD xmmreg|mask|z,xmmreg,xmmrm64|sae,imm8 [rvmi:t1s: evex.nds.lig.66.0f3a.w1 55 /r ib ] AVX512,FUTURE
|
||||||
|
|||||||
7
nasm.h
7
nasm.h
@@ -509,8 +509,12 @@ static inline uint8_t get_cond_opcode(enum ccode c)
|
|||||||
/*
|
/*
|
||||||
* EVEX bit field
|
* EVEX bit field
|
||||||
*/
|
*/
|
||||||
|
#define EVEX_P0MM 0x03 /* EVEX P[1:0] : Legacy escape */
|
||||||
#define EVEX_P0RP 0x10 /* EVEX P[4] : High-16 reg */
|
#define EVEX_P0RP 0x10 /* EVEX P[4] : High-16 reg */
|
||||||
#define EVEX_P0X 0x40 /* EVEX P[6] : High-16 rm */
|
#define EVEX_P0X 0x40 /* EVEX P[6] : High-16 rm */
|
||||||
|
#define EVEX_P1PP 0x03 /* EVEX P[9:8] : Legacy prefix */
|
||||||
|
#define EVEX_P1VVVV 0x78 /* EVEX P[14:11] : NDS register */
|
||||||
|
#define EVEX_P1W 0x80 /* EVEX P[15] : Osize extension */
|
||||||
#define EVEX_P2AAA 0x07 /* EVEX P[18:16] : Embedded opmask */
|
#define EVEX_P2AAA 0x07 /* EVEX P[18:16] : Embedded opmask */
|
||||||
#define EVEX_P2VP 0x08 /* EVEX P[19] : High-16 NDS reg */
|
#define EVEX_P2VP 0x08 /* EVEX P[19] : High-16 NDS reg */
|
||||||
#define EVEX_P2B 0x10 /* EVEX P[20] : Broadcast / RC / SAE */
|
#define EVEX_P2B 0x10 /* EVEX P[20] : Broadcast / RC / SAE */
|
||||||
@@ -523,7 +527,8 @@ static inline uint8_t get_cond_opcode(enum ccode c)
|
|||||||
*/
|
*/
|
||||||
enum vex_class {
|
enum vex_class {
|
||||||
RV_VEX = 0, /* C4/C5 */
|
RV_VEX = 0, /* C4/C5 */
|
||||||
RV_XOP = 1 /* 8F */
|
RV_XOP = 1, /* 8F */
|
||||||
|
RV_EVEX = 2, /* 62 */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user