mirror of
				https://github.com/netwide-assembler/nasm.git
				synced 2025-10-10 00:25:06 -04:00 
			
		
		
		
	Only VEX and EVEX may not take REP or OSZ prefixes. Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
		
			
				
	
	
		
			511 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			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;
 | |
| }
 |