0
0
mirror of https://github.com/netwide-assembler/nasm.git synced 2025-09-22 10:43:39 -04:00
Files
nasm/disasm/prefix.c
H. Peter Anvin 29bc7c4811 ndisasm: REX2 *can* take REP or OSZ prefixes
Only VEX and EVEX may not take REP or OSZ prefixes.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-09-05 02:56:27 -07:00

511 lines
13 KiB
C

/* ----------------------------------------------------------------------- *
*
* Copyright 2025 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for
* the specific copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ----------------------------------------------------------------------- */
#include "disasm.h"
#include "nasmlib.h"
/*
* Parse various register combinations. Note that this does NOT
* generate the REX_[BXR][1V] flags, as they are not used by the
* disassembler.
*/
static uint32_t
xbits(uint32_t val, unsigned int from, unsigned int count, unsigned int to)
{
const uint32_t tomask = ((UINT32_C(1) << count)-1) << to;
if (to < from)
return (val >> (from-to)) & tomask;
else
return (val << (to-from)) & tomask;
}
/* ------ EVEX decoding ------ */
#define EVEX_INVERTED 0x087cf000
static uint32_t
evexbits(uint32_t val, unsigned int from, unsigned int count, unsigned int to)
{
return xbits(val ^ EVEX_INVERTED, from, count, to);
}
static uint32_t evex_rreg(uint32_t evex)
{
return evexbits(evex,15,1,3) + evexbits(evex,12,1,4);
}
static uint32_t evex_xreg(uint32_t evex, bool xv)
{
uint32_t x = evexbits(evex,14,1,3);
x += evexbits(evex,xv ? 27 : 18,1,4);
return x;
}
static uint32_t evex_breg(uint32_t evex, bool bv)
{
uint32_t b = evexbits(evex,13,1,3);
b += evexbits(evex,bv ? 14 : 11,1,4);
return b;
}
static uint32_t evex_vreg(uint32_t evex, bool xv)
{
uint32_t v = evexbits(evex,19,4,0);
if (!xv)
v += evexbits(evex,27,1,4);
return v;
}
static uint32_t evex_aaa(uint32_t evex)
{
return evexbits(evex,24,3,0);
}
static uint32_t evex_z(uint32_t evex)
{
return evexbits(evex,31,1,0);
}
static uint32_t evex_l(uint32_t evex)
{
return evexbits(evex,29,2,0);
}
static uint32_t evex_b(uint32_t evex)
{
return evexbits(evex,28,1,0);
}
static uint32_t evex_nf(uint32_t evex)
{
return evexbits(evex,26,1,0);
}
static uint32_t evex_scc(uint32_t evex)
{
return evexbits(evex,24,4,0);
}
static uint32_t evex_dfl(uint32_t evex)
{
return evexbits(evex,19,4,0);
}
static uint32_t evex_map(uint32_t evex)
{
return evexbits(evex,8,3,0);
}
static uint32_t evex_w(uint32_t evex)
{
return evexbits(evex,23,1,0);
}
static uint32_t evex_pp(uint32_t evex)
{
return evexbits(evex,16,2,0);
}
/* ------ VEX3 decoding ------ */
static uint32_t vex2to3(uint32_t vex2)
{
return (vex2 & 0x80fe) + ((vex2 & 0x7f00) << 8) + 0x6100;
}
static uint32_t vex3_rreg(uint32_t vex)
{
return xbits(~vex,15,1,3);
}
static uint32_t vex3_xreg(uint32_t vex)
{
return xbits(~vex,14,1,3);
}
static uint32_t vex3_breg(uint32_t vex)
{
return xbits(~vex,13,1,3);
}
static uint32_t vex3_map(uint32_t vex)
{
return xbits(vex,8,5,0);
}
static uint32_t vex3_vreg(uint32_t vex)
{
return xbits(~vex,19,4,0);
}
static uint32_t vex3_l(uint32_t vex)
{
return xbits(vex,18,1,0);
}
static uint32_t vex3_pp(uint32_t vex)
{
return xbits(vex,16,2,0);
}
static uint32_t vex3_w(uint32_t vex)
{
return xbits(vex,23,1,0);
}
/* ------ REX2 decoding ------ */
static uint32_t rex2_rreg(uint32_t rex)
{
return xbits(rex,14,1,4) + xbits(rex,10,1,3);
}
static uint32_t rex2_xreg(uint32_t rex)
{
return xbits(rex,13,1,4) + xbits(rex,9,1,3);
}
static uint32_t rex2_breg(uint32_t rex)
{
return xbits(rex,12,1,4) + xbits(rex,8,1,3);
}
static uint32_t rex2_w(uint32_t rex)
{
return xbits(rex,11,1,0);
}
static uint32_t rex2_map(uint32_t rex)
{
return xbits(rex,15,1,0);
}
/* ------ REX decoding ------ */
static uint32_t rex_rreg(uint32_t rex)
{
return xbits(rex,2,1,3);
}
static uint32_t rex_xreg(uint32_t rex)
{
return xbits(rex,1,1,3);
}
static uint32_t rex_breg(uint32_t rex)
{
return xbits(rex,0,1,3);
}
static uint32_t rex_w(uint32_t rex)
{
return xbits(rex,3,1,0);
}
/*
* Parse an EVEX prefix.
*/
static void parse_evex(struct rexfields *rf, uint32_t val)
{
rf->type = REX_EVEX;
rf->len = 4;
rf->raw = val;
rf->opc = (uint8_t)val;
rf->breg = evex_breg(val, false);
rf->bregbv = evex_breg(val, true);
rf->xreg = evex_xreg(val, false);
rf->xregxv = evex_xreg(val, true);
rf->vreg = evex_vreg(val, false);
rf->vregxv = evex_vreg(val, true);
rf->rreg = evex_rreg(val);
rf->map = evex_map(val);
rf->xmap = rf->map + MAP_BASE_EVEX;
rf->pp = evex_pp(val);
rf->l = evex_l(val);
rf->w = evex_w(val);
rf->z = evex_z(val);
rf->b = evex_b(val);
rf->nd = rf->b;
rf->zu = rf->b;
rf->aaa = evex_aaa(val);
rf->scc = evex_scc(val);
rf->dfl = evex_dfl(val);
rf->nf = evex_nf(val);
rf->flags = REX_EV | REX_P | ((~val >> 13) & 7) | (rf->w << 3);
}
/* ------ Set value for all moptypes ------ */
/* case statements for original REX */
#define CASE_REX \
case 0x40: case 0x41: case 0x42: case 0x43: \
case 0x44: case 0x45: case 0x46: case 0x47: \
case 0x48: case 0x49: case 0x4a: case 0x4b: \
case 0x4c: case 0x4d: case 0x4e: case 0x4f
static const uint8_t *
parse_rex(struct rexfields *rf, uint8_t op, const uint8_t *p)
{
uint32_t breg = 0;
uint32_t xreg = 0;
uint32_t vreg = 0;
uint32_t val = op;
rf->opc = op;
switch (op) {
CASE_REX:
rf->type = REX_REX;
rf->flags = op;
rf->len = 1;
rf->raw = op;
rf->opc = 0x40; /* Mask out payload bits */
breg = rex_breg(op);
xreg = rex_xreg(op);
rf->rreg = rex_rreg(op);
rf->w = rex_w(op);
break;
case 0xd5:
rf->type = REX_REX2;
rf->len = 2;
rf->raw = val = getu16(p);
rf->flags = REX_2 | REX_P | ((val >> 8) & 15);
rf->opc = (uint8_t)val;
breg = rex2_breg(val);
xreg = rex2_xreg(val);
rf->rreg = rex2_rreg(val);
rf->w = rex2_w(val);
rf->map = rex2_map(val);
rf->xmap = rf->map + MAP_BASE_REX2;
break;
case 0xc5:
rf->raw = val = getu16(p);
val = vex2to3(val);
rf->map = 1;
rf->xmap = rf->map + MAP_BASE_VEX;
rf->len = 2;
goto vex_common;
case 0x8f:
rf->raw = val = op + (getu16(p+1) << 8);
rf->map = vex3_map(val);
if (rf->map < 8)
return NULL;
rf->xmap = rf->map + MAP_BASE_XOP;
rf->len = 3;
goto vex_common;
case 0xc4:
rf->raw = val = op + (getu16(p+1) << 8);
rf->map = vex3_map(val);
rf->xmap = rf->map + MAP_BASE_VEX;
rf->len = 3;
vex_common:
rf->type = REX_VEX;
breg = vex3_breg(val);
xreg = vex3_xreg(val);
vreg = vex3_vreg(val);
rf->rreg = vex3_rreg(val);
rf->pp = vex3_pp(val);
rf->l = vex3_l(val);
rf->w = vex3_w(val);
rf->flags = REX_P | REX_V | ((~val >> 8) & 7) | (rf->w << 3);
break;
case 0x62:
parse_evex(rf, getu32(p));
return p + rf->len;
default:
return p; /* Not a prefix */
}
rf->bregbv = rf->breg = breg;
rf->xregxv = rf->xreg = xreg;
rf->vregxv = rf->vreg = vreg;
return p + rf->len;
}
/*
* The buffer must contain at least 20 readable bytes, although the
* actual values beyond the end of the current valid instruction do
* not matter. This function returns NULL if the instruction is
* inherently invalid.
*/
const uint8_t *
parse_prefixes(struct prefix_info *pf, const uint8_t *data, int bits)
{
bool end_prefix;
const uint8_t *p = data;
const uint8_t *maxp;
nasm_zero(*pf);
/*
* The maximum instruction length is 15 bytes; fail in parse_prefixes()
* unless there is at least one byte left for the actual opcode.
*/
maxp = p + 15 - 1;
pf->asize = bits;
pf->osize = (bits == 64) ? 32 : bits;
/*
* WAIT is not really a prefix, but an instruction in its own
* right. Only decode it as the very first byte (otherwise
* prefixes apply to the WAIT instruction, not to anything
* following it!) so that in case WAIT actually is prefixed with
* something, those prefixes will be separately emitted by
* eat_byte().
*
* Since WAIT is really an instruction, it doesn't count towards
* the length of the following instruction, either.
*/
if (*p == 0x9b) {
pf->wait = *p++;
maxp++; /* Does not count toward instruction length */
}
end_prefix = false;
while (!end_prefix) {
uint8_t b = *p;
switch (b) {
case 0xf2:
case 0xf3:
pf->rep = b;
pf->rex.pp = b ^ 0xfd; /* F2 = 3, F3 = 2 */
p++;
break;
case 0xf0:
pf->lock = b;
p++;
break;
case 0x26:
pf->segover = R_ES;
goto isseg;
case 0x2e:
pf->segover = R_CS;
goto isseg;
case 0x36:
pf->segover = R_SS;
goto isseg;
case 0x3e:
pf->segover = R_DS;
goto isseg;
case 0x64:
pf->segover = R_FS;
goto isseg;
case 0x65:
pf->segover = R_GS;
isseg:
pf->seg = b;
p++;
break;
case 0x66:
pf->osize = (bits == 16) ? 32 : 16;
pf->osp = b;
pf->rex.pp = 1;
p++;
break;
case 0x67:
pf->asize = (bits == 32) ? 16 : 32;
pf->asp = b;
p++;
break;
CASE_REX:
case 0xd5: /* REX2 */
if (bits == 64)
p = parse_rex(&pf->rex, b, p);
end_prefix = true;
break;
case 0x8f: /* XOP */
if (!(p[1] & 030)) {
/* Only maps 8-31 valid to protect 8F /0 */
end_prefix = true;
break;
}
/* fall through */
case 0xc4: /* VEX2 */
case 0xc5: /* VEX3 */
case 0x62: /* EVEX */
if (bits == 64 || (p[1] & 0xe0) == 0xe0)
p = parse_rex(&pf->rex, b, p);
end_prefix = true;
break;
default:
end_prefix = true;
break;
}
if (p > maxp)
return NULL; /* Invalid instruction */
}
switch (pf->rex.type) {
case REX_VEX:
case REX_EVEX:
if (pf->osp || pf->rep)
return NULL; /* Invalid instruction (illegal prefix) */
break;
case REX_REX2:
break;
case REX_REX:
/* Redundant REX prefixes are ignored */
while ((*p & 0xf0) == 0x40) {
p++;
if (p > maxp)
return NULL;
}
/* fall through */
case REX_NONE:
/*
* Look for legacy map prefixes. These must come after all
* possible REX prefixes.
*/
if (*p == 0x0f) {
pf->rex.map = 1;
p++;
switch (*p) {
case 0x38:
pf->rex.map = 2;
p++;
break;
case 0x3a:
pf->rex.map = 3;
p++;
break;
default:
break;
}
}
pf->rex.xmap = pf->rex.map + MAP_BASE_NOVEX;
break;
}
if (p > maxp)
return NULL;
return p;
}