mirror of
https://github.com/netwide-assembler/nasm.git
synced 2025-11-08 23:27:15 -05:00
Fix matching of branch instructions with prefixes and sizes
Matching of branch instructions with prefixes and sizes is, to say the least, tricky. Work through it, and add a new macro to help. Fixes: https://github.com/netwide-assembler/nasm/issues/144 Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
This commit is contained in:
@@ -1400,28 +1400,9 @@ static int64_t calcsize(insn *ins, const struct itemplate * const temp)
|
||||
ins->itemp = temp; /* Instruction template */
|
||||
eat = EA_SCALAR; /* Expect a scalar EA */
|
||||
|
||||
/* Default operand size */
|
||||
/* Default operand size (prefixes are handled in the byte code) */
|
||||
ins->op_size = bits != 16 ? 32 : 16;
|
||||
|
||||
if (bits == 64) {
|
||||
if (ins->prefixes[PPS_ASIZE] == P_A16) {
|
||||
nasm_warn(WARN_PREFIX_BADMODE_A16,
|
||||
"a64 prefix invalid in 64-bit mode");
|
||||
ins->prefixes[PPS_ASIZE] = 0;
|
||||
}
|
||||
} else {
|
||||
if (ins->prefixes[PPS_OSIZE] == P_O64) {
|
||||
nasm_warn(WARN_PREFIX_BADMODE_O64,
|
||||
"o64 prefix invalid in %d-bit mode", bits);
|
||||
ins->prefixes[PPS_OSIZE] = P_none;
|
||||
}
|
||||
if (ins->prefixes[PPS_ASIZE] == P_A64) {
|
||||
nasm_warn(WARN_PREFIX_BADMODE_A64,
|
||||
"a64 prefix invalid in %d-bit mode", bits);
|
||||
ins->prefixes[PPS_ASIZE] = P_none;
|
||||
}
|
||||
}
|
||||
|
||||
nasm_zero(need_pfx);
|
||||
|
||||
while (*codes) {
|
||||
@@ -3061,7 +3042,7 @@ static enum match_result matches(const struct itemplate * const itemp,
|
||||
|
||||
/* "Default" operand size (from mode and prefixes only) */
|
||||
op_size = ins->op_size;
|
||||
if (itemp_has(itemp, IF_NWSIZE) && op_size == 32) {
|
||||
if (bits == 64 && itemp_has(itemp, IF_NWSIZE) && op_size == 32) {
|
||||
/* If this is an nw instruction, default to 64 bits in 64-bit mode */
|
||||
op_size = bits;
|
||||
}
|
||||
@@ -3101,18 +3082,23 @@ static enum match_result matches(const struct itemplate * const itemp,
|
||||
|
||||
/* Handle implied SHORT or NEAR */
|
||||
if (unlikely(ttype & (NEAR|SHORT))) {
|
||||
/* Treat BYTE as an alias for SHORT, ignoring size */
|
||||
if (isize[i] == BITS8) {
|
||||
itype[i] |= SHORT;
|
||||
isize[i] = 0;
|
||||
}
|
||||
/* An explicit SHORT or BITS8 cancels NEAR; are synonyms */
|
||||
if (itype[i] & SHORT) {
|
||||
itype[i] &= ~NEAR;
|
||||
}
|
||||
/* NEAR is implicit unless otherwise specified */
|
||||
if (!(itype[i] & (FAR|SHORT))) {
|
||||
itype[i] |= ttype & NEAR;
|
||||
}
|
||||
if ((ttype & (NEAR|SHORT)) == (NEAR|SHORT)) {
|
||||
/* Only a short form exists; allow both NEAR and SHORT */
|
||||
/* Only a short form exists; this is specially coded */
|
||||
if (!(itype[i] & (FAR|ABS)))
|
||||
itype[i] |= NEAR|SHORT;
|
||||
} else if ((itype[i] & SHORT) || isize[i] == BITS8) {
|
||||
/* An explicit SHORT or BITS8 cancel NEAR; are synonyms */
|
||||
itype[i] &= ~NEAR;
|
||||
if (!isize[i])
|
||||
isize[i] = BITS8;
|
||||
} else if (!(itype[i] & (FAR|ABS|SHORT))) {
|
||||
/* NEAR is implicit unless otherwise specified */
|
||||
itype[i] |= ttype & NEAR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -964,8 +964,10 @@ restart_parse:
|
||||
while (i == TOKEN_SPECIAL || i == TOKEN_SIZE) {
|
||||
switch (tokval.t_integer) {
|
||||
case S_BYTE:
|
||||
if (!setsize) /* we want to use only the first */
|
||||
if (!setsize) { /* we want to use only the first */
|
||||
result->opt |= OPTIM_NO_Jcc_RELAX | OPTIM_NO_JMP_RELAX;
|
||||
op->type |= BITS8;
|
||||
}
|
||||
setsize = 1;
|
||||
break;
|
||||
case S_WORD:
|
||||
@@ -1014,9 +1016,12 @@ restart_parse:
|
||||
op->type |= FAR;
|
||||
break;
|
||||
case S_NEAR:
|
||||
/* This is not legacy behavior, even if it perhaps should be */
|
||||
/* result->opt |= OPTIM_NO_Jcc_RELAX | OPTIM_NO_JMP_RELAX; */
|
||||
op->type |= NEAR;
|
||||
break;
|
||||
case S_SHORT:
|
||||
result->opt |= OPTIM_NO_Jcc_RELAX | OPTIM_NO_JMP_RELAX;
|
||||
op->type |= SHORT;
|
||||
break;
|
||||
case S_ABS:
|
||||
|
||||
@@ -259,20 +259,11 @@ pragma-unknown [off] unknown \c{%pragma} facility or directive
|
||||
Warns about an unknown \c{%pragma} directive.
|
||||
This is not yet implemented for most cases.
|
||||
|
||||
prefix-badmode-a64 [err] a64 prefix invalid in 16/32-bit mode
|
||||
Warns that an \c{a64} prefix was specified in 16- or 32-bit
|
||||
mode. If the error is demoted to a warning or suppressed, the
|
||||
prefix is ignored by the assembler.
|
||||
|
||||
prefix-badmode-o64 [err] o64 prefix invalid in 16/32-bit mode
|
||||
Warns that an \c{a64} prefix was specified in 16- or 32-bit
|
||||
mode. If the error is demoted to a warning or suppressed, the
|
||||
prefix is ignored by the assembler.
|
||||
|
||||
prefix-badmode-a16 [err] a16 prefix invalid in 64-bit mode
|
||||
Warns that an \c{a16} prefix was specified in 64-bit mode.
|
||||
If the error is demoted to a warning or suppressed, the
|
||||
prefix is ignored by the assembler.
|
||||
prefix is ignored by the assembler, but is likely to trigger
|
||||
futher errors.
|
||||
|
||||
prefix-bnd [on] invalid \c{BND} prefix
|
||||
=bnd
|
||||
|
||||
@@ -54,10 +54,9 @@ It is the production version of NASM since 2025.
|
||||
\b Hopefully fix building with OpenWatcom.
|
||||
|
||||
\b Generate a warning, promoted to error by default, on the use of
|
||||
\c{a64} or \c{o64} prefixes in 16- or 32-bit mode or \c{a16}
|
||||
prefixes in 64-bit mode. Those prefixes are not encodable; if
|
||||
demoted to a warning or suppressed the prefix is ignored, but
|
||||
likely will generate additional, harder to debug, error messages.
|
||||
\c{o64} prefixes in 16- or 32-bit mode. If demoted to a warning or
|
||||
suppressed the prefix is ignored, but likely will trigger
|
||||
subsequent, harder to debug, error messages.
|
||||
|
||||
|
||||
\S{cl-3.00} Version 3.00
|
||||
|
||||
3297
test/jmpxx.asm
Normal file
3297
test/jmpxx.asm
Normal file
File diff suppressed because it is too large
Load Diff
97
test/jmpxx.pl
Normal file
97
test/jmpxx.pl
Normal file
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use integer;
|
||||
|
||||
my $bw = 1;
|
||||
my @errs = ();
|
||||
foreach my $errf (@ARGV) {
|
||||
if (open(my $e, '<', $errf)) {
|
||||
while (defined(my $l = <$e>)) {
|
||||
if ($l =~ /^.*?\:([0-9]+)\:/) {
|
||||
$errs[$1] |= $bw;
|
||||
}
|
||||
}
|
||||
close($e);
|
||||
}
|
||||
$bw <<= 1;
|
||||
}
|
||||
|
||||
my $ln = 0;
|
||||
|
||||
$ln++; print "%pragma list options -befms\n";
|
||||
$ln++; print "%ifndef ERR\n";
|
||||
$ln++; print " %define ERR 0\n";
|
||||
$ln++; print "%endif\n";
|
||||
|
||||
my @nots = ('');
|
||||
|
||||
for (my $cc = 1; $cc < 7; $cc++) {
|
||||
my $ss = 'no';
|
||||
$ss .= 'w' if ($cc & 1);
|
||||
$ss .= 'd' if ($cc & 2);
|
||||
$ss .= 'q' if ($cc & 4);
|
||||
$ln++; print "%macro $ss 1+.nolist\n";
|
||||
$ln++; printf " %%if ERR || !(__BITS__ & 0x%02x)\n", $cc << 4;
|
||||
$ln++; print "\t%1\n";
|
||||
$ln++; print " %endif\n";
|
||||
$ln++; print "%endmacro\n";
|
||||
push(@nots, "$ss");
|
||||
}
|
||||
$ln++; print "%macro bogus 1+.nolist\n";
|
||||
$ln++; printf " %%if ERR\n";
|
||||
$ln++; print "\t%1\n";
|
||||
$ln++; print " %endif\n";
|
||||
$ln++; print "%endmacro\n";
|
||||
push(@nots, 'bogus');
|
||||
|
||||
$ln++; print "\n";
|
||||
|
||||
$ln++; print "\tsection text1\n";
|
||||
$ln++; print "top:\n";
|
||||
$ln++; print "\ttimes 128 nop\n";
|
||||
$ln++; print "\n";
|
||||
|
||||
foreach my $insn ('jmp', 'call', 'jz', 'jcxz', 'jecxz', 'jrcxz',
|
||||
'loop', 'loope', 'loopne') {
|
||||
$ln++; print "here_$insn:\n";
|
||||
|
||||
foreach my $tgt ('$', 'top', 'there') {
|
||||
foreach my $str ('', 'strict') {
|
||||
foreach my $sz ('', 'byte', 'word', 'dword', 'qword') {
|
||||
foreach my $o ('', 'o16', 'o32', 'o64') {
|
||||
foreach my $sn ('', 'short', 'near') {
|
||||
my $is_short =
|
||||
($sn eq 'short' || $insn =~ /^(j\w?cxz|loop\w*)$/);
|
||||
|
||||
$ln++;
|
||||
$errs[$ln] |= 3 if ($sz eq 'qword' || $o eq 'o64'
|
||||
|| $insn eq 'jrcxz');
|
||||
$errs[$ln] |= 4 if ($sz =~ /^d?word$'/ || $o =~ /^o(16|32)$/ ||
|
||||
$insn eq 'jcxz');
|
||||
if (($sz eq 'word' && $o =~ /^o(32|64)$/) ||
|
||||
($sz eq 'dword' && $o =~ /^o(16|64)$/) ||
|
||||
($sz eq 'qword' && $o =~ /^o(16|32)$/) ||
|
||||
($sz eq 'byte') ||
|
||||
($is_short &&
|
||||
($sn eq 'near' || $tgt ne '$' || $insn eq 'call'))) {
|
||||
$errs[$ln] |= 7;
|
||||
}
|
||||
|
||||
my $is_short =
|
||||
|
||||
printf " %-5s %s\n",
|
||||
$nots[$errs[$ln]],
|
||||
join(' ', grep { $_ ne '' }
|
||||
($o,$insn,$str,$sz,$sn,$tgt));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ln++; print "\n";
|
||||
$ln++; print "\tsection text2\n";
|
||||
$ln++; print "there:\n";
|
||||
$ln++; print "\tret\n";
|
||||
@@ -8,5 +8,5 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"error": "over"
|
||||
"update": false
|
||||
}
|
||||
|
||||
BIN
travis/test/jmpxx-o0.bin16.t
Normal file
BIN
travis/test/jmpxx-o0.bin16.t
Normal file
Binary file not shown.
BIN
travis/test/jmpxx-o0.bin32.t
Normal file
BIN
travis/test/jmpxx-o0.bin32.t
Normal file
Binary file not shown.
BIN
travis/test/jmpxx-o0.bin64.t
Normal file
BIN
travis/test/jmpxx-o0.bin64.t
Normal file
Binary file not shown.
BIN
travis/test/jmpxx-o1.bin16.t
Normal file
BIN
travis/test/jmpxx-o1.bin16.t
Normal file
Binary file not shown.
BIN
travis/test/jmpxx-o1.bin32.t
Normal file
BIN
travis/test/jmpxx-o1.bin32.t
Normal file
Binary file not shown.
BIN
travis/test/jmpxx-o1.bin64.t
Normal file
BIN
travis/test/jmpxx-o1.bin64.t
Normal file
Binary file not shown.
BIN
travis/test/jmpxx-ox.bin16.t
Normal file
BIN
travis/test/jmpxx-ox.bin16.t
Normal file
Binary file not shown.
BIN
travis/test/jmpxx-ox.bin32.t
Normal file
BIN
travis/test/jmpxx-ox.bin32.t
Normal file
Binary file not shown.
BIN
travis/test/jmpxx-ox.bin64.t
Normal file
BIN
travis/test/jmpxx-ox.bin64.t
Normal file
Binary file not shown.
3297
travis/test/jmpxx.asm
Normal file
3297
travis/test/jmpxx.asm
Normal file
File diff suppressed because it is too large
Load Diff
76
travis/test/jmpxx.json
Normal file
76
travis/test/jmpxx.json
Normal file
@@ -0,0 +1,76 @@
|
||||
[
|
||||
{
|
||||
"description": "Test combinations of jump instructions (-Ox, 16 bits)",
|
||||
"id": "jmpxx",
|
||||
"format": "bin",
|
||||
"source": "jmpxx.asm",
|
||||
"option": "--bits 16 -Ox",
|
||||
"target": [
|
||||
{ "output": "jmpxx-ox.bin16" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Test combinations of jump instructions (-O0, 16 bits)",
|
||||
"ref": "jmpxx",
|
||||
"option": "--bits 16 -O0",
|
||||
"target": [
|
||||
{ "output": "jmpxx-o0.bin16" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Test combinations of jump instructions (-O1, 16 bits)",
|
||||
"ref": "jmpxx",
|
||||
"option": "--bits 16 -O1",
|
||||
"target": [
|
||||
{ "output": "jmpxx-o1.bin16" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Test combinations of jump instructions (-Ox, 32 bits)",
|
||||
"ref": "jmpxx",
|
||||
"option": "--bits 32 -Ox",
|
||||
"target": [
|
||||
{ "output": "jmpxx-ox.bin32" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Test combinations of jump instructions (-O0, 32 bits)",
|
||||
"ref": "jmpxx",
|
||||
"option": "--bits 32 -O0",
|
||||
"target": [
|
||||
{ "output": "jmpxx-o0.bin32" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Test combinations of jump instructions (-O1, 32 bits)",
|
||||
"ref": "jmpxx",
|
||||
"option": "--bits 32 -O1",
|
||||
"target": [
|
||||
{ "output": "jmpxx-o1.bin32" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Test combinations of jump instructions (-Ox, 64 bits)",
|
||||
"ref": "jmpxx",
|
||||
"option": "--bits 64 -Ox",
|
||||
"target": [
|
||||
{ "output": "jmpxx-ox.bin64" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Test combinations of jump instructions (-O0, 64 bits)",
|
||||
"ref": "jmpxx",
|
||||
"option": "--bits 64 -O0",
|
||||
"target": [
|
||||
{ "output": "jmpxx-o0.bin64" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Test combinations of jump instructions (-O1, 64 bits)",
|
||||
"ref": "jmpxx",
|
||||
"option": "--bits 64 -O1",
|
||||
"target": [
|
||||
{ "output": "jmpxx-o1.bin64" }
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -30,7 +30,6 @@ if_("AR2", "SB, SW, SD applies to operand 2");
|
||||
if_("AR3", "SB, SW, SD applies to operand 3");
|
||||
if_("AR4", "SB, SW, SD applies to operand 4");
|
||||
# These must match the order of the BITSx flags in opflags.h
|
||||
# Are these obsolete?
|
||||
if_("SB", "Unsized operands can't be non-byte");
|
||||
if_("SW", "Unsized operands can't be non-word");
|
||||
if_("SD", "Unsized operands can't be non-dword");
|
||||
@@ -41,7 +40,8 @@ if_("SY", "Unsized operands can't be non-yword");
|
||||
if_("SZ", "Unsized operands can't be non-zword");
|
||||
# End BITSx order match requirement
|
||||
if_("NWSIZE", "Operand size defaults to 64 in 64-bit mode");
|
||||
if_("OSIZE", "Unsized operands must match the default operand size");
|
||||
# OSIZE can be modified by osp prefixes, but not by other operands
|
||||
if_("OSIZE", "Unsized operands must match the operand size");
|
||||
if_("ASIZE", "Unsized operands must match the address size");
|
||||
if_("ANYSIZE", "Ignore operand size even if explicit");
|
||||
if_("SX", "Unsized operands not allowed");
|
||||
|
||||
@@ -262,19 +262,15 @@ $bwd CMPXCHG486 rm#,reg# [mr: 0f a6# /r] 486,SM,UNDOC,NOLONG,ND,LOCK,OBSOL
|
||||
|
||||
;# Jumps
|
||||
; APX absolute 64-bit jmp
|
||||
JMPABS imm64 [i: a64 np rex2 a1 iq ] APX
|
||||
JMP imm64|abs [i: a64 np rex2 a1 iq ] APX,ND
|
||||
JMPABS imm64|abs [i: a64 np rex2 a1 iq ] APX,ND
|
||||
; Jump-over emulation of JMPABS on !APX
|
||||
JMPABS imm64 [i: a64 ff 25 00 00 00 00 iq ] NOAPX,LONG,ND
|
||||
JMP imm64|abs [i: a64 ff 25 00 00 00 00 iq ] NOAPX,LONG,ND
|
||||
JMPABS imm64|abs [i: a64 ff 25 00 00 00 00 iq ] NOAPX,LONG,ND
|
||||
JMPABS imm64|near [i: a64 np rex2 a1 iq ] APX
|
||||
JMP imm64|abs|near [i: a64 np rex2 a1 iq ] APX,ND
|
||||
JMPABS imm64|abs|near [i: a64 np rex2 a1 iq ] APX,ND
|
||||
|
||||
; Call/jmp near imm/reg/mem are always 64-bit in long mode.
|
||||
JMP imm8|short [i: nw eb rel8] 8086,NOAPX
|
||||
JMP imm [i: jmp8 nw eb rel8] 8086,JMP_RELAX,NOAPX,ND
|
||||
$wdq JMP imm#|near [i: nw o# e9 rel] 8086,BND,(wd:NOLONG,OSIZE)
|
||||
$wdq JMP rm#|near [m: nw o# ff /4] 8086,BND,(wd:NOLONG,OSIZE)
|
||||
$br JMP short [i: os eb rel8] 8086,NOAPX,ND
|
||||
$br JMP near [i: jmp8 os eb rel8] 8086,NOAPX,JMP_RELAX
|
||||
$br JMP near [i: os e9 rel] 8086,BND
|
||||
$wdq JMP rm#|near [m: nw o# ff /4] 8086,BND,OSIZE
|
||||
|
||||
$wd JMP imm#|far [i: o# ea iwd seg] 8086,OSIZE,ND,NOLONG
|
||||
; These are hacks to support the legacy syntax "[d]word seg:offs" to mean "seg:[d]word offs"
|
||||
@@ -287,37 +283,37 @@ $wd JMP imm16:imm#|far [ji: o# ea i# iw] 8086,OSIZE,AR1,NOLONG,ND
|
||||
; This is an intentional "programmer friendliness" quirk.
|
||||
$wdq JMP mem#|far [m: o# ff /5] 8086,OSIZE,NWSIZE,(w:NOLONG)
|
||||
|
||||
Jcc imm8|short [i: nw 70+c rel8] 8086,ND,BND,SX,JCC_HINT,NOAPX
|
||||
Jcc imm [i: jcc8 nw 70+c rel8] 8086,BND,SX,JCC_HINT,NOAPX
|
||||
$wdq Jcc imm#|near [i: nw o# 0f 80+c rel] 386,BND,NOAPX,JCC_HINT,(wd:NOLONG,OSIZE)
|
||||
$br Jcc short [i: os 70+c rel8] 8086,ND,BND,JCC_HINT,NOAPX
|
||||
$br Jcc near [i: jcc8 os 70+c rel8] 8086,BND,JCC_HINT,JMP_RELAX,NOAPX
|
||||
$br Jcc near [i: os 0f 80+c rel] 386,BND,NOAPX,JCC_HINT
|
||||
; Jump-over emulation of Jcc on < 386
|
||||
Jcc imm16|near [i: nw 71+c jlen e9 rel16] 8086,ND,NOAPX,NOLONG
|
||||
; This could/should be improved to handle osp properly
|
||||
Jcc imm [i: 71+c jlen e9 rel] 8086,ND,NOAPX,OSIZE
|
||||
|
||||
; The following only have short forms, hence imm8|near|short
|
||||
JCXZ imm8|near|short [i: a16 e3 rel8] 8086,NOLONG
|
||||
JECXZ imm8|near|short [i: a32 e3 rel8] 386,NOAPX
|
||||
JRCXZ imm8|near|short [i: a64 e3 rel8] X86_64,LONG,NOAPX
|
||||
$wdq JCXZ imm8|near|short,cx# [i-: a# e3 rel8] 8086,ND
|
||||
; The following only have short forms, but use the *address* size to encode
|
||||
; the size of the counter register.
|
||||
$br $wdq JCX#Z near|short [i: a# os e3 rel8] 8086,NOAPX
|
||||
$br $wdq JCXZ near|short,cx# [i: a# os e3 rel8] 8086,NOAPX,ND
|
||||
|
||||
$zwdq LOOP% imm8|near|short [i: a# nw e2 rel8] 8086,NOAPX,(wdq:ND)
|
||||
$zwdq LOOPE% imm8|near|short [i: a# nw e1 rel8] 8086,NOAPX,(wdq:ND)
|
||||
$zwdq LOOPNE% imm8|near|short [i: a# nw e0 rel8] 8086,NOAPX,(wdq:ND)
|
||||
$zwdq LOOPZ% imm8|near|short [i: a# nw e1 rel8] 8086,NOAPX,ND
|
||||
$zwdq LOOPNZ% imm8|near|short [i: a# nw e0 rel8] 8086,NOAPX,ND
|
||||
$wdq LOOP imm8|near|short,cx# [i-: a# nw e2 rel8] 8086,NOAPX
|
||||
$wdq LOOPE imm8|near|short,cx# [i-: a# nw e1 rel8] 8086,NOAPX
|
||||
$wdq LOOPNE imm8|near|short,cx# [i-: a# nw e0 rel8] 8086,NOAPX
|
||||
$wdq LOOPZ imm8|near|short,cx# [i-: a# nw e1 rel8] 8086,NOAPX,ND
|
||||
$wdq LOOPNZ imm8|near|short,cx# [i-: a# nw e0 rel8] 8086,NOAPX,ND
|
||||
$br $zwdq LOOP% near|short [i: a# os e2 rel8] 8086,NOAPX,(wdq:ND)
|
||||
$br $zwdq LOOPE% near|short [i: a# os e1 rel8] 8086,NOAPX,(wdq:ND)
|
||||
$br $zwdq LOOPNE% near|short [i: a# os e0 rel8] 8086,NOAPX,(wdq:ND)
|
||||
$br $zwdq LOOPZ% near|short [i: a# os e1 rel8] 8086,NOAPX,ND
|
||||
$br $zwdq LOOPNZ% near|short [i: a# os e0 rel8] 8086,NOAPX,ND
|
||||
$br $wdq LOOP near|short,cx# [i-: a# os e2 rel8] 8086,NOAPX
|
||||
$br $wdq LOOPE near|short,cx# [i-: a# os e1 rel8] 8086,NOAPX
|
||||
$br $wdq LOOPNE near|short,cx# [i-: a# os e0 rel8] 8086,NOAPX
|
||||
$br $wdq LOOPZ near|short,cx# [i-: a# os e1 rel8] 8086,NOAPX
|
||||
$br $wdq LOOPNZ near|short,cx# [i-: a# os e0 rel8] 8086,NOAPX
|
||||
|
||||
; JMPE is obsolete, but seems to be used by a fair number of virtual environments?
|
||||
$zwdq JMPE imm##|near [i: nw o# 0f b8 rel] IA64
|
||||
$br JMPE near [i: os 0f b8 rel] IA64
|
||||
; 0f 00 /6 with a prefix has been repurposed in long mode
|
||||
$wdq JMPE rm#|near [m: nw o# np 0f 00 /6] IA64
|
||||
$wd JMPE rm#|near [m: o# 0f 00 /6] IA64,ND,NOLONG
|
||||
$wdq JMPE rm#|near [m: nw o# np 0f 00 /6] IA64,OSIZE
|
||||
$wd JMPE rm#|near [m: o# 0f 00 /6] IA64,OSIZE,NOLONG
|
||||
|
||||
;# Call and return
|
||||
$wdq CALL imm##|near [i: nw o# e8 rel] 8086,BND,NOAPX,(wd:OSIZE,NOLONG)
|
||||
$br CALL near [i: os e8 rel] 8086,BND,NOAPX
|
||||
$wdq CALL rm#|near [m: nw o# ff /2] 8086,BND,(wd:OSIZE,NOLONG)
|
||||
|
||||
$wd CALL imm#|far [i: o# 9a iwd seg] 8086,ND,NOLONG,OSIZE
|
||||
@@ -2913,18 +2909,10 @@ VPGATHERQQ ymmreg,ymem64,ymmreg [rmv: vm64y vex.dds.256.66.0f38.w1 91 /r] AVX2
|
||||
|
||||
;# Intel Transactional Synchronization Extensions (TSX)
|
||||
XABORT imm8 [i: c6 f8 ib] RTM
|
||||
XBEGIN imm [i: nw odf c7 f8 rel] RTM
|
||||
XBEGIN imm|near [i: nw odf c7 f8 rel] RTM,SX,ND
|
||||
XBEGIN imm16 [i: o16 c7 f8 rel] RTM,NOLONG,SX
|
||||
XBEGIN imm16|near [i: o16 c7 f8 rel] RTM,NOLONG,SX,ND
|
||||
XBEGIN imm32 [i: o32 c7 f8 rel] RTM,NOLONG,SX
|
||||
XBEGIN imm32|near [i: o32 c7 f8 rel] RTM,NOLONG,SX,ND
|
||||
XBEGIN imm64 [i: o64nw c7 f8 rel] RTM,LONG,SX
|
||||
XBEGIN imm64|near [i: o64nw c7 f8 rel] RTM,LONG,SX,ND
|
||||
$br XBEGIN near [i: os c7 f8 rel] RTM
|
||||
XEND void [ 0f 01 d5] RTM
|
||||
XTEST void [ 0f 01 d6] HLE,RTM
|
||||
|
||||
|
||||
PREFETCHWT1 mem8 [m: 0f 0d /2 ] PREFETCHWT1
|
||||
|
||||
;# Intel Memory Protection Extensions (MPX)
|
||||
|
||||
@@ -487,7 +487,7 @@ if ( $output eq 'b') {
|
||||
print B " *";
|
||||
for ($j = 0; $j < 256; $j += 32) {
|
||||
print B " |" if ($j);
|
||||
printf B " %3o:%4d", $i+$j, $bytecode_count[$i+$j];
|
||||
printf B " %3o:%5d", $i+$j, $bytecode_count[$i+$j];
|
||||
}
|
||||
print B "\n";
|
||||
}
|
||||
@@ -691,12 +691,14 @@ sub count_bytecodes(@) {
|
||||
$skip = 1;
|
||||
} elsif (($bc & ~013) == 0144) {
|
||||
$skip = 1;
|
||||
} elsif ($bc == 0172 || $bc == 0173) {
|
||||
} elsif ($bc >= 0171 && $bc <= 0173) {
|
||||
$skip = 1;
|
||||
} elsif (($bc & ~3) == 0260 || $bc == 0270) { # VEX
|
||||
$skip = 2;
|
||||
} elsif (($bc & ~3) == 0240 || $bc == 0250) { # EVEX
|
||||
$skip = 4;
|
||||
} elsif (($bc & ~3) == 0304) {
|
||||
$skip = 2;
|
||||
} elsif ($bc == 0330) {
|
||||
$skip = 1;
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ sub func_multisize($$$) {
|
||||
$ins = $o.$ins;
|
||||
$o = '';
|
||||
|
||||
while ($ins =~ /^(.*?)((?:\b[0-9a-f]{2}(?:\+r)?|\bsbyte|\bimm|\bsel|\bopt\w?|\b[ioa]d?|\b(?:reg_)?[abcd]x|\bk?reg|\bk?rm|\bw)?\#{1,2}|\b(?:reg|rm)64\b|\b(?:o64)?nw\b|\b(?:NO)?LONG\w+\b|\%{1,2})(.*)$/) {
|
||||
while ($ins =~ /^(.*?)((?:\b[0-9a-f]{2}(?:\+r)?|\bsbyte|\bimm|\bsel|\bopt\w?|\b[ioa]d?|\b(?:reg_)?[abcd]x|\bk?reg|\bk?rm|\bw|\bS\b)?\#{1,2}|\b(?:reg|rm)64\b|\b(?:o64)?nw\b|\b(?:NO)?LONG\w+\b|\%{1,2}|[ABCD]X\#)(.*)$/) {
|
||||
$o .= $1;
|
||||
my $mw = $2;
|
||||
$ins = $3;
|
||||
@@ -178,15 +178,17 @@ sub func_multisize($$$) {
|
||||
$o .= !$i ? 'iwd' : ($s >= 64) ? 'id,s' : "i$sn";
|
||||
} elsif ($mw eq 'i##') {
|
||||
$o .= !$i ? 'iwdq' : "i$sn";
|
||||
} elsif ($mw =~ /^(?:reg_)?([abcd])x\#$/) {
|
||||
} elsif ($mw =~ /^(?:reg_)?([abcd])x\#$/i) {
|
||||
my $rl = $1;
|
||||
my $upr = ($rl =~ /^[A-Z]/);
|
||||
if ($i == 1) {
|
||||
$o .= "reg_${1}l";
|
||||
$o .= $upr ? "${rl}L" : "reg_${rl}l";
|
||||
} elsif ($i == 2) {
|
||||
$o .= "reg_${1}x";
|
||||
$o .= $upr ? "${rl}X" : "reg_${rl}x";
|
||||
} elsif ($i == 3) {
|
||||
$o .= "reg_e${1}x";
|
||||
$o .= $upr ? "E${rl}X" : "reg_e${rl}x";
|
||||
} elsif ($i == 4) {
|
||||
$o .= "reg_r${1}x";
|
||||
$o .= $upr ? "R${rl}X" : "reg_r${rl}x";
|
||||
$long |= 1;
|
||||
} else {
|
||||
die "$0:$infile:$line: register cannot be used with z\n";
|
||||
@@ -237,6 +239,8 @@ sub func_multisize($$$) {
|
||||
}
|
||||
} elsif ($mw eq 'w##') {
|
||||
$o .= 'w'.(($i-1) & 1);
|
||||
} elsif ($mw eq 'S#') {
|
||||
$o .= 'S'
|
||||
} elsif ($mw eq '#') {
|
||||
$o .= $s;
|
||||
} else {
|
||||
@@ -260,6 +264,39 @@ sub func_multisize($$$) {
|
||||
return @ol;
|
||||
}
|
||||
|
||||
# Near branch operand size patterns
|
||||
# This allows the "normal" size patterns to be used for
|
||||
# address size features, as used by JCXZ and LOOP.
|
||||
# This also allows the syntax "jmp dword foo" in 64-bit
|
||||
# mode, even though it is really bogus.
|
||||
$macros{'br'} = {
|
||||
'func' =>
|
||||
sub {
|
||||
my($mac, $args, $rawargs) = @_;
|
||||
my @ol;
|
||||
my $ins = join(' ', @$rawargs);
|
||||
|
||||
foreach my $wx ([16,16], [32,32], [64,64], [64,32]) {
|
||||
my($w,$iw,$sz) = @$wx;
|
||||
my $i = $ins;
|
||||
my $argn;
|
||||
if ($i =~ /^(.*)\b(near|short)\b/) {
|
||||
my $what = $2;
|
||||
next if ($what eq 'short' && $iw != $w);
|
||||
(my $argn = $1) =~ s/[^,:]+//g;
|
||||
$argn = 'AR'.length($argn);
|
||||
}
|
||||
$i =~ s/\b(near|short)\b/imm$iw|$1/;
|
||||
$i =~ s/\bos\b/nw o$w/;
|
||||
$i .= ",$argn";
|
||||
$i .= ($iw != $w) ? ',SX,ND' : ',OSIZE';
|
||||
$i .= ($w == 64) ? ',LONG' : ',NOLONG';
|
||||
push(@ol, $i);
|
||||
}
|
||||
return(@ol);
|
||||
}
|
||||
};
|
||||
|
||||
# Common pattern for K-register instructions
|
||||
$macros{'k'} = {
|
||||
'func' =>
|
||||
|
||||
Reference in New Issue
Block a user