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