blob: fb62e0fa76ec8cf6de7b20d04bdcf36d1df99331 [file] [log] [blame]
#! /usr/bin/env python
# x86 instructions and prefixes data and code generation
#
# Copyright (C) 2002-2007 Peter Johnson
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. 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 AUTHOR AND OTHER 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 AUTHOR OR OTHER 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.
#
# NOTE: operands are arranged in NASM / Intel order (e.g. dest, src)
import os
import sys
from sys import stdout, version_info
scriptname = "gen_x86_insn.py"
scriptrev = "HEAD"
ordered_cpus = [
"086", "186", "286", "386", "486", "586", "686", "K6", "Athlon", "P3",
"P4", "IA64", "Hammer"]
ordered_cpu_features = [
"FPU", "Cyrix", "AMD", "MMX", "3DNow", "SMM", "SSE", "SSE2",
"SSE3", "SVM", "PadLock", "SSSE3", "SSE41", "SSE42", "SSE4a", "SSE5",
"AVX", "FMA", "AES", "CLMUL", "MOVBE", "XOP", "FMA4", "F16C",
"FSGSBASE", "RDRAND", "XSAVEOPT", "EPTVPID", "SMX", "AVX2", "BMI1",
"BMI2", "INVPCID", "LZCNT", "TBM", "TSX", "SHA", "SMAP", "RDSEED", "ADX",
"PRFCHW"]
unordered_cpu_features = ["Priv", "Prot", "Undoc", "Obs"]
# Predefined VEX prefix field values
VEXW0 = 0xC0
VEXW1 = 0xC8
VEXL0 = 0xC0
VEXL1 = 0xC4
VEXpp = 0xC0 # OR with value
# Predefined XOP prefix field values
XOPW0 = 0x80
XOPW1 = 0x88
XOPL0 = 0x80
XOPL1 = 0x84
XOPpp = 0x80 # OR with value
def lprint(s, f = stdout, e = '\n') :
f.write(s + e)
def cpu_lcd(cpu1, cpu2):
"""Find the lowest common denominator of two CPU sets."""
retval = set()
# CPU
cpu1cpus = set(ordered_cpus) & set(cpu1)
if not cpu1cpus:
cpu1cpus.add("086")
cpu1mincpu = min(ordered_cpus.index(x) for x in cpu1cpus)
cpu2cpus = set(ordered_cpus) & set(cpu2)
if not cpu2cpus:
cpu2cpus.add("086")
cpu2mincpu = min(ordered_cpus.index(x) for x in cpu1cpus)
cpumin = ordered_cpus[min(cpu1mincpu, cpu2mincpu)]
if cpumin == "086":
cpumin = "Any"
if cpumin != "Any":
retval.add(cpumin)
# Feature
cpu1features = set(ordered_cpu_features) & set(cpu1)
if not cpu1features:
cpu1minfeature = -1
else:
cpu1minfeature = min(ordered_cpu_features.index(x)
for x in cpu1features)
cpu2features = set(ordered_cpu_features) & set(cpu2)
if not cpu2features:
cpu2minfeature = -1
else:
cpu2minfeature = min(ordered_cpu_features.index(x)
for x in cpu2features)
if cpu1minfeature != -1 and cpu2minfeature != -1:
featuremin = ordered_cpu_features[min(cpu1minfeature, cpu2minfeature)]
retval.add(featuremin)
# Unordered features
for feature in set(unordered_cpu_features) & set(cpu1) & set(cpu2):
retval.add(feature)
return retval
class Operand(object):
def __init__(self, **kwargs):
self.type = kwargs.pop("type")
self.size = kwargs.pop("size", "Any")
self.relaxed = kwargs.pop("relaxed", False)
self.dest = kwargs.pop("dest", None)
self.tmod = kwargs.pop("tmod", None)
self.opt = kwargs.pop("opt", None)
if kwargs:
for arg in kwargs:
lprint("Warning: unrecognized arg %s" % arg)
def __str__(self):
return "{"+ ", ".join(["OPT_%s" % self.type,
"OPS_%s" % self.size,
"%d" % self.relaxed,
self.dest == "EA64" and "1" or "0",
"OPTM_%s" % self.tmod,
"OPA_%s" % (self.dest == "EA64"
and "EA" or self.dest),
"OPAP_%s" % self.opt]) + "}"
def __eq__(self, other):
return (self.type == other.type and
self.size == other.size and
self.relaxed == other.relaxed and
self.dest == other.dest and
self.tmod == other.tmod and
self.opt == other.opt)
def __ne__(self, other):
return (self.type != other.type or
self.size != other.size or
self.relaxed != other.relaxed or
self.dest != other.dest or
self.tmod != other.tmod or
self.opt != other.opt)
class GroupForm(object):
def __init__(self, **kwargs):
# Parsers
self.parsers = set(kwargs.pop("parsers", ["gas", "nasm"]))
# CPU feature flags initialization
self.cpu = set(kwargs.pop("cpu", []))
# Misc flags
self.misc_flags = set(kwargs.pop("misc_flags", []))
if kwargs.pop("only64", False):
self.misc_flags.add("ONLY_64")
if kwargs.pop("not64", False):
self.misc_flags.add("NOT_64")
if kwargs.pop("onlyavx", False):
self.misc_flags.add("ONLY_AVX")
if kwargs.pop("notavx", False):
self.misc_flags.add("NOT_AVX")
# Operation size
self.opersize = kwargs.pop("opersize", 0)
if self.opersize == 8:
self.opersize = 0
if self.opersize == 64:
self.misc_flags.add("ONLY_64")
elif self.opersize == 32 and "ONLY_64" not in self.misc_flags:
self.cpu.add("386")
# Default operation size in 64-bit mode
self.def_opersize_64 = kwargs.pop("def_opersize_64", 0)
# GAS suffix
self.gen_suffix = kwargs.pop("gen_suffix", True)
self.suffixes = kwargs.pop("suffixes", None)
suffix = kwargs.pop("suffix", None)
if suffix is not None:
self.suffixes = [suffix]
req_suffix = kwargs.pop("req_suffix", False)
if not req_suffix:
if self.suffixes is None:
self.suffixes = ["Z"]
else:
self.suffixes.append("Z")
if self.suffixes is not None:
self.suffixes = set(x.upper() for x in self.suffixes)
# Special instruction prefix
self.special_prefix = "0"
if "prefix" in kwargs:
self.special_prefix = "0x%02X" % kwargs.pop("prefix")
# VEX prefix
if "vex" in kwargs:
self.misc_flags.add("ONLY_AVX")
vexW = kwargs.pop("vexw", 0)
if vexW not in [0, 1]:
raise ValueError("VEX.W must be 0 or 1")
vexL = kwargs.pop("vex")
if vexL == 128 or vexL == 0:
vexL = 0
elif vexL == 256:
vexL = 1
else:
raise ValueError("VEX.L must be 128 or 256")
if self.special_prefix in ["0", "0x00"]:
vexpp = 0
elif self.special_prefix == "0x66":
vexpp = 1
elif self.special_prefix == "0xF3":
vexpp = 2
elif self.special_prefix == "0xF2":
vexpp = 3
else:
raise ValueError("Cannot combine VEX and special prefix %s"
% self.special_prefix)
self.special_prefix = "0x%02X" % (0xC0 + vexW*8 + vexL*4 + vexpp)
# XOP prefix
if "xop" in kwargs:
xopW = kwargs.pop("xopw", 0)
if xopW not in [0, 1]:
raise ValueError("XOP.W must be 0 or 1")
xopL = kwargs.pop("xop")
if xopL == 128 or xopL == 0:
xopL = 0
elif xopL == 256:
xopL = 1
else:
raise ValueError("XOP.L must be 128 or 256")
# XOPpp is currently reserved (0)
xoppp = 0
if self.special_prefix not in ["0", "0x00"]:
raise ValueError("Cannot combine XOP and special prefix %s"
% self.special_prefix)
self.special_prefix = "0x%02X" % (0x80 + xopW*8 + xopL*4 + xoppp)
# Spare value
self.spare = kwargs.pop("spare", 0)
# Build opcodes string (C array initializer)
if "opcode" in kwargs:
# Usual case, just a single opcode
self.opcode = kwargs.pop("opcode")
self.opcode_len = len(self.opcode)
elif "opcode1" in kwargs and "opcode2" in kwargs:
# Two opcode case; the first opcode is the "optimized" opcode,
# the second is the "relaxed" opcode. For this to work, an
# opt="foo" must be set for one of the operands.
self.opcode1 = kwargs.pop("opcode1")
self.opcode2 = kwargs.pop("opcode2")
self.opcode_len = len(self.opcode1)
else:
raise KeyError("missing opcode")
# Build operands string (C array initializer)
self.operands = kwargs.pop("operands")
for op in self.operands:
if op.type in ["Reg", "RM", "Areg", "Creg", "Dreg"]:
if op.size == 64:
self.misc_flags.add("ONLY_64")
elif op.size == 32 and "ONLY_64" not in self.misc_flags:
self.cpu.add("386")
if op.type in ["Imm", "ImmNotSegOff"]:
if op.size == 64:
self.misc_flags.add("ONLY_64")
elif op.size == 32 and "ONLY_64" not in self.misc_flags:
self.cpu.add("386")
if op.type in ["FS", "GS"] and "ONLY_64" not in self.misc_flags:
self.cpu.add("386")
if op.type in ["CR4"] and "ONLY_64" not in self.misc_flags:
self.cpu.add("586")
if op.dest == "EA64":
self.misc_flags.add("ONLY_64")
# Modifiers
self.modifiers = kwargs.pop("modifiers", [])
# GAS flags
self.gas_only = ("nasm" not in self.parsers)
self.gas_illegal = ("gas" not in self.parsers)
self.gas_no_rev = (kwargs.pop("gas_no_reverse", False) or
kwargs.pop("gas_no_rev", False))
# CPU feature flags finalization
# Remove redundancies
maxcpu = -1
maxcpu_set = self.cpu & set(ordered_cpus)
if maxcpu_set:
maxcpu = max(ordered_cpus.index(x) for x in maxcpu_set)
if maxcpu != -1:
for cpu in ordered_cpus[0:maxcpu]:
self.cpu.discard(cpu)
if kwargs:
for arg in kwargs:
lprint("Warning: unrecognized arg %s" % arg)
def __str__(self):
if hasattr(self, "opcode"):
opcodes_str = ["0x%02X" % x for x in self.opcode]
elif hasattr(self, "opcode1") and hasattr(self, "opcode2"):
opcodes_str = ["0x%02X" % x for x in self.opcode1]
opcodes_str.extend("0x%02X" % x for x in self.opcode2)
# Ensure opcodes initializer string is 3 long
opcodes_str.extend(["0", "0", "0"])
opcodes_str = "{" + ', '.join(opcodes_str[0:3]) + "}"
cpus_str = "|".join("CPU_%s" % x for x in sorted(self.cpu))
if len(self.modifiers) > 3:
raise ValueError("too many modifiers: %s" % (self.modifiers,))
cpus_str = []
if self.cpu is not None:
if len(self.cpu) > 3:
raise ValueError("too many CPUs: %s" % (self.cpu,))
# Ensure CPUs initializer string is at least 3 long
cpus_str.extend("CPU_%s" % x for x in sorted(self.cpu))
# Ensure cpus initializer string is 3 long; 0=CPU_Any
cpus_str.extend(["0", "0", "0"])
mods = ["MOD_%s" % x for x in self.modifiers]
# Ensure mods initializer string is 3 long
mods.extend(["0", "0", "0"])
mod_str = "{" + ', '.join(mods[0:3]) + "}"
gas_flags = []
if self.gas_only:
gas_flags.append("GAS_ONLY")
if self.gas_illegal:
gas_flags.append("GAS_ILLEGAL")
if self.gas_no_rev:
gas_flags.append("GAS_NO_REV")
if self.suffixes:
gas_flags.extend("SUF_%s" % x for x in sorted(self.suffixes))
gas_flags = "|".join(gas_flags)
# Build instruction info structure initializer
return "{ "+ ", ".join([gas_flags or "0",
"|".join(self.misc_flags) or "0",
cpus_str[0],
cpus_str[1],
cpus_str[2],
mod_str,
"%d" % (self.opersize or 0),
"%d" % (self.def_opersize_64 or 0),
self.special_prefix or "0",
"%d" % self.opcode_len,
opcodes_str,
"%d" % (self.spare or 0),
"%d" % len(self.operands),
"%d" % self.all_operands_index]) + " }"
groups = {}
groupnames_ordered = []
def add_group(name, **kwargs):
forms = groups.setdefault(name, [])
forms.append(GroupForm(**kwargs))
groupnames_ordered.append(name)
class Insn(object):
def __init__(self, groupname, suffix=None, parser=None, modifiers=None,
cpu=None, misc_flags=None, only64=False, not64=False,
avx=False):
self.groupname = groupname
if suffix is None:
self.suffix = None
else:
self.suffix = suffix.upper()
self.parsers = None
if suffix is not None:
self.parsers = set(["gas"])
if parser is not None:
self.parsers = set([parser])
if modifiers is None:
self.modifiers = []
else:
self.modifiers = modifiers
if cpu is None:
self.cpu = None
else:
self.cpu = set(cpu)
if misc_flags is None:
self.misc_flags = None
else:
self.misc_flags = set([x for x in misc_flags])
if only64:
if self.misc_flags is None:
self.misc_flags = set()
self.misc_flags.add("ONLY_64")
if not64:
if self.misc_flags is None:
self.misc_flags = set()
self.misc_flags.add("NOT_64")
if avx:
if self.misc_flags is None:
self.misc_flags = set()
self.misc_flags.add("ONLY_AVX")
if self.cpu is None:
self.cpu = set(["AVX"])
def auto_cpu(self, parser):
"""Determine lowest common denominator CPU from group and suffix.
Does nothing if CPU is already set."""
if self.cpu is not None:
return
# Scan through group, matching parser and suffix
for form in groups[self.groupname]:
if parser not in form.parsers:
continue
if (self.suffix is not None and len(self.suffix) == 1 and
(form.suffixes is None or self.suffix not in form.suffixes)):
continue
if self.cpu is None:
self.cpu = set(form.cpu)
else:
self.cpu = cpu_lcd(self.cpu, form.cpu)
def auto_misc_flags(self, parser):
"""Determine lowest common denominator flags from group and suffix.
Does nothing if flags is already set."""
if self.misc_flags is not None:
return
# Scan through group, matching parser and suffix
for form in groups[self.groupname]:
if parser not in form.parsers:
continue
if (self.suffix is not None and len(self.suffix) == 1 and
(form.suffixes is None or self.suffix not in form.suffixes)):
continue
if self.misc_flags is None:
self.misc_flags = set(form.misc_flags)
else:
self.misc_flags &= form.misc_flags
def copy(self):
"""Return a shallow copy."""
return Insn(self.groupname,
suffix=self.suffix,
modifiers=self.modifiers,
cpu=self.cpu,
misc_flags=self.misc_flags)
def __str__(self):
if self.suffix is None:
suffix_str = "SUF_Z"
elif len(self.suffix) == 1:
suffix_str = "SUF_" + self.suffix
else:
suffix_str = self.suffix
cpus_str = []
if self.cpu is not None:
if len(self.cpu) > 3:
raise ValueError("too many CPUs: %s" % (self.cpu,))
cpus_str.extend("CPU_%s" % x for x in sorted(self.cpu))
# Ensure cpus initializer string is 3 long
cpus_str.extend(["0", "0", "0"])
if len(self.modifiers) > 3:
raise ValueError("too many modifiers")
mods_str = ["0x%02X" % x for x in self.modifiers]
# Ensure modifiers is at least 3 long
mods_str.extend(["0", "0", "0"])
return ",\t".join(["%s_insn" % self.groupname,
"%d" % len(groups[self.groupname]),
suffix_str,
mods_str[0],
mods_str[1],
mods_str[2],
"|".join(self.misc_flags or []) or "0",
cpus_str[0],
cpus_str[1],
cpus_str[2]])
insns = {}
def add_insn(name, groupname, **kwargs):
opts = insns.setdefault(name, [])
opts.append(Insn(groupname, **kwargs))
class Prefix(object):
def __init__(self, groupname, value, only64=False):
self.groupname = groupname
self.value = value
self.only64 = only64
def __str__(self):
return ",\t".join(["NULL",
"X86_%s>>8" % self.groupname,
"0x%02X" % self.value,
"0",
"0",
"0",
self.only64 and "ONLY_64" or "0",
"0",
"0",
"0"])
gas_insns = {}
nasm_insns = {}
def add_prefix(name, groupname, value, parser=None, **kwargs):
prefix = Prefix(groupname, value, **kwargs)
if parser is None or parser == "gas":
gas_insns[name] = prefix
if parser is None or parser == "nasm":
nasm_insns[name] = prefix
def finalize_insns():
unused_groups = set(groups.keys())
for name in insns:
for insn in insns[name]:
group = groups[insn.groupname]
unused_groups.discard(insn.groupname)
parsers = set()
for form in group:
parsers |= form.parsers
if insn.parsers is not None:
parsers &= insn.parsers
if "gas" in parsers:
suffixes = set()
if insn.suffix is None:
for form in group:
if form.gen_suffix and form.suffixes is not None:
suffixes |= form.suffixes
if not suffixes:
suffixes.add("Z")
for suffix in suffixes:
if suffix == "Z":
keyword = name
else:
keyword = name+suffix
keyword = keyword.lower()
if keyword in gas_insns:
raise ValueError("duplicate gas instruction %s" %
keyword)
newinsn = insn.copy()
if insn.suffix is None:
newinsn.suffix = suffix
newinsn.auto_cpu("gas")
newinsn.auto_misc_flags("gas")
gas_insns[keyword] = newinsn
if "nasm" in parsers:
keyword = name
if keyword in nasm_insns:
raise ValueError("duplicate nasm instruction %s" % keyword)
newinsn = insn.copy()
newinsn.auto_cpu("nasm")
newinsn.auto_misc_flags("nasm")
nasm_insns[keyword] = newinsn
unused_groups.discard("empty")
unused_groups.discard("not64")
if unused_groups:
lprint("warning: unused groups: %s" % ", ".join(unused_groups))
def output_insns(f, parser, insns):
lprint("/* Generated by %s r%s, do not edit */" % \
(scriptname, scriptrev), f)
lprint("""%%ignore-case
%%language=ANSI-C
%%compare-strncmp
%%readonly-tables
%%enum
%%struct-type
%%define hash-function-name insnprefix_%s_hash
%%define lookup-function-name insnprefix_%s_find
struct insnprefix_parse_data;
%%%%""" % (parser, parser), f)
for keyword in sorted(insns):
lprint("%s,\t%s" % (keyword.lower(), insns[keyword]), f)
def output_gas_insns(f):
output_insns(f, "gas", gas_insns)
def output_nasm_insns(f):
output_insns(f, "nasm", nasm_insns)
def output_groups(f):
# Merge all operand lists into single list
# Sort by number of operands to shorten output
all_operands = []
if version_info[0] == 2:
gi = groups.itervalues()
else:
gi = groups.values()
for form in sorted((form for g in gi for form in g),
key=lambda x:len(x.operands), reverse=True):
num_operands = len(form.operands)
for i in range(len(all_operands)):
if all_operands[i:i+num_operands] == form.operands:
form.all_operands_index = i
break
else:
form.all_operands_index = len(all_operands)
all_operands.extend(form.operands)
# Output operands list
lprint("/* Generated by %s r%s, do not edit */" % \
(scriptname, scriptrev), f)
lprint("static const x86_info_operand insn_operands[] = {", f)
lprint(" ", f, '')
lprint(",\n ".join(str(x) for x in all_operands), f)
lprint("};\n", f)
# Output groups
seen = set()
for name in groupnames_ordered:
if name in seen:
continue
seen.add(name)
lprint("static const x86_insn_info %s_insn[] = {" % name, f)
lprint(" ", f, '')
lprint(",\n ".join(str(x) for x in groups[name]), f)
lprint("};\n", f)
#####################################################################
# General instruction groupings
#####################################################################
#
# Empty instruction
#
add_group("empty", opcode=[], operands=[])
#
# Placeholder for instructions invalid in 64-bit mode
#
add_group("not64", opcode=[], operands=[], not64=True)
#
# One byte opcode instructions with no operands
#
add_group("onebyte",
modifiers=["Op0Add", "OpSizeR", "DOpS64R"],
opcode=[0x00],
operands=[])
#
# One byte opcode instructions with "special" prefix with no operands
#
add_group("onebyte_prefix",
modifiers=["PreAdd", "Op0Add"],
prefix=0x00,
opcode=[0x00],
operands=[])
#
# Two byte opcode instructions with no operands
#
add_group("twobyte",
gen_suffix=False,
suffixes=["l", "q"],
modifiers=["Op0Add", "Op1Add"],
opcode=[0x00, 0x00],
operands=[])
#
# Three byte opcode instructions with no operands
#
add_group("threebyte",
modifiers=["Op0Add", "Op1Add", "Op2Add"],
opcode=[0x00, 0x00, 0x00],
operands=[])
#
# One byte opcode instructions with general memory operand
#
add_group("onebytemem",
gen_suffix=False,
suffixes=["l", "q", "s"],
modifiers=["SpAdd", "Op0Add"],
opcode=[0x00],
spare=0,
operands=[Operand(type="Mem", dest="EA")])
#
# Two byte opcode instructions with general memory operand
#
add_group("twobytemem",
gen_suffix=False,
suffixes=["w", "l", "q", "s"],
modifiers=["SpAdd", "Op0Add", "Op1Add"],
opcode=[0x00, 0x00],
spare=0,
operands=[Operand(type="Mem", relaxed=True, dest="EA")])
#
# mov
#
# Absolute forms for non-64-bit mode
for sfx, sz in zip("bwl", [8, 16, 32]):
add_group("mov",
suffix=sfx,
not64=True,
opersize=sz,
opcode=[0xA0+(sz!=8)],
operands=[Operand(type="Areg", size=sz, dest=None),
Operand(type="MemOffs", size=sz, relaxed=True, dest="EA")])
for sfx, sz in zip("bwl", [8, 16, 32]):
add_group("mov",
suffix=sfx,
not64=True,
opersize=sz,
opcode=[0xA2+(sz!=8)],
operands=[Operand(type="MemOffs", size=sz, relaxed=True, dest="EA"),
Operand(type="Areg", size=sz, dest=None)])
# 64-bit absolute forms for 64-bit mode. Disabled for GAS, see movabs
for sz in (8, 16, 32, 64):
add_group("mov",
opersize=sz,
opcode=[0xA0+(sz!=8)],
only64=True,
operands=[Operand(type="Areg", size=sz, dest=None),
Operand(type="MemOffs", size=sz, relaxed=True, dest="EA64")])
for sz in (8, 16, 32, 64):
add_group("mov",
only64=True,
opersize=sz,
opcode=[0xA2+(sz!=8)],
operands=[Operand(type="MemOffs", size=sz, relaxed=True, dest="EA64"),
Operand(type="Areg", size=sz, dest=None)])
# General 32-bit forms using Areg / short absolute option
for sfx, sz in zip("bwlq", [8, 16, 32, 64]):
add_group("mov",
suffix=sfx,
opersize=sz,
opcode1=[0x88+(sz!=8)],
opcode2=[0xA2+(sz!=8)],
operands=[
Operand(type="RM", size=sz, relaxed=True, dest="EA", opt="ShortMov"),
Operand(type="Areg", size=sz, dest="Spare")])
# General 32-bit forms
for sfx, sz in zip("bwlq", [8, 16, 32, 64]):
add_group("mov",
suffix=sfx,
opersize=sz,
opcode=[0x88+(sz!=8)],
operands=[Operand(type="RM", size=sz, relaxed=True, dest="EA"),
Operand(type="Reg", size=sz, dest="Spare")])
# General 32-bit forms using Areg / short absolute option
for sfx, sz in zip("bwlq", [8, 16, 32, 64]):
add_group("mov",
suffix=sfx,
opersize=sz,
opcode1=[0x8A+(sz!=8)],
opcode2=[0xA0+(sz!=8)],
operands=[Operand(type="Areg", size=sz, dest="Spare"),
Operand(type="RM", size=sz, relaxed=True, dest="EA",
opt="ShortMov")])
# General 32-bit forms
for sfx, sz in zip("bwlq", [8, 16, 32, 64]):
add_group("mov",
suffix=sfx,
opersize=sz,
opcode=[0x8A+(sz!=8)],
operands=[Operand(type="Reg", size=sz, dest="Spare"),
Operand(type="RM", size=sz, relaxed=True, dest="EA")])
# Segment register forms
add_group("mov",
suffix="w",
opcode=[0x8C],
operands=[Operand(type="Mem", size=16, relaxed=True, dest="EA"),
Operand(type="SegReg", size=16, relaxed=True, dest="Spare")])
for sfx, sz in zip("wlq", [16, 32, 64]):
add_group("mov",
suffix=sfx,
opersize=sz,
opcode=[0x8C],
operands=[
Operand(type="Reg", size=sz, dest="EA"),
Operand(type="SegReg", size=16, relaxed=True, dest="Spare")])
add_group("mov",
suffix="w",
opcode=[0x8E],
operands=[Operand(type="SegReg", size=16, relaxed=True, dest="Spare"),
Operand(type="RM", size=16, relaxed=True, dest="EA")])
for sfx, sz in zip("lq", [32, 64]):
add_group("mov",
suffix=sfx,
opcode=[0x8E],
operands=[
Operand(type="SegReg", size=16, relaxed=True, dest="Spare"),
Operand(type="Reg", size=sz, dest="EA")])
# Immediate forms
add_group("mov",
suffix="b",
opcode=[0xB0],
operands=[Operand(type="Reg", size=8, dest="Op0Add"),
Operand(type="Imm", size=8, relaxed=True, dest="Imm")])
for sfx, sz in zip("wl", [16, 32]):
add_group("mov",
suffix=sfx,
opersize=sz,
opcode=[0xB8],
operands=[Operand(type="Reg", size=sz, dest="Op0Add"),
Operand(type="Imm", size=sz, relaxed=True, dest="Imm")])
# 64-bit forced size form
add_group("mov",
parsers=["nasm"],
opersize=64,
opcode=[0xB8],
operands=[Operand(type="Reg", size=64, dest="Op0Add"),
Operand(type="Imm", size=64, dest="Imm")])
add_group("mov",
suffix="q",
opersize=64,
opcode1=[0xB8],
opcode2=[0xC7],
operands=[Operand(type="Reg", size=64, dest="Op0Add"),
Operand(type="Imm", size=64, relaxed=True, dest="Imm",
opt="SImm32Avail")])
# Need two sets here, one for strictness on left side, one for right.
for sfx, sz, immsz in zip("bwlq", [8, 16, 32, 64], [8, 16, 32, 32]):
add_group("mov",
suffix=sfx,
opersize=sz,
opcode=[0xC6+(sz!=8)],
operands=[Operand(type="RM", size=sz, relaxed=True, dest="EA"),
Operand(type="Imm", size=immsz, dest="Imm")])
for sfx, sz, immsz in zip("bwlq", [8, 16, 32, 64], [8, 16, 32, 32]):
add_group("mov",
suffix=sfx,
opersize=sz,
opcode=[0xC6+(sz!=8)],
operands=[Operand(type="RM", size=sz, dest="EA"),
Operand(type="Imm", size=immsz, relaxed=True, dest="Imm")])
# CR forms
add_group("mov",
suffix="l",
not64=True,
cpu=["Priv"],
opcode=[0x0F, 0x22],
operands=[Operand(type="CR4", size=32, dest="Spare"),
Operand(type="Reg", size=32, dest="EA")])
add_group("mov",
suffix="l",
not64=True,
cpu=["Priv"],
opcode=[0x0F, 0x22],
operands=[Operand(type="CRReg", size=32, dest="Spare"),
Operand(type="Reg", size=32, dest="EA")])
add_group("mov",
suffix="q",
cpu=["Priv"],
opcode=[0x0F, 0x22],
operands=[Operand(type="CRReg", size=32, dest="Spare"),
Operand(type="Reg", size=64, dest="EA")])
add_group("mov",
suffix="l",
not64=True,
cpu=["Priv"],
opcode=[0x0F, 0x20],
operands=[Operand(type="Reg", size=32, dest="EA"),
Operand(type="CR4", size=32, dest="Spare")])
add_group("mov",
suffix="l",
cpu=["Priv"],
not64=True,
opcode=[0x0F, 0x20],
operands=[Operand(type="Reg", size=32, dest="EA"),
Operand(type="CRReg", size=32, dest="Spare")])
add_group("mov",
suffix="q",
cpu=["Priv"],
opcode=[0x0F, 0x20],
operands=[Operand(type="Reg", size=64, dest="EA"),
Operand(type="CRReg", size=32, dest="Spare")])
# DR forms
add_group("mov",
suffix="l",
not64=True,
cpu=["Priv"],
opcode=[0x0F, 0x23],
operands=[Operand(type="DRReg", size=32, dest="Spare"),
Operand(type="Reg", size=32, dest="EA")])
add_group("mov",
suffix="q",
cpu=["Priv"],
opcode=[0x0F, 0x23],
operands=[Operand(type="DRReg", size=32, dest="Spare"),
Operand(type="Reg", size=64, dest="EA")])
add_group("mov",
suffix="l",
not64=True,
cpu=["Priv"],
opcode=[0x0F, 0x21],
operands=[Operand(type="Reg", size=32, dest="EA"),
Operand(type="DRReg", size=32, dest="Spare")])
add_group("mov",
suffix="q",
cpu=["Priv"],
opcode=[0x0F, 0x21],
operands=[Operand(type="Reg", size=64, dest="EA"),
Operand(type="DRReg", size=32, dest="Spare")])
# MMX forms for GAS parser (copied from movq)
add_group("mov",
suffix="q",
cpu=["MMX"],
parsers=["gas"],
opcode=[0x0F, 0x6F],
operands=[Operand(type="SIMDReg", size=64, dest="Spare"),
Operand(type="SIMDRM", size=64, relaxed=True, dest="EA")])
add_group("mov",
suffix="q",
cpu=["MMX"],
parsers=["gas"],
opersize=64,
opcode=[0x0F, 0x6E],
operands=[Operand(type="SIMDReg", size=64, dest="Spare"),
Operand(type="RM", size=64, relaxed=True, dest="EA")])
add_group("mov",
suffix="q",
cpu=["MMX"],
parsers=["gas"],
opcode=[0x0F, 0x7F],
operands=[Operand(type="SIMDRM", size=64, relaxed=True, dest="EA"),
Operand(type="SIMDReg", size=64, dest="Spare")])
add_group("mov",
suffix="q",
cpu=["MMX"],
parsers=["gas"],
opersize=64,
opcode=[0x0F, 0x7E],
operands=[Operand(type="RM", size=64, relaxed=True, dest="EA"),
Operand(type="SIMDReg", size=64, dest="Spare")])
# SSE2 forms for GAS parser (copied from movq)
add_group("mov",
suffix="q",
cpu=["SSE2"],
parsers=["gas"],
prefix=0xF3,
opcode=[0x0F, 0x7E],
operands=[Operand(type="SIMDReg", size=128, dest="Spare"),
Operand(type="SIMDReg", size=128, dest="EA")])
add_group("mov",
suffix="q",
cpu=["SSE2"],
parsers=["gas"],
prefix=0xF3,
opcode=[0x0F, 0x7E],
operands=[Operand(type="SIMDReg", size=128, dest="Spare"),
Operand(type="SIMDRM", size=64, relaxed=True, dest="EA")])
add_group("mov",
suffix="q",
cpu=["SSE2"],
parsers=["gas"],
opersize=64,
prefix=0x66,
opcode=[0x0F, 0x6E],
operands=[Operand(type="SIMDReg", size=128, dest="Spare"),
Operand(type="RM", size=64, relaxed=True, dest="EA")])
add_group("mov",
suffix="q",
cpu=["SSE2"],
parsers=["gas"],
prefix=0x66,
opcode=[0x0F, 0xD6],
operands=[Operand(type="SIMDRM", size=64, relaxed=True, dest="EA"),
Operand(type="SIMDReg", size=128, dest="Spare")])
add_group("mov",
suffix="q",
cpu=["SSE2"],
parsers=["gas"],
opersize=64,
prefix=0x66,
opcode=[0x0F, 0x7E],
operands=[Operand(type="RM", size=64, relaxed=True, dest="EA"),
Operand(type="SIMDReg", size=128, dest="Spare")])
add_insn("mov", "mov")
#
# 64-bit absolute move (for GAS).
# These are disabled for GAS for normal mov above.
#
add_group("movabs",
suffix="b",
only64=True,
opcode=[0xA0],
operands=[Operand(type="Areg", size=8, dest=None),
Operand(type="MemOffs", size=8, relaxed=True, dest="EA64")])
for sfx, sz in zip("wlq", [16, 32, 64]):
add_group("movabs",
only64=True,
suffix=sfx,
opersize=sz,
opcode=[0xA1],
operands=[Operand(type="Areg", size=sz, dest=None),
Operand(type="MemOffs", size=sz, relaxed=True,
dest="EA64")])
add_group("movabs",
suffix="b",
only64=True,
opcode=[0xA2],
operands=[Operand(type="MemOffs", size=8, relaxed=True, dest="EA64"),
Operand(type="Areg", size=8, dest=None)])
for sfx, sz in zip("wlq", [16, 32, 64]):
add_group("movabs",
suffix=sfx,
only64=True,
opersize=sz,
opcode=[0xA3],
operands=[Operand(type="MemOffs", size=sz, relaxed=True,
dest="EA64"),
Operand(type="Areg", size=sz, dest=None)])
# 64-bit immediate form
add_group("movabs",
suffix="q",
opersize=64,
opcode=[0xB8],
operands=[Operand(type="Reg", size=64, dest="Op0Add"),
Operand(type="Imm", size=64, relaxed=True, dest="Imm")])
add_insn("movabs", "movabs", parser="gas")
#
# Move with sign/zero extend
#
add_group("movszx",
suffix="b",
cpu=["386"],
modifiers=["Op1Add"],
opersize=16,
opcode=[0x0F, 0x00],
operands=[Operand(type="Reg", size=16, dest="Spare"),
Operand(type="RM", size=8, relaxed=True, dest="EA")])
add_group("movszx",
suffix="b",
cpu=["386"],
modifiers=["Op1Add"],
opersize=32,
opcode=[0x0F, 0x00],
operands=[Operand(type="Reg", size=32, dest="Spare"),
Operand(type="RM", size=8, dest="EA")])
add_group("movszx",
suffix="b",
modifiers=["Op1Add"],
opersize=64,
opcode=[0x0F, 0x00],
operands=[Operand(type="Reg", size=64, dest="Spare"),
Operand(type="RM", size=8, dest="EA")])
add_group("movszx",
suffix="w",
cpu=["386"],
modifiers=["Op1Add"],
opersize=32,
opcode=[0x0F, 0x01],
operands=[Operand(type="Reg", size=32, dest="Spare"),
Operand(type="RM", size=16, dest="EA")])
add_group("movszx",
suffix="w",
modifiers=["Op1Add"],
opersize=64,
opcode=[0x0F, 0x01],
operands=[Operand(type="Reg", size=64, dest="Spare"),
Operand(type="RM", size=16, dest="EA")])
add_insn("movsbw", "movszx", suffix="b", modifiers=[0xBE])
add_insn("movsbl", "movszx", suffix="b", modifiers=[0xBE])
add_insn("movswl", "movszx", suffix="w", modifiers=[0xBE])
add_insn("movsbq", "movszx", suffix="b", modifiers=[0xBE], only64=True)
add_insn("movswq", "movszx", suffix="w", modifiers=[0xBE], only64=True)
add_insn("movsx", "movszx", modifiers=[0xBE])
add_insn("movzbw", "movszx", suffix="b", modifiers=[0xB6])
add_insn("movzbl", "movszx", suffix="b", modifiers=[0xB6])
add_insn("movzwl", "movszx", suffix="w", modifiers=[0xB6])
add_insn("movzbq", "movszx", suffix="b", modifiers=[0xB6], only64=True)
add_insn("movzwq", "movszx", suffix="w", modifiers=[0xB6], only64=True)
add_insn("movzx", "movszx", modifiers=[0xB6])
#
# Move with sign-extend doubleword (64-bit mode only)
#
add_group("movsxd",
suffix="l",
opersize=64,
opcode=[0x63],
operands=[Operand(type="Reg", size=64, dest="Spare"),
Operand(type="RM", size=32, dest="EA")])
add_insn("movslq", "movsxd", suffix="l")
add_insn("movsxd", "movsxd", parser="nasm")
#
# Push instructions
#
add_group("push",
def_opersize_64=64,
opcode=[0x50],
operands=[Operand(type="Reg", size="BITS", dest="Op0Add")])
add_group("push",
suffix="w",
opersize=16,
def_opersize_64=64,
opcode=[0x50],
operands=[Operand(type="Reg", size=16, dest="Op0Add")])
add_group("push",
suffix="l",
not64=True,
opersize=32,
opcode=[0x50],
operands=[Operand(type="Reg", size=32, dest="Op0Add")])
add_group("push",
suffix="q",
only64=True,
def_opersize_64=64,
opcode=[0x50],
operands=[Operand(type="Reg", size=64, dest="Op0Add")])
add_group("push",
def_opersize_64=64,
opcode=[0xFF],
spare=6,
operands=[Operand(type="RM", size="BITS", dest="EA")])
add_group("push",
suffix="w",
opersize=16,
def_opersize_64=64,
opcode=[0xFF],
spare=6,
operands=[Operand(type="RM", size=16, dest="EA")])
add_group("push",
suffix="l",
not64=True,
opersize=32,
opcode=[0xFF],
spare=6,
operands=[Operand(type="RM", size=32, dest="EA")])
add_group("push",
suffix="q",
only64=True,
def_opersize_64=64,
opcode=[0xFF],
spare=6,
operands=[Operand(type="RM", size=64, dest="EA")])
add_group("push",
cpu=["186"],
parsers=["nasm"],
def_opersize_64=64,
opcode=[0x6A],
operands=[Operand(type="Imm", size=8, dest="SImm")])
add_group("push",
cpu=["186"],
parsers=["gas"],
def_opersize_64=64,
opcode=[0x6A],
operands=[Operand(type="Imm", size=8, relaxed=True, dest="SImm")])
add_group("push",
suffix="q",
only64=True,
opersize=64,
def_opersize_64=64,
opcode1=[0x6A],
opcode2=[0x68],
operands=[Operand(type="Imm", size=32, relaxed=True, dest="SImm",
opt="SImm8")])
add_group("push",
not64=True,
cpu=["186"],
parsers=["nasm"],
opcode1=[0x6A],
opcode2=[0x68],
operands=[Operand(type="Imm", size="BITS", relaxed=True, dest="Imm",
opt="SImm8")])
add_group("push",
suffix="w",
cpu=["186"],
opersize=16,
def_opersize_64=64,
opcode1=[0x6A],
opcode2=[0x68],
operands=[Operand(type="Imm", size=16, relaxed=True, dest="Imm",
opt="SImm8")])
add_group("push",
suffix="l",
not64=True,
opersize=32,
opcode1=[0x6A],
opcode2=[0x68],
operands=[Operand(type="Imm", size=32, relaxed=True, dest="Imm",
opt="SImm8")])
# Need these when we don't match the BITS size, but they need to be
# below the above line so the optimizer can kick in by default.
add_group("push",
cpu=["186"],
parsers=["nasm"],
opersize=16,
def_opersize_64=64,
opcode=[0x68],
operands=[Operand(type="Imm", size=16, dest="Imm")])
add_group("push",
not64=True,
parsers=["nasm"],
opersize=32,
opcode=[0x68],
operands=[Operand(type="Imm", size=32, dest="Imm")])
add_group("push",
only64=True,
parsers=["nasm"],
opersize=64,
def_opersize_64=64,
opcode=[0x68],
operands=[Operand(type="Imm", size=32, dest="SImm")])
add_group("push",
not64=True,
opcode=[0x0E],
operands=[Operand(type="CS", dest=None)])
add_group("push",
suffix="w",
not64=True,
opersize=16,
opcode=[0x0E],
operands=[Operand(type="CS", size=16, dest=None)])
add_group("push",
suffix="l",
not64=True,
opersize=32,
opcode=[0x0E],
operands=[Operand(type="CS", size=32, dest=None)])
add_group("push",
not64=True,
opcode=[0x16],
operands=[Operand(type="SS", dest=None)])
add_group("push",
suffix="w",
not64=True,
opersize=16,
opcode=[0x16],
operands=[Operand(type="SS", size=16, dest=None)])
add_group("push",
suffix="l",
not64=True,
opersize=32,
opcode=[0x16],
operands=[Operand(type="SS", size=32, dest=None)])
add_group("push",
not64=True,
opcode=[0x1E],
operands=[Operand(type="DS", dest=None)])
add_group("push",
suffix="w",
not64=True,
opersize=16,
opcode=[0x1E],
operands=[Operand(type="DS", size=16, dest=None)])
add_group("push",
suffix="l",
not64=True,
opersize=32,
opcode=[0x1E],
operands=[Operand(type="DS", size=32, dest=None)])
add_group("push",
not64=True,
opcode=[0x06],
operands=[Operand(type="ES", dest=None)])
add_group("push",
suffix="w",
not64=True,
opersize=16,
opcode=[0x06],
operands=[Operand(type="ES", size=16, dest=None)])
add_group("push",
suffix="l",
not64=True,
opersize=32,
opcode=[0x06],
operands=[Operand(type="ES", size=32, dest=None)])
add_group("push",
opcode=[0x0F, 0xA0],
operands=[Operand(type="FS", dest=None)])
add_group("push",
suffix="w",
opersize=16,
opcode=[0x0F, 0xA0],
operands=[Operand(type="FS", size=16, dest=None)])
add_group("push",
suffix="l",
opersize=32,
opcode=[0x0F, 0xA0],
operands=[Operand(type="FS", size=32, dest=None)])
add_group("push",
opcode=[0x0F, 0xA8],
operands=[Operand(type="GS", dest=None)])
add_group("push",
suffix="w",
opersize=16,
opcode=[0x0F, 0xA8],
operands=[Operand(type="GS", size=16, dest=None)])
add_group("push",
suffix="l",
opersize=32,
opcode=[0x0F, 0xA8],
operands=[Operand(type="GS", size=32, dest=None)])
add_insn("push", "push")
add_insn("pusha", "onebyte", modifiers=[0x60, 0], cpu=["186"], not64=True)
add_insn("pushad", "onebyte", parser="nasm", modifiers=[0x60, 32],
cpu=["386"], not64=True)
add_insn("pushal", "onebyte", parser="gas", modifiers=[0x60, 32],
cpu=["386"], not64=True)
add_insn("pushaw", "onebyte", modifiers=[0x60, 16], cpu=["186"], not64=True)
#
# Pop instructions
#
add_group("pop",
def_opersize_64=64,
opcode=[0x58],
operands=[Operand(type="Reg", size="BITS", dest="Op0Add")])
add_group("pop",
suffix="w",
opersize=16,
def_opersize_64=64,
opcode=[0x58],
operands=[Operand(type="Reg", size=16, dest="Op0Add")])
add_group("pop",
suffix="l",
not64=True,
opersize=32,
opcode=[0x58],
operands=[Operand(type="Reg", size=32, dest="Op0Add")])
add_group("pop",
suffix="q",
only64=True,
def_opersize_64=64,
opcode=[0x58],
operands=[Operand(type="Reg", size=64, dest="Op0Add")])
add_group("pop",
def_opersize_64=64,
opcode=[0x8F],
operands=[Operand(type="RM", size="BITS", dest="EA")])
add_group("pop",
suffix="w",
opersize=16,
def_opersize_64=64,
opcode=[0x8F],
operands=[Operand(type="RM", size=16, dest="EA")])
add_group("pop",
suffix="l",
not64=True,
opersize=32,
opcode=[0x8F],
operands=[Operand(type="RM", size=32, dest="EA")])
add_group("pop",
suffix="q",
only64=True,
def_opersize_64=64,
opcode=[0x8F],
operands=[Operand(type="RM", size=64, dest="EA")])
# POP CS is debateably valid on the 8086, if obsolete and undocumented.
# We don't include it because it's VERY unlikely it will ever be used
# anywhere. If someone really wants it they can db 0x0F it.
#add_group("pop",
# cpu=["Undoc", "Obs"],
# opcode=[0x0F],
# operands=[Operand(type="CS", dest=None)])
add_group("pop",
not64=True,
opcode=[0x17],
operands=[Operand(type="SS", dest=None)])
add_group("pop",
not64=True,
opersize=16,
opcode=[0x17],
operands=[Operand(type="SS", size=16, dest=None)])
add_group("pop",
not64=True,
opersize=32,
opcode=[0x17],
operands=[Operand(type="SS", size=32, dest=None)])
add_group("pop",
not64=True,
opcode=[0x1F],
operands=[Operand(type="DS", dest=None)])
add_group("pop",
not64=True,
opersize=16,
opcode=[0x1F],
operands=[Operand(type="DS", size=16, dest=None)])
add_group("pop",
not64=True,
opersize=32,
opcode=[0x1F],
operands=[Operand(type="DS", size=32, dest=None)])
add_group("pop",
not64=True,
opcode=[0x07],
operands=[Operand(type="ES", dest=None)])
add_group("pop",
not64=True,
opersize=16,
opcode=[0x07],
operands=[Operand(type="ES", size=16, dest=None)])
add_group("pop",
not64=True,
opersize=32,
opcode=[0x07],
operands=[Operand(type="ES", size=32, dest=None)])
add_group("pop",
opcode=[0x0F, 0xA1],
operands=[Operand(type="FS", dest=None)])
add_group("pop",
opersize=16,
opcode=[0x0F, 0xA1],
operands=[Operand(type="FS", size=16, dest=None)])
add_group("pop",
opersize=32,
opcode=[0x0F, 0xA1],
operands=[Operand(type="FS", size=32, dest=None)])
add_group("pop",
opcode=[0x0F, 0xA9],
operands=[Operand(type="GS", dest=None)])
add_group("pop",
opersize=16,
opcode=[0x0F, 0xA9],
operands=[Operand(type="GS", size=16, dest=None)])
add_group("pop",
opersize=32,
opcode=[0x0F, 0xA9],
operands=[Operand(type="GS", size=32, dest=None)])
add_insn("pop", "pop")
add_insn("popa", "onebyte", modifiers=[0x61, 0], cpu=["186"], not64=True)
add_insn("popad", "onebyte", parser="nasm", modifiers=[0x61, 32],
cpu=["386"], not64=True)
add_insn("popal", "onebyte", parser="gas", modifiers=[0x61, 32],
cpu=["386"], not64=True)
add_insn("popaw", "onebyte", modifiers=[0x61, 16], cpu=["186"], not64=True)
#
# Exchange instructions
#
add_group("xchg",
suffix="b",
opcode=[0x86],
operands=[Operand(type="RM", size=8, relaxed=True, dest="EA"),
Operand(type="Reg", size=8, dest="Spare")])
add_group("xchg",
suffix="b",
opcode=[0x86],
operands=[Operand(type="Reg", size=8, dest="Spare"),
Operand(type="RM", size=8, relaxed=True, dest="EA")])
# We could be extra-efficient in the 64-bit mode case here.
# XCHG AX, AX in 64-bit mode is a NOP, as it doesn't clear the
# high 48 bits of RAX. Thus we don't need the operand-size prefix.
# But this feels too clever, and probably not what the user really
# expects in the generated code, so we don't do it.
#add_group("xchg",
# suffix="w",
# only64=True,
# opcode=[0x90],
# operands=[Operand(type="Areg", size=16, dest=None),
# Operand(type="AReg", size=16, dest="Op0Add")])
add_group("xchg",
suffix="w",
opersize=16,
opcode=[0x90],
operands=[Operand(type="Areg", size=16, dest=None),
Operand(type="Reg", size=16, dest="Op0Add")])
add_group("xchg",
suffix="w",
opersize=16,
opcode=[0x90],
operands=[Operand(type="Reg", size=16, dest="Op0Add"),
Operand(type="Areg", size=16, dest=None)])
add_group("xchg",
suffix="w",
opersize=16,
opcode=[0x87],
operands=[Operand(type="RM", size=16, relaxed=True, dest="EA"),
Operand(type="Reg", size=16, dest="Spare")])
add_group("xchg",
suffix="w",
opersize=16,
opcode=[0x87],
operands=[Operand(type="Reg", size=16, dest="Spare"),
Operand(type="RM", size=16, relaxed=True, dest="EA")])
# Be careful with XCHG EAX, EAX in 64-bit mode. This needs to use
# the long form rather than the NOP form, as the long form clears
# the high 32 bits of RAX. This makes all 32-bit forms in 64-bit
# mode have consistent operation.
#
# FIXME: due to a hard-to-fix bug in how we handle generating gas suffix CPU
# rules, this causes xchgl to be CPU_Any instead of CPU_386. A hacky patch
# could fix it, but it's doubtful anyone will ever notice, so leave it.
add_group("xchg",
suffix="l",
only64=True,
opersize=32,
opcode=[0x87],
operands=[Operand(type="Areg", size=32, dest="EA"),
Operand(type="Areg", size=32, dest="Spare")])
add_group("xchg",
suffix="l",
opersize=32,
opcode=[0x90],
operands=[Operand(type="Areg", size=32, dest=None),
Operand(type="Reg", size=32, dest="Op0Add")])
add_group("xchg",
suffix="l",
opersize=32,
opcode=[0x90],
operands=[Operand(type="Reg", size=32, dest="Op0Add"),
Operand(type="Areg", size=32, dest=None)])
add_group("xchg",
suffix="l",
opersize=32,
opcode=[0x87],
operands=[Operand(type="RM", size=32, relaxed=True, dest="EA"),
Operand(type="Reg", size=32, dest="Spare")])
add_group("xchg",
suffix="l",
opersize=32,
opcode=[0x87],
operands=[Operand(type="Reg", size=32, dest="Spare"),
Operand(type="RM", size=32, relaxed=True, dest="EA")])
# Be efficient with XCHG RAX, RAX.
# This is a NOP and thus doesn't need the REX prefix.
add_group("xchg",
suffix="q",
only64=True,
opcode=[0x90],
operands=[Operand(type="Areg", size=64, dest=None),
Operand(type="Areg", size=64, dest="Op0Add")])
add_group("xchg",
suffix="q",
opersize=64,
opcode=[0x90],
operands=[Operand(type="Areg", size=64, dest=None),
Operand(type="Reg", size=64, dest="Op0Add")])
add_group("xchg",
suffix="q",
opersize=64,
opcode=[0x90],
operands=[Operand(type="Reg", size=64, dest="Op0Add"),
Operand(type="Areg", size=64, dest=None)])
add_group("xchg",
suffix="q",
opersize=64,
opcode=[0x87],
operands=[Operand(type="RM", size=64, relaxed=True, dest="EA"),
Operand(type="Reg", size=64, dest="Spare")])
add_group("xchg",
suffix="q",
opersize=64,
opcode=[0x87],
operands=[Operand(type="Reg", size=64, dest="Spare"),
Operand(type="RM", size=64, relaxed=True, dest="EA")])
add_insn("xchg", "xchg")
#####################################################################
# In/out from ports
#####################################################################
add_group("in",
suffix="b",
opcode=[0xE4],
operands=[Operand(type="Areg", size=8, dest=None),
Operand(type="Imm", size=8, relaxed=True, dest="Imm")])
for sfx, sz in zip("wl", [16, 32]):
add_group("in",
suffix=sfx,
opersize=sz,
opcode=[0xE5],
operands=[Operand(type="Areg", size=sz, dest=None),
Operand(type="Imm", size=8, relaxed=True, dest="Imm")])
add_group("in",
suffix="b",
opcode=[0xEC],
operands=[Operand(type="Areg", size=8, dest=None),
Operand(type="Dreg", size=16, dest=None)])
for sfx, sz in zip("wl", [16, 32]):
add_group("in",
suffix=sfx,
opersize=sz,
opcode=[0xED],
operands=[Operand(type="Areg", size=sz, dest=None),
Operand(type="Dreg", size=16, dest=None)])
# GAS-only variants (implicit accumulator register)
add_group("in",
suffix="b",
parsers=["gas"],
opcode=[0xE4],
operands=[Operand(type="Imm", size=8, relaxed=True, dest="Imm")])
for sfx, sz in zip("wl", [16, 32]):
add_group("in",
suffix=sfx,
parsers=["gas"],
opersize=sz,
opcode=[0xE5],
operands=[Operand(type="Imm", size=8, relaxed=True, dest="Imm")])
add_group("in",
suffix="b",
parsers=["gas"],
opcode=[0xEC],
operands=[Operand(type="Dreg", size=16, dest=None)])
add_group("in",
suffix="w",
parsers=["gas"],
opersize=16,
opcode=[0xED],
operands=[Operand(type="Dreg", size=16, dest=None)])
add_group("in",
suffix="l",
cpu=["386"],
parsers=["gas"],
opersize=32,
opcode=[0xED],
operands=[Operand(type="Dreg", size=16, dest=None)])
add_insn("in", "in")
add_group("out",
suffix="b",
opcode=[0xE6],
operands=[Operand(type="Imm", size=8, relaxed=True, dest="Imm"),
Operand(type="Areg", size=8, dest=None)])
for sfx, sz in zip("wl", [16, 32]):
add_group("out",
suffix=sfx,
opersize=sz,
opcode=[0xE7],
operands=[Operand(type="Imm", size=8, relaxed=True, dest="Imm"),
Operand(type="Areg", size=sz, dest=None)])
add_group("out",
suffix="b",
opcode=[0xEE],
operands=[Operand(type="Dreg", size=16, dest=None),
Operand(type="Areg", size=8, dest=None)])
for sfx, sz in zip("wl", [16, 32]):
add_group("out",
suffix=sfx,
opersize=sz,
opcode=[0xEF],
operands=[Operand(type="Dreg", size=16, dest=None),
Operand(type="Areg", size=sz, dest=None)])
# GAS-only variants (implicit accumulator register)
add_group("out",
suffix="b",
parsers=["gas"],
opcode=[0xE6],
operands=[Operand(type="Imm", size=8, relaxed=True, dest="Imm")])
add_group("out",
suffix="w",
parsers=["gas"],
opersize=16,
opcode=[0xE7],
operands=[Operand(type="Imm", size=8, relaxed=True, dest="Imm")])
add_group("out",
suffix="l",
cpu=["386"],
parsers=["gas"],
opersize=32,
opcode=[0xE7],
operands=[Operand(type="Imm", size=8, relaxed=True, dest="Imm")])
add_group("out",
suffix="b",
parsers=["gas"],
opcode=[0xEE],
operands=[Operand(type="Dreg", size=16, dest=None)])
add_group("out",
suffix="w",
parsers=["gas"],
opersize=16,
opcode=[0xEF],
operands=[Operand(type="Dreg", size=16, dest=None)])
add_group("out",
suffix="l",
cpu=["386"],
parsers=["gas"],
opersize=32,
opcode=[0xEF],
operands=[Operand(type="Dreg", size=16, dest=None)])
add_insn("out", "out")
#
# Load effective address
#
for sfx, sz in zip("wlq", [16, 32, 64]):
add_group("lea",
suffix=sfx,
opersize=sz,
opcode=[0x8D],
operands=[Operand(type="Reg", size=sz, dest="Spare"),
Operand(type="Mem", relaxed=True, dest="EA")])
add_insn("lea", "lea")
#
# Load segment registers from memory
#
for sfx, sz in zip("wl", [16, 32]):
add_group("ldes",
suffix=sfx,
not64=True,
modifiers=["Op0Add"],
opersize=sz,
opcode=[0x00],
operands=[Operand(type="Reg", size=sz, dest="Spare"),
Operand(type="Mem", relaxed=True, dest="EA")])
add_insn("lds", "ldes", modifiers=[0xC5])
add_insn("les", "ldes", modifiers=[0xC4])
for sfx, sz in zip("wlq", [16, 32, 64]):
add_group("lfgss",
suffix=sfx,
cpu=["386"],
modifiers=["Op1Add"],
opersize=sz,
opcode=[0x0F, 0x00],
operands=[Operand(type="Reg", size=sz, dest="Spare"),
Operand(type="Mem", relaxed=True, dest="EA")])
add_insn("lfs", "lfgss", modifiers=[0xB4])
add_insn("lgs", "lfgss", modifiers=[0xB5])
add_insn("lss", "lfgss", modifiers=[0xB2])
#
# Flags registers instructions
#
add_insn("clc", "onebyte", modifiers=[0xF8])
add_insn("cld", "onebyte", modifiers=[0xFC])
add_insn("cli", "onebyte", modifiers=[0xFA])
add_insn("clts", "twobyte", modifiers=[0x0F, 0x06], cpu=["286", "Priv"])
add_insn("cmc", "onebyte", modifiers=[0xF5])
add_insn("lahf", "onebyte", modifiers=[0x9F])
add_insn("sahf", "onebyte", modifiers=[0x9E])
add_insn("pushf", "onebyte", modifiers=[0x9C, 0, 64])
add_insn("pushfd", "onebyte", parser="nasm", modifiers=[0x9C, 32],
cpu=["386"], not64=True)
add_insn("pushfl", "onebyte", parser="gas", modifiers=[0x9C, 32],
cpu=["386"], not64=True)
add_insn("pushfw", "onebyte", modifiers=[0x9C, 16, 64])
add_insn("pushfq", "onebyte", modifiers=[0x9C, 64, 64], only64=True)
add_insn("popf", "onebyte", modifiers=[0x9D, 0, 64])
add_insn("popfd", "onebyte", parser="nasm", modifiers=[0x9D, 32],
cpu=["386"], not64=True)
add_insn("popfl", "onebyte", parser="gas", modifiers=[0x9D, 32],
cpu=["386"], not64=True)
add_insn("popfw", "onebyte", modifiers=[0x9D, 16, 64])
add_insn("popfq", "onebyte", modifiers=[0x9D, 64, 64], only64=True)
add_insn("stc", "onebyte", modifiers=[0xF9])
add_insn("std", "onebyte", modifiers=[0xFD])
add_insn("sti", "onebyte", modifiers=[0xFB])
#
# Arithmetic - general
#
add_group("arith",
suffix="b",
modifiers=["Op0Add"],
opcode=[0x04],
operands=[Operand(type="Areg", size=8, dest=None),
Operand(type="Imm", size=8, relaxed=True, dest="Imm")])
for sfx, sz, immsz in zip("wlq", [16, 32, 64], [16, 32, 32]):
add_group("arith",
suffix=sfx,
modifiers=["Op2Add", "Op1AddSp"],
opersize=sz,
opcode1=[0x83, 0xC0],
opcode2=[0x05],
operands=[Operand(type="Areg", size=sz, dest=None),
Operand(type="Imm", size=immsz, relaxed=True, dest="Imm",
opt="SImm8")])
add_group("arith",
suffix="b",
modifiers=["Gap", "SpAdd"],
opcode=[0x80],
spare=0,
operands=[Operand(type="RM", size=8, dest="EA"),
Operand(type="Imm", size=8, relaxed=True, dest="Imm")])
add_group("arith",
suffix="b",
modifiers=["Gap", "SpAdd"],
opcode=[0x80],
spare=0,
operands=[Operand(type="RM", size=8, relaxed=True, dest="EA"),
Operand(type="Imm", size=8, dest="Imm")])
add_group("arith",
suffix="w",
modifiers=["Gap", "SpAdd"],
opersize=16,
opcode=[0x83],
spare=0,
operands=[Operand(type="RM", size=16, dest="EA"),
Operand(type="Imm", size=8, dest="SImm")])
add_group("arith",
parsers=["nasm"],
modifiers=["Gap", "SpAdd"],
opersize=16,
opcode1=[0x83],
opcode2=[0x81],
spare=0,
operands=[Operand(type="RM", size=16, relaxed=True, dest="EA"),
Operand(type="Imm", size=16, dest="Imm", opt="SImm8")])
add_group("arith",
suffix="w",
modifiers=["Gap", "SpAdd"],
opersize=16,
opcode1=[0x83],
opcode2=[0x81],
spare=0,
operands=[
Operand(type="RM", size=16, dest="EA"),
Operand(type="Imm", size=16, relaxed=True, dest="Imm", opt="SImm8")])
add_group("arith",
suffix="l",
modifiers=["Gap", "SpAdd"],
opersize=32,
opcode=[0x83],
spare=0,
operands=[Operand(type="RM", size=32, dest="EA"),
Operand(type="Imm", size=8, dest="SImm")])
# Not64 because we can't tell if add [], dword in 64-bit mode is supposed
# to be a qword destination or a dword destination.
add_group("arith",
not64=True,
parsers=["nasm"],
modifiers=["Gap", "SpAdd"],
opersize=32,
opcode1=[0x83],
opcode2=[0x81],
spare=0,
operands=[Operand(type="RM", size=32, relaxed=True, dest="EA"),
Operand(type="Imm", size=32, dest="Imm", opt="SImm8")])
add_group("arith",
suffix="l",
modifiers=["Gap", "SpAdd"],
opersize=32,
opcode1=[0x83],
opcode2=[0x81],
spare=0,
operands=[
Operand(type="RM", size=32, dest="EA"),
Operand(type="Imm", size=32, relaxed=True, dest="Imm", opt="SImm8")])
# No relaxed-RM mode for 64-bit destinations; see above Not64 comment.
add_group("arith",
suffix="q",
modifiers=["Gap", "SpAdd"],
opersize=64,
opcode=[0x83],
spare=0,
operands=[Operand(type="RM", size=64, dest="EA"),
Operand(type="Imm", size=8, dest="SImm")])
add_group("arith",
suffix="q",
modifiers=["Gap", "SpAdd"],
opersize=64,
opcode1=[0x83],
opcode2=[0x81],
spare=0,
operands=[
Operand(type="RM", size=64, dest="EA"),
Operand(type="Imm", size=32, relaxed=True, dest="Imm", opt="SImm8")])
for sfx, sz in zip("bwlq", [8, 16, 32, 64]):
add_group("arith",
suffix=sfx,
modifiers=["Op0Add"],
opersize=sz,
opcode=[0x00+(sz!=8)],
operands=[Operand(type="RM", size=sz, relaxed=True, dest="EA"),
Operand(type="Reg", size=sz, dest="Spare")])
for sfx, sz in zip("bwlq", [8, 16, 32, 64]):
add_group("arith",
suffix=sfx,
modifiers=["Op0Add"],
opersize=sz,
opcode=[0x02+(sz!=8)],
operands=[Operand(type="Reg", size=sz, dest="Spare"),
Operand(type="RM", size=sz, relaxed=True, dest="EA")])
add_insn("add", "arith", modifiers=[0x00, 0])
add_insn("or", "arith", modifiers=[0x08, 1])
add_insn("adc", "arith", modifiers=[0x10, 2])
add_insn("sbb", "arith", modifiers=[0x18, 3])
add_insn("and", "arith", modifiers=[0x20, 4])
add_insn("sub", "arith", modifiers=[0x28, 5])
add_insn("xor", "arith", modifiers=[0x30, 6])
add_insn("cmp", "arith", modifiers=[0x38, 7])
#
# Arithmetic - inc/dec
#
add_group("incdec",
suffix="b",
modifiers=["Gap", "SpAdd"],
opcode=[0xFE],
spare=0,
operands=[Operand(type="RM", size=8, dest="EA")])
for sfx, sz in zip("wl", [16, 32]):
add_group("incdec",
suffix=sfx,
not64=True,
modifiers=["Op0Add"],
opersize=sz,
opcode=[0x00],
operands=[Operand(type="Reg", size=sz, dest="Op0Add")])
add_group("incdec",
suffix=sfx,
modifiers=["Gap", "SpAdd"],
opersize=sz,
opcode=[0xFF],
spare=0,
operands=[Operand(type="RM", size=sz, dest="EA")])
add_group("incdec",
suffix="q",
modifiers=["Gap", "SpAdd"],
opersize=64,
opcode=[0xFF],
spare=0,
operands=[Operand(type="RM", size=64, dest="EA")])
add_insn("inc", "incdec", modifiers=[0x40, 0])
add_insn("dec", "incdec", modifiers=[0x48, 1])
#
# Arithmetic - mul/neg/not F6 opcodes
#
for sfx, sz in zip("bwlq", [8, 16, 32, 64]):
add_group("f6",
suffix=sfx,
modifiers=["SpAdd"],
opersize=sz,
opcode=[0xF6+(sz!=8)],
spare=0,
operands=[Operand(type="RM", size=sz, dest="EA")])
add_insn("not", "f6", modifiers=[2])
add_insn("neg", "f6", modifiers=[3])
add_insn("mul", "f6", modifiers=[4])
#
# Arithmetic - div/idiv F6 opcodes
# These allow explicit accumulator in GAS mode.
#
for sfx, sz in zip("bwlq", [8, 16, 32, 64]):
add_group("div",
suffix=sfx,
modifiers=["SpAdd"],
opersize=sz,
opcode=[0xF6+(sz!=8)],
spare=0,
operands=[Operand(type="RM", size=sz, dest="EA")])
# Versions with explicit accumulator
for sfx, sz in zip("bwlq", [8, 16, 32, 64]):
add_group("div",
suffix=sfx,
modifiers=["SpAdd"],
opersize=sz,
opcode=[0xF6+(sz!=8)],
spare=0,
operands=[Operand(type="Areg", size=sz, dest=None),
Operand(type="RM", size=sz, dest="EA")])
add_insn("div", "div", modifiers=[6])
add_insn("idiv", "div", modifiers=[7])
#
# Arithmetic - test instruction
#
for sfx, sz, immsz in zip("bwlq", [8, 16, 32, 64], [8, 16, 32, 32]):
add_group("test",
suffix=sfx,
opersize=sz,
opcode=[0xA8+(sz!=8)],
operands=[Operand(type="Areg", size=sz, dest=None),
Operand(type="Imm", size=immsz, relaxed=True, dest="Imm")])
for sfx, sz, immsz in zip("bwlq", [8, 16, 32, 64], [8, 16, 32, 32]):
add_group("test",
suffix=sfx,
opersize=sz,
opcode=[0xF6+(sz!=8)],
operands=[Operand(type="RM", size=sz, dest="EA"),
Operand(type="Imm", size=immsz, relaxed=True, dest="Imm")])
add_group("test",
suffix=sfx,
opersize=sz,
opcode=[0xF6+(sz!=8)],
operands=[Operand(type="RM", size=sz, relaxed=True, dest="EA"),
Operand(type="Imm", size=immsz, dest="Imm")])
for sfx, sz in zip("bwlq", [8, 16, 32, 64]):
add_group("test",
suffix=sfx,
opersize=sz,
opcode=[0x84+(sz!=8)],
operands=[Operand(type="RM", size=sz, relaxed=True, dest="EA"),
Operand(type="Reg", size=sz, dest="Spare")])
for sfx, sz in zip("bwlq", [8, 16, 32, 64]):
add_group("test",
suffix=sfx,
opersize=sz,
opcode=[0x84+(sz!=8)],
operands=[Operand(type="Reg", size=sz, dest="Spare"),
Operand(type="RM", size=sz, relaxed=True, dest="EA")])
add_insn("test", "test")
#
# Arithmetic - aad/aam
#
add_group("aadm",
modifiers=["Op0Add"],
opcode=[0xD4, 0x0A],
operands=[])
add_group("aadm",
modifiers=["Op0Add"],
opcode=[0xD4],
operands=[Operand(type="Imm", size=8, relaxed=True, dest="Imm")])
add_insn("aaa", "onebyte", modifiers=[0x37], not64=True)
add_insn("aas", "onebyte", modifiers=[0x3F], not64=True)
add_insn("daa", "onebyte", modifiers=[0x27], not64=True)
add_insn("das", "onebyte", modifiers=[0x2F], not64=True)
add_insn("aad", "aadm", modifiers=[0x01], not64=True)
add_insn("aam", "aadm", modifiers=[0x00], not64=True)
#
# Conversion instructions
#
add_insn("cbw", "onebyte", modifiers=[0x98, 16])
add_insn("cwde", "onebyte", modifiers=[0x98, 32], cpu=["386"])
add_insn("cdqe", "onebyte", modifiers=[0x98, 64], only64=True)
add_insn("cwd", "onebyte", modifiers=[0x99, 16])
add_insn("cdq", "onebyte", modifiers=[0x99, 32], cpu=["386"])
add_insn("cqo", "onebyte", modifiers=[0x99, 64], only64=True)
#
# Conversion instructions - GAS / AT&T naming
#
add_insn("cbtw", "onebyte", parser="gas", modifiers=[0x98, 16])
add_insn("cwtl", "onebyte", parser="gas", modifiers=[0x98, 32], cpu=["386"])
add_insn("cltq", "onebyte", parser="gas", modifiers=[0x98, 64], only64=True)
add_insn("cwtd", "onebyte", parser="gas", modifiers=[0x99, 16])
add_insn("cltd", "onebyte", parser="gas", modifiers=[0x99, 32], cpu=["386"])
add_insn("cqto", "onebyte", parser="gas", modifiers=[0x99, 64], only64=True)
#
# Arithmetic - imul
#
for sfx, sz in zip("bwlq", [8, 16, 32, 64]):
add_group("imul",
suffix=sfx,
opersize=sz,
opcode=[0xF6+(sz!=8)],
spare=5,
operands=[Operand(type="RM", size=sz, dest="EA")])
for sfx, sz in zip("wlq", [16, 32, 64]):
add_group("imul",
suffix=sfx,
cpu=["386"],
opersize=sz,
opcode=[0x0F, 0xAF],
operands=[Operand(type="Reg", size=sz, dest="Spare"),
Operand(type="RM", size=sz, relaxed=True, dest="EA")])
for sfx, sz in zip("wlq", [16, 32, 64]):
add_group("imul",
suffix=sfx,
cpu=["186"],
opersize=sz,
opcode=[0x6B],
operands=[Operand(type="Reg", size=sz, dest="Spare"),
Operand(type="RM", size=sz, relaxed=True, dest="EA"),
Operand(type="Imm", size=8, dest="SImm")])
for sfx, sz in zip("wlq", [16, 32, 64]):
add_group("imul",
suffix=sfx,
cpu=["186"],
opersize=sz,
opcode=[0x6B],
operands=[Operand(type="Reg", size=sz, dest="SpareEA"),
Operand(type="Imm", size=8, dest="SImm")])
for sfx, sz, immsz in zip("wlq", [16, 32, 64], [16, 32, 32]):
add_group("imul",
suffix=sfx,
cpu=["186"],
opersize=sz,
opcode1=[0x6B],
opcode2=[0x69],
operands=[Operand(type="Reg", size=sz, dest="Spare"),
Operand(type="RM", size=sz, relaxed=True, dest="EA"),
Operand(type="Imm", size=immsz, relaxed=True, dest="SImm",
opt="SImm8")])
for sfx, sz, immsz in zip("wlq", [16, 32, 64], [16, 32, 32]):
add_group("imul",
suffix=sfx,
cpu=["186"],
opersize=sz,
opcode1=[0x6B],
opcode2=[0x69],
operands=[Operand(type="Reg", size=sz, dest="SpareEA"),
Operand(type="Imm", size=immsz, relaxed=True, dest="SImm",
opt="SImm8")])
add_insn("imul", "imul")
#
# Shifts - standard
#
for sfx, sz in zip("bwlq", [8, 16, 32, 64]):
add_group("shift",
suffix=sfx,
modifiers=["SpAdd"],
opersize=sz,
opcode=[0xD2+(sz!=8)],
spare=0,
operands=[Operand(type="RM", size=sz, dest="EA"),
Operand(type="Creg", size=8, dest=None)])
add_group("shift",
suffix=sfx,
modifiers=["SpAdd"],
opersize=sz,
opcode=[0xD0+(sz!=8)],
spare=0,
operands=[Operand(type="RM", size=sz, dest="EA"),
Operand(type="Imm1", size=8, relaxed=True, dest=None)])
add_group("shift",
suffix=sfx,
cpu=["186"],
modifiers=["SpAdd"],
opersize=sz,
opcode=[0xC0+(sz!=8)],
spare=0,
operands=[Operand(type="RM", size=sz, dest="EA"),
Operand(type="Imm", size=8, relaxed=True, dest="Imm")])
# In GAS mode, single operands are equivalent to shifting by 1 forms
for sfx, sz in zip("bwlq", [8, 16, 32, 64]):
add_group("shift",
suffix=sfx,
parsers=["gas"],
modifiers=["SpAdd"],
opersize=sz,
opcode=[0xD0+(sz!=8)],
spare=0,
operands=[Operand(type="RM", size=sz, dest="EA")])
add_insn("rol", "shift", modifiers=[0])
add_insn("ror", "shift", modifiers=[1])
add_insn("rcl", "shift", modifiers=[2])
add_insn("rcr", "shift", modifiers=[3])
add_insn("sal", "shift", modifiers=[4])
add_insn("shl", "shift", modifiers=[4])
add_insn("shr", "shift", modifiers=[5])
add_insn("sar", "shift", modifiers=[7])
#
# Shifts - doubleword
#
for sfx, sz in zip("wlq", [16, 32, 64]):
add_group("shlrd",
suffix=sfx,
cpu=["386"],
modifiers=["Op1Add"],
opersize=sz,
opcode=[0x0F, 0x00],
operands=[Operand(type="RM", size=sz, relaxed=True, dest="EA"),
Operand(type="Reg", size=sz, dest="Spare"),
Operand(type="Imm", size=8, relaxed=True, dest="Imm")])
add_group("shlrd",
suffix=sfx,
cpu=["386"],
modifiers=["Op1Add"],
opersize=sz,
opcode=[0x0F, 0x01],
operands=[Operand(type="RM", size=sz, relaxed=True, dest="EA"),
Operand(type="Reg", size=sz, dest="Spare"),
Operand(type="Creg", size=8, dest=None)])
# GAS parser supports two-operand form for shift with CL count
for sfx, sz in zip("wlq", [16, 32, 64]):
add_group("shlrd",
suffix=sfx,
cpu=["386"],
parsers=["gas"],
modifiers=["Op1Add"],
opersize=sz,
opcode=[0x0F, 0x01],
operands=[Operand(type="RM", size=sz, relaxed=True, dest="EA"),
Operand(type="Reg", size=sz, dest="Spare")])
add_insn("shld", "shlrd", modifiers=[0xA4])
add_insn("shrd", "shlrd", modifiers=[0xAC])
#####################################################################
# Control transfer instructions (unconditional)
#####################################################################
#
# call
#
add_group("call",
opcode=[],
operands=[Operand(type="ImmNotSegOff", dest="JmpRel")])
add_group("call",
suffix="w",
opersize=16,
opcode=[],
operands=[Operand(type="ImmNotSegOff", size=16, dest="JmpRel")])
add_group("call",
suffix="l",
not64=True,
opersize=32,
opcode=[],
operands=[Operand(type="ImmNotSegOff", size=32, dest="JmpRel")])
add_group("call",
suffixes=["l", "q"],
only64=True,
opersize=64,
opcode=[],
operands=[Operand(type="ImmNotSegOff", size=32, dest="JmpRel")])
add_group("call",
opersize=16,
not64=True, #there should not be 16bit call in 64bit mode
opcode=[0xE8],
operands=[Operand(type="Imm", size=16, tmod="Near", dest="JmpRel")])
add_group("call",
not64=True,
opersize=32,
opcode=[0xE8],
operands=[Operand(type="Imm", size=32, tmod="Near", dest="JmpRel")])
add_group("call",
only64=True,
opersize=64,
def_opersize_64=64,
opcode=[0xE8],
operands=[Operand(type="Imm", size=32, tmod="Near", dest="JmpRel")])
add_group("call",
def_opersize_64=64,
opcode=[0xE8],
operands=[Operand(type="Imm", tmod="Near", dest="JmpRel")])
add_group("call",
suffix="w",
req_suffix=True,
opersize=16,
opcode=[0xFF],
spare=2,
operands=[Operand(type="RM", size=16, dest="EA")])
add_group("call",
suffix="l",
req_suffix=True,
not64=True,
opersize=32,
opcode=[0xFF],
spare=2,
operands=[Operand(type="RM", size=32, dest="EA")])
add_group("call",
suffix="q",
req_suffix=True,
opersize=64,
def_opersize_64=64,
opcode=[0xFF],
spare=2,
operands=[Operand(type="RM", size=64, dest="EA")])
add_group("call",
parsers=["gas"],
def_opersize_64=64,
opcode=[0xFF],
spare=2,
operands=[Operand(type="Reg", size="BITS", dest="EA")])
add_group("call",
def_opersize_64=64,
opcode=[0xFF],
spare=2,
operands=[Operand(type="Mem", dest="EA")])
add_group("call",
parsers=["nasm"],
opersize=16,
def_opersize_64=64,
opcode=[0xFF],
spare=2,
operands=[Operand(type="RM", size=16, tmod="Near", dest="EA")])
add_group("call",
parsers=["nasm"],
not64=True,
opersize=32,
opcode=[0xFF],
spare=2,
operands=[Operand(type="RM", size=32, tmod="Near", dest="EA")])
add_group("call",
parsers=["nasm"],
opersize=64,
def_opersize_64=64,
opcode=[0xFF],
spare=2,
operands=[Operand(type="RM", size=64, tmod="Near", dest="EA")])
add_group("call",
parsers=["nasm"],
def_opersize_64=64,
opcode=[0xFF],
spare=2,
operands=[Operand(type="Mem", tmod="Near", dest="EA")])
# Far indirect (through memory). Needs explicit FAR override (NASM only)
for sz in [16, 32, 64]:
add_group("call",
parsers=["nasm"],
opersize=sz,
opcode=[0xFF],
spare=3,
operands=[Operand(type="Mem", size=sz, tmod="Far", dest="EA")])
add_group("call",
parsers=["nasm"],
opcode=[0xFF],
spare=3,
operands=[Operand(type="Mem", tmod="Far", dest="EA")])
# With explicit FAR override
for sz in [16, 32]:
add_group("call",
parsers=["nasm"],
not64=True,
opersize=sz,
opcode=[0x9A],
operands=[Operand(type="Imm", size=sz, tmod="Far", dest="JmpFar")])
add_group("call",
parsers=["nasm"],
not64=True,
opcode=[0x9A],
operands=[Operand(type="Imm", tmod="Far", dest="JmpFar")])
# Since not caught by first ImmNotSegOff group, implicitly FAR (in NASM).
for sz in [16, 32]:
add_group("call",
parsers=["nasm"],
not64=True,