| #! /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) |
| |
| 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, |
| opersize=sz, |
| opcode=[0x9A], |
| operands=[Operand(type="Imm", size=sz, dest="JmpFar")]) |
| add_group("call", |
| parsers=["nasm"], |
| not64=True, |
| opcode=[0x9A], |
| operands=[Operand(type="Imm", dest="JmpFar")]) |
| |
| # Two-operand FAR (GAS only) |
| for sfx, sz in zip("wl", [16, 32]): |
| add_group("call", |
| suffix=sfx, |
| req_suffix=True, |
| parsers=["gas"], |
| not64=True, |
| gas_no_reverse=True, |
| opersize=sz, |
| opcode=[0x9A], |
| operands=[Operand(type="Imm", size=16, relaxed=True, dest="JmpFar"), |
| Operand(type="Imm", size=sz, relaxed=True, dest="JmpFar")]) |
| add_group("call", |
| parsers=["gas"], |
| not64=True, |
| gas_no_reverse=True, |
| opcode=[0x9A], |
| operands=[Operand(type="Imm", size=16, relaxed=True, dest="JmpFar"), |
| Operand(type="Imm", size="BITS", relaxed=True, dest="JmpFar")]) |
| |
| add_insn("call", "call") |
| |
| # |
| # jmp |
| # |
| add_group("jmp", |
| opcode=[], |
| operands=[Operand(type="ImmNotSegOff", dest="JmpRel")]) |
| add_group("jmp", |
| suffix="w", |
| opersize=16, |
| opcode=[], |
| operands=[Operand(type="ImmNotSegOff", size=16, dest="JmpRel")]) |
| add_group("jmp", |
| suffix="l", |
| not64=True, |
| opersize=32, |
| opcode=[0x00], |
| operands=[Operand(type="ImmNotSegOff", size=32, dest="JmpRel")]) |
| add_group("jmp", |
| suffixes=["l", "q"], |
| only64=True, |
| opersize=64, |
| opcode=[0x00], |
| operands=[Operand(type="ImmNotSegOff", size=32, dest="JmpRel")]) |
| |
| add_group("jmp", |
| def_opersize_64=64, |
| opcode=[0xEB], |
| operands=[Operand(type="Imm", tmod="Short", dest="JmpRel")]) |
| add_group("jmp", |
| opersize=16, |
| def_opersize_64=64, |
| opcode=[0xE9], |
| operands=[Operand(type="Imm", size=16, tmod="Near", dest="JmpRel")]) |
| add_group("jmp", |
| not64=True, |
| cpu=["386"], |
| opersize=32, |
| opcode=[0xE9], |
| operands=[Operand(type="Imm", size=32, tmod="Near", dest="JmpRel")]) |
| add_group("jmp", |
| only64=True, |
| opersize=64, |
| def_opersize_64=64, |
| opcode=[0xE9], |
| operands=[Operand(type="Imm", size=32, tmod="Near", dest="JmpRel")]) |
| add_group("jmp", |
| def_opersize_64=64, |
| opcode=[0xE9], |
| operands=[Operand(type="Imm", tmod="Near", dest="JmpRel")]) |
| |
| add_group("jmp", |
| suffix="w", |
| req_suffix=True, |
| opersize=16, |
| def_opersize_64=64, |
| opcode=[0xFF], |
| spare=4, |
| operands=[Operand(type="RM", size=16, dest="EA")]) |
| add_group("jmp", |
| suffix="l", |
| req_suffix=True, |
| not64=True, |
| opersize=32, |
| opcode=[0xFF], |
| spare=4, |
| operands=[Operand(type="RM", size=32, dest="EA")]) |
| add_group("jmp", |
| suffix="q", |
| req_suffix=True, |
| opersize=64, |
| def_opersize_64=64, |
| opcode=[0xFF], |
| spare=4, |
| operands=[Operand(type="RM", size=64, dest="EA")]) |
| add_group("jmp", |
| parsers=["gas"], |
| def_opersize_64=64, |
| opcode=[0xFF], |
| spare=4, |
| operands=[Operand(type="Reg", size="BITS", dest="EA")]) |
| add_group("jmp", |
| def_opersize_64=64, |
| opcode=[0xFF], |
| spare=4, |
| operands=[Operand(type="Mem", dest="EA")]) |
| add_group("jmp", |
| parsers=["nasm"], |
| opersize=16, |
| def_opersize_64=64, |
| opcode=[0xFF], |
| spare=4, |
| operands=[Operand(type="RM", size=16, tmod="Near", dest="EA")]) |
| add_group("jmp", |
| parsers=["nasm"], |
| not64=True, |
| cpu=["386"], |
| opersize=32, |
| opcode=[0xFF], |
| spare=4, |
| operands=[Operand(type="RM", size=32, tmod="Near", dest="EA")]) |
| add_group("jmp", |
| parsers=["nasm"], |
| opersize=64, |
| def_opersize_64=64, |
| opcode=[0xFF], |
| spare=4, |
| operands=[Operand(type="RM", size=64, tmod="Near", dest="EA")]) |
| add_group("jmp", |
| parsers=["nasm"], |
| def_opersize_64=64, |
| opcode=[0xFF], |
| spare=4, |
| operands=[Operand(type="Mem", tmod="Near", dest="EA")]) |
| |
| # Far indirect (through memory). Needs explicit FAR override. |
| for sz in [16, 32, 64]: |
| add_group("jmp", |
| opersize=sz, |
| opcode=[0xFF], |
| spare=5, |
| operands=[Operand(type="Mem", size=sz, tmod="Far", dest="EA")]) |
| add_group("jmp", |
| opcode=[0xFF], |
| spare=5, |
| operands=[Operand(type="Mem", tmod="Far", dest="EA")]) |
| |
| # With explicit FAR override |
| for sz in [16, 32]: |
| add_group("jmp", |
| not64=True, |
| opersize=sz, |
| opcode=[0xEA], |
| operands=[Operand(type="Imm", size=sz, tmod="Far", dest="JmpFar")]) |
| add_group("jmp", |
| not64=True, |
| opcode=[0xEA], |
| 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("jmp", |
| parsers=["nasm"], |
| not64=True, |
| opersize=sz, |
| opcode=[0xEA], |
| operands=[Operand(type="Imm", size=sz, dest="JmpFar")]) |
| add_group("jmp", |
| parsers=["nasm"], |
| not64=True, |
| opcode=[0xEA], |
| operands=[Operand(type="Imm", dest="JmpFar")]) |
| |
| # Two-operand FAR (GAS only) |
| for sfx, sz in zip("wl", [16, 32]): |
| add_group("jmp", |
| parsers=["gas"], |
| suffix=sfx, |
| req_suffix=True, |
| not64=True, |
| gas_no_reverse=True, |
| opersize=sz, |
| opcode=[0xEA], |
| operands=[Operand(type="Imm", size=16, relaxed=True, dest="JmpFar"), |
| Operand(type="Imm", size=sz, relaxed=True, dest="JmpFar")]) |
| add_group("jmp", |
| parsers=["gas"], |
| not64=True, |
| gas_no_reverse=True, |
| opcode=[0xEA], |
| operands=[Operand(type="Imm", size=16, relaxed=True, dest="JmpFar"), |
| Operand(type="Imm", size="BITS", relaxed=True, dest="JmpFar")]) |
| |
| add_insn("jmp", "jmp") |
| |
| # |
| # GAS far calls/jumps |
| # |
| |
| # Far indirect (through memory) |
| for sfx, sz in zip("wlq", [16, 32, 64]): |
| add_group("ljmpcall", |
| suffix=sfx, |
| req_suffix=True, |
| opersize=sz, |
| modifiers=["SpAdd"], |
| opcode=[0xFF], |
| spare=0, |
| operands=[Operand(type="Mem", size=sz, relaxed=True, dest="EA")]) |
| add_group("ljmpcall", |
| modifiers=["SpAdd"], |
| opcode=[0xFF], |
| spare=0, |
| operands=[Operand(type="Mem", size="BITS", relaxed=True, dest="EA")]) |
| |
| # Two-operand far |
| for sfx, sz in zip("wl", [16, 32]): |
| add_group("ljmpcall", |
| not64=True, |
| gas_no_reverse=True, |
| suffix=sfx, |
| req_suffix=True, |
| opersize=sz, |
| modifiers=["Gap", "Op0Add"], |
| opcode=[0x00], |
| operands=[Operand(type="Imm", size=16, relaxed=True, dest="JmpFar"), |
| Operand(type="Imm", size=sz, relaxed=True, dest="JmpFar")]) |
| add_group("ljmpcall", |
| not64=True, |
| gas_no_reverse=True, |
| modifiers=["Gap", "Op0Add"], |
| opcode=[0x00], |
| operands=[Operand(type="Imm", size=16, relaxed=True, dest="JmpFar"), |
| Operand(type="Imm", size="BITS", relaxed=True, dest="JmpFar")]) |
| |
| add_insn("ljmp", "ljmpcall", parser
|