diff options
author | Anas Nashif <anas.nashif@intel.com> | 2013-04-14 01:07:52 -0700 |
---|---|---|
committer | Anas Nashif <anas.nashif@intel.com> | 2013-04-14 01:07:52 -0700 |
commit | 02a48f17aa3a8080563593ab849bd2458a0c3113 (patch) | |
tree | e683d520d73e96fcb7a6827026d23537c0817788 /insns.pl | |
parent | 300d4816804c8ceb4a4601a49ec3ec479c1951b5 (diff) | |
download | nasm-upstream/2.10.07.tar.gz nasm-upstream/2.10.07.tar.bz2 nasm-upstream/2.10.07.zip |
Imported Upstream version 2.10.07upstream/2.10.07upstream-2.10.07
Diffstat (limited to 'insns.pl')
-rwxr-xr-x | insns.pl | 1042 |
1 files changed, 520 insertions, 522 deletions
@@ -1,7 +1,7 @@ #!/usr/bin/perl ## -------------------------------------------------------------------------- -## -## Copyright 1996-2009 The NASM Authors - All Rights Reserved +## +## Copyright 1996-2012 The NASM Authors - All Rights Reserved ## See the file AUTHORS included with the NASM distribution for ## the specific copyright holders. ## @@ -15,7 +15,7 @@ ## 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 @@ -52,9 +52,9 @@ $vex_classes = scalar(@vex_class); for ($c = 0; $c < $vex_classes; $c++) { $vexmap{$vex_class[$c]} = $c; for ($m = 0; $m < 32; $m++) { - for ($p = 0; $p < 4; $p++) { - push(@vexlist, sprintf("%s%02X%01X", $vex_class[$c], $m, $p)); - } + for ($p = 0; $p < 4; $p++) { + push(@vexlist, sprintf("%s%02X%01X", $vex_class[$c], $m, $p)); + } } } @disasm_prefixes = (@vexlist, @disasm_prefixes); @@ -67,13 +67,13 @@ print STDERR "Reading insns.dat...\n"; undef $output; foreach $arg ( @ARGV ) { if ( $arg =~ /^\-/ ) { - if ( $arg =~ /^\-([abdin])$/ ) { - $output = $1; - } else { - die "$0: Unknown option: ${arg}\n"; - } + if ( $arg =~ /^\-([abdin])$/ ) { + $output = $1; + } else { + die "$0: Unknown option: ${arg}\n"; + } } else { - push (@args, $arg); + push (@args, $arg); } } @@ -91,72 +91,72 @@ while (<F>) { next if ( /^\s*(\;.*|)$/ ); # comments or blank lines unless (/^\s*(\S+)\s+(\S+)\s+(\S+|\[.*\])\s+(\S+)\s*$/) { - warn "line $line does not contain four fields\n"; - next; + warn "line $line does not contain four fields\n"; + next; } @fields = ($1, $2, $3, $4); @field_list = ([@fields, 0]); if ($fields[1] =~ /\*/) { - # This instruction has relaxed form(s) - if ($fields[2] !~ /^\[/) { - warn "line $line has an * operand but uses raw bytecodes\n"; - next; - } - - $opmask = 0; - @ops = split(/,/, $fields[1]); - for ($oi = 0; $oi < scalar @ops; $oi++) { - if ($ops[$oi] =~ /\*$/) { - if ($oi == 0) { - warn "line $line has a first operand with a *\n"; - next; - } - $opmask |= 1 << $oi; - } - } - - for ($oi = 1; $oi < (1 << scalar @ops); $oi++) { - if (($oi & ~$opmask) == 0) { - my @xops = (); - my $omask = ~$oi; - for ($oj = 0; $oj < scalar(@ops); $oj++) { - if ($omask & 1) { - push(@xops, $ops[$oj]); - } - $omask >>= 1; - } - push(@field_list, [$fields[0], join(',', @xops), - $fields[2], $fields[3], $oi]); - } - } + # This instruction has relaxed form(s) + if ($fields[2] !~ /^\[/) { + warn "line $line has an * operand but uses raw bytecodes\n"; + next; + } + + $opmask = 0; + @ops = split(/,/, $fields[1]); + for ($oi = 0; $oi < scalar @ops; $oi++) { + if ($ops[$oi] =~ /\*$/) { + if ($oi == 0) { + warn "line $line has a first operand with a *\n"; + next; + } + $opmask |= 1 << $oi; + } + } + + for ($oi = 1; $oi < (1 << scalar @ops); $oi++) { + if (($oi & ~$opmask) == 0) { + my @xops = (); + my $omask = ~$oi; + for ($oj = 0; $oj < scalar(@ops); $oj++) { + if ($omask & 1) { + push(@xops, $ops[$oj]); + } + $omask >>= 1; + } + push(@field_list, [$fields[0], join(',', @xops), + $fields[2], $fields[3], $oi]); + } + } } foreach $fptr (@field_list) { - @fields = @$fptr; - ($formatted, $nd) = format_insn(@fields); - if ($formatted) { - $insns++; - $aname = "aa_$fields[0]"; - push @$aname, $formatted; - } - if ( $fields[0] =~ /cc$/ ) { - # Conditional instruction - $k_opcodes_cc{$fields[0]}++; - } else { - # Unconditional instruction - $k_opcodes{$fields[0]}++; - } - if ($formatted && !$nd) { - push @big, $formatted; - my @sseq = startseq($fields[2], $fields[4]); - foreach $i (@sseq) { - if (!defined($dinstables{$i})) { - $dinstables{$i} = []; - } - push(@{$dinstables{$i}}, $#big); - } - } + @fields = @$fptr; + ($formatted, $nd) = format_insn(@fields); + if ($formatted) { + $insns++; + $aname = "aa_$fields[0]"; + push @$aname, $formatted; + } + if ( $fields[0] =~ /cc$/ ) { + # Conditional instruction + $k_opcodes_cc{$fields[0]}++; + } else { + # Unconditional instruction + $k_opcodes{$fields[0]}++; + } + if ($formatted && !$nd) { + push @big, $formatted; + my @sseq = startseq($fields[2], $fields[4]); + foreach $i (@sseq) { + if (!defined($dinstables{$i})) { + $dinstables{$i} = []; + } + push(@{$dinstables{$i}}, $#big); + } + } } } @@ -178,9 +178,9 @@ foreach $bl (@bytecode_list) { push(@bytecode_array, $bl); while ($h ne '') { - $bytecode_pos{$h} = $bytecode_next; - $h = substr($h, 2); - $bytecode_next++; + $bytecode_pos{$h} = $bytecode_next; + $h = substr($h, 2); + $bytecode_next++; } } undef @bytecode_list; @@ -203,12 +203,12 @@ if ( !defined($output) || $output eq 'b') { $p = 0; foreach $bl (@bytecode_array) { - printf B " /* %5d */ ", $p; - foreach $d (@$bl) { - printf B "%#o,", $d; - $p++; - } - printf B "\n"; + printf B " /* %5d */ ", $p; + foreach $d (@$bl) { + printf B "%#o,", $d; + $p++; + } + printf B "\n"; } print B "};\n"; @@ -217,12 +217,12 @@ if ( !defined($output) || $output eq 'b') { print B " * Bytecode frequencies (including reuse):\n"; print B " *\n"; for ($i = 0; $i < 32; $i++) { - print B " *"; - for ($j = 0; $j < 256; $j += 32) { - print B " |" if ($j); - printf B " %3o:%4d", $i+$j, $bytecode_count[$i+$j]; - } - print B "\n"; + print B " *"; + for ($j = 0; $j < 256; $j += 32) { + print B " |" if ($j); + printf B " %3o:%4d", $i+$j, $bytecode_count[$i+$j]; + } + print B "\n"; } print B " */\n"; @@ -241,16 +241,16 @@ if ( !defined($output) || $output eq 'a' ) { print A "#include \"insns.h\"\n\n"; foreach $i (@opcodes, @opcodes_cc) { - print A "static const struct itemplate instrux_${i}[] = {\n"; - $aname = "aa_$i"; - foreach $j (@$aname) { - print A " ", codesubst($j), "\n"; - } - print A " ITEMPLATE_END\n};\n\n"; + print A "static const struct itemplate instrux_${i}[] = {\n"; + $aname = "aa_$i"; + foreach $j (@$aname) { + print A " ", codesubst($j), "\n"; + } + print A " ITEMPLATE_END\n};\n\n"; } print A "const struct itemplate * const nasm_instructions[] = {\n"; foreach $i (@opcodes, @opcodes_cc) { - print A " instrux_${i},\n"; + print A " instrux_${i},\n"; } print A "};\n"; @@ -271,69 +271,69 @@ if ( !defined($output) || $output eq 'd' ) { print D "static const struct itemplate instrux[] = {\n"; $n = 0; foreach $j (@big) { - printf D " /* %4d */ %s\n", $n++, codesubst($j); + printf D " /* %4d */ %s\n", $n++, codesubst($j); } print D "};\n"; foreach $h (sort(keys(%dinstables))) { - next if ($h eq ''); # Skip pseudo-instructions - print D "\nstatic const struct itemplate * const itable_${h}[] = {\n"; - foreach $j (@{$dinstables{$h}}) { - print D " instrux + $j,\n"; - } - print D "};\n"; + next if ($h eq ''); # Skip pseudo-instructions + print D "\nstatic const struct itemplate * const itable_${h}[] = {\n"; + foreach $j (@{$dinstables{$h}}) { + print D " instrux + $j,\n"; + } + print D "};\n"; } @prefix_list = (); foreach $h (@disasm_prefixes, '') { - for ($c = 0; $c < 256; $c++) { - $nn = sprintf("%s%02X", $h, $c); - if ($is_prefix{$nn} || defined($dinstables{$nn})) { - # At least one entry in this prefix table - push(@prefix_list, $h); - $is_prefix{$h} = 1; - last; - } - } + for ($c = 0; $c < 256; $c++) { + $nn = sprintf("%s%02X", $h, $c); + if ($is_prefix{$nn} || defined($dinstables{$nn})) { + # At least one entry in this prefix table + push(@prefix_list, $h); + $is_prefix{$h} = 1; + last; + } + } } foreach $h (@prefix_list) { - print D "\n"; - print D "static " unless ($h eq ''); - print D "const struct disasm_index "; - print D ($h eq '') ? 'itable' : "itable_$h"; - print D "[256] = {\n"; - for ($c = 0; $c < 256; $c++) { - $nn = sprintf("%s%02X", $h, $c); - if ($is_prefix{$nn}) { - die "$fname: ambiguous decoding of $nn\n" - if (defined($dinstables{$nn})); - printf D " /* 0x%02x */ { itable_%s, -1 },\n", $c, $nn; - } elsif (defined($dinstables{$nn})) { - printf D " /* 0x%02x */ { itable_%s, %u },\n", $c, - $nn, scalar(@{$dinstables{$nn}}); - } else { - printf D " /* 0x%02x */ { NULL, 0 },\n", $c; - } - } - print D "};\n"; + print D "\n"; + print D "static " unless ($h eq ''); + print D "const struct disasm_index "; + print D ($h eq '') ? 'itable' : "itable_$h"; + print D "[256] = {\n"; + for ($c = 0; $c < 256; $c++) { + $nn = sprintf("%s%02X", $h, $c); + if ($is_prefix{$nn}) { + die "$fname: ambiguous decoding of $nn\n" + if (defined($dinstables{$nn})); + printf D " /* 0x%02x */ { itable_%s, -1 },\n", $c, $nn; + } elsif (defined($dinstables{$nn})) { + printf D " /* 0x%02x */ { itable_%s, %u },\n", $c, + $nn, scalar(@{$dinstables{$nn}}); + } else { + printf D " /* 0x%02x */ { NULL, 0 },\n", $c; + } + } + print D "};\n"; } printf D "\nconst struct disasm_index * const itable_vex[%d][32][4] =\n", $vex_classes; print D "{\n"; for ($c = 0; $c < $vex_classes; $c++) { - print D " {\n"; - for ($m = 0; $m < 32; $m++) { - print D " { "; - for ($p = 0; $p < 4; $p++) { - $vp = sprintf("%s%02X%01X", $vex_class[$c], $m, $p); - printf D "%-15s", - ($is_prefix{$vp} ? sprintf("itable_%s,", $vp) : 'NULL,'); - } - print D "},\n"; - } - print D " },\n"; + print D " {\n"; + for ($m = 0; $m < 32; $m++) { + print D " { "; + for ($p = 0; $p < 4; $p++) { + $vp = sprintf("%s%02X%01X", $vex_class[$c], $m, $p); + printf D "%-15s", + ($is_prefix{$vp} ? sprintf("itable_%s,", $vp) : 'NULL,'); + } + print D "},\n"; + } + print D " },\n"; } print D "};\n"; @@ -355,10 +355,10 @@ if ( !defined($output) || $output eq 'i' ) { print I "enum opcode {\n"; $maxlen = 0; foreach $i (@opcodes, @opcodes_cc) { - print I "\tI_${i},\n"; - $len = length($i); - $len++ if ( $i =~ /cc$/ ); # Condition codes can be 3 characters long - $maxlen = $len if ( $len > $maxlen ); + print I "\tI_${i},\n"; + $len = length($i); + $len++ if ( $i =~ /cc$/ ); # Condition codes can be 3 characters long + $maxlen = $len if ( $len > $maxlen ); } print I "\tI_none = -1\n"; print I "};\n\n"; @@ -381,12 +381,12 @@ if ( !defined($output) || $output eq 'n' ) { print N "const char * const nasm_insn_names[] = {"; $first = 1; foreach $i (@opcodes, @opcodes_cc) { - print N "," if ( !$first ); - $first = 0; - $ilower = $i; - $ilower =~ s/cc$//; # Remove conditional cc suffix - $ilower =~ tr/A-Z/a-z/; # Change to lower case (Perl 4 compatible) - print N "\n\t\"${ilower}\""; + print N "," if ( !$first ); + $first = 0; + $ilower = $i; + $ilower =~ s/cc$//; # Remove conditional cc suffix + $ilower =~ tr/A-Z/a-z/; # Change to lower case (Perl 4 compatible) + print N "\n\t\"${ilower}\""; } print N "\n};\n"; close N; @@ -398,24 +398,24 @@ printf STDERR "Done: %d instructions\n", $insns; sub count_bytecodes(@) { my $skip = 0; foreach my $bc (@_) { - if ($skip) { - $skip--; - next; - } - $bytecode_count[$bc]++; - if ($bc >= 01 && $bc <= 04) { - $skip = $bc; - } elsif (($bc & ~03) == 010) { - $skip = 1; - } elsif (($bc & ~013) == 0144) { - $skip = 1; - } elsif ($bc == 0172) { - $skip = 1; - } elsif ($bc >= 0260 && $bc <= 0270) { - $skip = 2; - } elsif ($bc == 0330) { - $skip = 1; - } + if ($skip) { + $skip--; + next; + } + $bytecode_count[$bc]++; + if ($bc >= 01 && $bc <= 04) { + $skip = $bc; + } elsif (($bc & ~03) == 010) { + $skip = 1; + } elsif (($bc & ~013) == 0144) { + $skip = 1; + } elsif ($bc == 0172 || $bc == 0173) { + $skip = 1; + } elsif ($bc >= 0260 && $bc <= 0270) { + $skip = 2; + } elsif ($bc == 0330) { + $skip = 1; + } } } @@ -432,38 +432,38 @@ sub format_insn($$$$$) { $operands =~ s/:/|colon,/g; @ops = (); if ($operands ne 'void') { - foreach $op (split(/,/, $operands)) { - if ($op =~ /^\=([0-9]+)$/) { - $op = "same_as|$1"; - } else { - @opx = (); - foreach $opp (split(/\|/, $op)) { - @oppx = (); - if ($opp =~ /^(.*[^\d])(8|16|32|64|80|128|256)$/) { - my $ox = $1; - my $on = $2; - if ($ox !~ /^sbyte$/) { - $opp = $ox; - push(@oppx, "bits$on"); - } - } - $opp =~ s/^mem$/memory/; - $opp =~ s/^memory_offs$/mem_offs/; - $opp =~ s/^imm$/immediate/; - $opp =~ s/^([a-z]+)rm$/rm_$1/; - $opp =~ s/^rm$/rm_gpr/; - $opp =~ s/^reg$/reg_gpr/; - push(@opx, $opp, @oppx); - } - $op = join('|', @opx); - } - push(@ops, $op); - } + foreach $op (split(/,/, $operands)) { + if ($op =~ /^\=([0-9]+)$/) { + $op = "same_as|$1"; + } else { + @opx = (); + foreach $opp (split(/\|/, $op)) { + @oppx = (); + if ($opp =~ /^(.*[^\d])(8|16|32|64|80|128|256)$/) { + my $ox = $1; + my $on = $2; + if ($ox !~ /^(sbyte|sdword|udword)$/) { + $opp = $ox; + push(@oppx, "bits$on"); + } + } + $opp =~ s/^mem$/memory/; + $opp =~ s/^memory_offs$/mem_offs/; + $opp =~ s/^imm$/immediate/; + $opp =~ s/^([a-z]+)rm$/rm_$1/; + $opp =~ s/^rm$/rm_gpr/; + $opp =~ s/^reg$/reg_gpr/; + push(@opx, $opp, @oppx); + } + $op = join('|', @opx); + } + push(@ops, $op); + } } $num = scalar(@ops); while (scalar(@ops) < $MAX_OPERANDS) { - push(@ops, '0'); + push(@ops, '0'); } $operands = join(',', @ops); $operands =~ tr/a-z/A-Z/; @@ -490,11 +490,11 @@ sub codesubst($) { my $n; while ($s =~ /\@\@CODES-([0-9A-F]+)\@\@/) { - my $pos = $bytecode_pos{$1}; - if (!defined($pos)) { - die "$fname: no position assigned to byte code $1\n"; - } - $s = $` . "nasm_bytecodes+${pos}" . "$'"; + my $pos = $bytecode_pos{$1}; + if (!defined($pos)) { + die "$fname: no position assigned to byte code $1\n"; + } + $s = $` . "nasm_bytecodes+${pos}" . "$'"; } return $s; } @@ -505,7 +505,7 @@ sub addprefix ($@) { my @l = (); foreach $x (@list) { - push(@l, sprintf("%s%02X", $prefix, $x)); + push(@l, sprintf("%s%02X", $prefix, $x)); } return @l; @@ -521,23 +521,25 @@ sub decodify($$) { my($codestr, $relax) = @_; if ($codestr =~ /^\s*\[([^\]]*)\]\s*$/) { - return byte_code_compile($1, $relax); + return byte_code_compile($1, $relax); } my $c = $codestr; my @codes = (); - while ($c ne '') { - if ($c =~ /^\\x([0-9a-f]+)(.*)$/i) { - push(@codes, hex $1); - $c = $2; - next; - } elsif ($c =~ /^\\([0-7]{1,3})(.*)$/) { - push(@codes, oct $1); - $c = $2; - next; - } else { - die "$fname: unknown code format in \"$codestr\"\n"; + unless ($codestr eq 'ignore') { + while ($c ne '') { + if ($c =~ /^\\x([0-9a-f]+)(.*)$/i) { + push(@codes, hex $1); + $c = $2; + next; + } elsif ($c =~ /^\\([0-7]{1,3})(.*)$/) { + push(@codes, oct $1); + $c = $2; + next; + } else { + die "$fname: unknown code format in \"$codestr\"\n"; + } } } @@ -550,7 +552,7 @@ sub hexstr(@) { my $c; foreach $c (@_) { - $s .= sprintf("%02X", $c); + $s .= sprintf("%02X", $c); } return $s; } @@ -575,63 +577,63 @@ sub startseq($$) { @codes = decodify($codestr, $relax); while ($c0 = shift(@codes)) { - $c1 = $codes[0]; - if ($c0 >= 01 && $c0 <= 04) { - # Fixed byte string - my $fbs = $prefix; - while (1) { - if ($c0 >= 01 && $c0 <= 04) { - while ($c0--) { - $fbs .= sprintf("%02X", shift(@codes)); - } - } else { - last; - } - $c0 = shift(@codes); - } - - foreach $pfx (@disasm_prefixes) { - if (substr($fbs, 0, length($pfx)) eq $pfx) { - $prefix = $pfx; - $fbs = substr($fbs, length($pfx)); - last; - } - } - - if ($fbs ne '') { - return ($prefix.substr($fbs,0,2)); - } - - unshift(@codes, $c0); - } elsif ($c0 >= 010 && $c0 <= 013) { - return addprefix($prefix, $c1..($c1+7)); - } elsif (($c0 & ~013) == 0144) { - return addprefix($prefix, $c1, $c1|2); - } elsif ($c0 == 0330) { - return addprefix($prefix, $c1..($c1+15)); - } elsif ($c0 == 0 || $c0 == 0340) { - return $prefix; - } elsif ($c0 == 0344) { - return addprefix($prefix, 0x06, 0x0E, 0x16, 0x1E); - } elsif ($c0 == 0345) { - return addprefix($prefix, 0x07, 0x17, 0x1F); - } elsif ($c0 == 0346) { - return addprefix($prefix, 0xA0, 0xA8); - } elsif ($c0 == 0347) { - return addprefix($prefix, 0xA1, 0xA9); - } elsif (($c0 & ~3) == 0260 || $c0 == 0270) { - my $c,$m,$wlp; - $m = shift(@codes); - $wlp = shift(@codes); - $c = ($m >> 6); - $m = $m & 31; - $prefix .= sprintf('%s%02X%01X', $vex_class[$c], $m, $wlp & 3); - } elsif ($c0 >= 0172 && $c0 <= 174) { - shift(@codes); # Skip is4 control byte - } else { - # We really need to be able to distinguish "forbidden" - # and "ignorable" codes here - } + $c1 = $codes[0]; + if ($c0 >= 01 && $c0 <= 04) { + # Fixed byte string + my $fbs = $prefix; + while (1) { + if ($c0 >= 01 && $c0 <= 04) { + while ($c0--) { + $fbs .= sprintf("%02X", shift(@codes)); + } + } else { + last; + } + $c0 = shift(@codes); + } + + foreach $pfx (@disasm_prefixes) { + if (substr($fbs, 0, length($pfx)) eq $pfx) { + $prefix = $pfx; + $fbs = substr($fbs, length($pfx)); + last; + } + } + + if ($fbs ne '') { + return ($prefix.substr($fbs,0,2)); + } + + unshift(@codes, $c0); + } elsif ($c0 >= 010 && $c0 <= 013) { + return addprefix($prefix, $c1..($c1+7)); + } elsif (($c0 & ~013) == 0144) { + return addprefix($prefix, $c1, $c1|2); + } elsif ($c0 == 0330) { + return addprefix($prefix, $c1..($c1+15)); + } elsif ($c0 == 0 || $c0 == 0340) { + return $prefix; + } elsif ($c0 == 0344) { + return addprefix($prefix, 0x06, 0x0E, 0x16, 0x1E); + } elsif ($c0 == 0345) { + return addprefix($prefix, 0x07, 0x17, 0x1F); + } elsif ($c0 == 0346) { + return addprefix($prefix, 0xA0, 0xA8); + } elsif ($c0 == 0347) { + return addprefix($prefix, 0xA1, 0xA9); + } elsif (($c0 & ~3) == 0260 || $c0 == 0270) { + my $c,$m,$wlp; + $m = shift(@codes); + $wlp = shift(@codes); + $c = ($m >> 6); + $m = $m & 31; + $prefix .= sprintf('%s%02X%01X', $vex_class[$c], $m, $wlp & 3); + } elsif ($c0 >= 0172 && $c0 <= 173) { + shift(@codes); # Skip is4 control byte + } else { + # We really need to be able to distinguish "forbidden" + # and "ignorable" codes here + } } return $prefix; } @@ -649,7 +651,6 @@ sub startseq($$) { # r = register field in the modr/m # m = modr/m # v = VEX "v" field -# d = DREX "dst" field # i = immediate # s = register field of is4/imz2 field # - = implicit (unencoded) operand @@ -668,267 +669,264 @@ sub byte_code_compile($$) { my $op, $oq; my $opex; + my %imm_codes = ( + 'ib,s' => 014, # Signed imm8 + 'ib' => 020, # imm8 + 'ib,u' => 024, # Unsigned imm8 + 'iw' => 030, # imm16 + 'ibx' => 0274, # imm8 sign-extended to opsize + 'iwd' => 034, # imm16 or imm32, depending on opsize + 'id' => 040, # imm32 + 'idx' => 0254, # imm32 extended to 64 bits + 'iwdq' => 044, # imm16/32/64, depending on opsize + 'rel8' => 050, + 'iq' => 054, + 'rel16' => 060, + 'rel' => 064, # 16 or 32 bit relative operand + 'rel32' => 070, + 'seg' => 074, + 'ibw' => 0140, # imm16 that can be bytified + 'ibd' => 0150, # imm32 that can be bytified + 'ibd,s' => 0250 # imm32 that can be bytified, sign extended to 64 bits + ); + my %imm_codes_bytifiers = ( + 'ibw' => 0144, + 'ibd' => 0154, + 'ibd,s' => 0154 + ); + my %plain_codes = ( + 'o16' => 0320, # 16-bit operand size + 'o32' => 0321, # 32-bit operand size + 'odf' => 0322, # Operand size is default + 'o64' => 0324, # 64-bit operand size requiring REX.W + 'o64nw' => 0323, # Implied 64-bit operand size (no REX.W) + 'a16' => 0310, + 'a32' => 0311, + 'adf' => 0312, # Address size is default + 'a64' => 0313, + '!osp' => 0364, + '!asp' => 0365, + 'f2i' => 0332, # F2 prefix, but 66 for operand size is OK + 'f3i' => 0333, # F3 prefix, but 66 for operand size is OK + 'pushseg' => 0344, + 'popseg' => 0345, + 'pushseg2' => 0346, + 'popseg2' => 0347, + 'mustrep' => 0336, + 'mustrepne' => 0337, + 'rex.l' => 0334, + 'norexb' => 0314, + 'norexx' => 0315, + 'norexr' => 0316, + 'norexw' => 0317, + 'repe' => 0335, + 'nohi' => 0325, # Use spl/bpl/sil/dil even without REX + 'wait' => 0341, # Needs a wait prefix + 'resb' => 0340, + 'jcc8' => 0370, # Match only if Jcc possible with single byte + 'jmp8' => 0371, # Match only if JMP possible with single byte + 'jlen' => 0373, # Length of jump + 'hlexr' => 0271, + 'hlenl' => 0272, + 'hle' => 0273, + # This instruction takes XMM VSIB + 'vsibx' => 0374, + 'vm32x' => 0374, + 'vm64x' => 0374, + # This instruction takes YMM VSIB + 'vsiby' => 0375, + 'vm32y' => 0375, + 'vm64y' => 0375 + ); + unless ($str =~ /^(([^\s:]*)\:|)\s*(.*\S)\s*$/) { - die "$fname: $line: cannot parse: [$str]\n"; + die "$fname: $line: cannot parse: [$str]\n"; } $opr = "\L$2"; $opc = "\L$3"; my $op = 0; for ($i = 0; $i < length($opr); $i++) { - my $c = substr($opr,$i,1); - if ($c eq '+') { - $op--; - } else { - if ($relax & 1) { - $op--; - } - $relax >>= 1; - $oppos{$c} = $op++; - } + my $c = substr($opr,$i,1); + if ($c eq '+') { + $op--; + } else { + if ($relax & 1) { + $op--; + } + $relax >>= 1; + $oppos{$c} = $op++; + } } - $prefix_ok = 1; + my $last_imm = 'h'; + my $prefix_ok = 1; foreach $op (split(/\s*(?:\s|(?=[\/\\]))/, $opc)) { - if ($op eq 'o16') { - push(@codes, 0320); - } elsif ($op eq 'o32') { - push(@codes, 0321); - } elsif ($op eq 'o64') { # 64-bit operand size requiring REX.W - push(@codes, 0324); - } elsif ($op eq 'o64nw') { # Implied 64-bit operand size (no REX.W) - push(@codes, 0323); - } elsif ($op eq 'a16') { - push(@codes, 0310); - } elsif ($op eq 'a32') { - push(@codes, 0311); - } elsif ($op eq 'a64') { - push(@codes, 0313); - } elsif ($op eq '!osp') { - push(@codes, 0364); - } elsif ($op eq '!asp') { - push(@codes, 0365); - } elsif ($op eq 'rex.l') { - push(@codes, 0334); - } elsif ($op eq 'repe') { - push(@codes, 0335); - } elsif ($op eq 'nohi') { # Use spl/bpl/sil/dil even without REX - push(@codes, 0325); - } elsif ($prefix_ok && $op =~ /^(66|f2|f3|np)$/) { - # 66/F2/F3 prefix used as an opcode extension, or np = no prefix - if ($op eq '66') { - push(@codes, 0361); - } elsif ($op eq 'f2') { - push(@codes, 0362); - } elsif ($op eq 'f3') { - push(@codes, 0363); - } else { - push(@codes, 0360); - } - } elsif ($op =~ /^[0-9a-f]{2}$/) { - if (defined($litix) && $litix+$codes[$litix]+1 == scalar @codes && - $codes[$litix] < 4) { - $codes[$litix]++; - push(@codes, hex $op); - } else { - $litix = scalar(@codes); - push(@codes, 01, hex $op); - } - $prefix_ok = 0; - } elsif ($op eq '/r') { - if (!defined($oppos{'r'}) || !defined($oppos{'m'})) { - die "$fname: $line: $op requires r and m operands\n"; - } - $opex = (($oppos{'m'} & 4) ? 06 : 0) | - (($oppos{'r'} & 4) ? 05 : 0); - push(@codes, $opex) if ($opex); - push(@codes, 0100 + (($oppos{'m'} & 3) << 3) + ($oppos{'r'} & 3)); - $prefix_ok = 0; - } elsif ($op =~ m:^/([0-7])$:) { - if (!defined($oppos{'m'})) { - die "$fname: $line: $op requires m operand\n"; - } - push(@codes, 06) if ($oppos{'m'} & 4); - push(@codes, 0200 + (($oppos{'m'} & 3) << 3) + $1); - $prefix_ok = 0; - } elsif ($op =~ /^(vex|xop)(|\..*)$/) { - my $c = $vexmap{$1}; - my ($m,$w,$l,$p) = (undef,2,undef,0); - my $has_nds = 0; - my @subops = split(/\./, $op); - shift @subops; # Drop prefix - foreach $oq (@subops) { - if ($oq eq '128' || $oq eq 'l0' || $oq eq 'lz') { - $l = 0; - } elsif ($oq eq '256' || $oq eq 'l1') { - $l = 1; - } elsif ($oq eq 'lig') { - $l = 2; - } elsif ($oq eq 'w0') { - $w = 0; - } elsif ($oq eq 'w1') { - $w = 1; - } elsif ($oq eq 'wig') { - $w = 2; - } elsif ($oq eq 'ww') { - $w = 3; - } elsif ($oq eq 'p0') { - $p = 0; - } elsif ($oq eq '66' || $oq eq 'p1') { - $p = 1; - } elsif ($oq eq 'f3' || $oq eq 'p2') { - $p = 2; - } elsif ($oq eq 'f2' || $oq eq 'p3') { - $p = 3; - } elsif ($oq eq '0f') { - $m = 1; - } elsif ($oq eq '0f38') { - $m = 2; - } elsif ($oq eq '0f3a') { - $m = 3; - } elsif ($oq =~ /^m([0-9]+)$/) { - $m = $1+0; - } elsif ($oq eq 'nds' || $oq eq 'ndd' || $oq eq 'dds') { - if (!defined($oppos{'v'})) { - die "$fname: $line: vex.$oq without 'v' operand\n"; - } - $has_nds = 1; - } else { - die "$fname: $line: undefined VEX subcode: $oq\n"; - } - } - if (!defined($m) || !defined($w) || !defined($l) || !defined($p)) { - die "$fname: $line: missing fields in VEX specification\n"; - } - if (defined($oppos{'v'}) && !$has_nds) { - die "$fname: $line: 'v' operand without vex.nds or vex.ndd\n"; - } - push(@codes, defined($oppos{'v'}) ? 0260+($oppos{'v'} & 3) : 0270, - ($c << 6)+$m, ($w << 4)+($l << 2)+$p); - $prefix_ok = 0; - } elsif ($op =~ /^\/drex([01])$/) { - my $oc0 = $1; - if (!defined($oppos{'d'})) { - die "$fname: $line: DREX without a 'd' operand\n"; - } - # Note the use of *unshift* here, as opposed to *push*. - # This is because NASM want this byte code at the start of - # the instruction sequence, but the AMD documentation puts - # this at (roughly) the position of the drex byte itself. - # This allows us to match the AMD documentation and still - # do the right thing. - unshift(@codes, 0160+($oppos{'d'} & 3)+($oc0 ? 4 : 0)); - unshift(@codes, 05) if ($oppos{'d'} & 4); - } elsif ($op =~ /^(ib\,s|ib|ibx|ib\,w|iw|iwd|id|idx|iwdq|rel|rel8|rel16|rel32|iq|seg|ibw|ibd|ibd,s)$/) { - if (!defined($oppos{'i'})) { - die "$fname: $line: $op without 'i' operand\n"; - } - if ($op eq 'ib,s') { # Signed imm8 - push(@codes, 05) if ($oppos{'i'} & 4); - push(@codes, 014+($oppos{'i'} & 3)); - } elsif ($op eq 'ib') { # imm8 - push(@codes, 05) if ($oppos{'i'} & 4); - push(@codes, 020+($oppos{'i'} & 3)); - } elsif ($op eq 'ib,u') { # Unsigned imm8 - push(@codes, 05) if ($oppos{'i'} & 4); - push(@codes, 024+($oppos{'i'} & 3)); - } elsif ($op eq 'iw') { # imm16 - push(@codes, 05) if ($oppos{'i'} & 4); - push(@codes, 030+($oppos{'i'} & 3)); - } elsif ($op eq 'ibx') { # imm8 sign-extended to opsize - push(@codes, 05) if ($oppos{'i'} & 4); - push(@codes, 0274+($oppos{'i'} & 3)); - } elsif ($op eq 'iwd') { # imm16 or imm32, depending on opsize - push(@codes, 05) if ($oppos{'i'} & 4); - push(@codes, 034+($oppos{'i'} & 3)); - } elsif ($op eq 'id') { # imm32 - push(@codes, 05) if ($oppos{'i'} & 4); - push(@codes, 040+($oppos{'i'} & 3)); - } elsif ($op eq 'idx') { # imm32 extended to 64 bits - push(@codes, 05) if ($oppos{'i'} & 4); - push(@codes, 0254+($oppos{'i'} & 3)); - } elsif ($op eq 'iwdq') { # imm16/32/64, depending on opsize - push(@codes, 05) if ($oppos{'i'} & 4); - push(@codes, 044+($oppos{'i'} & 3)); - } elsif ($op eq 'rel8') { - push(@codes, 05) if ($oppos{'i'} & 4); - push(@codes, 050+($oppos{'i'} & 3)); - } elsif ($op eq 'iq') { - push(@codes, 05) if ($oppos{'i'} & 4); - push(@codes, 054+($oppos{'i'} & 3)); - } elsif ($op eq 'rel16') { - push(@codes, 05) if ($oppos{'i'} & 4); - push(@codes, 060+($oppos{'i'} & 3)); - } elsif ($op eq 'rel') { # 16 or 32 bit relative operand - push(@codes, 05) if ($oppos{'i'} & 4); - push(@codes, 064+($oppos{'i'} & 3)); - } elsif ($op eq 'rel32') { - push(@codes, 05) if ($oppos{'i'} & 4); - push(@codes, 070+($oppos{'i'} & 3)); - } elsif ($op eq 'seg') { - push(@codes, 05) if ($oppos{'i'} & 4); - push(@codes, 074+($oppos{'i'} & 3)); - } elsif ($op eq 'ibw') { # imm16 that can be bytified - if (!defined($s_pos)) { - die "$fname: $line: $op without a +s byte\n"; - } - $codes[$s_pos] += 0144; - push(@codes, 05) if ($oppos{'i'} & 4); - push(@codes, 0140+($oppos{'i'} & 3)); - } elsif ($op eq 'ibd') { # imm32 that can be bytified - if (!defined($s_pos)) { - die "$fname: $line: $op without a +s byte\n"; - } - $codes[$s_pos] += 0154; - push(@codes, 05) if ($oppos{'i'} & 4); - push(@codes, 0150+($oppos{'i'} & 3)); - } elsif ($op eq 'ibd,s') { - # imm32 that can be bytified, sign extended to 64 bits - if (!defined($s_pos)) { - die "$fname: $line: $op without a +s byte\n"; - } - $codes[$s_pos] += 0154; - push(@codes, 05) if ($oppos{'i'} & 4); - push(@codes, 0250+($oppos{'i'} & 3)); - } - $prefix_ok = 0; - } elsif ($op eq '/is4') { - if (!defined($oppos{'s'})) { - die "$fname: $line: $op without 's' operand\n"; - } - if (defined($oppos{'i'})) { - push(@codes, 0172, ($oppos{'s'} << 3)+$oppos{'i'}); - } else { - push(@codes, 0174, $oppos{'s'}); - } - $prefix_ok = 0; - } elsif ($op =~ /^\/is4\=([0-9]+)$/) { - my $imm = $1; - if (!defined($oppos{'s'})) { - die "$fname: $line: $op without 's' operand\n"; - } - if ($imm < 0 || $imm > 15) { - die "$fname: $line: invalid imm4 value for $op: $imm\n"; - } - push(@codes, 0173, ($oppos{'s'} << 4) + $imm); - $prefix_ok = 0; - } elsif ($op =~ /^([0-9a-f]{2})\+s$/) { - if (!defined($oppos{'i'})) { - die "$fname: $line: $op without 'i' operand\n"; - } - $s_pos = scalar @codes; - push(@codes, 05) if ($oppos{'i'} & 4); - push(@codes, $oppos{'i'} & 3, hex $1); - $prefix_ok = 0; - } elsif ($op =~ /^([0-9a-f]{2})\+c$/) { - push(@codes, 0330, hex $1); - $prefix_ok = 0; - } elsif ($op =~ /^\\([0-7]+|x[0-9a-f]{2})$/) { - # Escape to enter literal bytecodes - push(@codes, oct $1); - } else { - die "$fname: $line: unknown operation: $op\n"; - } + my $pc = $plain_codes{$op}; + + if (defined $pc) { + # Plain code + push(@codes, $pc); + } elsif ($prefix_ok && $op =~ /^(66|f2|f3|np)$/) { + # 66/F2/F3 prefix used as an opcode extension, or np = no prefix + if ($op eq '66') { + push(@codes, 0361); + } elsif ($op eq 'f2') { + push(@codes, 0362); + } elsif ($op eq 'f3') { + push(@codes, 0363); + } else { + push(@codes, 0360); + } + } elsif ($op =~ /^[0-9a-f]{2}$/) { + if (defined($litix) && $litix+$codes[$litix]+1 == scalar @codes && + $codes[$litix] < 4) { + $codes[$litix]++; + push(@codes, hex $op); + } else { + $litix = scalar(@codes); + push(@codes, 01, hex $op); + } + $prefix_ok = 0; + } elsif ($op eq '/r') { + if (!defined($oppos{'r'}) || !defined($oppos{'m'})) { + die "$fname: $line: $op requires r and m operands\n"; + } + $opex = (($oppos{'m'} & 4) ? 06 : 0) | + (($oppos{'r'} & 4) ? 05 : 0); + push(@codes, $opex) if ($opex); + push(@codes, 0100 + (($oppos{'m'} & 3) << 3) + ($oppos{'r'} & 3)); + $prefix_ok = 0; + } elsif ($op =~ m:^/([0-7])$:) { + if (!defined($oppos{'m'})) { + die "$fname: $line: $op requires m operand\n"; + } + push(@codes, 06) if ($oppos{'m'} & 4); + push(@codes, 0200 + (($oppos{'m'} & 3) << 3) + $1); + $prefix_ok = 0; + } elsif ($op =~ /^(vex|xop)(|\..*)$/) { + my $c = $vexmap{$1}; + my ($m,$w,$l,$p) = (undef,2,undef,0); + my $has_nds = 0; + my @subops = split(/\./, $op); + shift @subops; # Drop prefix + foreach $oq (@subops) { + if ($oq eq '128' || $oq eq 'l0' || $oq eq 'lz') { + $l = 0; + } elsif ($oq eq '256' || $oq eq 'l1') { + $l = 1; + } elsif ($oq eq 'lig') { + $l = 2; + } elsif ($oq eq 'w0') { + $w = 0; + } elsif ($oq eq 'w1') { + $w = 1; + } elsif ($oq eq 'wig') { + $w = 2; + } elsif ($oq eq 'ww') { + $w = 3; + } elsif ($oq eq 'p0') { + $p = 0; + } elsif ($oq eq '66' || $oq eq 'p1') { + $p = 1; + } elsif ($oq eq 'f3' || $oq eq 'p2') { + $p = 2; + } elsif ($oq eq 'f2' || $oq eq 'p3') { + $p = 3; + } elsif ($oq eq '0f') { + $m = 1; + } elsif ($oq eq '0f38') { + $m = 2; + } elsif ($oq eq '0f3a') { + $m = 3; + } elsif ($oq =~ /^m([0-9]+)$/) { + $m = $1+0; + } elsif ($oq eq 'nds' || $oq eq 'ndd' || $oq eq 'dds') { + if (!defined($oppos{'v'})) { + die "$fname: $line: vex.$oq without 'v' operand\n"; + } + $has_nds = 1; + } else { + die "$fname: $line: undefined VEX subcode: $oq\n"; + } + } + if (!defined($m) || !defined($w) || !defined($l) || !defined($p)) { + die "$fname: $line: missing fields in VEX specification\n"; + } + if (defined($oppos{'v'}) && !$has_nds) { + die "$fname: $line: 'v' operand without vex.nds or vex.ndd\n"; + } + push(@codes, defined($oppos{'v'}) ? 0260+($oppos{'v'} & 3) : 0270, + ($c << 6)+$m, ($w << 4)+($l << 2)+$p); + $prefix_ok = 0; + } elsif (defined $imm_codes{$op}) { + if ($op eq 'seg') { + if ($last_imm lt 'i') { + die "$fname: $line: seg without an immediate operand\n"; + } + } else { + $last_imm++; + if ($last_imm gt 'j') { + die "$fname: $line: too many immediate operands\n"; + } + } + if (!defined($oppos{$last_imm})) { + die "$fname: $line: $op without '$last_imm' operand\n"; + } + push(@codes, 05) if ($oppos{$last_imm} & 4); + push(@codes, $imm_codes{$op} + ($oppos{$last_imm} & 3)); + if (defined $imm_codes_bytifiers{$op}) { + if (!defined($s_pos)) { + die "$fname: $line: $op without a +s byte\n"; + } + $codes[$s_pos] += $imm_codes_bytifiers{$op}; + } + $prefix_ok = 0; + } elsif ($op eq '/is4') { + if (!defined($oppos{'s'})) { + die "$fname: $line: $op without 's' operand\n"; + } + if (defined($oppos{'i'})) { + push(@codes, 0172, ($oppos{'s'} << 3)+$oppos{'i'}); + } else { + push(@codes, 05) if ($oppos{'s'} & 4); + push(@codes, 0174+($oppos{'s'} & 3)); + } + $prefix_ok = 0; + } elsif ($op =~ /^\/is4\=([0-9]+)$/) { + my $imm = $1; + if (!defined($oppos{'s'})) { + die "$fname: $line: $op without 's' operand\n"; + } + if ($imm < 0 || $imm > 15) { + die "$fname: $line: invalid imm4 value for $op: $imm\n"; + } + push(@codes, 0173, ($oppos{'s'} << 4) + $imm); + $prefix_ok = 0; + } elsif ($op =~ /^([0-9a-f]{2})\+s$/) { + if (!defined($oppos{'i'})) { + die "$fname: $line: $op without 'i' operand\n"; + } + $s_pos = scalar @codes; + push(@codes, 05) if ($oppos{'i'} & 4); + push(@codes, $oppos{'i'} & 3, hex $1); + $prefix_ok = 0; + } elsif ($op =~ /^([0-9a-f]{2})\+c$/) { + push(@codes, 0330, hex $1); + $prefix_ok = 0; + } elsif ($op =~ /^([0-9a-f]{2})\+r$/) { + if (!defined($oppos{'r'})) { + die "$fname: $line: $op without 'r' operand\n"; + } + push(@codes, 05) if ($oppos{'r'} & 4); + push(@codes, 010 + ($oppos{'r'} & 3), hex $1); + $prefix_ok = 0; + } elsif ($op =~ /^\\([0-7]+|x[0-9a-f]{2})$/) { + # Escape to enter literal bytecodes + push(@codes, oct $1); + } else { + die "$fname: $line: unknown operation: $op\n"; + } } return @codes; |