mirror of
				https://github.com/netwide-assembler/nasm.git
				synced 2025-10-10 00:25:06 -04:00 
			
		
		
		
	Infrastructure support for AMD's new XOP prefix
Handle AMD's XOP prefixes; they use basically the same encoding as VEX prefixes, so treat them simply as a variant of VEX. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
This commit is contained in:
		
							
								
								
									
										21
									
								
								assemble.c
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								assemble.c
									
									
									
									
									
								
							| @@ -56,19 +56,20 @@ | |||||||
|  *                 is not equal to the truncated and sign-extended 32-bit |  *                 is not equal to the truncated and sign-extended 32-bit | ||||||
|  *                 operand; used for 32-bit immediates in 64-bit mode. |  *                 operand; used for 32-bit immediates in 64-bit mode. | ||||||
|  * \254..\257    - a signed 32-bit operand to be extended to 64 bits. |  * \254..\257    - a signed 32-bit operand to be extended to 64 bits. | ||||||
|  * \260..\263    - this instruction uses VEX rather than REX, with the |  * \260..\263    - this instruction uses VEX/XOP rather than REX, with the | ||||||
|  *		   V field taken from operand 0..3. |  *		   V field taken from operand 0..3. | ||||||
|  * \270		 - this instruction uses VEX rather than REX, with the |  * \270		 - this instruction uses VEX/XOP rather than REX, with the | ||||||
|  *		   V field set to 1111b. |  *		   V field set to 1111b. | ||||||
|  * |  * | ||||||
|  * VEX prefixes are followed by the sequence: |  * VEX/XOP prefixes are followed by the sequence: | ||||||
|  * \mm\wlp         where mm is the M field; and wlp is: |  * \tmm\wlp        where mm is the M field; and wlp is: | ||||||
|  *                 00 0ww lpp |  *                 00 0ww lpp | ||||||
|  *                 [w0] ww = 0 for W = 0 |  *                 [w0] ww = 0 for W = 0 | ||||||
|  *                 [w1] ww = 1 for W = 1 |  *                 [w1] ww = 1 for W = 1 | ||||||
|  *                 [wx] ww = 2 for W don't care (always assembled as 0) |  *                 [wx] ww = 2 for W don't care (always assembled as 0) | ||||||
|  *                 [ww] ww = 3 for W used as REX.W |  *                 [ww] ww = 3 for W used as REX.W | ||||||
|  * |  * | ||||||
|  |  * t = 0 for VEX (C4/C5), t = 1 for XOP (8F). | ||||||
|  * |  * | ||||||
|  * \274..\277    - a signed byte immediate operand, from operand 0..3, |  * \274..\277    - a signed byte immediate operand, from operand 0..3, | ||||||
|  *                 which is to be extended to the operand size. |  *                 which is to be extended to the operand size. | ||||||
| @@ -936,14 +937,14 @@ static int64_t calcsize(int32_t segment, int64_t offset, int bits, | |||||||
| 	case4(0260): | 	case4(0260): | ||||||
| 	    ins->rex |= REX_V; | 	    ins->rex |= REX_V; | ||||||
| 	    ins->drexdst = regval(opx); | 	    ins->drexdst = regval(opx); | ||||||
| 	    ins->vex_m = *codes++; | 	    ins->vex_cm = *codes++; | ||||||
| 	    ins->vex_wlp = *codes++; | 	    ins->vex_wlp = *codes++; | ||||||
| 	    break; | 	    break; | ||||||
|  |  | ||||||
| 	case 0270: | 	case 0270: | ||||||
| 	    ins->rex |= REX_V; | 	    ins->rex |= REX_V; | ||||||
| 	    ins->drexdst = 0; | 	    ins->drexdst = 0; | ||||||
| 	    ins->vex_m = *codes++; | 	    ins->vex_cm = *codes++; | ||||||
| 	    ins->vex_wlp = *codes++; | 	    ins->vex_wlp = *codes++; | ||||||
| 	    break; | 	    break; | ||||||
|  |  | ||||||
| @@ -1141,7 +1142,7 @@ static int64_t calcsize(int32_t segment, int64_t offset, int bits, | |||||||
| 	    errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode"); | 	    errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode"); | ||||||
| 	    return -1; | 	    return -1; | ||||||
| 	} | 	} | ||||||
| 	if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_R|REX_B))) | 	if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_R|REX_B))) | ||||||
| 	    length += 3; | 	    length += 3; | ||||||
| 	else | 	else | ||||||
| 	    length += 2; | 	    length += 2; | ||||||
| @@ -1536,9 +1537,9 @@ static void gencode(int32_t segment, int64_t offset, int bits, | |||||||
| 	case4(0260): | 	case4(0260): | ||||||
| 	case 0270: | 	case 0270: | ||||||
| 	    codes += 2; | 	    codes += 2; | ||||||
| 	    if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_X|REX_B))) { | 	    if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B))) { | ||||||
| 		bytes[0] = 0xc4; | 		bytes[0] = (ins->vex_cm >> 6) ? 0x8f : 0xc4; | ||||||
| 		bytes[1] = ins->vex_m | ((~ins->rex & 7) << 5); | 		bytes[1] = (ins->vex_cm & 31) | ((~ins->rex & 7) << 5); | ||||||
| 		bytes[2] = ((ins->rex & REX_W) << (7-3)) | | 		bytes[2] = ((ins->rex & REX_W) << (7-3)) | | ||||||
| 		    ((~ins->drexdst & 15)<< 3) | (ins->vex_wlp & 07); | 		    ((~ins->drexdst & 15)<< 3) | (ins->vex_wlp & 07); | ||||||
| 		out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG); | 		out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG); | ||||||
|   | |||||||
							
								
								
									
										25
									
								
								disasm.c
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								disasm.c
									
									
									
									
									
								
							| @@ -49,6 +49,7 @@ struct prefix_info { | |||||||
|     uint8_t wait;		/* WAIT "prefix" present */ |     uint8_t wait;		/* WAIT "prefix" present */ | ||||||
|     uint8_t lock;		/* Lock prefix present */ |     uint8_t lock;		/* Lock prefix present */ | ||||||
|     uint8_t vex[3];		/* VEX prefix present */ |     uint8_t vex[3];		/* VEX prefix present */ | ||||||
|  |     uint8_t vex_c;		/* VEX "class" (VEX, XOP, ...) */ | ||||||
|     uint8_t vex_m;		/* VEX.M field */ |     uint8_t vex_m;		/* VEX.M field */ | ||||||
|     uint8_t vex_v; |     uint8_t vex_v; | ||||||
|     uint8_t vex_lp;		/* VEX.LP fields */ |     uint8_t vex_lp;		/* VEX.LP fields */ | ||||||
| @@ -1049,6 +1050,7 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, | |||||||
| 		prefix.vex[1] = *data++; | 		prefix.vex[1] = *data++; | ||||||
|  |  | ||||||
| 		prefix.rex = REX_V; | 		prefix.rex = REX_V; | ||||||
|  | 		prefix.vex_c = 0; | ||||||
|  |  | ||||||
| 		if (prefix.vex[0] == 0xc4) { | 		if (prefix.vex[0] == 0xc4) { | ||||||
| 		    prefix.vex[2] = *data++; | 		    prefix.vex[2] = *data++; | ||||||
| @@ -1064,7 +1066,28 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, | |||||||
| 		    prefix.vex_lp = prefix.vex[1] & 7; | 		    prefix.vex_lp = prefix.vex[1] & 7; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		ix = itable_VEX[prefix.vex_m][prefix.vex_lp]; | 		ix = itable_VEX[0][prefix.vex_m][prefix.vex_lp]; | ||||||
|  | 	    } | ||||||
|  | 	    end_prefix = true; | ||||||
|  | 	    break; | ||||||
|  |  | ||||||
|  | 	case 0x8F: | ||||||
|  | 	    if ((data[1] & 030) != 0 && | ||||||
|  | 		(segsize == 64 || (data[1] & 0xc0) == 0xc0)) { | ||||||
|  | 		prefix.vex[0] = *data++; | ||||||
|  | 		prefix.vex[1] = *data++; | ||||||
|  | 		prefix.vex[2] = *data++; | ||||||
|  |  | ||||||
|  | 		prefix.rex = REX_V; | ||||||
|  | 		prefix.vex_c = 1; | ||||||
|  |  | ||||||
|  | 		prefix.rex |= (~prefix.vex[1] >> 5) & 7; /* REX_RXB */ | ||||||
|  | 		prefix.rex |= (prefix.vex[2] >> (7-3)) & REX_W; | ||||||
|  | 		prefix.vex_m = prefix.vex[1] & 0x1f; | ||||||
|  | 		prefix.vex_v = (~prefix.vex[2] >> 3) & 15; | ||||||
|  | 		prefix.vex_lp = prefix.vex[2] & 7; | ||||||
|  |  | ||||||
|  | 		ix = itable_VEX[1][prefix.vex_m][prefix.vex_lp]; | ||||||
| 	    } | 	    } | ||||||
| 	    end_prefix = true; | 	    end_prefix = true; | ||||||
| 	    break; | 	    break; | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								insns.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								insns.h
									
									
									
									
									
								
							| @@ -32,7 +32,7 @@ struct disasm_index { | |||||||
| /* Tables for the assembler and disassembler, respectively */ | /* Tables for the assembler and disassembler, respectively */ | ||||||
| extern const struct itemplate * const nasm_instructions[]; | extern const struct itemplate * const nasm_instructions[]; | ||||||
| extern const struct disasm_index itable[256]; | extern const struct disasm_index itable[256]; | ||||||
| extern const struct disasm_index * const itable_VEX[32][8]; | extern const struct disasm_index * const itable_VEX[2][32][8]; | ||||||
|  |  | ||||||
| /* Common table for the byte codes */ | /* Common table for the byte codes */ | ||||||
| extern const uint8_t nasm_bytecodes[]; | extern const uint8_t nasm_bytecodes[]; | ||||||
|   | |||||||
							
								
								
									
										61
									
								
								insns.pl
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								insns.pl
									
									
									
									
									
								
							| @@ -14,11 +14,17 @@ | |||||||
| # This should match MAX_OPERANDS from nasm.h | # This should match MAX_OPERANDS from nasm.h | ||||||
| $MAX_OPERANDS = 5; | $MAX_OPERANDS = 5; | ||||||
|  |  | ||||||
| # Add VEX prefixes | # Add VEX/XOP prefixes | ||||||
|  | @vex_class = ( 'VEX', 'XOP' ); | ||||||
|  | $vex_classes = scalar(@vex_class); | ||||||
| @vexlist = (); | @vexlist = (); | ||||||
| for ($m = 0; $m < 32; $m++) { | %vexmap = (); | ||||||
|     for ($lp = 0; $lp < 8; $lp++) { | for ($c = 0; $c < $vex_classes; $c++) { | ||||||
| 	push(@vexlist, sprintf("VEX%02X%01X", $m, $lp)); |     $vexmap{"\L$vex_class[$c]"} = $c; | ||||||
|  |     for ($m = 0; $m < 32; $m++) { | ||||||
|  | 	for ($lp = 0; $lp < 8; $lp++) { | ||||||
|  | 	    push(@vexlist, sprintf("%s%02X%01X", $vex_class[$c], $m, $lp)); | ||||||
|  | 	} | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @disasm_prefixes = (@vexlist, @disasm_prefixes); | @disasm_prefixes = (@vexlist, @disasm_prefixes); | ||||||
| @@ -243,20 +249,26 @@ if ( !defined($output) || $output eq 'd' ) { | |||||||
| 	print D "};\n"; | 	print D "};\n"; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     print D "\nconst struct disasm_index * const itable_VEX[32][8] = {\n   "; |     printf D "\nconst struct disasm_index * const itable_VEX[%d][32][8] =\n", | ||||||
|     for ($m = 0; $m < 32; $m++) { |         $vex_classes; | ||||||
| 	print D " {\n"; |     print D "{\n"; | ||||||
| 	for ($lp = 0; $lp < 8; $lp++) { |     for ($c = 0; $c < $vex_classes; $c++) { | ||||||
| 	    $vp = sprintf("VEX%02X%01X", $m, $lp); | 	print D "    {\n"; | ||||||
| 	    if ($is_prefix{$vp}) { | 	for ($m = 0; $m < 32; $m++) { | ||||||
| 		printf D "        itable_%s,\n", $vp; | 	    print D "        {\n"; | ||||||
| 	    } else { | 	    for ($lp = 0; $lp < 8; $lp++) { | ||||||
| 		print  D "        NULL,\n"; | 		$vp = sprintf("%s%02X%01X", $vex_class[$c], $m, $lp); | ||||||
|  | 		if ($is_prefix{$vp}) { | ||||||
|  | 		    printf D "            itable_%s,\n", $vp; | ||||||
|  | 		} else { | ||||||
|  | 		    print  D "            NULL,\n"; | ||||||
|  | 		} | ||||||
| 	    } | 	    } | ||||||
|  | 	    print D "        },\n"; | ||||||
| 	} | 	} | ||||||
| 	print D "    },"; | 	print D "    },\n"; | ||||||
|     } |     } | ||||||
|     print D "\n};\n"; |     print D "};\n"; | ||||||
|  |  | ||||||
|     close D; |     close D; | ||||||
| } | } | ||||||
| @@ -521,10 +533,12 @@ sub startseq($) { | |||||||
|       } elsif ($c0 == 0347) { |       } elsif ($c0 == 0347) { | ||||||
| 	  return addprefix($prefix, 0xA1, 0xA9); | 	  return addprefix($prefix, 0xA1, 0xA9); | ||||||
|       } elsif (($c0 & ~3) == 0260 || $c0 == 0270) { |       } elsif (($c0 & ~3) == 0260 || $c0 == 0270) { | ||||||
| 	  my $m,$wlp,$vxp; | 	  my $c,$m,$wlp; | ||||||
| 	  $m   = shift(@codes); | 	  $m   = shift(@codes); | ||||||
| 	  $wlp = shift(@codes); | 	  $wlp = shift(@codes); | ||||||
| 	  $prefix .= sprintf('VEX%02X%01X', $m, $wlp & 7); | 	  $c = ($m >> 6); | ||||||
|  | 	  $m = $m & 31; | ||||||
|  | 	  $prefix .= sprintf('%s%02X%01X', $vex_class[$c], $m, $wlp & 7); | ||||||
|       } elsif ($c0 >= 0172 && $c0 <= 174) { |       } elsif ($c0 >= 0172 && $c0 <= 174) { | ||||||
| 	  shift(@codes);	# Skip is4 control byte | 	  shift(@codes);	# Skip is4 control byte | ||||||
|       } else { |       } else { | ||||||
| @@ -644,13 +658,14 @@ sub byte_code_compile($) { | |||||||
| 	    push(@codes, 06) if ($oppos{'m'} & 4); | 	    push(@codes, 06) if ($oppos{'m'} & 4); | ||||||
| 	    push(@codes, 0200 + (($oppos{'m'} & 3) << 3) + $1); | 	    push(@codes, 0200 + (($oppos{'m'} & 3) << 3) + $1); | ||||||
| 	    $prefix_ok = 0; | 	    $prefix_ok = 0; | ||||||
| 	} elsif ($op =~ /^vex(|\..*)$/) { | 	} elsif ($op =~ /^(vex|xop)(|\..*)$/) { | ||||||
|  | 	    my $c = $vexmap{$1}; | ||||||
| 	    my ($m,$w,$l,$p) = (undef,2,undef,0); | 	    my ($m,$w,$l,$p) = (undef,2,undef,0); | ||||||
| 	    my $has_nds = 0; | 	    my $has_nds = 0; | ||||||
| 	    foreach $oq (split(/\./, $op)) { | 	    my @subops = split(/\./, $op); | ||||||
| 		if ($oq eq 'vex') { | 	    shift @subops;	# Drop prefix | ||||||
| 		    # prefix | 	    foreach $oq (@subops) { | ||||||
| 		} elsif ($oq eq '128' || $oq eq 'l0') { | 		if ($oq eq '128' || $oq eq 'l0') { | ||||||
| 		    $l = 0; | 		    $l = 0; | ||||||
| 		} elsif ($oq eq '256' || $oq eq 'l1') { | 		} elsif ($oq eq '256' || $oq eq 'l1') { | ||||||
| 		    $l = 1; | 		    $l = 1; | ||||||
| @@ -692,7 +707,7 @@ sub byte_code_compile($) { | |||||||
| 		die "$fname: $line: 'v' operand without vex.nds or vex.ndd\n"; | 		die "$fname: $line: 'v' operand without vex.nds or vex.ndd\n"; | ||||||
| 	    } | 	    } | ||||||
| 	    push(@codes, defined($oppos{'v'}) ? 0260+($oppos{'v'} & 3) : 0270, | 	    push(@codes, defined($oppos{'v'}) ? 0260+($oppos{'v'} & 3) : 0270, | ||||||
| 		 $m, ($w << 3)+($l << 2)+$p); | 		 ($c << 6)+$m, ($w << 3)+($l << 2)+$p); | ||||||
| 	    $prefix_ok = 0; | 	    $prefix_ok = 0; | ||||||
| 	} elsif ($op =~ /^\/drex([01])$/) { | 	} elsif ($op =~ /^\/drex([01])$/) { | ||||||
| 	    my $oc0 = $1; | 	    my $oc0 = $1; | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								nasm.h
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								nasm.h
									
									
									
									
									
								
							| @@ -599,7 +599,7 @@ enum ccode {			/* condition code names */ | |||||||
| #define REX_H		0x80	/* High register present, REX forbidden */ | #define REX_H		0x80	/* High register present, REX forbidden */ | ||||||
| #define REX_D		0x0100	/* Instruction uses DREX instead of REX */ | #define REX_D		0x0100	/* Instruction uses DREX instead of REX */ | ||||||
| #define REX_OC		0x0200	/* DREX suffix has the OC0 bit set */ | #define REX_OC		0x0200	/* DREX suffix has the OC0 bit set */ | ||||||
| #define REX_V		0x0400	/* Instruction uses VEX instead of REX */ | #define REX_V		0x0400	/* Instruction uses VEX/XOP instead of REX */ | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Note that because segment registers may be used as instruction |  * Note that because segment registers may be used as instruction | ||||||
| @@ -702,7 +702,7 @@ typedef struct insn {		/* an instruction itself */ | |||||||
|     bool forw_ref;              /* is there a forward reference? */ |     bool forw_ref;              /* is there a forward reference? */ | ||||||
|     int rex;			/* Special REX Prefix */ |     int rex;			/* Special REX Prefix */ | ||||||
|     int drexdst;		/* Destination register for DREX/VEX suffix */ |     int drexdst;		/* Destination register for DREX/VEX suffix */ | ||||||
|     int vex_m;			/* M register for VEX prefix */ |     int vex_cm;			/* Class and M field for VEX prefix */ | ||||||
|     int vex_wlp;		/* W, P and L information for VEX prefix */ |     int vex_wlp;		/* W, P and L information for VEX prefix */ | ||||||
| } insn; | } insn; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user