/* ----------------------------------------------------------------------- * * * 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; }