=============================================================================== B A S T A R D disassembly environment Libdisasm Perl Disassembler HOWTO or "Mammon_'s Guide to Writing Disassemblers in Perl, You Morons!" ================================================================================ Contents 1. Writing an x86 disassembler in Perl 2. Parsing i386.opcodes.map 3. Working with binary files 4. Parsing an ELF file 5. Disassembling x86 opcodes 6. Generating an intermediate representation 7. Producing output 8. End Results A. Source code for x86disasm.pl B. Source code for i386.opcodes.map ================================================================================ 1: Writing a disassembler in Perl This document was born out of a conversation on IRC regarding the looming next generation of objdump output analyzers during a relative dearth of "true" disassembler projects, and as a result has had many working titles. "The Lazy Man's Guide to Overcoming Effete Programming". "Disassembler Writing for Web Designers". "How to Write a Real Disassembler Even in Perl, You Primitive Screwheads". "Perl: It's Not Just For Lamers Anymore." In the end, a nod to the BTAF apostrophe guide was chosen for its elegance, poise, and grace under pressure. Why the venom towards objdump output analysers? Well, the first one was good. The next few were OK. The last dozen were embarassing. Historically speaking, the problem with objdump has never been the output; the problem has been the the output generator ... but more on that in a minute. What is becoming obvious is that potential programmers are becoming more interested in developing "output prettifiers" for someone else's poorly-written program than in producing a poorly written program of their own. A sad choice, really, since that reduces the chance of any of these projects ever being worth a damn to zero. Why Perl? Perl seems to be the language of choice for the unenlightened, and has been the crutch upon which many an aspiring disassembler writer has lurched along towards oblivion. In an attempt to reach this audience, the bulk of whom have undoubtedly been turned away by the heavy-handed derision of their lifeswork in the previous paragraphs, Perl is used here in combination with the opcode tables of a C disassembler to demonstrate how to write a "real" disassembler without having to actually learn anything as difficult as, say, C. The opcode tables used here are from the libdisasm module of the bastard disassembler project, though the same principle could be applied to opcode tables from ndisasm, libopcodes, borg, or any other open-source disassembler. Why write a disassembler at all when there is objdump? To lapse into technical jargon, objdump sucks. As a disassembler, it discards a great deal of information about each instruction; as an ELF file parser, it fails to handle sstrip(1)ed binaries [i.e. those missing section headers] -- a fault of the GNU BFD library, which it was based on. There is a lesson here which one would do well to heed: all GNU tools are intended to work on binaries for which the source code is available; they are clumsy when working on foreign binaries, and useless when faced with hostile code. Note: This paper builds on concepts and code presented in the forthcoming paper "Linux on the Half-ELF" [currently in private release, and containing a sample objdump output analyzer to show how it should be done, if that route is to be taken]. For this reason, topics such as ELF file format parsing, the need for an intermediate representation, and the weaknesses of the GNU binutils package will have limited treatment. The reader who is not comfortable with Perl, the ELF file format, or Intel assembly language is advised to undertake an independent study of these areas before continuing. ================================================================================ 2: Parsing i386.opcodes.map The most important step in writing a Perl disassembler is to find one written in C and rip it off. This will save you a lot of hard work in creating the opcode tables that will be used during disassembly, and allows you to use the C source as a reference when writing opcode table lookup routines. One could always go the extra mile and translate the C opcode tables to Perl, but that is not strictly necessary -- and since the [rather huge] opcode tables are going to be stored in a separate file anyways, the C representation is as good as any other. The opcode tables are stored as arrays of C structures; since each table has a different range of index values, an array of table definitions or descriptions [if you swing that way] is used to pre-process the table index value before a lookup is performed. These table definitions have the following structure: table_def { $name; # name of table $shft; # value to shift byte by before lookup $mask; # value to mask byte by before lookup $min; # minimum value in table $max; # maximum value in table }; ...and are stored in @tables_list when i386.opcodes.map is read. The tables themselves are loaded into %tables, where the key is the table name and the value is a pointer to an array of instruction definitions. The instruction definitions within an opcode table have the structure insn_def { $table; # index of table to reference $iflg; # flags for instruction $dflg; # flags for dest operand $sflg; # flags for source operand $aflg; # flags for extra operand $cpu; # CPU version $insn; # instruction mnemonic $dest; # hard-coded dest operand $src; # hard-coded source operand $aux; # hard-coded "extra" operand }; where $table is 0 if the instruction is defined here, or an index into @table_list if an additional table lookup is required [see 5. Disassembling x86 Opcodes]. The perl code for parsing i386.opcode.map is essentially a loop through the entire file scanning elements of the table definition and instruction definition arrays: if ( /^\s*instr\s+([A-Za-z0-9_]+)\[[0-9]*\]\s*=\s*\{/ ) { # this is the start of an opcode table # set current table to $i $intable = $1; } elsif ( /^\s*asmtable\s+tables86\[\]\s*=\s*\{/ ){ # this is the start of the table definitions $tablelst = "tables86"; } elsif ( /^\s*\};/ ) { if ( $intable ) { # we are no longer in a table $intable = ""; } elsif ( $tablelst ) { # we are no longer in the table of tables $tablelst = ""; } } elsif ( /^\s*\{([^}]+)\}/ ) { if ( $intable ) { # this is an instruction definition push @{$tables{$intable}}, new_insn( $i ); } elsif ( $tablelst ) { # this is a table definition push @table_list, new_table($1); } # else ignore } The new_insn() and new_table() routines are responsible for translating the C structures into equivalent Perl hashes: sub new_table { local($line) = shift; local(%t); $line =~ s/\s//g; ($t{name}, $t{shft}, $t{mask}, $t{min}, $t{max}) = split ',', $line; return \%t; } sub new_insn { local($line) = shift; local(%i); $line =~ s/\s//g; $line =~ s/"//g; ($i{table}, $i{iflg}, $i{dflg}, $i{sflg}, $i{aflg}, $i{cpu}, $i{insn}, $i{dest}, $i{src}, $i{aux}) = split ',', $line; return \%i; } Note that the primary purpose of these routines is to allocate and fill new hashes; since the hashes are being added to an array, these routines return a reference to the new hash, not the hash itself. In the C source file, the opcode tables are declared by name, but referenced by index from within an instruction definition. The index of a table is not known until the table definitions are fully parsed; thus, the instructions within a table are stored in a hash indexed by table name, and the name for a table must be derived from an index value by performing a lookup: $table_def = $table_list[$table_index]; $table = $tables{$table_def{name}}; $insn = $$table[$insn_index]; or, in obfu^H^H^H^Hperl style, $insn = $$tables{$$table_list[$table_index]{name}}[$insn_index] ...though for obvious reasons this style will be avoided as much as possible. ================================================================================ 3: Working with binary files Despite the strange uses to which it has been put, Perl is primarily a text processing language. Working with binary data is more difficult than in C, and requires a bit of extra code. To begin with, the target must be opened in raw mode; this can be performed with a simple operation on the file handle: binmode( FILE, ":raw" ); Dealing with buffers of bytes is a bit awkward, since buffers are treated as scalars and not as arrays of bytes. The way to obtain a byte value from a buffer is $byte = unpack( "C", substr $buf, $index, 1 ); ...where substr() returns the byte at $index, and unpack() converts the byte to a binary value. The unpack() routine is essential to working with binary data; it is used, for example, to implement the get_immediate() routine: if ( $sign ) { if ( $size == 1 ) { $imm_str = "c"; } elsif ( $size == 2 ) { $imm_str = "s"; } elsif ( $size == 4 ) { $imm_str = "i"; } elsif ( $size == 8 ) { $imm_str = "q"; } elsif ( $size == 16 ) { $imm_str = "q2"; } } else { if ( $size == 1 ) { $imm_str = "C"; } elsif ( $size == 2 ) { $imm_str = "v"; } elsif ( $size == 4 ) { $imm_str = "V"; } elsif ( $size == 8 ) { $imm_str = "Q"; } elsif ( $size == 16 ) { $imm_str = "Q2"; } } $imm = unpack $imm_str, $buf; The formatting codes used in unpack() are documented in the perlfunc man page for pack(). For the most part, working with a binary value using the bitwise operators &, ^, |, <<, and >> is fairly straightforward; however, there are occasions where Perl gets confused on whether a value is a number or a string, particularly if it has not been operated on before ... with the unfortunate effect that the bitwise operations return empty values when the number is treated as a string. I know of nothing in the history of any programming language that would lead one to expect this behavior; I blame the same lost soul who decided that objects in Perl were a good idea. When bitwise operations fail to work correctly, one must explain to Perl in slow, simple, monosyllabic words that the bits being operated on are, in fact, bits of a binary value and not components of a string: $bit_mask *= 1; # multiple to show Perl this is an integer $value &= $bit_mask; # mask value with bitmask Yes, all this is ugly and should be entirely unnecessary; at the very least, Perl should provide some means of casting a scalar specifically to a "number" or "string" -- given Perl's track record, leaving out casting for fear of "feature creep" would be like Kiss^H^H^H^HPol Pot suddenly expressing a concern for human rights. Similar problems occur when working with data which has been stored in hexadecimal format; Perl does not recognize these as numbers but instead treats them as strings [i.e., `$byte = "2"` causes $byte to be interpreted as a number, but `$byte = "0xFF"` causes $byte to be interpreted as a string]. In such cases, the "hex" command must be used to ensure proper handling of the variable: $byte = hex($byte); # convert $byte from hexadecimal to numeric Again, this should be solved by casting the type of $byte to numeric or "not-string", however the closest Perl comes is the scalar() function which simply casts to the type "number-or-string". This would be a good time to point out the notations used in the provided source, since Perl's "more than one way to do it" philosophy apparently applies to language syntax as well as semantics. The syntax for using pointers in Perl is pretty odd to say the least: Operator Meaning Example Comment -------------------------------------------------------------------------- \ Address of \@array # address of @array $ Dereference $$array[0] # dereference $array {} Cast @{$array} # cast $array to ARRAY type Note that the dereference operator is the same as the SCALAR type indicator, and that the casting braces are the same as the HASH key dereference braces. One may start to spot a trend, after noticing that ARRAY types are initialized using parentheses, and HASH types are initalized using parentheses, but anonymous ARRAY types are initialized using brackets and anonymous HASH types [e.g., those in an array of hashes] are initialized using braces. It is little inconsistencies like this that people refer to when they describe Perl affectionately as "not a real language". The following example demonstrates the use of these operators: my %insn, $i; # "insn" hash, pointer to hash my @bytes, $b; # "bytes" array, pointer to array my $index, $x; # "index" scalar, pointer to scalar # initialization %insn = ( offset => 0, name => "push", dest => "eax" ); @bytes = ( 0x55, 0x89 ); $index = 1; # set pointers $i = \%insn; # set i to address of %insn $b = \@bytes; # set b to address of @bytes $x = \$index; # set x to address of $index print "$insn{name}"; # prints "push" print "$$i{name}"; # ditto printf "%02X", $bytes[$index]; # prints "0x89" printf "%02X", $$b[$index]; # ditto printf "%02X", $$b[$$x]; # ditto $$i{bytes} = \@bytes; # sets $insn{bytes} to addr of @bytes $$i{bytes} = $b; # ditto printf "%02X", $insn{bytes}[$index]; # prints "0x89" printf "%02X", $$i{bytes}[$index]; # prints "0x89" $$x = 2; # sets $index to 2 $bytes[$$x] = \%insn; # sets $bytes[2] to address of %insn $$b[$$x] = $i; # ditto print $bytes[$$x]{name}; # prints "push" print $$b[$$x]{name}; # ditto foreach ( @bytes ) { print } # print all values in @bytes foreach ( @{$b} ) { print } # ditto foreach ( keys( %insn ) ) { print }; # print all keys in %insn foreach ( keys( %{$i} ) ) { print }; # ditto Awful lot of $'s floating around in that code, eh? The cast operator is particularly useful as it allows explicit treatment of a scalar as a hash or array when necessary, though one must be careful to close all curly braces when using casting with, say, nested hash tables. ================================================================================ 4: Parsing an ELF file A good example of examining structured binary data with Perl is the parsing of an ELF file header. The ELF file format itself will not be discussed here; the reader is assumed to understand the structure and the importance of the file header, the section headers, the program headers, and the dynamic linking information. The first step, of course, is to read the ELF header in order to determine the offsets of the section and program header tables: sub elf_read { # read in magic number sysread FILE, $buf, 16; ($id, $class, $data, $jnk) = unpack "a4aaa10", $buf; if ( $id ne "\177ELF" ) { return 0; } if ( $class == 2 ) { $target_info{bits} = 64; } else { $target_info{bits} = 32; } if ( $data == 2 ) { $target_info{endian} = "big"; $endian_str = "a16n2N5n6"; } else { $target_info{endian} = "little"; $endian_str = "a16v2V5v6"; } # read in entire ELF header sysseek FILE, 0, SEEK_SET; sysread FILE, $buf, $elf_size; ($e_hdr{e_ident}, $e_hdr{e_type}, $e_hdr{e_machine}, $e_hdr{e_version}, $e_hdr{e_entry}, $e_hdr{e_phoff}, $e_hdr{e_shoff}, $e_hdr{e_flags}, $e_hdr{e_ehsize}, $e_hdr{e_phentsize}, $e_hdr{e_phnum}, $e_hdr{e_shentsize}, $e_hdr{e_shnum}, $e_hdr{e_shstrndx} ) = unpack $endian_str, $buf; $target_info{header} = \%e_hdr; $target_info{entry} = $e_hdr{e_entry}; elf_shdr_read( \%e_hdr ); elf_dynamic( \%e_hdr ); } The section headers contain the most information about the binary; they are examined in order to create sections in the target and to identify the location of the dynamic linking information. In keeping with the spirit of objdump, only the section headers are parsed in this example; code for handling program headers can be found in Appendix A. sub elf_shdr_read { local( $e_hdr ) = shift; # read in section header table sysseek FILE, $$e_hdr{e_shoff}, SEEK_SET; # iterate over headers, saving header & looking for strtab for ( $x = 0; $x < $$e_hdr{e_shnum}; $x++ ) { # read section header sysread FILE, $buf, $$e_hdr{e_shentsize}; $shdr = new_shdr( $buf ); # recognize section header strtab if ( $x && $x == $$e_hdr{e_shstrndx} ) { $shstrtab = $$shdr{sh_offset}; $shstrsz = $$shdr{sh_size}; } push @{$$e_hdr{shtab}}, $shdr; } # read in copy of strtab sysseek FILE, $shstrtab, SEEK_SET; sysread FILE, $shstrbuf, $shstrsz; # process sections based on section name foreach ( @{$$e_hdr{shtab}} ) { $shdr = $_; $$shdr{sh_name} = substr $shstrbuf, $$shdr{sh_name}; $$shdr{sh_name} =~ s/\x00.*//; if ( $$shdr{sh_name} eq ".dynamic" ) { # dynamic linking info $$e_hdr{dynhdr} = $shdr; } elsif ( $$shdr{sh_name} eq ".dynstr" ) { # dynamic linking strings $$e_hdr{dyn_strtab} = $$shdr{sh_offset}; $$e_hdr{dyn_strsz} = $$shdr{sh_size}; } elsif ( $$shdr{sh_name} eq ".dynsym" ) { # dynamic linking symbols $$e_hdr{dyn_symtab} = $$shdr{sh_offset}; $$e_hdr{dyn_syment} = $$shdr{sh_entsize}; $$e_hdr{dyn_symsz} = $$shdr{sh_size}; } elsif ( $$shdr{sh_type} eq "SHT_PROGBITS" && $$shdr{sh_flags} =~ /SHF_ALLOC/ ) { if ( $$shdr{sh_flags} =~ /SHF_WRITE/ ) { # make .data section } elsif ($$shdr{sh_flags} =~ /SHF_EXECINSTR/) { # make .text } else { # make .rodata } } elsif ( $$shdr{sh_type} eq "SHT_NOGBITS" && $$shdr{sh_flags} =~ /SHF_ALLOC/ ) { if ( $$shdr{sh_flags} =~ /SHF_WRITE/ ) { # make .bss section } } } return; } sub new_shdr { local($buf) = shift; local(%shdr); if ( $target_info{endian} eq "big" ) {$shdr_str = "NNNNNNNNNN"; } else { $shdr_str = "VVVVVVVVVV"; } ( $shdr{sh_name}, $shdr{sh_type}, $shdr{sh_flags}, $shdr{sh_addr}, $shdr{sh_offset}, $shdr{sh_size}, $shdr{sh_link}, $shdr{sh_info}, $shdr{sh_addralign}, $shdr{sh_entsize} ) = unpack $shdr_str, $buf; if ( $shdr{sh_type} == 0 ) { $shdr{sh_type} = "SHT_NULL"; } elsif ($shdr{sh_type} == 1 ){ $shdr{sh_type} = "SHT_PROGBITS"; } elsif ($shdr{sh_type} == 2 ){ $shdr{sh_type} = "SHT_SYMTAB"; } elsif ($shdr{sh_type} == 3 ){ $shdr{sh_type} = "SHT_STRTAB"; } elsif ($shdr{sh_type} == 4 ){ $shdr{sh_type} = "SHT_RELA"; } elsif ($shdr{sh_type} == 5 ){ $shdr{sh_type} = "SHT_HASH"; } elsif ($shdr{sh_type} == 6 ){ $shdr{sh_type} = "SHT_DYNAMIC"; } elsif ($shdr{sh_type} == 7 ){ $shdr{sh_type} = "SHT_NOTE"; } elsif ($shdr{sh_type} == 8 ){ $shdr{sh_type} = "SHT_NOBITS"; } elsif ($shdr{sh_type} == 9 ){ $shdr{sh_type} = "SHT_REL"; } elsif ($shdr{sh_type} == 10 ){$shdr{sh_type} = "SHT_SHLIB"; } elsif ($shdr{sh_type} == 11 ){$shdr{sh_type} = "SHT_DYNSYM"; } if ( $shdr{sh_flags} & 0x01 ){ $buf .= "SHF_WRITE|"; } if ( $shdr{sh_flags} & 0x02 ){ $buf .= "SHF_ALLOC|"; } if ( $shdr{sh_flags} & 0x04 ){ $buf .= "SHF_EXECINSTR|"; } $shdr{sh_flags} = $buf; return \%shdr; } Now that the section headers have been parsed, the location of the .dynamic section is known, and the dynamic linking info can be examined for global imported symbols. Each dynamic section is loaded in order to find the dynamic string table and symbol table, and the dynamic symbol table is then processed. sub elf_dynamic { local($e_hdr) = shift; #read temporary copy of strtab sysseek FILE, $$e_hdr{dyn_strtab}, SEEK_SET; sysread FILE, $str_buf, $$e_hdr{dyn_strsz}; # process symtab sysseek FILE, $$e_hdr{dyn_symtab}, SEEK_SET; for ( $x = 0; $x < $$e_hdr{dyn_symsz} / $$e_hdr{dyn_syment}; $x++ ){ # read in symbol sysread FILE, $buf, $$e_hdr{dyn_syment}; $sym = new_sym( $e_hdr, $buf, $str_buf ); } return; } sub new_dyn { local($buf) = shift; local(%dyn); if ( $target_info{endian} eq "big" ) { $dyn_str = "NN"; } else { $dyn_str = "VV"; } ( $dyn{d_tag}, $dyn{d_val} ) = unpack $dyn_str, $buf; if ( $dyn{d_tag} == 0 ) { $dyn{d_tag} = "DT_NULL"; } elsif ( $dyn{d_tag} == 1 ) { $dyn{d_tag} = "DT_NEEDED"; } elsif ( $dyn{d_tag} == 2 ) { $dyn{d_tag} = "DT_PLTRELSZ"; } elsif ( $dyn{d_tag} == 3 ) { $dyn{d_tag} = "DT_PLTGOT"; } elsif ( $dyn{d_tag} == 4 ) { $dyn{d_tag} = "DT_HASH"; } elsif ( $dyn{d_tag} == 5 ) { $dyn{d_tag} = "DT_STRTAB"; } elsif ( $dyn{d_tag} == 6 ) { $dyn{d_tag} = "DT_SYMTAB"; } elsif ( $dyn{d_tag} == 7 ) { $dyn{d_tag} = "DT_RELA"; } elsif ( $dyn{d_tag} == 8 ) { $dyn{d_tag} = "DT_RELASZ"; } elsif ( $dyn{d_tag} == 9 ) { $dyn{d_tag} = "DT_RELAENT"; } elsif ( $dyn{d_tag} == 10 ) { $dyn{d_tag} = "DT_STRSZ"; } elsif ( $dyn{d_tag} == 11 ) { $dyn{d_tag} = "DT_SYMENT"; } elsif ( $dyn{d_tag} == 12 ) { $dyn{d_tag} = "DT_INIT"; } elsif ( $dyn{d_tag} == 13 ) { $dyn{d_tag} = "DT_FINI"; } elsif ( $dyn{d_tag} == 14 ) { $dyn{d_tag} = "DT_SONAME"; } elsif ( $dyn{d_tag} == 15 ) { $dyn{d_tag} = "DT_RPATH"; } elsif ( $dyn{d_tag} == 16 ) { $dyn{d_tag} = "DT_SYMBOLIC"; } elsif ( $dyn{d_tag} == 17 ) { $dyn{d_tag} = "DT_REL"; } elsif ( $dyn{d_tag} == 18 ) { $dyn{d_tag} = "DT_RELSZ"; } elsif ( $dyn{d_tag} == 19 ) { $dyn{d_tag} = "DT_RELENT"; } elsif ( $dyn{d_tag} == 20 ) { $dyn{d_tag} = "DT_PLTREL"; } elsif ( $dyn{d_tag} == 21 ) { $dyn{d_tag} = "DT_DEBUG"; } elsif ( $dyn{d_tag} == 22 ) { $dyn{d_tag} = "DT_TEXTREL"; } elsif ( $dyn{d_tag} == 23 ) { $dyn{d_tag} = "DT_JMPREL"; } elsif ( $dyn{d_tag} == 24 ) { $dyn{d_tag} = "DT_BIND_NOW"; } return \%dyn; } An ELF symbol is a relatively simple data structure, consisting primarily of an index into the string table, a value indicating the address of the symbol, and a type which determines the binding and scope of the symbol. The new_sym() routine uses this information to build a symbol hash, which it then returns a reference to. sub new_sym { local($buf) = shift; local(%sym); if ( $target_info{endian} eq "big" ) { $sym_str = "NNNCCn"; } else { $sym_str = "VVVCCv"; } # Get symbol data from $buf ( $sym{st_name}, $sym{st_value}, $sym{st_size}, $sym{st_info}, $sym{st_other}, $sym{st_shndx} ) = unpack $sym_str, $buf; $bind = $sym{st_info} >> 4; $type = $sym{st_info} &0xF; $symbol{type} = ""; if ( $bind == 0 ) { $symbol{type} = "LOCAL|"; } elsif ($bind == 1 ) { $symbol{type} = "GLOBAL|"; } if ( $type == 1 ) { $symbol{type} .= "OBJECT"; } elsif ( $type == 2 ) { $symbol{type} .= "FUNCTION"; } elsif ( $type == 3 ) { $symbol{type} .= "FILE"; } elsif ( $type == 4 ) { $symbol{type} .= "SECTION"; } $symbol{type} =~ s/^\|//g; $symbol{va} = $sym{st_value}; $symbol{offset} = elf_va_to_offset( $e_hdr, $sym{st_value} ); # get symbol name from dynamic strtab $symbol{name} = substr $strtab, $sym{st_name}; $symbol{name} =~ s/\x00.*//; return \%symbol; } Naturally, parsing an ELF header is a complicated process. The above code demonstrates the basic algorithms implemented in Perl; however, for a true reference implementation the reader is directed to examine the disassembler source provided in Appendix A. ================================================================================ 5: Disassembling x86 opcodes Disassembling Intel IA32 instructions by hand is possible, providing good documentation is at hand. The bible of course is the Intel Architecture Software Developer's Manual, available in 3 volumes from the Literature Center of the Developer section at www.intel.com . For the past few years I have kept a printout of the Intel Opcode Map Appendix [Vol 2, p. A1 to A23], the Instruction Format Chapter [Vol 2, p. 2-1 to 2-7], and the Eflags Cross- Reference [Vol 1, p. A-1 to A-4]; these along with the ELF standard have to be replaced every six or so months when the paper wears out. Any reader serious about working with disassemblers is urged to download the manuals and print hard copies of these sections. Any naieve belief that there is a method to Intel's madness can be dispelled by perusing the "Instruction Formats and Encodings" Appendix [Vol 2, p. B-1 to B-18]. There is the semblance of a pattern, in that each instruction can be broken up into fields with regular values ... but determining whether the fields exist in an instruction, and where in the instruction they begin, requires a great deal of "special case" processing. Using [admittedly large] tables of opcodes is faster and requires a much more simple algorithm; this is the approach used in this paper. Opcode Decoding --------------- Assembled Intel instructions have the format instruction { opcode; operands; } ...where "opcode" has the structure: opcode { prefixes; # 0 - 4 prefix bytes opcode; # 1 - 2 opcode bytes } ...and "operands" has the structure: operands { modrm; # 0 or 1 ModR/M byte sib; # 0 or 1 SIB byte displacement; # 0 - 4 byte immediate value immediate; # 0 - 4 byte immediate value } Note that the only required field is the "opcode" field. A prefix byte may be from one of any four prefix groups: 1. Lock/Repeat : LOCK, REP, REPZ, REPNZ 2. Segment Override : CS, SS, DS, ES, FS, GS 3. Operand Size Override 4. Address Size Override The Intel documentation claims that only one byte from each group can be used in a single instruction; however empirical tests show that up to 12 different prefixes can be used before an Illegal Instruction exception is generated. The operand fields will be discussed later on; suffice to say that there can only be a single ModR/M byte and a single SIB byte, and that the SIB byte will only present if a ModR/M byte precedes it. There may be one displacement value and one immediate value per instruction, and these can range from one to four bytes. What this boils down to is that the "official" maximum instruction length is 4 prefix + 2 opcode + 1 modrm + 1 sib + 4 displacement + 4 immediate ------------------------ = 16 bytes ...though one may want to assume a 24-byte instruction length to avoid possible buffer overruns when disassembling instructions with more than 4 prefix bytes. Opcode Tables ------------- The opcode tables in i386.opcode.map are constructed so that a recursive table lookup can be performed using a small number of arithmetic instructions; the tables retain the same semichaotic layout as the tables in the Opcode Map appendix of the Intel manual, which makes the process a bit more confusing than is absolutely necessary. To begin with, the table lookup routine is passed the numeric ID of the opcode table to use [this is an index into an array of pointers to opcode table definitions], along with a buffer of byte values to use for table lookups [e.g., the binary code being disassembled]. The first byte value is used as an index into the table. For tables of 256 opcodes, this works great; however, as many who have gone on to curse Intel's name have found out, the tables have varying sizes, start with different byte values, and may even use only the middle three bits of the index byte. This results in the need to pre-process the index value before performing a table lookup. The algorithm is a bit strange: index = ( (byte - table_def.min) >> table_def.shift) & table_def.mask; ...however it becomes less complex when one realizes that for most of the cases, table_def.min and table_def.shft are 0, and table_def.mask is 0xFF. The purpose of the shift and mask lies in the use of the reg field of the Intel ModR/M byte [more on this later] to store an opcode extension. The ModR/M byte has the structure struct { unsigned int rm: 3; /* lower three bits */ unsigned int reg: 3; /* middle three bits */ unsigned int mod: 2; /* upper two bits */ } modrm; and is often used to encode one to two instruction operands. Some [arbitrary] instructions, however, use the reg field [a value from 0-7] as an index into an additional opcode table, where the actual instruction definition is located. Note that this is in addition to the "coprocessor escape" bytes and the "two-byte instruction escape" bytes, both of which switch to a separate opcode table and use the byte following the current index byte as an index into that table. It gets pretty hairy. The lookup process is hard to follow without a copy of the lookup source and some printed Intel documentation; however, here are some sample lookups that will expose the reader to the true horror that lies in the yawning pits of the IA32 architecture: 1. 0x00 ... This starts off in tbl_Main and is immediately found: tbl_Main { 0, 0xFF, 0, 0xFF }; /* shift, mask, min, max */ ((00 - 0) >> 0) & 0xFF = 00; { 0, INS_ADD, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_G....} As far as disassembly goes, this is as good as it gets. The 0x00 byte is now "processed" and the next byte is used to decode operands. 2. 0x0F 0x8E ... This starts off in tbl_Main and immediately identifies table[1] as the additional table to perform a lookup on: tbl_Main { 0, 0xFF, 0, 0xFF }; /* shift, mask, min, max */ ((0F - 0) >> 0) & 0xFF = 0F; {1, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0...} The table definition with index 1 is tbl_0F; the 0x0F byte is considered "processed" and the next byte used as an index into tbl_0F: tbl_0F { 0, 0xFF, 0, 0xFF }; /* shift, mask, min, max */ ((8E - 0) >> 0) & 0xFF = 8E; { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_v| OP_X,...} At this point the instruction is decoded, the 0x8E byte is considered processed, and the next byte is used to decode operands. 3. 0x83 0xD2 ... This decoding begins in tbl_Main like the others: tbl_Main { 0, 0xFF, 0, 0xFF }; /* shift, mask, min, max */ ((0F - 0) >> 0) & 0xFF = 0F; {5, 0, ADDRMETH_E | OPTYPE_v, ADDRMETH_I | OPTYPE_b...} Things quickly go awry when tbl_83 is encountered; this is a table that requires the 'reg' field of the ModR/M byte [the next byte in the buffer] for decoding: tbl_83 { 3, 0x07, 0, 0xFF }; /* shift, mask, min, max */ ((D2 - 0) >> 3) & 0x07 = 02; { 0, INS_ADD, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I...} The instruction has now been decoded, but the 0xD2 byte cannot be considered processed; it will be used to decode operands. The algorithm for opcode lookup therefore appears as follows: sub disasm_table_lookup { local($table) = shift; local($buf) = shift; local($byte, $tbl_def, $table, $insn_def); # get table to perform lookup on $tbl_def = $table_list[$table_num]; # get table definition $table = $tables{$$tbl_def{name}}; # get table of insns # prepare byte to use as index into table $byte = unpack "C", $buf; # get byte from buffer $byte = disasm_table_adjust_byte( $tbl_def, $byte ); # perform lookup $insn_def = $$table[$byte]; # get insn definition if ( $$insn_def{table} ) { # need additional table disasm_table_lookup($$insn_def{table}, substr($buf, 1)); return; } elsif ( $$insn_def{iflg} =~ /INSTR_PREFIX/ ) { # handle prefix byte here # recurse back into tbl_Main to handle byte after prefix disasm_table_lookup( 0, substr($buf, 1) ); } else { # instruction has been decoded; decode operands here } } ...with disasm_table_adjust_byte() being a routine with implements the byte adjustment [((byte-min)>>shift)&mask] mentioned above. The tables are all designed to work with the above algorithm; multiple prefix bytes and FPU instructions will require a few recursions, but the majority of instructions will decode with only one or two recursions. Operand Decoding ---------------- Each instruction definition contains a specification for the operands it expects; this specification conists of an Addressing Method and an Operand Type, and is defined for all instructions in the Opcode Map Appendix. The valid Addressing Methods are referred to in shorthand with uppercase letters: A Direct Address encoded in insn C ModR/M reg field is a control register D ModR/M reg field is a debug register E ModR/M specifies a general register or memory address F Operand is the Eflags register G ModR/M reg field is a general purpose register I Immediate value encoded in instruction J Immediate value to be added to eip M ModR/M only refers to memory O Offset of operand encoded in instruction P ModR/M reg field is an MMX register Q ModR/M specifies an MMX register or memory address R ModR/M mod field only refers to a general register S ModR/M reg field is a segment register T ModR/M reg field is a test register V ModR/M reg field is an SIMD register W ModR/M specifies an SIMD register or a memory address X Operand is addressed by DS:ESI Y Operand is addressed by ES:EDI Notice that A, I, J, and O encode immediate data in the instruction; F, X, and Y "hard-code" the operand to a specific register and add no bytes to the overall instruction length; C, D, G, P, S, T, and V are "secondary" operands using the reg field of the ModR/M byte [and thus not adding to the overall instruction length; E, M, Q, R, and W require a ModR/M byte and may require an SIB byte as well. The Operand Types use one or two lowercase letters: a Two WORDs or DWORDs, depending on operand-size attribute b Byte c Byte or WORD [2 bytes], depending on operand-size d DWORD [4 bytes] dq DQWORD [16 bytes] p 4-byte or 6-byte pointer, depending on operand-size pi QWORD MMX register ps FP data [16 bytes] q QWORD [8 bytes] s Descriptor [6 bytes] ss FP Scalar [16 bytes] si DWORD integer register v WORD [2 bytes] or DWORD [4 bytes], depending on operand-size w WORD [2 bytes] "WORD" and "DWORD" are Intelspeak for "half word" and "word"; the first is two bytes [half of a machine word on a 32-bit machine], and the second is four bytes. It should also be noted that Operand Type 'a' is used only by the bound instruction. In the Opcode Map Appendix, each instruction specifies either a hard-coded operand [such as 0x0E, "push cs"], or an Addressing Method and Operand type for each operand. One should be aware that the ModR/M byte is the only means of specifying general registers [aside from hard-coding them], thus it is used in almost every instruction. Remember that the ModR/M byte has the following format: struct { unsigned int rm: 3; /* lower three bits */ unsigned int reg: 3; /* middle three bits */ unsigned int mod: 2; /* upper two bits */ } modrm; The Perl code for unpacking a ModR/M byte is $rm = $byte & 0x07; $reg = ($byte >> 3) & 0x07; $mod = ($byte >> 6) & 0x03; Decoding the ModR/M byte requires referencing the table "32-bit Addressing Forms with the ModR/M byte" [Vol 2, p. 2-6], which gives the effective address [EADDR] specified by the combination of the mod and r/m fields on the left, and the register specified by the reg field [if the reg field was not used as an opcode extension; thanks a bunch Intel] along the top row. Note that the reg row and the "mod = 11b" rows specify registers from a number of register sets: the r(8) set if byte registers, the r16 set of two-byte registers, the r32 set of 4-byte registers, the mm set of MMX registers, and the xmm set of SIMD registers. Which register set is used is determined by the C, D, G, P, S, T, V Addessing Modes for the reg field, and by the E, Q, R, W Addressing modes for the mod+r/m combo. Decoding the reg field is fairly straightforward; however, the mod+r/m combo can get fairly tricky. As can be seen from the table, the mod field is used to determine the general format of the effective address: mod format operand is... ----------------------------------------------------- 00 [register] pointed to by contents of reg 01 [register + disp8] "" offset by a 1-byte disp 10 [register + disp32] "" offset by a 4-byte disp 11 register contents of register Thus any operand enclosed in brackets indicates that the expression in the brackets must be evaluated and the result dereferenced. A 4-byte displacement generally indicates a virtual address, while a 1-byte displacement is a simple offset, such as the "-12" in "[ebp-12]". Now keep in mind that this is Intel we're dealing with, and that means there are exceptions to deal with [Note to the uninitiated: any design with a lot of "exceptions" to its own rules, ala "every mod+r/m combo with a value of 01 means that a disp8 is encoded in the instruction EXCEPT for when r/m is 100b", is a hackjob; this can be witnessed in source code, cpu architectures, tax tables, and legal systems worldwide, and is generally an indication that the design is being patched by "special interests" rather than improved by reasonable men]. The exceptions in the ModR/M table are as follows: mod rm format meaning ------------------------------------------------------------------------ 00 100 [SIB] operand uses an SIB byte 00 101 [disp32] operand uses a 4-byte disp only 01 101 [disp8 + SIB] operand adds 1-byte disp to SIB byte 10 101 [disp32 + SIB] operand adds 4-byte disp to SIB byte Attractive, eh? Instead of adding an Addressing Method which means "encode a 4-byte displacement in the instruction", which would require extra opcodes to encode [funny, that never seemed to stop Intel before], Intel added a special line to the first mod group. The SIB byte is "another ModR/M byte" requiring a table lookup; its structure is similar to the ModR/M: struct { unsigned int base: 3; /* lower three bits */ unsigned int index: 3; /* middle three bits */ unsigned int scale: 2; /* upper two bits */ } sib; and lookups are performed on the "32-bit Addressing Forms with the SIB Byte" table [Vol 2, p. 2-7]. This table is used to specify effective addresses [the Intel term for "address expression"] of the form (scale * index) + base + displacement which have the assembler syntax [base+scale*index+displacement] # Intel Syntax displacement(base,index,scale) # AT&T Syntax It should be noted that scale, index, and base are often present when addressing an array offset [base being element 0 of the array, scale being the array element size, and index being the element in the array being addressed], while base and displacement are often present when addressing a field in a structure [base being the start of the structure, displacement being the offset of the field], or when addressing stack frame variables/arguments. The left side of the SIB table specifies the scale and index components; the top row specifies the base. Note that the index field and the base field can only be general registers; the scale field can be 1, 2, 4, or 8. Like the ModR/M table, the left column describes groups, which in this case are scale and index combinations: scale form meaning ------------------------------------------------------ 00 [reg] index in 'reg' is scaled by 1 01 [reg*2] index in 'reg' is scaled by 2 10 [reg*4] index in 'reg' is scaled by 4 11 [reg*8] index in 'reg' is scaled by 8 Once again, as with the ModR/M table, there are exceptions, and as a mark of Intel's progress in worshipping Arioch they have made these as ridiculous as possible: scale index base meaning ------------------------------------------------------ 00 100 * no scaled index 01 100 * no scaled index 10 100 * no scaled index 11 100 * no scaled index * * 101 [disp32] or [EBP] How are these ridiculous? Well, to begin with, a scale-index-base combo with no scale or index is just a base -- and this is what the first mod+rm group is for! The base field exception screams out "hack!" like a madman in the night: in Intel's own words -- and squeamish readers are at this point discouraged from finishing the paragraph -- "a disp32 with no base if MOD is 00, [EBP] otherwise." The purpose here is to provide the following addressing modes: mod r/m base form ------------------------------------------------------------------- 00 100 101 [(scale * index) + disp32] 01 100 101 [ebp + (scale * index) + disp8] 10 100 101 [ebp + (scale * index) + disp32] This means that very special [in the Downs sense] instructions can be produced when the index field is 100, e.g. [disp32], [ebp+disp8], [ebp+disp32] ... yes, more ModR/M operands duplicated by hackjob special cases in the SIB table. Decoding instructions with a ModR/M byte can be a bit tricky, as the first and second operands may both reference the ModR/M byte, or one of the operands may be an immediate value [or address] encoded directly in the instruction. Since the immediate value is always at the end of the instruction -- following the bytes taken up by the ModR/M, SIB, and any displacement -- the ModR/M operands must be decoded first in order to know where the immediate value starts. Fortunately, a destination operand will never be an immediate value since it refers to a location; thus by decoding the destination operand first and the source operand second, no problems will be encountered ... this probably goes a long way towards explaining why Intel uses a "mnemonic dest, source" syntax instead of the "mnemonic source, dest" syntax used by the rest of the industry. At this point, a demonstration of decoding a ModR/M byte would probably help make things more clear. 1. 0B 44 8B 08 This begins with a one-byte opcode in tbl_Main: {0, ADDRMETH_G|OPTYPE_v, ADDRMETH_E|OPTYPE_v, ... "or"} The Addressing Methods E and G indicate that the following byte is a ModR/M byte, which is decoded as struct modrm{ 01b, 000b, 100b }; /* 0x44 */ ...which according to the ModR/M table is of the form "disp8[SIB]", with a register operand of eax. The next byte is therefore an SIB byte, and is decoded as struct sib { 10b, 001b, 011b }; /* 0x8B */ ...which is of the form "[ebx+ecx*4]" according to the table. Since the dest operand is of method G and the source operand is of method E, the instruction will have the form or eax, disp8[ebx+ecx*4] The last byte in the instruction is the disp8; this results in the final disassembled instruction of or eax, [ebx+ecx*4+8] 2. 83 55 FC 10 This begins with a tbl_Main with an immediate subtable lookup: {5, ADDRMETH_E|OPTYPE_v, ADDRMETH_I|OPTYPE_b ... } The reg field of the MordR/M is used as an index into tbl_83: {0, ADDRMETH_E|OPTYPE_v, ADDRMETH_I|OPTYPE_b, ... "adc"} The Addressing Methods E and I indicate that a ModR/M byte and an immediate value follow the opcode. The 0x55 byte is re-used as the ModR/M, and decodes to struct modrm { 01b, 010b, 101b }; /* 0x55 */ ...which indicates a form of "disp8[ebp]". The next byte is the disp 8 [a signed value, and the last byte in the instruction is the immediate byte: adc [ebp-4], 0x10 3. 8C E3 This instruction is a single-byte opcode in tbl_Main: {0, ADDRMETH_E|OPTYPE_w, ADDRMETH_S|OPTYPE_w, ... "mov"} The next byte is a ModR/M as indicated by the E and S: struct modrm { 11b, 100b, 011b } /* 0xE3 */ ...which decodes directly into two register operands: mov bx, fs 4. 8B 35 50 95 04 08 This last sequence of bytes decodes to an instruction in tbl_Main: {0, ADDRMETH_G|OPTYPE_v, ADDRMETH_E|OPTYPE_v, ... "mov"} The second byte is a ModR/M: struct modrm { 00b, 110b, 101b }; /* 0x35 */ which has the form "[disp32]" with a reg field of esi. The last four bytes are the disp32 in little endian order, decoding to: mov [8049550], esi The astute reader who has been following along with the ModR/M and SIB tables will have noticed that the register encodings are consistent in the values they use for each register; the register sets can therefore be assumed to take the form of arrays of register names with the following order: r_32("eax","ecx","edx","ebx","esp","ebp","esi","edi"); r_16("ax","cx","dx","bx","sp","bp","si","di"); r_8("al","cl","dl","bl","ah","ch","dh","bh"); r_s("es","cs","ss","ds","fs","gs"); r_mmx("mm0","mm1","mm2","mm3","mm4","mm5","mm6","mm7"); r_simd("xmm0","xmm1","xmm2","xmm3","xmm4","xmm5","xmm6","xmm7"); r_dbg("dr0","dr1","dr2","dr3","dr4","dr5","dr6","dr7"); r_ctl("cr0","cr1","cr2","cr3","cr4","cr5","cr6","cr7"); r_tst("tr0","tr1","tr2","tr3","tr4","tr5","tr6","tr7"); r_fpu("st(0)","st(1)","st(2)","st(3)","st(4)","st(5)","st(6)","st(7)"); That should provide enough of an introduction to x86 instruction disassembly for the reader to follow the algorithm used in the disassembler. The following code is a simplified version of what appears in the actual disassembler, intended to illustrate the process and not provide a detailed solution. sub disasm_addr { local($buf) = $shift; local(%insn); # perform table lookup $size = disasm_table_lookup( 0, $buf, \%insn ); $buf = substr $buf, $size; # advance buffer "pointer" # decode operands $bytes = 0; #position in buffer if ( $insn{dest} ) { $bytes += disasm_operand_decode(\$insn{dest}, $buf, $pos); } if ( $insn{src} ) { $bytes += disasm_operand_decode(\$insn{src}, $buf, $pos); } if ( $insn{aux} ) { $bytes += disasm_operand_decode(\$insn{aux}, $buf, $pos); } $size += $bytes; $insn{size} = $size; return \%insn; } sub disasm_table_lookup { local($table_num, $buf, $insn) = $@; $byte = unpack "C", $buf; $tbl_def = $table_list[$table_num]; $byte = disasm_table_adjust_byte( $tbl_def, $byte ); # set size to 0 if table uses reg field of ModR/M if ( hex($$tbl_def{mask}) != 0xFF ) { $size = 0; } $table = $tables{$$tbl_def{name}}; $insn_def = $$table[$byte]; if (! $insn_def ) { # ERROR! return 0; } elsif ( $$insn_def{table} ) { # Additional table lookup using next byte return ( $size + disasm_table_lookup($$insn_def{table}, substr($buf, 1), $insn) ); } else { $buf = substr $buf, $size; # copy mnemonics and operand types into "result" hash disasm_fill_insn( $insn, $insn_def ); } return $size; } sub disasm_table_adjust_byte { local($tbl_def, $byte) = $@; $byte -= hex($$tbl_def{min}); $byte = $byte >> $$tbl_def{shft}; $byte &= hex($$tbl_def{mask}); return( $byte ); } sub disasm_operand_decode { local($op, $buf, $pos) = $@; # is operand hard-coded in insn? if ( $$op ) { if ( $flg =~ /OP_REG/ ) { $$op = disasm_get_reg(@r_32, $$op); } return(0); # no bytes used } if ( $flg =~ /ADDRMETH_([A-Z])/ ) { $addr_meth =$1; } # default return value and buffer position $size = 0; $buf = substr $main_buf, $pos; # handle operand based on addressing method if ($addr_meth eq "E") { # modR/M EA, gen reg or mem $size = disasm_modrm_decode( $buf, $op, @r_32, 1 ); # .... CODE OMITTED } elsif ($addr_meth eq "C"){ # modR/M reg: control reg $buf = $main_buf; disasm_modrm_decode( $buf, $op, @r_ctl, 0 ); # .... CODE OMITTED } elsif ($addr_meth eq "A"){ # direct address in insn $size = $sz_addr; $$op = disasm_get_imm( $buf, $sz_addr, 0 ); } elsif ($addr_meth eq "I"){ # immediate value in insn $size = $sz_op; if ( $flg =~ /OP_SIGNED/ ) { $$op = disasm_get_imm( $buf, $sz_op, 1 ); } else { $$op = disasm_get_imm( $buf, $sz_op, 0 ); } # .... CODE OMITTED } elsif ($addr_meth eq "Y"){ # memory addresses by ES:EDI $$op = "es:edi"; } return $size; } sub disasm_modrm_decode { local($buf, $op, $reg_table, $ea) = $@; $count = 1; ($modrm, $sib) = unpack "CC", $buf; ($mod, $reg, $rm) = byte_unpack $modrm; ($scale, $index, $base) = byte_unpack $sib; if (! $ea ) { # this uses the 'reg' field of modR/M $$op = disasm_get_reg($reg_table, $reg); return(0); # no bytes consumed } if ( $mod == 3 ) { # mod = 11 [register, no memory addr] $$op = disasm_get_reg($reg_table, $rm); return($count); } if ( ! $mod ) { # mod = 00 [no displacement] if ( $rm == 5 ) { # rm = 101 [disp32 -- no reg] $$op = disasm_get_imm( substr($buf, $count), 4, 1 ); $count += 4; } elsif ( $rm == 4 ) { # rm = 100 [no disp -- SIB] $count++; $scale = 0x01 << $scale; if ( $index != 4 ) { # index = 100 $index = disasm_get_reg($reg_table, $index); } if ( $base == 5 ) { # base = 101, mod = 0 $disp = disasm_get_imm( substr($buf, $count), 4, 1 ); } else { $base = disasm_get_reg($reg_table, $base); } $$op = "[$base+$scale*$index+$disp]"; } else { # register with no disp $$op = disasm_get_reg($reg_table, $rm); } } else { # this is a disp[reg] combo if ( $rm == 4 ) { # rm = 100 [disp8+SIB] $count++; $scale = 0x01 << $scale; if ( $index != 4 ) { # index = 100 $index = disasm_get_reg($reg_table, $index); } $base = disasm_get_reg($reg_table, $base); } else { # disp[reg] $base = disasm_get_reg($reg_table, $rm); } if ( $mod == 1 ) { # mod = 01 [disp8] $disp = disasm_get_imm( substr($buf, $count), 1, 1 ); $count ++; } else { # mod = 10 [disp32] $disp = disasm_get_imm( substr($buf, $count), 4, 1 ); $count += 4; } $$op = "[$base+$scale*$index+$disp]"; } return($count); } The disasm_address routine can be called from within a loop in order to disassemble all bytes within a given range. sub disasm_buffer { local($buf, $offset, $va, $max ) = $@; # use $dis_buf as a pointer to the current byte $dis_buf = substr $$buf, $offset; for ( $pos = 0; $pos < $max; $pos += $$insn{size} ) { # do not disassemble twice $insn = $$target_info{insn_idx}{$va + $pos}; if ($$insn{size}) { $dis_buf = substr $dis_buf, $$insn{size}; next; }; # get insn hash from disassembler $insn = disasm_addr( $dis_buf ); if ( ! $insn ) { # invalid instruction: skip a byte and continue $$insn{size} = 1; $dis_buf = substr $dis_buf, 1; next; }; $$insn{va} = $va + $pos; $$insn{offset} = $offset + $pos; # store hexadecimal bytes representing insn in an array $hex_str = ""; for ( $x = 0; $x < $$insn{size}; $x ++ ) { $hex_str .= "C"; } @{$$insn{bytes}} = unpack $hex_str, $dis_buf; # add insn to list push(@{$target_info{insns}}, $insn); $$target_info{insn_idx}{$$insn{va}} = $insn; # advance buffer position $dis_buf = substr $dis_buf, $$insn{size}; } } Full source code for the disassembler is provided in Appendix A. The above algorithm should suffice to illustrate the general -- and somewhat tedious -- process of decoding an x86 instruction in Perl. ================================================================================ 6: Generating an intermediate representation In order to do any serious disassembly, the target must be represented as more than a linked list of instructions. The following structure represents all of the relevant data regarding the target: target_info { $entry; # entry point VA $entry_offset; # entry point file offset $bits; # number of bits in machine word $endian; # little or big endian $size; # size of target %header; # ELF header @sections; # array of section hashes @insns; # array of insn hashes %insn_idx; # insn hashes indexed by VA @functions; # array of function hashes %func_idx; # func hashes indexed by VA @symbols; # array of symbol hashes %sym_idx; # symbol hashes indexed by VA @names; # array of name hashes %name_idx; # name hashes indexed by VA @xrefs; # array of xref hashes @data; # array of data hashes %data_idx; # data hashes indexed by VA @strings; # array of string hashes %string_idx; # string hases indexed by VA }; This is essentially a global data structure that contains pointers to lists of all other data structures used by the disassembler. Sections and instructions are generated by the ELF parser and the disassembler: section { $va; # Virtual Address of section start $offset; # File Offset of section start $size; # Size of section $type; # Section type [CODE, DATA] $perm; # Section permissions [rwx] $name; # Section name }; insn { $va; # Virtual Address $offset; # File offset $size; # Size of insn @bytes; # Array of instruction bytes $mnemonic; # Mnemonic for insn $type; # Type of insn $src; # Source operand $stype; # Source operand type $s_perm; # Source operand permissions $dest; # Destination operand $dtype; # Destination operand type $d_perm; # Destination operand permissions $aux; # Aux operand $atype; # Aux operand type $a_perm; # Aux operand permissions $name; # Address name }; It is useful to make a note of functions found within the code sections; this breaks the target into logical components that can be examined separately. func { $va; # Virtual Address of function start $offset; # File offset $name; # Name of function }; The use of stack frames in Intel code makes finding functions relatively easy; one simply has to iterate through the bytes in each code section looking for 55 push %ebp 89 E5 movl %esp, %ebp ...which can be done by analyzing the disassembled instructions, or by searching for the bytes directly. The following code iterates over the list of instructions and creates function structures when a function prologue is encountered: foreach ( sort( keys( %{$$target_info{insn_idx}} ) ) ) { $insn = $$target_info{insn_idx}{$_}; # look for 'push ebp' if ( $$insn{mnemonic} =~ /^push/ && $$insn{dest} =~ /bp$/ ) { $next = $$target_info{insn_idx}{ $$insn{va} + $$insn{size} }; # look for 'mov ebp, esp' if ( $$next{mnemonic} =~ /^mov/ && $$next{dest} =~ /bp$/ && $$next{src} =~ /sp$/ ) { new_func($$insn{va}, $insn{offset}, 0); } } } Cross references between addresses in the target provide a wealth of information about which pieces of code or data effect others. The cross reference or 'xref' is simply a reference [i.e. a data read/write or a code execute] from one address to another; thus the xref structure is simple: xref { $from; # "From" VA $to; # "To" VA $type; # Reference type [rwx] }; Xrefs should be generated at the time of disassembly in order to avoid making yet another pass over the entire list of instructions: sub disasm_gen_xrefs { local($va, $op, $type, $perm) = $@; # try to generate an address from OP_EADDR if ( $type =~ /OP_EADDR/ ) { ($disp,$scale,$index,$base,$flags) = split /:/, $op; if (! $scale && ! $index && ! $base && $flags=~/DISP32/ ) { $op = $disp; $type = "OP_ADDR"; } } # use OP_IMM if it is a valid program address if ( $type =~ /OP_IMM/ && disasm_is_addr($op) ) { $type = "OP_ADDR"; } # now create an xref for the address if ( $type =~ /OP_ADDR/ || ($type =~ /OP_OFF/ && $type !~ /OPSIZE_BYTE/) ) { if ( $perm =~ /r/ ) { new_xref( $va, $op, "r" ); } if ( $perm =~ /w/ ) { new_xref( $va, $op, "w" ); } if ( $perm =~ /x/ ) { new_xref( $va, $op, "x" ); } } return; } Names are generated for addresses whenever a cross reference is encountered, or a function is found. Address names take the form of "var_$va" for data addresses, "sub_$va" for function addresses, and "loc_$va" for code labels. name { $va; # VA $type; # Type of address $name; # Text of name }; Most disassembler users are particularly interested in the ASCII strings present in the target; for this reason a string structure is provided. string { $va; # VA $offset; # Offset in file $string; # Text of string }; The algorithm for recognizing strings in arbitrary binary code simply requires an iteration over the binary code, looking for sequences of printable ASCII characters of four or more bytes in length. $pos = 0; while ($pos < $$sec{size}) { $buf = substr $buf, $pos; for ($x = 0; $x + $pos < $$sec{size}; $x ++ ) { $c = chr(unpack "c", substr($buf,$x,1)); if ( $c !~ /[ \n!"#\$%&'()*+,-.\/0-z{}|~\s]/ ) { last; } } if ($x >= 4 ) { $str = substr($buf, 0, $x); $pos += $x; $num++; new_string( $$sec{va} + $pos, $$sec{offset} + $pos, $str ); } else { $pos++; } } This code can be run over all data sections in the target in order to generate a list of ASCII strings. The final data structure is the catch-all "data" structure; all references to non-code addresses within the target cause a data structure to be generated for that address; this allows variables to be declared in data sections of the assembly language output by the disassembler. data { $va; # VA $offset; # File offset $size; # Size of data @bytes; # Array of data bytes $type; # Type of data $name; # Name of address }; Note that 'size' and 'type' are difficult to determine in the initial analysis; these are provided for future expansion. ================================================================================ 7: Producing output Now, at last for the part that objdump beautifiers will love the most: producing output. The reader should remember that the output is not limited to AT&T syntax assembler; the disassembler can print a direct dump of the intermediate representation, a list of strings, a list of imports, or even pseudocode that represents high-level language operations. Dumping the intermediate format is quite straightforward; each array or hash of structures is printed in delimited format: sub int_output { # print target info print "#TARGET|name|entry_va|entry_offset|size|endian|bits\n"; printf "TARGET|%s|0x%08X|0x%X|$d|%d|%s\n", $target_info{name}, $target_info{entry}, $target_info{entry_offset}, $target_info{size}, $target_info{endian}, $target_info{bits}; # print sections print "#SEC|va|offset|size|type|perm|name\n"; foreach ( keys( %{$$target_info{sections}} ) ) { $ptr = $$target_info{sections}{$_}; printf "SEC|0x%08X|0x%X|%d|", $$ptr{va}, $$ptr{offset}, $$ptr{size}; print "$$ptr{type}|$$ptr{perm}|$$ptr{name}\n"; } # print instructions print "#INSN|va|offset|size|hex|mnemonic|type|"; print "src|type|perm|dest|type|perm|aux|type|perm|name\n"; foreach $ptr ( @{$target_info{insns}} ) { $buf = ""; printf "INSN|0x%08X|0x%X|%d|",$$ptr{va},$$ptr{offset}, $$ptr{size}; foreach ( @{$$ptr{bytes}} ) { $buf .= sprintf "%02X ", $_; } $buf =~ s/\s*$//g; print "$buf|$$ptr{mnemonic}|$$ptr{type}|"; print "$$ptr{src}|$$ptr{stype}|$$ptr{sprm}|"; print "$$ptr{dest}|$$ptr{dtype}|$$ptr{dprm}|"; print "$$ptr{aux}|$$ptr{atype}|$$ptr{aprm}|"; print "$$ptr{name}"; print "\n"; } #...print other structures here return; } The output of int_output() includes comment lines that specify the field names of each record type: #TARGET|name|entry_va|entry_offset|size|endian|bits TARGET|a.out|0x080487B0|0x7B0||5704|little #SEC|va|offset|size|type|perm|name SEC|0x0804A098|0x1098|12|DATA||.data SEC|0x080480F4|0xF4|19|RODATA||.interp SEC|0x080487B0|0x7B0|1484|CODE||.text SEC|0x0804A0A8|0x10A8|8|DATA||.ctors SEC|0x08048620|0x620|49|CODE||.init SEC|0x0804A0B8|0x10B8|96|DATA||.got SEC|0x08048DA0|0xDA0|759|RODATA||.rodata SEC|0x0804A0A4|0x10A4|4|DATA||.eh_frame SEC|0x08048D7C|0xD7C|28|CODE||.fini SEC|0x0804A0B0|0x10B0|8|DATA||.dtors SEC|0x08048654|0x654|336|CODE||.plt #INSN|va|offset|size|hex|mnemonic|type|src|type|perm|dest|type|perm|... INSN|0x080487B0|0x7B0|2|31 ED|xor|INS_XOR|ebp|OPSIZE_WORD,OP_REG... INSN|0x080487B2|0x7B2|1|5E|pop|INS_POP||||esi|OP_REG,REG_GENERAL... INSN|0x080487B3|0x7B3|2|89 E1|mov|INS_MOV|esp|OPSIZE_WORD,OP_REG... INSN|0x080487B5|0x7B5|3|83 E4 F8|and|INS_AND|248|OPSIZE_BYTE,OP_IMM... INSN|0x080487B8|0x7B8|1|50|push|INS_PUSH||||eax|OP_REG,REG_GENERAL... INSN|0x080487B9|0x7B9|1|54|push|INS_PUSH||||esp|OP_REG,REG_SP... This output can be processed by additional scripts in order to generate control flow graphs, to rename parameters to library functions based on prototypes in include files, or to generate high-level language source code. Of course, the most interesting output format will be assembly language. AT&T syntax is more complex than Intel syntax, and will be demonstrated here. Note that these output routines are based on the intermediate format generated by the disassembler in Appendix A, and not on the less detailed code presented in the previous sections. The asm_output() routine simply iterates through the instructions in each code section, calling insn_output() to actually print the instruction. sub asm_output { foreach ( keys( %{$$target_info{sections}} ) ) { $sec = $$target_info{sections}{$_}; print ";-------------------------------------------\n"; printf "; SECTION %s va %08X size 0x%X\n\n", $$sec{name}, $$sec{va}, $$sec{size}; if ( $$sec{type} =~ /CODE/ ) { foreach(sort keys(%{$$target_info{insn_idx}}) ){ if ( $_ >= $$sec{va} && $_ < $$sec{va} + $$sec{size} ) { insn_output( $$target_info{insn_idx}{$_} ); } } print "\n\n\n"; # mark end of section } return; } sub insn_output { local($insn) = shift; # print address addr_output( $$insn{va}, $$insn{size}, $$insn{bytes} $$insn{name} ); # print mnemonic and operands if ( $$insn{mnemonic} ) { printf "\t%s\t", insn_format($$insn{mnemonic}, $$insn{dtype}); if ( $$insn{stype} ) { printf "%s", op_format($$insn{va}+$$insn{size}, $$insn{src}, $$insn{stype} ); } if ( $$insn{dtype} ) { if ( $$insn{stype} ) { print ", "; } printf "%s", op_format($$insn{va}+$$insn{size}, $$insn{dest}, $$insn{dtype}); } if ( $$insn{atype} ) { printf ", %s", op_format($$insn{va} + $$insn{size}, $$insn{aux}, $$insn{atype} ); } print "\n"; } else { print "\t\n"; } return; } The addr_output() routine prints a code label if appropriate, then the virtual address and up to eight bytes of the instruction in hex. sub addr_output { local($va, $size, $bytes, $name) = $@; if ( $name ) { print "$name:\n"; } printf "%08X: ", $va; for ($x = 0; $x < 8; $x++ ) { if ( $x < $size ) { printf "%02X ",$$bytes[$x]; } else { print " "; } } return; } In AT&T syntax, each mnemonic can have different suffixes depending on the size of the operands. The insn_format() routine returns the AT&T-style mnemonic. sub insn_format { local($insn, $optype); if ($optype =~ /OPSIZE_([A-Z0-9]+)/) { if ( $1 =~ /BYTE/ && $insn !~ /^j/ ) { return $insn . "b"; } elsif ($1 =~ /HWORD/ && $insn !~ /^j/ ) { return $insn . "w"; } elsif ($1 =~ /DWORD/ && $insn !~ /^j/ ) { return $insn . "q"; } elsif ($1 =~ /^WORD/ ) { if ( $insn eq "jmp" ) { return "ljmp"; } if ( $insn eq "call" ) { return "lcall"; } if ( $insn =~ /^j/ ) {return $insn; } return $insn ."l"; } } return $insn; } The AT&T format also adds prefixes to operands in order to specify their type -- i.e., $ for immediate data, * for a pointer, and % for a register. The op_format() routine generates the correct representation for an operand. sub op_format { local($next_va, $op, $optype) = $@; # relative offset from %eip if ( $optype =~ /OP_REL/ ) { $op += $next_va; $optype =~ s/OP_REL/OP_ADDR/; } # either virtual address or relative offset to %eip if ( $optype =~ /OP_OFF/ ) { if ( $optype =~ /OP_BYTE/ ) { $op += $next_va; } $optype =~ s/OP_OFF/OP_ADDR/; } # address expression ["effective address"] if ( $optype =~ /OP_EADDR/ ) { ($disp,$scale,$index,$base,$flags) = split /:/, $op; if ( $flags =~ /DISP32/ ) { $buf = addr_format($disp, "DISP32"); } else { $buf = $disp; } $buf .= "($base"; if ( $index ) { $buf .= ",$index"; } if ($scale) { $buf .= ",$scale"; } elsif ( $disp && ! $base && ! $index ) { # AT&T/GNU as 'syntax exception $buf .= ",1"; } $buf .= ")"; return $buf; } # CPU register if ( $optype =~ /OP_REG/ ) { return "%$op"; } # Immediate value if ( $optype =~ /OP_IMM/ ) { if ( $optype =~ /OP_SIGNED/ || $optype =~ /OP_BYTE/ ) { return sprintf "\$%d", $op; } else { return addr_format($op, "OP_IMM"); } } # Virtual address if ( $optype =~ /OP_ADDR/ ) { return addr_format($op, "OP_ADDR"); } return $op; } The addr_format() routine exists as convenience routine which returns either the address in hex, or the symbol name for the address if one exists. sub addr_format { local($addr, $type) = $@; #if symbol [e.g. import] return symbol name $sym = $$target_info{sym_idx}{$addr}; if ( $$sym{name} ) { return $$sym{name}; } if ( $type =~ /OP_ADDR/ ) { return sprintf "*0x%08X", $addr; } if ( $type =~ /DISP32/ ) { return sprintf "0x%08X", $addr; } return sprintf "\$0x%X", $addr; } The output for these routines is fairly passable AT&T assembler: ;-------------------------------------------------- ; SECTION .text va 080487B0 size 0x5CC 080487B0: 31 ED xorl %ebp, %ebp 080487B2: 5E popl %esi 080487B3: 89 E1 movl %esp, %ecx 080487B5: 83 E4 F8 andl $0xF8, %esp 080487B8: 50 pushl %eax 080487B9: 54 pushl %esp 080487BA: 52 pushl %edx 080487BB: 68 7C 8D 04 08 pushl $0x8048D7C 080487C0: 68 20 86 04 08 pushl $0x8048620 080487C5: 51 pushl %ecx 080487C6: 56 pushl %esi 080487C7: 68 C4 89 04 08 pushl $0x80489C4 080487CC: E8 43 FF FF FF lcall __libc_start_main 080487D1: F4 hlt ================================================================================ 8: End Results At this point the reader should have enough of an understanding of writing an x86 disassembler to use Perl to create real binary analysis tools -- or, failing that, to rip the code in Appendix A and base a new project on it. The opcode tables in Appendix B are from the libdisasm module of the bastard disassembler; these were chosen for the additional information they provide, such as operand types and instruction types. The idea behind this HOWTO is that the opcode tables of any C disassembler can be used as a base for a Perl disassembler -- there is no need to hand-generate the opcode tables, and reusing tables allows one to reuse the code that performs table lookups as well. It is hoped that the number of objdump output parsers will diminish, and that the number of "real disassemblers" being produced for the UNIX environment will increase. ================================================================================ A: Source code for x86disasm.pl The entire source code for the x86 disassembler discussed in this article is provided below. Those printing this article are advised to truncate the file #!/usr/bin/perl # settings for opcode.map file my $opcode_dir="."; my $opcode_file="$opcode_dir/i386.opcode.map"; # runtime temp vars my $section; # current section my $i; # iterator :P # opcode tables my @table_list; # array of table_defs [numeric index in INSN struct] my %tables; # hash of table names: values = arrays of insn hashs my %prefixes; # hash or prefixes: values = prefix type # command line options my $opt_intcode; # output intermediate format my $opt_intel; # output Intel syntax my $opt_att; # output AT&T syntax my $opt_forward; # disasm forward from entry my $opt_text; # disasm text sections my $opt_phdr; # use program headers my $opt_shdr; # use section headers my $opt_xref; # show cross-references my $opt_quiet; # suppress progress output my $opt_entry; # disassemble from forward $opt_entry my $opt_section; # disassemble $opt_section only my $opt_hexbytes; # number of hex bytes to print my $target; # what we are disassembling :) my $target_image; # buffer containing target my $f; # file stats # disassembly info my %target_info; # =============================================================== # Check options if ( ! $ARGV[0] ) { print_usage(); exit(0); } while ( $ARGV[0] =~ /^-/ ) { if ( $ARGV[0] eq "-c" ) { $opt_intcode = 1; shift; } elsif ( $ARGV[0] eq "-i" ) { $opt_intel = 1; shift; } elsif ( $ARGV[0] eq "-a" ) { $opt_att = 1; shift; } elsif ( $ARGV[0] eq "-f" ) { $opt_forward = 1; shift; } elsif ( $ARGV[0] eq "-t" ) { $opt_text = 1; shift; } elsif ( $ARGV[0] eq "-p" ) { $opt_phdr = 1; shift; } elsif ( $ARGV[0] eq "-s" ) { $opt_shdr = 1; shift; } elsif ( $ARGV[0] eq "-x" ) { $opt_xref = 1; shift; } elsif ( $ARGV[0] eq "-q" ) { $opt_quiet = 1; shift; } elsif ( $ARGV[0] eq "-e" ) { shift; $opt_entry = shift; $opt_forward = 1; } elsif ( $ARGV[0] eq "-S" ) { shift; $opt_section = shift; $opt_text = 1; } elsif ( $ARGV[0] eq "-H" ) { shift; $opt_hexbytes = shift; } else { print_usage(); exit(1); } } # set defaults if ( !$opt_intcode && ! $opt_intel && ! $opt_att ) { $opt_att = 1; } if ( !$opt_text && ! $opt_forward) { $opt_text = 1; } if ( !$opt_shdr && ! $opt_phdr) { $opt_shdr = 1; } if ( !$opt_hexbytes ) { $opt_hexbytes = 8; } # load x86 opcode tables $opt_quiet || print "Loading opcode tables from $opcode_file\n"; load_opcode_tables( $opcode_file ); # =============================================================== # Open file for disassembly $target = shift; if ( $target ) { ($f{dev},$f{ino},$f{mode},$f{nlink},$f{uid},$f{gid},$f{rdev},$f{size}, $f{atime},$f{mtime},$f{ctime},$f{blksize},$f{blocks}) = stat $target; $target_info{size} = $f{size}; } else { #$$target = "-"; die "No target specified!\n"; } open( TGT, $target ) || die "unable to open $target\n"; binmode( TGT, ":raw" ); $target_info{name} = $target; # =============================================================== # Parse file header to determine bytes to disassemble $opt_quiet || print "Parsing ELF header\n"; $target_info{header} = elf_read(); if (! $target_info{header} ) { die "ERROR: $target is not an ELF file\n"}; # =============================================================== # Do Disassembly $opt_quiet || print "Performing Disassembly\n"; # read target into buffer sysseek TGT, 0, SEEK_SET; sysread TGT, $target_image, $f{size}; # disassemble, finally if ( $opt_forward ) { if ( $opt_entry ) { $target_info{entry} = hex($opt_entry); $target_info{entry_offset} = disasm_va2off($target_info{entry}); if ( ! $target_info{entry} || ! $target_info{entry_offset} ) { die "ERROR: Invalid entry point '$opt_entry'\n"; } } disasm_buffer( \$target_image, $target_info{entry_offset}, $target_info{entry}, $f{size}, 1 ); } elsif ( $opt_text ) { if ( $opt_section ) { $section = $$target_info{sections}{$opt_section}; if ( $$section{name} ) { disasm_section( $section, \$target_image ); } else { die "ERROR: Invalid section '$opt_section'\n"; } } else { foreach ( keys( %{$$target_info{sections}} ) ) { $section = $$target_info{sections}{$_}; if ( $$section{type} eq "CODE" ) { disasm_section( $section, \$target_image ); } } } } else { die "Invalid disassembler option!\n"; } # look for strings $opt_quiet || print "Searching for strings in data sections\n"; disasm_strings(); # look for unrecognized subroutines disasm_subroutines(); # =============================================================== # Done... output the result if ( $opt_intcode ) { int_output(); } else { asm_output(); } close( TGT ); exit; #=============================================================================== # DEBUG routines sub dbg_print_tables { local(%t); foreach (keys( %tables )) { print "TABLE $_:\n"; # foreach instruution in table foreach ( @{$tables{$_}} ) { # print instruction %t = %$_; foreach (keys( %t )) { print "$_ = $t{$_},"; } print "\n"; } } } sub dbg_print_tablelist { local(%t); local($x) = 0; foreach ( @table_list ) { %t = %$_; printf"TABLE $x : "; foreach( keys(%t) ) { print "$_ = $t{$_},"; } print "\n"; $x++; } } #=============================================================================== # "NEW" routines sub new_table { local($line) = shift; local(%t); $line =~ s/\s//g; ($t{name}, $t{shft}, $t{mask}, $t{min}, $t{max}) = split ',', $line; return \%t; } sub new_insn { local($line) = shift; local(%i); $line =~ s/\s//g; $line =~ s/"//g; ($i{table}, $i{iflg}, $i{dflg}, $i{sflg}, $i{aflg}, $i{cpu}, $i{insn}, $i{dest}, $i{src}, $i{aux}) = split ',', $line; return \%i; } sub new_section { local($offset) = shift; local($size) = shift; local($va) = shift; local($name) = shift; local($type) = shift; local($perms) = shift; local(%s); $s{offset} = $offset; $s{size} = $size; $s{va} = $va; $s{type} = $type; $s{perms} = $perms; if ( defined($%{$target_info{sections}}{$name}) ) { $name .= "_$offset"; } $s{name} = $name; $$target_info{sections}{$name} = \%s; return \%s; } sub new_func { local($va) = shift; local($offset) = shift; local($name) = shift;; local(%func, $n, $sym); $sym = $$target_info{sym_idx}{$va}; if ( $$sym{name} ) { $name = $$sym{name}; } if ( ! $name ) { $n = new_name( $va, "sub_$va", "FUNCTION" ); $name = $$n{name}; } $func{name} = $name; $func{va} = $va; $func{offset} = $offset; push @{$target_info{functions}}, \%func; $$target_info{func_idx}{$va} = \%func; return \%func; } sub new_xref { local($from_va) = shift; local($to_va) = shift; local($type) = shift; local(%xref, $name); $name = sprintf "%08X_to_%08X", $from_va, $to_va; if ( $$target_info{xref_idx}{$name}{from} ) { return $$target_info{xref_idx}{$name}; } $xref{name} = $name; $xref{from} = $from_va; $xref{to} = $to_va; $xref{type} = $type; push @{$target_info{xrefs}}, \%xref; $$target_info{xref_idx}{$name} = \%xref; return \%xref; } sub new_name { local($va) = shift; local($name) = shift; local($type) = shift; local(%n, $sym); # check for existing NAME if ( $$target_info{name_idx}{$va}{name} ) { return $$target_info{name_idx}{$va}; } # check for existing symbol to use as name $sym = $$target_info{sym_idx}{$va}; if ( $$sym{name} ) { $name = $$sym{name}; } $n{va} = $va; $n{name} = $name; $n{type} = $type; push @{$target_info{names}}, \%n; $$target_info{name_idx}{$va} = \%n; return \%n; } sub new_string { local($va) = shift; local($offset) = shift; local($string) = shift; local(%s, $name); # check for existing STRING if ( $$target_info{string_idx}{$va}{string} ) { return $$target_info{string_idx}{$va}; } # create name for STRING if ( ! $$target_info{name_idx}{$va}{name} ) { new_name( $va, "str_$va", "STRING" ); } $s{va} = $va; $s{offset} = $offset; $s{string} = $string; push @{$target_info{strings}}, \%s; $$target_info{string_idx}{$va} = \%s; # add data item for STRING if ( $$target_info{data_idx}{$va}{size} ) { $$target_info{data_idx}{$va}{size} = length $string; $$target_info{data_idx}{$va}{type} = "STRING"; } else { new_data( $va, $offset, length($string), "STRING" ); } return \%s; } sub new_data { local($va) = shift; local($offset) = shift; local($size) = shift; local($type) = shift; local(%d, $sym, $n, $x, $hexstr, $buf); # check for existing NAME if ( $$target_info{data_idx}{$va}{size} ) { return $$target_info{data_idx}{$va}; } # check for existing symbol to use as name $sym = $$target_info{sym_idx}{$va}; if ( $$sym{name} ) { $d{name} = $$sym{name}; #check for existing NAME } elsif ( $$target_info{name_idx}{$va}{name} ) { $d{name} = $$target_info{name_idx}{$va}{name}; } if ( ! $d{name} ) { $n = new_name( $va, "var_$va", "DATA" ); $d{name} = $$n{name}; } $d{va} = $va; $d{offset} = $offset; $d{size} = $size; $d{type} = $type; # do hex bytes $hex_str = ""; for ( $x = 0; $x < $size; $x ++ ) { $hex_str .= "C"; } $buf = substr $target_image, $offset, $size; @{$d{bytes}} = unpack $hex_str, $buf; push @{$target_info{data}}, \%d; $$target_info{data_idx}{$va} = \%d; return \%d; } #=============================================================================== # OPCODE table management routines sub table_from_index { local($idx) = shift; return $table_list[$idx]; } sub insn_array_from_index { local($idx) = shift; local(%t); %t = %{ table_from_index($idx) }; return $tables{$t{name}}; } # Prepare instruction tables from libdisasm opcode map sub load_opcode_tables { local($file) = shift; local($intable, $tablelst, $prefixtbl); open(OPCODES, $file ) || die "Cannot open map $file\n"; foreach ( ) { if ( /^\s*instr\s+([A-Za-z0-9_]+)\[[0-9]*\]\s*=\s*\{/ ) { # we are in table named $1 $intable = $1; } elsif ( /^\s*asmtable\s+tables86\[\]\s*=\s*\{/ ){ # we are in the table of tables $tablelst = "tables86"; } elsif ( /^\s*int\s+prefix_table\[13\]\[2\]\s*=\s*\{/ ){ # we are in the table of prefixes $prefixtbl = "prefix_table"; } elsif ( /^\s*\};/ ) { if ( $intable ) { # we are no longer in a table $intable = ""; } elsif ( $tablelst ) { # we are no longer in the table of tables $tablelst = ""; } elsif ( $prefixtbl ) { # we are no longer in the table of prefixes $prefixtbl = ""; } } elsif ( /^\s*\{([^}]+)\}/ ) { if ( $intable ) { # this must be an insn! $i = new_insn( $1 ); push @{$tables{$intable}}, $i; } elsif ( $tablelst ) { # this must be a table push @table_list, new_table($1); } elsif ( $prefixtbl ) { # this is a prefix I guess if ($1 =~ /^\s*(0x[0-9A-F]+), (PREFIX_[A-Z_]+)/){ $prefixes{$1} = $2; } } # else ignore } # yup, ignore with extreme prejudice } # debug out if you want to convince yourself it works ;) #dbg_print_tables(); #dbg_print_tablelist(); close( OPCODES ); return 1; } #=============================================================================== # ELF parsing routines sub elf_read { local($buf); local(%e_hdr); local($elf_size) = 52; local($lil_endian) = "a16v2V5v6"; local($big_endian) = "a16n2N5n6"; local($id, $class, $data, $jnk); local($endian_str); sysread TGT, $buf, 16; ($id, $class, $data, $jnk) = unpack "a4aaa10", $buf; if ( $id ne "\177ELF" ) { return 0; } # x86 is always little endian: this doubles as an ELF parsing lesson if ( $class == 2 ) { $target_info{bits} = 64; } else { $target_info{bits} = 32; # default to 32 bits } if ( $data == 2 ) { $target_info{endian} = "big"; $endian_str = $big_endian; } else { $target_info{endian} = "little"; $endian_str = $lil_endian; } sysseek TGT, 0, SEEK_SET; sysread TGT, $buf, $elf_size; # We don't need all these values: once again, a Perl ELF lesson ($e_hdr{e_ident}, $e_hdr{e_type}, $e_hdr{e_machine}, $e_hdr{e_version}, $e_hdr{e_entry}, $e_hdr{e_phoff}, $e_hdr{e_shoff}, $e_hdr{e_flags}, $e_hdr{e_ehsize}, $e_hdr{e_phentsize}, $e_hdr{e_phnum}, $e_hdr{e_shentsize}, $e_hdr{e_shnum}, $e_hdr{e_shstrndx} ) = unpack $endian_str, $buf; $target_info{header} = \%e_hdr; $target_info{entry} = $e_hdr{e_entry}; $opt_quiet || print "\tHandling ELF Section headers\n"; elf_shdr_read( \%e_hdr ); $opt_quiet || print "\tHandling ELF Program headers\n"; elf_phdr_read( \%e_hdr ); $opt_quiet || print "\tGetting symbols from ELF dynamic linking info\n"; elf_dynamic( \%e_hdr ); return \%e_hdr; } sub elf_phdr_read { local($e_hdr) = shift; local($phdr); local($x); sysseek TGT, $$e_hdr{e_phoff}, SEEK_SET; for ( $x = 0; $x < $$e_hdr{e_phnum}; $x++ ) { # read header, create new header object sysread TGT, $buf, $$e_hdr{e_phentsize}; $phdr = new_phdr( $buf ); # add to list of program headers push @{$$e_hdr{phtab}}, $phdr; next if (! $opt_phdr ); #section headers used for setup # build target sections based on program headers if ( $$phdr{p_type} eq "PT_LOAD" ) { if ( $$phdr{p_flags} =~ /PF_X/ ) { new_section( $$phdr{p_offset}, $$phdr{p_filesz}, $$phdr{p_vaddr}, ".text", "CODE" ); } elsif ( $$phdr{p_flags} =~ /PF_W/ ) { new_section( $$phdr{p_offset}, $$phdr{p_filesz}, $$phdr{p_vaddr}, ".data", "DATA" ); } elsif ( $$phdr{p_flags} =~ /PF_R/ ) { new_section( $$phdr{p_offset}, $$phdr{p_filesz}, $$phdr{p_vaddr}, ".rodata", "DATA" ); } } elsif ( $$phdr{p_type} eq "PT_DYNAMIC" ) { $$e_hdr{dynhdr} = $phdr; } elsif ( $$phdr{p_type} eq "PT_INTERP" ) { $$e_hdr{interp} = $phdr; } } $target_info{entry_offset} = elf_va_to_offset( $e_hdr, $target_info{entry} ); return; } sub new_phdr { local($buf) = shift; local($phdr_str); local(%phdr); if ( $target_info{endian} eq "big" ) { $phdr_str = "NNNNNNNN"; } else { $phdr_str = "VVVVVVVV"; } ( $phdr{p_type}, $phdr{p_offset}, $phdr{p_vaddr}, $phdr{p_paddr}, $phdr{p_filesz}, $phdr{p_memsz}, $phdr{p_flags}, $phdr{p_align} ) = unpack $phdr_str, $buf; if ( $phdr{p_type} == 0 ) { $phdr{p_type} = "PT_NULL"; } elsif ( $phdr{p_type} == 1 ) { $phdr{p_type} = "PT_LOAD"; } elsif ( $phdr{p_type} == 2 ) { $phdr{p_type} = "PT_DYNAMIC"; } elsif ( $phdr{p_type} == 3 ) { $phdr{p_type} = "PT_INTERP"; } elsif ( $phdr{p_type} == 4 ) { $phdr{p_type} = "PT_NOTE"; } elsif ( $phdr{p_type} == 5 ) { $phdr{p_type} = "PT_SHLIB"; } elsif ( $phdr{p_type} == 6 ) { $phdr{p_type} = "PT_PHDR"; } else { $phdr{p_type} = "PT_UNK"; } $buf = ""; if ( $phdr{p_flags} & 0x01 ) { $buf .= "PF_X|"; } if ( $phdr{p_flags} & 0x02 ) { $buf .= "PF_W|"; } if ( $phdr{p_flags} & 0x04 ) { $buf .= "PF_R|"; } $buf =~ s/\|$//g; $phdr{p_flags} = $buf; return \%phdr; } sub elf_shdr_read { local($e_hdr) = shift; local($shdr); local($x, $shstrtab, $shstrsz, $shstrbuf); if (! $$e_hdr{e_shoff} || ! $$e_hdr{e_shnum} ) { # this is an sstrip'ed binary: switch to phdr mode $opt_shdr = 0; $opt_phdr = 1; return; } sysseek TGT, $$e_hdr{e_shoff}, SEEK_SET; for ( $x = 0; $x < $$e_hdr{e_shnum}; $x++ ) { sysread TGT, $buf, $$e_hdr{e_shentsize}; $shdr = new_shdr( $buf ); if ( $x && $x == $$e_hdr{e_shstrndx} ) { $shstrtab = $$shdr{sh_offset}; $shstrsz = $$shdr{sh_size}; } # add to list of section headers push @{$$e_hdr{shtab}}, $shdr; } if (! $opt_shdr || ! $shstrtab || ! $shstrsz ) { $opt_phdr = 1; # cannot do much w/o shstrtab return; # prog headers used for setup } # read in copy of strtab sysseek TGT, $shstrtab, SEEK_SET; sysread TGT, $shstrbuf, $shstrsz; # Now that we know strtab, we can do real processing foreach ( @{$$e_hdr{shtab}} ) { $shdr = $_; $$shdr{sh_name} = substr $shstrbuf, $$shdr{sh_name}; $$shdr{sh_name} =~ s/\x00.*//; if ( $$shdr{sh_name} eq ".dynamic" ) { # dynamic linking info $$e_hdr{dynhdr} = $shdr; } elsif ( $$shdr{sh_name} eq ".dynstr" ) { # dynamic linking strings $$e_hdr{dyn_strtab} = $$shdr{sh_offset}; $$e_hdr{dyn_strsz} = $$shdr{sh_size}; } elsif ( $$shdr{sh_name} eq ".dynsym" ) { # dynamic linking symbols $$e_hdr{dyn_symtab} = $$shdr{sh_offset}; $$e_hdr{dyn_syment} = $$shdr{sh_entsize}; $$e_hdr{dyn_symsz} = $$shdr{sh_size}; } elsif ( $$shdr{sh_type} eq "SHT_PROGBITS" && $$shdr{sh_flags} =~ /SHF_ALLOC/ ) { if ( $$shdr{sh_flags} =~ /SHF_WRITE/ ) { # .data section new_section( $$shdr{sh_offset}, $$shdr{sh_size}, $$shdr{sh_addr}, $$shdr{sh_name}, "DATA" ); } elsif ( $$shdr{sh_flags} =~ /SHF_EXECINSTR/ ) { # .text new_section( $$shdr{sh_offset}, $$shdr{sh_size}, $$shdr{sh_addr}, $$shdr{sh_name}, "CODE" ); } else { # .rodata new_section( $$shdr{sh_offset}, $$shdr{sh_size}, $$shdr{sh_addr}, $$shdr{sh_name}, "RODATA" ); } } elsif ( $$shdr{sh_type} eq "SHT_NOGBITS" && $$shdr{sh_flags} =~ /SHF_ALLOC/ ) { if ( $$shdr{sh_flags} =~ /SHF_WRITE/ ) { # .bss section new_section( $$shdr{sh_offset}, $$shdr{sh_size}, $$shdr{sh_addr}, $$shdr{sh_name}, "BSS" ); } } # else ignore } return; } sub new_shdr { local($buf) = shift; local($shdr_str); local(%shdr); if ( $target_info{endian} eq "big" ) { $shdr_str = "NNNNNNNNNN"; } else { $shdr_str = "VVVVVVVVVV"; } ( $shdr{sh_name}, $shdr{sh_type}, $shdr{sh_flags}, $shdr{sh_addr}, $shdr{sh_offset}, $shdr{sh_size}, $shdr{sh_link}, $shdr{sh_info}, $shdr{sh_addralign}, $shdr{sh_entsize} ) = unpack $shdr_str, $buf; if ( $shdr{sh_type} == 0 ) { $shdr{sh_type} = "SHT_NULL"; } elsif ($shdr{sh_type} == 1 ) { $shdr{sh_type} = "SHT_PROGBITS"; } elsif ($shdr{sh_type} == 2 ) { $shdr{sh_type} = "SHT_SYMTAB"; } elsif ($shdr{sh_type} == 3 ) { $shdr{sh_type} = "SHT_STRTAB"; } elsif ($shdr{sh_type} == 4 ) { $shdr{sh_type} = "SHT_RELA"; } elsif ($shdr{sh_type} == 5 ) { $shdr{sh_type} = "SHT_HASH"; } elsif ($shdr{sh_type} == 6 ) { $shdr{sh_type} = "SHT_DYNAMIC"; } elsif ($shdr{sh_type} == 7 ) { $shdr{sh_type} = "SHT_NOTE"; } elsif ($shdr{sh_type} == 8 ) { $shdr{sh_type} = "SHT_NOBITS"; } elsif ($shdr{sh_type} == 9 ) { $shdr{sh_type} = "SHT_REL"; } elsif ($shdr{sh_type} == 10 ) { $shdr{sh_type} = "SHT_SHLIB"; } elsif ($shdr{sh_type} == 11 ) { $shdr{sh_type} = "SHT_DYNSYM"; } $buf = ""; if ( $shdr{sh_flags} & 0x01 ) { $buf .= "SHF_WRITE|"; } if ( $shdr{sh_flags} & 0x02 ) { $buf .= "SHF_ALLOC|"; } if ( $shdr{sh_flags} & 0x04 ) { $buf .= "SHF_EXECINSTR|"; } $buf =~ s/\|$//g; $shdr{sh_flags} = $buf; return \%shdr; } sub elf_dynamic { local($e_hdr) = shift; local($dyntab) = $$e_hdr{dynhdr}; local($dynsize) = 8; local($buf, $dyn_str, $str_buf, $x); local($sym); if ( $opt_phdr ) { # use program header data for dynamic section sysseek TGT, $$dyntab{p_offset}, SEEK_SET; for ( $x = 0; $x < $$dyntab{p_filesz}; $x += $dynsize ) { sysread TGT, $buf, $dynsize; $dyn = new_dyn( $buf ); push @{$$e_hdr{dyntab}}, $dyn; } # identify strtab and symtab foreach ( @{$$e_hdr{dyntab}} ) { if ( $$_{d_tag} eq "DT_STRTAB" ) { $$e_hdr{dyn_strtab} = elf_va_to_offset( $e_hdr, $$_{d_val} ); } elsif ( $$_{d_tag} eq "DT_SYMTAB" ) { $$e_hdr{dyn_symtab} = elf_va_to_offset( $e_hdr, $$_{d_val} ); } elsif ( $$_{d_tag} eq "DT_SYMENT" ) { $$e_hdr{dyn_syment} = $$_{d_val}; } elsif ( $$_{d_tag} eq "DT_STRSZ" ) { $$e_hdr{dyn_strsz} = $$_{d_val}; } } if (! $$e_hdr{dyn_strtab} || ! $$e_hdr{dyn_symtab} ) { return 0; } $$e_hdr{dyn_symsz} = $$e_hdr{dyn_strtab} - $$e_hdr{dyn_symtab}; } # else rely on section headers #read temporary copy of strtab sysseek TGT, $$e_hdr{dyn_strtab}, SEEK_SET; sysread TGT, $str_buf, $$e_hdr{dyn_strsz}; # process symtab sysseek TGT, $$e_hdr{dyn_symtab}, SEEK_SET; for ( $x = 0; $x < $$e_hdr{dyn_symsz} / $$e_hdr{dyn_syment}; $x++ ){ sysread TGT, $buf, $$e_hdr{dyn_syment}; $sym = new_sym( $e_hdr, $buf, $str_buf ); if ( $sym ) { push @{$target_info{symbols}}, $sym; # add to index $$target_info{sym_idx}{$$sym{va}} = $sym; } } return; } sub new_dyn { local($buf) = shift; local(%dyn); if ( $target_info{endian} eq "big" ) { $dyn_str = "NN"; } else { $dyn_str = "VV"; } ( $dyn{d_tag}, $dyn{d_val} ) = unpack $dyn_str, $buf; if ( $dyn{d_tag} == 0 ) { $dyn{d_tag} = "DT_NULL"; } elsif ( $dyn{d_tag} == 1 ) { $dyn{d_tag} = "DT_NEEDED"; } elsif ( $dyn{d_tag} == 2 ) { $dyn{d_tag} = "DT_PLTRELSZ"; } elsif ( $dyn{d_tag} == 3 ) { $dyn{d_tag} = "DT_PLTGOT"; } elsif ( $dyn{d_tag} == 4 ) { $dyn{d_tag} = "DT_HASH"; } elsif ( $dyn{d_tag} == 5 ) { $dyn{d_tag} = "DT_STRTAB"; } elsif ( $dyn{d_tag} == 6 ) { $dyn{d_tag} = "DT_SYMTAB"; } elsif ( $dyn{d_tag} == 7 ) { $dyn{d_tag} = "DT_RELA"; } elsif ( $dyn{d_tag} == 8 ) { $dyn{d_tag} = "DT_RELASZ"; } elsif ( $dyn{d_tag} == 9 ) { $dyn{d_tag} = "DT_RELAENT"; } elsif ( $dyn{d_tag} == 10 ) { $dyn{d_tag} = "DT_STRSZ"; } elsif ( $dyn{d_tag} == 11 ) { $dyn{d_tag} = "DT_SYMENT"; } elsif ( $dyn{d_tag} == 12 ) { $dyn{d_tag} = "DT_INIT"; } elsif ( $dyn{d_tag} == 13 ) { $dyn{d_tag} = "DT_FINI"; } elsif ( $dyn{d_tag} == 14 ) { $dyn{d_tag} = "DT_SONAME"; } elsif ( $dyn{d_tag} == 15 ) { $dyn{d_tag} = "DT_RPATH"; } elsif ( $dyn{d_tag} == 16 ) { $dyn{d_tag} = "DT_SYMBOLIC"; } elsif ( $dyn{d_tag} == 17 ) { $dyn{d_tag} = "DT_REL"; } elsif ( $dyn{d_tag} == 18 ) { $dyn{d_tag} = "DT_RELSZ"; } elsif ( $dyn{d_tag} == 19 ) { $dyn{d_tag} = "DT_RELENT"; } elsif ( $dyn{d_tag} == 20 ) { $dyn{d_tag} = "DT_PLTREL"; } elsif ( $dyn{d_tag} == 21 ) { $dyn{d_tag} = "DT_DEBUG"; } elsif ( $dyn{d_tag} == 22 ) { $dyn{d_tag} = "DT_TEXTREL"; } elsif ( $dyn{d_tag} == 23 ) { $dyn{d_tag} = "DT_JMPREL"; } elsif ( $dyn{d_tag} == 24 ) { $dyn{d_tag} = "DT_BIND_NOW"; } return \%dyn; } sub new_sym { local($e_hdr) = shift; local($buf) = shift; local($strtab) = shift; local($sym_str); local(%sym, %symbol, $type, $bind); if ( $target_info{endian} eq "big" ) { $sym_str = "NNNCCn"; } else { $sym_str = "VVVCCv"; } ( $sym{st_name}, $sym{st_value}, $sym{st_size}, $sym{st_info}, $sym{st_other}, $sym{st_shndx} ) = unpack $sym_str, $buf; $bind = $sym{st_info} >> 4; $type = $sym{st_info} &0xF; $symbol{type} = ""; if ( $bind == 0 ) { $symbol{type} = "LOCAL|"; } elsif ($bind == 1 ) { $symbol{type} = "GLOBAL|"; } if ( $type == 1 ) { $symbol{type} .= "OBJECT"; } elsif ( $type == 2 ) { $symbol{type} .= "FUNCTION"; } elsif ( $type == 3 ) { $symbol{type} .= "FILE"; } elsif ( $type == 4 ) { $symbol{type} .= "SECTION"; } $symbol{type} =~ s/^\|//g; $symbol{name} = substr $strtab, $sym{st_name}; $symbol{name} =~ s/\x00.*//; $symbol{va} = $sym{st_value}; $symbol{offset} = elf_va_to_offset( $e_hdr, $sym{st_value} ); return \%symbol; } sub elf_va_to_offset { local($e_hdr) = shift; local($va) = shift; local($phdr); foreach ( @{$$e_hdr{phtab}} ) { $phdr = $_; if ( $$phdr{p_vaddr} <= $va && ($$phdr{p_vaddr} + $$phdr{p_filesz}) > $va ) { return( $$phdr{p_offset} + ($va - $$phdr{p_vaddr}) ); } } return( $va ); } #=============================================================================== # Register Data # register table -- used for mapping opcode.map register IDs to reg names # format: reg { name, type, size } # types: REG_GENERAL, REG_SIMD, REG_DEBUG, REG_SYS, REG_CODESEG, REG_DATASEG, # REG_STACKSEG, REG_INVALID, REG_FPU, REG_CC, REG_FPU, REG_PC, REG_FP, # REG_SP, REG_CNT, REG_RET, REG_SRC, REG_DEST # Usage: disasm_get_reg( index, 0 ) to get reg by index # disasm_get_reg( 0, name ) to get reg by name sub disasm_get_reg { local($num) = shift; local($name) = shift; local(@reg_table) = ( {name => "eax", type => "REG_GENERAL,REG_RET", size => "OPSIZE_WORD"}, {name => "ecx", type => "REG_GENERAL,REG_COUNT", size => "OPSIZE_WORD"}, {name => "edx", type => "REG_GENERAL", size => "OPSIZE_WORD"}, {name => "ebx", type => "REG_GENERAL", size => "OPSIZE_WORD"}, {name => "esp", type => "REG_SP", size => "OPSIZE_WORD"}, {name => "ebp", type => "REG_GENERAL,REG_FP", size => "OPSIZE_WORD"}, {name => "esi", type => "REG_GENERAL,REG_SRC", size => "OPSIZE_WORD"}, {name => "edi", type => "REG_GENERAL,REG_DEST", size => "OPSIZE_WORD"}, {name => "ax", type => "REG_GENERAL,REG_RET", size => "OPSIZE_HWORD"}, {name => "cx", type => "REG_GENERAL,REG_COUNT", size => "OPSIZE_HWORD"}, {name => "dx", type => "REG_GENERAL", size => "OPSIZE_HWORD"}, {name => "bx", type => "REG_GENERAL", size => "OPSIZE_HWORD"}, {name => "sp", type => "REG_SP", size => "OPSIZE_HWORD"}, {name => "bp", type => "REG_GENERAL,REG_FP", size => "OPSIZE_HWORD"}, {name => "si", type => "REG_GENERAL,REG_SRC", size => "OPSIZE_HWORD"}, {name => "di", type => "REG_GENERAL,REG_DEST", size => "OPSIZE_HWORD"}, {name => "al", type => "REG_GENERAL", size => "OPSIZE_BYTE"}, {name => "cl", type => "REG_GENERAL", size => "OPSIZE_BYTE"}, {name => "dl", type => "REG_GENERAL", size => "OPSIZE_BYTE"}, {name => "bl", type => "REG_GENERAL", size => "OPSIZE_BYTE"}, {name => "ah", type => "REG_GENERAL", size => "OPSIZE_BYTE"}, {name => "ch", type => "REG_GENERAL", size => "OPSIZE_BYTE"}, {name => "dh", type => "REG_GENERAL", size => "OPSIZE_BYTE"}, {name => "bh", type => "REG_GENERAL", size => "OPSIZE_BYTE"}, {name => "mm0", type => "REG_SIMD", size => "OPSIZE_WORD"}, {name => "mm1", type => "REG_SIMD", size => "OPSIZE_WORD"}, {name => "mm2", type => "REG_SIMD", size => "OPSIZE_WORD"}, {name => "mm3", type => "REG_SIMD", size => "OPSIZE_WORD"}, {name => "mm4", type => "REG_SIMD", size => "OPSIZE_WORD"}, {name => "mm5", type => "REG_SIMD", size => "OPSIZE_WORD"}, {name => "mm6", type => "REG_SIMD", size => "OPSIZE_WORD"}, {name => "mm7", type => "REG_SIMD", size => "OPSIZE_WORD"}, {name => "xmm0", type => "REG_SIMD", size => "OPSIZE_WORD"}, {name => "xmm1", type => "REG_SIMD", size => "OPSIZE_WORD"}, {name => "xmm2", type => "REG_SIMD", size => "OPSIZE_WORD"}, {name => "xmm3", type => "REG_SIMD", size => "OPSIZE_WORD"}, {name => "xmm4", type => "REG_SIMD", size => "OPSIZE_WORD"}, {name => "xmm5", type => "REG_SIMD", size => "OPSIZE_WORD"}, {name => "xmm6", type => "REG_SIMD", size => "OPSIZE_WORD"}, {name => "xmm7", type => "REG_SIMD", size => "OPSIZE_WORD"}, {name => "dr0", type => "REG_DEBUG", size => "OPSIZE_WORD"}, {name => "dr1", type => "REG_DEBUG", size => "OPSIZE_WORD"}, {name => "dr2", type => "REG_DEBUG", size => "OPSIZE_WORD"}, {name => "dr3", type => "REG_DEBUG", size => "OPSIZE_WORD"}, {name => "dr4", type => "REG_DEBUG", size => "OPSIZE_WORD"}, {name => "dr5", type => "REG_DEBUG", size => "OPSIZE_WORD"}, {name => "dr6", type => "REG_DEBUG,REG_SYS", size => "OPSIZE_WORD"}, {name => "dr7", type => "REG_DEBUG,REG_SYS", size => "OPSIZE_WORD"}, {name => "cr0", type => "REG_SYS", size => "OPSIZE_WORD"}, {name => "cr1", type => "REG_SYS", size => "OPSIZE_WORD"}, {name => "cr2", type => "REG_SYS", size => "OPSIZE_WORD"}, {name => "cr3", type => "REG_SYS", size => "OPSIZE_WORD"}, {name => "cr4", type => "REG_SYS", size => "OPSIZE_WORD"}, {name => "cr5", type => "REG_SYS", size => "OPSIZE_WORD"}, {name => "cr6", type => "REG_SYS", size => "OPSIZE_WORD"}, {name => "cr7", type => "REG_SYS", size => "OPSIZE_WORD"}, {name => "tr0", type => "REG_SYS", size => "OPSIZE_WORD"}, {name => "tr1", type => "REG_SYS", size => "OPSIZE_WORD"}, {name => "tr2", type => "REG_SYS", size => "OPSIZE_WORD"}, {name => "tr3", type => "REG_SYS", size => "OPSIZE_WORD"}, {name => "tr4", type => "REG_SYS", size => "OPSIZE_WORD"}, {name => "tr5", type => "REG_SYS", size => "OPSIZE_WORD"}, {name => "tr6", type => "REG_SYS", size => "OPSIZE_WORD"}, {name => "tr7", type => "REG_SYS", size => "OPSIZE_WORD"}, {name => "es", type => "REG_DATASEG", size => "OPSIZE_HWORD"}, {name => "cs", type => "REG_CODESEG", size => "OPSIZE_HWORD"}, {name => "ss", type => "REG_STACKSEG", size => "OPSIZE_HWORD"}, {name => "ds", type => "REG_DATASEG", size => "OPSIZE_HWORD"}, {name => "fs", type => "REG_DATASEG", size => "OPSIZE_HWORD"}, {name => "gs", type => "REG_DATASEG", size => "OPSIZE_HWORD"}, {name => " ", type => "REG_INVALID", size => 0}, {name => " ", type => "REG_INVALID", size => 0}, {name => "st(0)", type => "REG_FPU", size => "OPSIZE_FPREG"}, {name => "st(1)", type => "REG_FPU", size => "OPSIZE_FPREG"}, {name => "st(2)", type => "REG_FPU", size => "OPSIZE_FPREG"}, {name => "st(3)", type => "REG_FPU", size => "OPSIZE_FPREG"}, {name => "st(4)", type => "REG_FPU", size => "OPSIZE_FPREG"}, {name => "st(5)", type => "REG_FPU", size => "OPSIZE_FPREG"}, {name => "st(6)", type => "REG_FPU", size => "OPSIZE_FPREG"}, {name => "st(7)", type => "REG_FPU", size => "OPSIZE_FPREG"}, {name => "eflags", type => "REG_CC", size => "OPSIZE_FPREG"}, {name => "fpctrl", type => "REG_FPU,REG_SYS", size => "OPSIZE_HWORD"}, {name => "fpstat", type => "REG_FPU,REG_SYS", size => "OPSIZE_HWORD"}, {name => "fptag", type => "REG_FPU,REG_SYS", size => "OPSIZE_HWORD"}, {name => "eip", type => "REG_PC", size => "OPSIZE_WORD"}, {name => "ip", type => "REG_PC", size => "OPSIZE_HWORD"} ); if ( $name ) { foreach( @reg_table ) { if ( $$_{name} eq $name ) { return $_; } } return 0; } return( $reg_table[$num] ); } sub disasm_optable_regfix { local($op) = shift; local($reg_num); local(%reg_off) = ( REG_DWORD_OFFSET => 0, REG_WORD_OFFSET => 8, REG_BYTE_OFFSET => 16, REG_MMX_OFFSET => 24, REG_SIMD_OFFSET => 32, REG_DEBUG_OFFSET => 40, REG_CTRL_OFFSET => 48, REG_TEST_OFFSET => 56, REG_SEG_OFFSET => 64, REG_FPU_OFFSET => 72, REG_FLAGS_INDEX => 80, REG_FPCTRL_INDEX => 81, REG_FPSTATUS_INDEX => 82, REG_FPTAG_INDEX => 83, REG_EIP_INDEX => 84, REG_IP_INDEX => 85 ); if ( $op =~ /([0-9]*)\s*\+?\s*(REG_[A-Z_]+)\s*\+?\s*([0-9]*)/ ) { $reg_num = $reg_off{$2} + $1 + $3; return $reg_num; } return 0; } #=============================================================================== # Opcode disassembly routines # disasm_get_imm( unsigned char *buf, int size, int sign ); # Returns operand sub disasm_get_imm { local($buf) = shift; local($size) = shift; local($sign) = shift; local($imm_str) = "L"; local($imm); if ( $sign ) { if ( $size == 1 ) { $imm_str = "c"; } elsif ( $size == 2 ) { $imm_str = "s"; } elsif ( $size == 4 ) { $imm_str = "i"; } elsif ( $size == 8 ) { $imm_str = "q"; } elsif ( $size == 16 ) { $imm_str = "q2"; } } else { if ( $size == 1 ) { $imm_str = "C"; } elsif ( $size == 2 ) { $imm_str = "v"; } elsif ( $size == 4 ) { $imm_str = "V"; } elsif ( $size == 8 ) { $imm_str = "Q"; } elsif ( $size == 16 ) { $imm_str = "Q2"; } } $imm = unpack $imm_str, $buf; return $imm; } sub byte_unpack { local($byte) = shift; local($a2, $b3, $c3); $c3 = $byte & 0x07; $b3 = ($byte >> 3) & 0x07; $a2 = ($byte >> 6) & 0x03; return ($a2, $b3, $c3); } # TYPE EADDR DISP|SCALE|INDEX|BASE # Return size sub disasm_modrm_decode { local($buf) = shift; local($op) = shift; # pointer to insn{op} local($flg) = shift; # pointer to insn{opflag} local($base_reg) = shift; local($ea)= shift; local($modrm, $mod, $reg, $rm); local($sib, $scale, $index, $base, $disp, $r, $eaddr); local($disp_flag, $base_flag, $idx_flag); local($count) = 1; ($modrm, $sib) = unpack "CC", $buf; ($mod, $reg, $rm) = byte_unpack $modrm; ($scale, $index, $base) = byte_unpack $sib; if (! $ea ) { # this is using the 'reg' field of modR/M $r = disasm_get_reg($base_reg + $reg, 0); $$op = $$r{name}; $$flg = "OP_REG,$$r{type},$$r{size}"; return(0); # no bytes consumed } if ( $mod == 3 ) { # mod = 11 [register, no memory addr] $r = disasm_get_reg($base_reg + $rm, 0); $$op = $$r{name}; $$flg = "OP_REG,$$r{type},$$r{size}"; return($count); } if ( ! $mod ) { # mod = 00 [no displacement] if ( $rm == 5 ) { # rm = 101 [disp32 -- no reg] $disp = disasm_get_imm( substr($buf, $count), 4, 1 ); $scale = $index = $base = ""; $disp_flag = "DISP32"; $count += 4; } elsif ( $rm == 4 ) { # rm = 100 [no disp -- SIB] $count++; # DO SIB $scale = 0x01 << $scale; if ( $index != 4 ) { # index = 100 $r = disasm_get_reg($index, 0); $index = $$r{name}; $idx_flag = "$$r{type},$$r{size}"; } else { $index = $scale = ""; } if ( $base == 5 ) { # base = 101, mod = 0 $disp = disasm_get_imm( substr($buf, $count), 4, 1 ); $disp_flag = "DISP32"; $base = ""; } else { $r = disasm_get_reg($base, 0); $base = $$r{name}; $base_flag = "$$r{type},$$r{size}"; $disp = ""; } } else { # register with no disp $r = disasm_get_reg($rm, 0); $base = $$r{name}; $base_flag = "$$r{type},$$r{size}"; $scale = $index = $disp = ""; } } else { # this is a disp[reg] combo # handle [SIB] or [register] if ( $rm == 4 ) { # rm = 100 [disp8+SIB] $count++; # DO SIB $scale = 0x01 << $scale; if ( $index != 4 ) { # index = 100 $r = disasm_get_reg($index, 0); $index = $$r{name}; $idx_flag = "$$r{type},$$r{size}"; } else { $index = $scale = ""; } $r = disasm_get_reg($base, 0); $base = $$r{name}; $base_flag = "$$r{type},$$r{size}"; } else { # disp[reg] $r = disasm_get_reg($rm, 0); $base = $$r{name}; $base_flag = "$$r{type},$$r{size}"; $scale = $index = ""; } # handle displacement if ( $mod == 1 ) { # mod = 01 [disp8] $disp = disasm_get_imm( substr($buf, $count), 1, 1 ); $disp_flag = "DISP8"; $count ++; } else { # mod = 10 [disp32] $disp = disasm_get_imm( substr($buf, $count), 4, 1 ); $disp_flag = "DISP32"; $count += 4; } } if ( $scale == 1 ) { $scale = ""; } $$op = "$disp:$scale:$index:$base:$disp_flag:$idx_flag:$base_flag"; $$flg = "OP_EADDR"; return($count); } #disasm_operand_decode( INSN *insn, char *opname, unsigned char *buf ); #Examine operand $opname in $insn, using bytes in $buf for any encoded data. #Return number of bytes "consumed" in $buf by decoding immediate values, etc. sub disasm_operand_decode { local($insn) = shift; local($opname) = shift; local($main_buf) = shift; local($pos) = shift; local($sz_addr) = 4; # 32-bit addresses local($sz_op) = 4; # 32-bit operands local($addr_meth, $op_type, $base_reg, $reg); local($buf, $opflg, $opprm, $op, $flg, $size); if ( $$insn{type} =~ /PREFIX_ADDR_SIZE/ ) { $sz_addr = 2; } if ( $$insn{type} =~ /PREFIX_OP_SIZE/ ) { $sz_op = 2; } $op = $$insn{$opname}; $$insn{$opname} = ""; $opflg = substr( $opname, 0, 1 ) . "type"; $flg = $$insn{$opflg}; $$insn{$opflg} = ""; # clear flags field $opprm = substr( $opname, 0, 1 ) . "prm"; # set operand permissions if ( $flg =~/\WOP_R(\W.*)*$/ ) { $$insn{$opprm} .="r"; } else {$$insn{$opprm} .="-";} if ( $flg =~/\WOP_W(\W.*)*$/ ) { $$insn{$opprm} .="w"; } else {$$insn{$opprm} .="-";} if ( $flg =~/\WOP_X(\W.*)*$/ ) { $$insn{$opprm} .="x"; } else {$$insn{$opprm} .="-";} # is operand hard-coded in insn? if ( $op ) { if ( $flg =~ /OP_REG/ ) { $reg = disasm_get_reg(disasm_optable_regfix($op), 0); $$insn{$opname} = $$reg{name}; $$insn{$opflg} = "OP_REG,$$reg{type},$$reg{size}"; } else { $$insn{$opname} = $op; $$insn{$opflg} = $flg; $$insn{$opflg} =~ s/\|/,/g; # comma delim } return(0); # no bytes used } if ( $flg =~ /ADDRMETH_([A-Z])/ ) { $addr_meth =$1; } if ( $flg =~ /OPTYPE_([a-z]+)/ ) { $op_type = $1; } # do operand size based on $op_type # My kingdom for a switch statement! if ( $op_type eq "c" ) { # byte or hword by $sz_op if ( $sz_op == 4 ) { $sz_op = 2; $$insn{$opflg} .= ",OPSIZE_HWORD"; } else { $sz_op = 1; $$insn{$opflg} .= ",OPSIZE_BYTE"; } } elsif ($op_type eq "a" ) { # 2 hwords or 2 words by $sz_op if ( $sz_op == 4 ) { $sz_op = 8; $$insn{$opflg} .= ",OPSIZE_DWORD"; } else { $sz_op = 4; $$insn{$opflg} .= ",OPSIZE_WORD"; } } elsif ($op_type eq "v" ) { # hword or word by $sz_op if ( $sz_op == 4 ) { $$insn{$opflg} .= ",OPSIZE_WORD"; } else { $$insn{$opflg} .= ",OPSIZE_HWORD"; } } elsif ($op_type eq "p" ) { # 32/48-bit ptr by $sz_op if ( $sz_op == 4 ) { $sz_op = 6; $$insn{$opflg} .= ",OPSIZE_6BYTE"; } else { $sz_op = 4; $$insn{$opflg} .= ",OPSIZE_WORD"; } } elsif ($op_type eq "b" ) { # byte $sz_op = 1; $$insn{$opflg} .= ",OPSIZE_BYTE"; } elsif ($op_type eq "w" ) { # hword $sz_op = 2; $$insn{$opflg} .= ",OPSIZE_HWORD"; } elsif ($op_type eq "d" || # word $op_type eq "si" ) { # dword integer register $sz_op = 4; $$insn{$opflg} .= ",OPSIZE_WORD"; } elsif ($op_type eq "s" ) { # 6-byte psuedo-descriptor $sz_op = 6; $$insn{$opflg} .= ",OPSIZE_6BYTE"; } elsif ($op_type eq "q" || # dword $op_type eq "pi" ) { # qword mmx register $sz_op = 8; $$insn{$opflg} .= ",OPSIZE_DWORD"; } elsif ($op_type eq "m" ) { # fake op type used for "lea Gv, M $sz_op = $sz_addr; if ( $sz_addr == 4 ) { $$insn{$opflg} .= ",OPSIZE_WORD"; } else { $$insn{$opflg} .= ",OPSIZE_HWORD"; } } elsif ($op_type eq "dq" ) { # quad word $sz_op = 16; $$insn{$opflg} .= ",OPSIZE_QWORD"; } elsif ($op_type eq "ps" ) { # 128-bit floating point $sz_op = 16; $$insn{$opflg} .= ",OPSIZE_FPDATA"; } elsif ($op_type eq "ss" ) { # 128 bit floating scalar $sz_op = 16; $$insn{$opflg} .= ",OPSIZE_FPSCALAR"; } elsif ($op_type eq "fs" ) { # single-real $sz_op = 4; $$insn{$opflg} .= ",OPSIZE_SREAL"; } elsif ($op_type eq "fd" ) { # double-real $sz_op = 4; $$insn{$opflg} .= ",OPSIZE_EREAL"; } elsif ($op_type eq "fe" ) { # extended real $sz_op = 4; $$insn{$opflg} .= ",OPSIZE_XREAL"; } elsif ($op_type eq "fb" ) { # packed BCD $sz_op = 4; $$insn{$opflg} .= ",OPSIZE_BCD"; } elsif ($op_type eq "fv" ) { # FPU env: 14/28-bytes $sz_op = 4; $$insn{$opflg} .= ",OPSIZE_FPENV"; } else { if ( $sz_op == 4 ) { $$insn{$opflg} .= ",OPSIZE_WORD"; } else { $$insn{$opflg} .= ",OPSIZE_HWORD"; } } # override base index in register table if ( $sz_op == 1 ) { $base_reg = 16; } # 1-byte reg elsif ($sz_op == 2) { $base_reg = 8; } # 2-byte reg elsif ($sz_op == 8) { $base_reg = 24; } # mmx reg # default return value and buffer position $size = 0; $buf = substr $main_buf, $pos; # handle operand based on addressing method if ($addr_meth eq "E") { # modR/M EA, general reg or memory $size = disasm_modrm_decode( $buf, \$op, \$flg, $base_reg, 1 ); $$insn{$opflg} .= ",$flg"; $$insn{$opname} = $op; $insn{modrm} = 1; } elsif ($addr_meth eq "M"){ # modR/M EA, memory only $size = disasm_modrm_decode( $buf, \$op, \$flg, 0, 1 ); $$insn{$opflg} .= ",$flg"; $$insn{$opname} = $op; $insn{modrm} = 1; } elsif ($addr_meth eq "Q"){ # modR/M EA, mmx reg or memory $size = disasm_modrm_decode( $buf, \$op, \$flg, 24, 1 ); $$insn{$opflg} .= ",$flg"; $$insn{$opname} = $op; $insn{modrm} = 1; } elsif ($addr_meth eq "R"){ # modR/M EA, general reg $size = disasm_modrm_decode( $buf, \$op, \$flg, $base_reg, 1 ); $$insn{$opflg} .= ",$flg"; $$insn{$opname} = $op; $insn{modrm} = 1; } elsif ($addr_meth eq "W"){ # modR/M EA, SIMD reg or memory $size = disasm_modrm_decode( $buf, \$op, \$flg, 32, 1 ); $$insn{$opflg} .= ",$flg"; $$insn{$opname} = $op; $insn{modrm} = 1; } elsif ($addr_meth eq "C"){ # modR/M reg: control reg $buf = $main_buf; disasm_modrm_decode( $buf, \$op, \$flg, 48, 0 ); $$insn{$opflg} .= ",$flg"; $$insn{$opname} = $op; } elsif ($addr_meth eq "D"){ # modR/M reg: debug reg $buf = $main_buf; disasm_modrm_decode( $buf, \$op, \$flg, 40, 0 ); $$insn{$opflg} .= ",$flg"; $$insn{$opname} = $op; } elsif ($addr_meth eq "G"){ # modR/M reg: general reg $buf = $main_buf; disasm_modrm_decode( $buf, \$op, \$flg, $base_reg, 0 ); $$insn{$opflg} .= ",$flg"; $$insn{$opname} = $op; } elsif ($addr_meth eq "P"){ # modR/M reg: MMX reg $buf = $main_buf; disasm_modrm_decode( $buf, \$op, \$flg, 24, 0 ); $$insn{$opflg} .= ",$flg"; $$insn{$opname} = $op; } elsif ($addr_meth eq "S"){ # modR/M reg: segment reg $buf = $main_buf; disasm_modrm_decode( $buf, \$op, \$flg, 64, 0 ); $$insn{$opflg} .= ",$flg"; $$insn{$opname} = $op; } elsif ($addr_meth eq "T"){ # modR/M reg: test reg $buf = $main_buf; disasm_modrm_decode( $buf, \$op, \$flg, 56, 0 ); $$insn{$opflg} .= ",$flg"; $$insn{$opname} = $op; } elsif ($addr_meth eq "V"){ # modR/M reg: SIMD reg $buf = $main_buf; disasm_modrm_decode( $buf, \$op, \$flg, 32, 0 ); $$insn{$opflg} .= ",$flg"; $$insn{$opname} = $op; } elsif ($addr_meth eq "A"){ # direct address in insn $size = $sz_addr; $$insn{$opflg} .= ",OP_ADDR"; $$insn{$opname} = disasm_get_imm( $buf, $sz_addr, 0 ); } elsif ($addr_meth eq "F"){ # eflags register $$insn{$opflg} .= ",OP_REG,REG_CC"; $$insn{$opname} = "eflags"; } elsif ($addr_meth eq "I"){ # immediate value in insn $size = $sz_op; if ( $flg =~ /OP_SIGNED/ ) { $$insn{$opflg} .= ",OP_IMM,OP_SIGNED"; $$insn{$opname} = disasm_get_imm( $buf, $sz_op, 1 ); } else { $$insn{$opflg} .= ",OP_IMM"; $$insn{$opname} = disasm_get_imm( $buf, $sz_op, 0 ); } } elsif ($addr_meth eq "J"){ # immediate val = offset to eip $size = $sz_op; $$insn{$opflg} .= ",OP_REL,OP_SIGNED"; $$insn{$opname} = disasm_get_imm( $buf, $sz_op, 1 ); } elsif ($addr_meth eq "O"){ # offset (va) in insn $size = $sz_op; $$insn{$opflg} .= ",OP_OFF,OP_SIGNED"; $$insn{$opname} = disasm_get_imm( $buf, $sz_op, 1 ); } elsif ($addr_meth eq "X"){ # memory addresses by DS:ESI $$insn{$opflg} .= ",OP_REG,OP_STRING,REG_GENERAL,REG_SRC"; $$insn{$opname} = "ds:esi"; } elsif ($addr_meth eq "Y"){ # memory addresses by ES:EDI $$insn{$opflg} .= ",OP_REG,OP_STRING,REG_GENERAL,REG_DEST"; $$insn{$opname} = "es:edi"; } $$insn{$opflg} =~ s/^,//; return $size; } # disasm_table_adjust_byte( OPCODE_TABLE_DEF *tbl_def, unsigned char *byte ); # Adjust $byte to ranges of table, return $byte adjusted to be index into table sub disasm_table_adjust_byte { local($tbl_def) = shift; local($byte) = shift; # used for tables < 256 values if ( (hex($$tbl_def{max}) < 0xFF) && $byte > hex($$tbl_def{max}) ) { $tbl_def = $table_list[$table_num + 1]; } # used for tables < 256 values if ( hex($$tbl_def{min}) ) { $byte -= hex($$tbl_def{min}); } # overcome perl's & and >> stupidity $$tbl_def{shft} *= 1; # used for tables < 256 values if ( $$tbl_def{shft} ) { $byte = $byte >> $$tbl_def{shft}; } # this is a modr/m extension $byte &= hex($$tbl_def{mask}); return( $byte ); } #disasm_table_lookup( int table_num, unsigned char *buf, INSN *insn); #Use bytes in $buf to look up instruction in opcode table # $table_num #Fill $insn with instruction details. Return size [# of bytes used to decode]. sub disasm_table_lookup { local($table_num) = shift; local($buf) = shift; local($insn) = shift; local($size) = 1; local($tbl_def, $insn_def, $table, $byte, $prefix); $byte = unpack "C", $buf; $tbl_def = $table_list[$table_num]; $byte = disasm_table_adjust_byte( $tbl_def, $byte ); # adjust buf unless this opcode was from a modrm nyte if ( hex($$tbl_def{mask}) != 0xFF ) { $size = 0; } $table = $tables{$$tbl_def{name}}; $insn_def = $$table[$byte]; if (! $insn_def ) { return 0; } elsif ( $$insn_def{table} ) { return ( $size + disasm_table_lookup($$insn_def{table}, substr($buf, 1), $insn) ); } elsif ( $$insn_def{iflg} =~ /INSTR_PREFIX/ ) { # get prefix, save in insn $prefix = sprintf "0x%02X", $byte; if ( $prefixes{$prefix} eq "PREFIX_LOCK" ) { $$insn{type} .= ",INS_LOCK"; } elsif ( $prefixes{$prefix} eq "PREFIX_REPNZ" ) { $$insn{type} .= ",INS_REPNZ"; } elsif ( $prefixes{$prefix} eq "PREFIX_REPZ" ) { $$insn{type} .= ",INS_REPZ"; } else { $$insn{type} .= ",$prefixes{$prefix}"; $$insn{type} =~ s/PREFIX_/SEG_/; } $$insn{type} =~ s/^,//; return ( 1 + disasm_table_lookup(0, substr($buf, 1), $insn) ); } else { $buf = substr $buf, $size; # fill mnemonics $$insn{mnemonic} = $$insn_def{insn}; # "type" may already contain a prefix $$insn{type} .= "$$insn_def{iflg},"; # insn type $$insn{type} .= "$$insn_def{cpu}"; # cpu req. $$insn{type} =~ s/,cpu_[A-Za-z0-9]*//; # fill insn operands $$insn{dest} = $$insn_def{dest}; # destination $$insn{dtype} = $$insn_def{dflg}; $$insn{src} = $$insn_def{src}; # source $$insn{stype} = $$insn_def{sflg}; $$insn{aux} = $$insn_def{aux}; # third op (imm) $$insn{atype} = $$insn_def{aflg}; } return $size; } #=============================================================================== # Disassembly "helper" routines sub section_strings { local($sec) = shift; local($buf, $pos, $num); $pos = 0; $num = 0; $buf = substr $target_image, $$sec{offset}, $$sec{size}; while ($pos < $$sec{size}) { for ($x = 0; $x + $pos < $$sec{size}; $x ++ ) { $c = chr(unpack "c", substr($buf,$x,1)); if ( $c !~ /[ \n!"#\$%&'()*+,-.\/0-z{}|~\s]/ ) { last; } } if ($x >= 4 ) { $str = substr($buf, 0, $x); $pos += $x; $num++; new_string( $$sec{va} + $pos, $$sec{offset} + $pos, $str ); $buf = substr $buf, $x; } else { $pos++; $buf = substr $buf, 1; } } return $num; } sub disasm_strings { local($sec, $num); foreach ( keys( %{$$target_info{sections}} ) ) { $sec = $$target_info{sections}{$_}; if ( $$sec{type} !~ "CODE" ) { $num = section_strings( $sec ); $opt_quiet || print "\t$$sec{name} : $num found\n"; } } return; } sub disasm_subroutines { local($insn, $next); foreach ( sort( keys( %{$$target_info{insn_idx}} ) ) ) { $insn = $$target_info{insn_idx}{$_}; # look for 'push ebp' if ( $$insn{mnemonic} =~ /^push/ && $$insn{dest} =~ /bp$/ ) { $next = $$target_info{insn_idx}{ $$insn{va} + $$insn{size} }; # look for 'mov ebp, esp' if ( $$next{mnemonic} =~ /^mov/ && $$next{dest} =~ /bp$/ && $$next{src} =~ /sp$/ ) { new_func($$insn{va}, $insn{offset}, 0); } } } return; } sub xrefs_to { local($to_va) = shift; local(@xrefs); #foreach ( keys( %{$$target_info{xref_idx}} ) ) { foreach ( @{$target_info{xrefs}} ) { if ( $$_{to} == $to_va ) { push @xrefs, $_; } } return @xrefs; } #disasm_branch_target($$insn{dest}, $$insn{dtype}); sub disasm_branch_target { local($insn) = shift; local($op) = shift; local($type) = shift; # try to make an OP_ADDR out of the operand if ( $type =~ /OP_OFF/) { if ( $type =~ /OPSIZE_BYTE/ ) { return $$insn{va} + $$insn{size} + $op; } return $op; } if ( $type =~ /OP_REL/) { return $$insn{va} + $$insn{size} + $op; } if ( $type =~ /OP_IMM/ ) { if ( $type =~ /WORD/ && $type !~ /OP_SIGNED/ ) { return $op; } } if ( $type =~ /OP_ADDR/ ) { return $op; } return -1; } sub disasm_va2off { local($va) = shift; local($sec); foreach ( keys( %{$$target_info{sections}} ) ) { $sec = $$target_info{sections}{$_}; if ($va >= $$sec{va} && $va < $$sec{va} + $$sec{size} ) { return $$sec{offset} + ($va - $$sec{va}); } } return(-1); } sub disasm_is_addr { local($va) = shift; foreach ( keys( %{$$target_info{sections}} ) ) { $sec = $$target_info{sections}{$_}; if ( $va >= $$sec{va} && $va < $$sec{va} + $$sec{size} ) { return 1; } } return 0; } sub disasm_is_data_addr { local($va) = shift; foreach ( keys( %{$$target_info{sections}} ) ) { $sec = $$target_info{sections}{$_}; if ( $$sec{type} =~ /DATA/ && $va >= $$sec{va} && $va < $$sec{va} + $$sec{size} ) { return 1; } } return 0; } sub disasm_is_code_addr { local($va) = shift; foreach ( keys( %{$$target_info{sections}} ) ) { $sec = $$target_info{sections}{$_}; if ( $$sec{type} =~ /CODE/ && $va >= $$sec{va} && $va < $$sec{va} + $$sec{size} ) { return 1; } } return 0; } sub disasm_op_size { local($type) = shift; if ( $type =~ /OPSIZE_QWORD/ ) { return 16; } if ( $type =~ /OPSIZE_DWORD/ ) { return 8; } if ( $type =~ /OPSIZE_HWORD/ ) { return 2; } if ( $type =~ /OPSIZE_BYTE/ ) { return 1; } if ( $type =~ /OPSIZE_WORD/ ) { return 4; } if ( $type =~ /OPSIZE_6BYTE/ ) { return 6; } if ( $type =~ /OPSIZE_FPDATA/ ) { return 16; } if ( $type =~ /OPSIZE_FPSCALAR/ ) { return 16; } if ( $type =~ /OPSIZE_FPENV/ ) { return 4; } if ( $type =~ /OPSIZE_SREAL/ ) { return 4; } if ( $type =~ /OPSIZE_EREAL/ ) { return 4; } if ( $type =~ /OPSIZE_XREAL/ ) { return 4; } if ( $type =~ /OPSIZE_BCD/ ) { return 4; } return 4; # default size } sub disasm_do_op { local($va) = shift; local($op) = shift; local($type) = shift; local($perm) = shift; local($size); local($disp,$scale,$index,$base,$flags); if ( $type =~ /OP_EADDR/ ) { ($disp,$scale,$index,$base,$flags) = split /:/, $op; #see if we can do anything with the disp if ( ! $scale && ! $index && ! $base && $flags=~/DISP32/ ) { $op = $disp; $type = "OP_ADDR"; } } if ( $type =~ /OP_IMM/ && disasm_is_addr($op) ) { $type = "OP_ADDR"; } if ( $type =~ /OP_ADDR/ || ($type =~ /OP_OFF/ && $type !~ /OPSIZE_BYTE/) ) { if ( $perm =~ /r/ ) { new_xref( $va, $op, "r" ); } if ( $perm =~ /w/ ) { new_xref( $va, $op, "w" ); } if ( ! disasm_is_data_addr($va) ) { $size = disasm_op_size($type); new_data( $va, disasm_va2off($va), $size, 0); } } return; } sub disasm_check_insn { local($insn) = shift; local($sym, $name); # check for a name for this address $sym = $$target_info{sym_idx}{$$insn{$va}}; $name = $$target_info{name_idx}{$$insn{$va}}; if ( $$sym{name} ) { $$insn{name} = $$sym{name}; } elsif ( $$name{name} ) { $$insn{name} = $$name{name}; } # check for addresses in operands # branches are handled in disassemble_buffer() if ( $$insn{type} =~ /(BRANCH)|(CALL)|(INS_RET)/ ) { return; } if ( $$insn{stype} ) { disasm_do_op( $va, $$insn{src}, $$insn{stype}, $$insn{sprm} ); } if ( $$insn{dtype} ) { disasm_do_op( $va, $$insn{dest}, $$insn{dtype}, $$insn{dprm} ); } if ( $$insn{atype} ) { disasm_do_op( $va, $$insn{aux}, $$insn{atype}, $$insn{aprm} ); } # additional stuff like stack management can go here return; } # disasm_addr( char *buf, int max ); # Call disasm_table_lookup to get insn based on up to $max bytes in $buf # Fix operands, fill INSN %i with instruction details. Return %i. sub disasm_addr { local($buf) = shift; local($max) = shift; local($size, $bytes); local(%i); $size = disasm_table_lookup( 0, $buf, \%i ); if (! $size ) { return(0); } # advance buffer "pointer" $buf = substr $buf, $size; # decode operands $bytes = 0; if ( $i{dtype} && $i{dtype} !~ /ARG_NONE/ ) { $bytes += disasm_operand_decode( \%i, "dest", $buf, $bytes ); } else { $i{dtype} = $i{dest} = ""; } if ( $i{stype} && $i{stype} !~ /ARG_NONE/ ) { $bytes += disasm_operand_decode( \%i, "src", $buf, $bytes ); } else { $i{stype} = $i{src} = ""; } if ( $i{atype} && $i{atype} !~ /ARG_NONE/) { $bytes += disasm_operand_decode( \%i, "aux", $buf, $bytes ); } else { $i{atype} = $i{aux} = ""; } $size += $bytes; $i{size} = $size; return \%i; } sub disasm_buffer { local($buf) = shift; local($offset) = shift; local($va) = shift; local($max) = shift; local($follow) = shift; local($hex_str) = ""; local($pos, $dis_buf, $insn, $x, $n_va, $n_off); $dis_buf = substr $$buf, $offset; if ( $follow ) { $opt_quiet || printf "Disassembling forward from %08X\n", $va; } for ( $pos = 0; $pos < $max; $pos += $$insn{size} ) { # do not disassemble twice $insn = $$target_info{insn_idx}{$va + $pos}; if ($$insn{size}) { $dis_buf = substr $dis_buf, $$insn{size}; next; }; # get insn hash from disassembler $insn = disasm_addr( $dis_buf, $max ); if ( ! $insn ) { # invalid instruction -- skip a byte and cont $$insn{size} = 1; $dis_buf = substr $dis_buf, 1; next; }; $$insn{va} = $va + $pos; $$insn{offset} = $offset + $pos; # store hexadecimal bytes representing insn in an array $hex_str = ""; for ( $x = 0; $x < $$insn{size}; $x ++ ) { $hex_str .= "C"; } @{$$insn{bytes}} = unpack $hex_str, $dis_buf; # add insn to list push(@{$target_info{insns}}, $insn); $$target_info{insn_idx}{$$insn{va}} = $insn; # check operands for data disasm_check_insn( $insn ); # follow flow of execution if ( $$insn{type} =~ /(CALL)|(BRANCH)/ ) { $n_va = disasm_branch_target( $insn, $$insn{dest}, $$insn{dtype} ); if ( disasm_is_code_addr( $n_va ) ) { $n_off = disasm_va2off($n_va); if ( $$insn{type} =~ /CALL/ ) { # create function new_func( $n_va, $n_off, 0 ); } else { new_name( $n_va, "loc_$va", "LABEL" ); } new_xref( $$insn{va}, $n_va, "x" ); if ( $follow ) { disasm_buffer( $buf, $n_off, $n_va, $size, 1 ); } } } if ( $follow && $$insn{type} =~/(RET)|(BRANCH\W)/ ) { # stop disassembly $pos = $max; } # advance buffer position $dis_buf = substr $dis_buf, $$insn{size}; } } sub disasm_section { local($sec) = shift; local($buf) = shift; $opt_quiet || print "Disassembling Section $$sec{name}\n"; disasm_buffer($buf, $$sec{offset}, $$sec{va}, $$sec{size}, 0); return(1); } #=============================================================================== # Output routines sub print_usage { print "x86 Disassembler: IA32 disassembler based on libdisasm.so\n"; print " (c) 2002 the bastard disassembler project\n"; print " http://bastard.sourceforge.net\n"; print "Usage:\tx86disam.pl [options...] file\n"; print "\t\t-c Output intermediate code\n"; print "\t\t-i Output Intel syntax\n"; print "\t\t-a Output AT\&T syntax [default]\n"; print "\t\t-f Disassemble forward from entry point\n"; print "\t\t-t Disassemble executable code sections [default]\n"; print "\t\t-p Use program headers for ELF info\n"; print "\t\t-s Use section headers for ELF info [default]\n"; print "\t\t-x Display cross-references\n"; print "\t\t-q Suppress visual feedback\n"; print "\tAdvanced options:\n"; print "\t\t-e entry\tDisassemble from address 'entry'\n"; print "\t\t-S section\tDisassemble section named 'section'\n"; print "\t\t-H number\tNumber of hexadecimal bytes to print\n"; } sub addr_format { local($addr) = shift; local($type) = shift; local($insn, $sym); #if va->insn_idx->name $insn = $$target_info{insn_idx}{$addr}; if ( $$insn{name} ) { return $$insn{name}; } #if symbol [e.g. import] return symbol name $sym = $$target_info{sym_idx}{$addr}; if ( $$sym{name} ) { return $$sym{name}; } # else, just print address if ( $opt_intel ) { return sprintf "0x%08X", $addr; } else { if ( $type =~ /OP_ADDR/ ) { return sprintf "*0x%08X", $addr; } if ( $type =~ /DISP32/ ) { return sprintf "0x%08X", $addr; } return sprintf "\$0x%X", $addr; } } sub op_format { local($next_va) = shift; local($op) = shift; local($optype) = shift; local($disp,$scale,$index,$base,$flags,$buf); if ( $optype =~ /OP_REL/ ) { $op += $next_va; $optype =~ s/OP_REL/OP_ADDR/; } if ( $optype =~ /OP_OFF/ ) { # these are either offets to eip or va's if ( $optype =~ /OP_BYTE/ ) { $op += $next_va; } $optype =~ s/OP_OFF/OP_ADDR/; } if ( $opt_intel ) { if ( $optype =~ /OP_EADDR/ ) { ($disp,$scale,$index,$base,$flags) = split /:/, $op; $buf = "["; if ( $base ) { $buf .= $base; } if ( $index ) { if ( $base ) { $buf .= "+"; } if ( $scale ) { $buf .= "($index*$scale)"; } else { $buf .= $index; } } if ( $disp ) { if ( $base || $index ) { $buf .= "+"; } if ( $flags =~ /DISP32/ ) { $buf .= addr_format($disp, "DISP32"); } else { $buf .= $disp; } } $buf .="]"; return $buf; } if ( $optype =~ /OP_IMM/ ) { if ( $optype =~ /OP_SIGNED/ || $optype =~ /OP_BYTE/ ) { return sprintf "%d", $op; } else { return addr_format($op, "OP_IMM"); } } if ( $optype =~ /OP_ADDR/ ) { return addr_format($op, "OP_ADDR"); } return $op; } else { if ( $optype =~ /OP_EADDR/ ) { ($disp,$scale,$index,$base,$flags) = split /:/, $op; if ( $flags =~ /DISP32/ ) { $buf = addr_format($disp, "DISP32"); } else { $buf = $disp; } $buf .= "($base"; if ( $index ) { $buf .= ",$index"; } if ($scale) { $buf .= ",$scale"; } elsif ( $disp && ! $base && ! $index ) { # AT&T/GNU as 'syntax exception $buf .= ",1"; } $buf .= ")"; return $buf; } if ( $optype =~ /OP_REG/ ) { return "%$op"; } if ( $optype =~ /OP_IMM/ ) { if ( $optype =~ /OP_SIGNED/ || $optype =~ /OP_BYTE/ ) { return sprintf "\$%d", $op; } else { return addr_format($op, "OP_IMM"); } } if ( $optype =~ /OP_ADDR/ ) { return addr_format($op, "OP_ADDR"); } } return $op; } sub insn_format { local($insn) = shift; local($optype) = shift; if ( $opt_intel ) { return $insn; } if ($optype =~ /OPSIZE_([A-Z0-9]+)/) { if ( $1 =~ /BYTE/ && $insn !~ /^j/ ) { return $insn . "b"; } elsif ($1 =~ /HWORD/ && $insn !~ /^j/ ) { return $insn . "w"; } elsif ($1 =~ /DWORD/ && $insn !~ /^j/ ) { return $insn . "q"; } elsif ($1 =~ /^WORD/ ) { if ( $insn eq "jmp" ) { return "ljmp"; } if ( $insn eq "call" ) { return "lcall"; } if ( $insn =~ /^j/ ) {return $insn; } return $insn ."l"; } } return $insn; } sub addr_output { local($va) = shift; local($size) = shift; local($bytes) = shift; local($name) = shift; local($x); if ( $name ) { print "$name:\n"; } printf "%08X: ", $va; for ($x = 0; $x < $opt_hexbytes; $x++ ) { if ( $x < $size ) { printf "%02X ",$$bytes[$x]; } else { print " "; } } return; } sub insn_prefix { local($type) = shift; local($prefix); if ($type =~ /INS_LOCK/ ) { $prefix .= "lock "; } elsif ( $type =~ /INS_REPNZ/ ) { $prefix .= "repnz "; } elsif ( $type =~ /INS_REPZ/ ) { $prefix .= "repz "; } elsif ( $type =~ /SEG_([A-Z]+)/ ) { $prefix .= lc($1) . ": "; } return $prefix; } sub insn_output { local($insn) = shift; local($from, $func); $func = $$target_info{func_idx}{$$insn{va}}; if ( $$func{va} ) { print "\n"; print ";-------------------------------------------\n"; print "; Subroutine $$func{name}\n\n"; } addr_output( $$insn{va}, $$insn{size}, $$insn{bytes}, $$insn{name} ); if ( $$insn{mnemonic} ) { printf "\t%s", insn_prefix($${type}); printf "%s\t", insn_format($$insn{mnemonic}, $$insn{dtype}); if ( $opt_intel ) { if ( $$insn{dtype} ) { printf "%s", op_format($$insn{va}+$$insn{size}, $$insn{dest}, $$insn{dtype}); if ( $$insn{stype} ) { printf ", %s", op_format($$insn{va} + $$insn{size}, $$insn{src}, $$insn{stype} ); } if ( $$insn{atype} ) { printf ", %s", op_format($$insn{va} + $$insn{size}, $$insn{aux}, $$insn{atype} ); } } } else { if ( $$insn{stype} ) { printf "%s", op_format($$insn{va}+$$insn{size}, $$insn{src}, $$insn{stype} ); } if ( $$insn{dtype} ) { if ( $$insn{stype} ) { print ", "; } printf "%s", op_format($$insn{va}+$$insn{size}, $$insn{dest}, $$insn{dtype}); } if ( $$insn{atype} ) { printf ", %s", op_format($$insn{va} + $$insn{size}, $$insn{aux}, $$insn{atype} ); } } print "\n"; # print xrefs if ( $opt_xref ) { foreach ( xrefs_to($$insn{va}) ) { $from = addr_format($$_{from}, "OP_ADDR"); $from =~ s/^\*//g; print "\t\t\t\t\t; "; print "XREF ($$_{type}) from $from\n"; } } # print an extra line if this was a ret print "\n\n" if ( $$insn{type} =~ /INS_RET/ ); print "\n" if ( $$insn{type} =~ /(INS_BRANCH)|(INS_CALL)/ ); } else { print "\t\n"; } return; } sub data_output { local($data) = shift; local($string, $from); addr_output( $$data{va}, $$data{size}, $$data{bytes}, $$data{name} ); if ( $$data{type} =~ "STRING" ) { $string = $$target_info{string_idx}{$$data{va}}; print "\t ; String '$$string{string}'"; } print "\n"; # print xrefs if ( $opt_xref ) { foreach ( xrefs_to($$data{va}) ) { $from = addr_format($$_{from}, "OP_ADDR"); $from =~ s/^\*//g; print "\t\t\t\t\t; XREF ($$_{type}) from $from\n"; } } return; } sub asm_output { foreach ( keys( %{$$target_info{sections}} ) ) { $sec = $$target_info{sections}{$_}; print "---------------------------------------------------\n"; printf "; SECTION %s va %08X size 0x%X\n\n", $$sec{name}, $$sec{va}, $$sec{size}; if ( $$sec{type} =~ /CODE/ ) { # print code foreach( sort keys( %{$$target_info{insn_idx}} ) ) { if ( $_ >= $$sec{va} && $_ < $$sec{va} + $$sec{size} ) { insn_output( $$target_info{insn_idx}{$_} ); } } } else { # print data foreach( sort keys( %{$$target_info{data_idx}} ) ) { if ( $_ >= $$sec{va} && $_ < $$sec{va} + $$sec{size} ) { data_output( $$target_info{data_idx}{$_} ); } } } print "\n\n\n"; # mark end of section } return; } # Output intermediate code: Just output every field of all hashes sub int_output { local($ptr); local($buf); # print target info print "#TARGET|name|entry_va|entry_offset|size|endian|bits\n"; printf "TARGET|%s|0x%08X|0x%X|$d|%d|%s\n", $target_info{name}, $target_info{entry}, $target_info{entry_offset}, $target_info{size}, $target_info{endian}, $target_info{bits}; # print sections print "#SEC|va|offset|size|type|perm|name\n"; foreach ( keys( %{$$target_info{sections}} ) ) { $ptr = $$target_info{sections}{$_}; printf "SEC|0x%08X|0x%X|%d|", $$ptr{va}, $$ptr{offset}, $$ptr{size}; print "$$ptr{type}|$$ptr{perm}|$$ptr{name}\n"; } # print symbols print "#SYM|va|offset|type|name\n"; foreach $ptr ( @{$target_info{symbols}} ) { printf "SYM|0x%08X|0x%X|", $$ptr{va}, $$ptr{offset}; print "$$ptr{type}|$$ptr{name}\n"; } #print names print "#NAME|va|type|name\n"; foreach $ptr ( @{$target_info{names}} ) { printf "NAME|0x%08X|%s|%s\n", $$ptr{va}, $$ptr{type}, $$ptr{name}; } # print instructions print "#INSN|va|offset|size|hex|mnemonic|type|"; print "src|type|perm|dest|type|perm|aux|type|perm|name\n"; foreach $ptr ( @{$target_info{insns}} ) { $buf = ""; printf "INSN|0x%08X|0x%X|%d|",$$ptr{va},$$ptr{offset}, $$ptr{size}; foreach ( @{$$ptr{bytes}} ) { $buf .= sprintf "%02X ", $_; } $buf =~ s/\s*$//g; print "$buf|$$ptr{mnemonic}|$$ptr{type}|"; print "$$ptr{src}|$$ptr{stype}|$$ptr{sprm}|"; print "$$ptr{dest}|$$ptr{dtype}|$$ptr{dprm}|"; print "$$ptr{aux}|$$ptr{atype}|$$ptr{aprm}|"; print "$$ptr{name}"; print "\n"; } #print functions print "#FUNC|va|offset|name\n"; foreach $ptr ( @{$target_info{functions}} ) { printf "FUNC|0x%08X|0x%X|%s\n", $$ptr{va}, $$ptr{offset}, $$ptr{name}; } #print data print "#DATA|va|offset|size|bytes|type|name\n"; foreach $ptr ( @{$target_info{data}} ) { printf "DATA|0x%08X|0x%X|%d|", $$ptr{va}, $$ptr{offset}, $$ptr{size}; $buf=""; foreach ( @{$$ptr{bytes}} ) { $buf .= sprintf "%02X ", $_; } $buf =~ s/\s*$//g; print "$buf|$$ptr{type}|$$ptr{name}\n"; } #print strings print "#STRING|va|offset|string\n"; foreach $ptr ( @{$target_info{strings}} ) { $$ptr{string} =~ s/\n/\\n/; # escape newlines :) printf "STRING|0x%08X|0x%X|%s\n", $$ptr{va}, $$ptr{offset}, $$ptr{string}; } #print xrefs print "#XREF|from|to|type|name\n"; foreach $ptr ( @{$target_info{xrefs}} ) { printf "XREF|0x%08X|0x%08X|%s|%s\n", $$ptr{from}, $$ptr{to}, $$ptr{type}, $$ptr{name}; } return; } ================================================================================ B: Source code for i386.opcode.map The entire source code for the opcode map used in libdisasm, and which the Perl disassembler was written to parse, is provided below. Its location should be recorded in the $opcode_dir and $opcode_file variables at the start of x86disasm.pl; if the bastard is installed locally, the share/bastard directory is an ideal location. The opcode maps have not been rewritten in Perl in order to demonstrate how to reuse C code from existing disassemblers; the reader is welcome to perform this task themselves in order to have a more portable [in the mobile sense of the word] Perl script. Those who printed Appendix A are warned that the contents of Appendix B run over 1300 lines in length. /* ======================================= OPCODE TABLES =================== */ /* Format: table, mnemonic flags, dest operand flags, src operand flags, aux operand flags, minimim CPU model [unused], mnemonic text, dest operand text, src operand text, aux operand text Credits: Derived [with permission] from the opcode tables of Borg by Cronos */ instr tbl_Main[] = { { 0, INS_ADD, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_G | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "add", 0, 0, 0}, /* 0x0 */ { 0, INS_ADD, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "add", 0, 0, 0}, /* 0x1 */ { 0, INS_ADD, ADDRMETH_G | OPTYPE_b | OP_W, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "add", 0, 0, 0}, /* 0x2 */ { 0, INS_ADD, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "add", 0, 0, 0}, /* 0x3 */ { 0, INS_ADD, OP_REG | OP_W, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "add", 0 + REG_BYTE_OFFSET, 0, 0}, /* 0x4 */ { 0, INS_ADD, OP_REG | OP_W, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "add", 0 + REG_DWORD_OFFSET, 0, 0}, /* 0x5 */ {0, INS_PUSH, OP_REG | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "push", 0 + REG_SEG_OFFSET, 0, 0}, /* 0x6 */ {0, INS_POP, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "pop", 0 + REG_SEG_OFFSET, 0, 0}, /* 0x7 */ { 0, INS_OR, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_G | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "or", 0, 0, 0}, /* 0x8 */ { 0, INS_OR, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "or", 0, 0, 0}, /* 0x9 */ { 0, INS_OR, ADDRMETH_G | OPTYPE_b | OP_W, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "or", 0, 0, 0}, /* 0xA */ { 0, INS_OR, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "or", 0, 0, 0}, /* 0xB */ { 0, INS_OR, OP_REG | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "or", 0 + REG_BYTE_OFFSET, 0, 0}, /* 0xC */ { 0, INS_OR, OP_REG | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "or", 0 + REG_DWORD_OFFSET, 0, 0}, /* 0xD */ {0, INS_PUSH, OP_REG | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "push", 1 + REG_SEG_OFFSET, 0, 0}, /* 0xE */ {1, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0xF */ { 0, INS_ADD, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_G | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "adc", 0, 0, 0}, /* 0x10 */ { 0, INS_ADD, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "adc", 0, 0, 0}, /* 0x11 */ { 0, INS_ADD, ADDRMETH_G | OPTYPE_b | OP_W, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "adc", 0, 0, 0}, /* 0x12 */ { 0, INS_ADD, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "adc", 0, 0, 0}, /* 0x13 */ { 0, INS_ADD, OP_REG | OP_W, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "adc", 0 + REG_BYTE_OFFSET, 0, 0}, /* 0x14 */ { 0, INS_ADD, OP_REG | OP_W, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "adc", 0 + REG_DWORD_OFFSET, 0, 0}, /* 0x15 */ {0, INS_PUSH, OP_REG | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "push", 2 + REG_SEG_OFFSET, 0, 0}, /* 0x16 */ {0, INS_POP, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "pop", 2 + REG_SEG_OFFSET, 0, 0}, /* 0x17 */ { 0, INS_SUB, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_G | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "sbb", 0, 0, 0}, /* 0x18 */ { 0, INS_SUB, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "sbb", 0, 0, 0}, /* 0x19 */ { 0, INS_SUB, ADDRMETH_G | OPTYPE_b | OP_W, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "sbb", 0, 0, 0}, /* 0x1A */ { 0, INS_SUB, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "sbb", 0, 0, 0}, /* 0x1B */ { 0, INS_SUB, OP_REG | OP_W, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "sbb", 0 + REG_BYTE_OFFSET, 0, 0}, /* 0x1C */ { 0, INS_SUB, OP_REG | OP_W, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "sbb", 0 + REG_DWORD_OFFSET, 0, 0}, /* 0x1D */ {0, INS_PUSH, OP_REG | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "push", 3 + REG_SEG_OFFSET, 0, 0}, /* 0x1E */ {0, INS_POP, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "pop", 3 + REG_SEG_OFFSET, 0, 0}, /* 0x1F */ { 0, INS_AND, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_G | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "and", 0, 0, 0}, /* 0x20 */ { 0, INS_AND, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "and", 0, 0, 0}, /* 0x21 */ { 0, INS_AND, ADDRMETH_G | OPTYPE_b | OP_W, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "and", 0, 0, 0}, /* 0x22 */ { 0, INS_AND, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "and", 0, 0, 0}, /* 0x23 */ { 0, INS_AND, OP_REG | OP_W, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "and", 0 + REG_BYTE_OFFSET, 0, 0}, /* 0x24 */ { 0, INS_AND, OP_REG | OP_W, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "and", 0 + REG_DWORD_OFFSET, 0, 0}, /* 0x25 */ { 0, INSTR_PREFIX, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0x26 */ {0, INS_BCDCONV, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "daa", 0, 0, 0}, /* 0x27 */ { 0, INS_SUB, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_G | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "sub", 0, 0, 0}, /* 0x28 */ { 0, INS_SUB, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "sub", 0, 0, 0}, /* 0x29 */ { 0, INS_SUB, ADDRMETH_G | OPTYPE_b | OP_W, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "sub", 0, 0, 0}, /* 0x2A */ { 0, INS_SUB, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "sub", 0, 0, 0}, /* 0x2B */ { 0, INS_SUB, OP_REG | OP_W, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "sub", 0 + REG_BYTE_OFFSET, 0, 0}, /* 0x2C */ { 0, INS_SUB, OP_REG | OP_W, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "sub", 0 + REG_DWORD_OFFSET, 0, 0}, /* 0x2D */ { 0, INSTR_PREFIX, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0x2E */ {0, INS_BCDCONV, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "das", 0, 0, 0}, /* 0x2F */ { 0, INS_XOR, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_G | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "xor", 0, 0, 0}, /* 0x30 */ { 0, INS_XOR, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "xor", 0, 0, 0}, /* 0x31 */ { 0, INS_XOR, ADDRMETH_G | OPTYPE_b | OP_W, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "xor", 0, 0, 0}, /* 0x32 */ { 0, INS_XOR, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "xor", 0, 0, 0}, /* 0x33 */ { 0, INS_XOR, OP_REG | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "xor", 0 + REG_BYTE_OFFSET, 0, 0}, /* 0x34 */ { 0, INS_XOR, OP_REG | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "xor", 0 + REG_DWORD_OFFSET, 0, 0}, /* 0x35 */ { 0, INSTR_PREFIX, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0x36 */ {0, INS_BCDCONV, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "aaa", 0, 0, 0}, /* 0x37 */ { 0, INS_CMP, ADDRMETH_E | OPTYPE_b | OP_R, ADDRMETH_G | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "cmp", 0, 0, 0}, /* 0x38 */ { 0, INS_CMP, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "cmp", 0, 0, 0}, /* 0x39 */ { 0, INS_CMP, ADDRMETH_G | OPTYPE_b | OP_R, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "cmp", 0, 0, 0}, /* 0x3A */ { 0, INS_CMP, ADDRMETH_G | OPTYPE_v | OP_R, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "cmp", 0, 0, 0}, /* 0x3B */ { 0, INS_CMP, OP_REG | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "cmp", 0 + REG_BYTE_OFFSET, 0, 0}, /* 0x3C */ { 0, INS_CMP, OP_REG | OP_R, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "cmp", 0 + REG_DWORD_OFFSET, 0, 0}, /* 0x3D */ { 0, INSTR_PREFIX, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0x3E */ {0, INS_BCDCONV, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "aas", 0, 0, 0}, /* 0x3F */ { 0, INS_INC, OP_REG | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "inc", 0 + REG_DWORD_OFFSET, 0, 0}, /* 0x40 */ { 0, INS_INC, OP_REG | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "inc", 1 + REG_DWORD_OFFSET, 0, 0}, /* 0x41 */ { 0, INS_INC, OP_REG | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "inc", 2 + REG_DWORD_OFFSET, 0, 0}, /* 0x42 */ { 0, INS_INC, OP_REG | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "inc", 3 + REG_DWORD_OFFSET, 0, 0}, /* 0x43 */ { 0, INS_INC, OP_REG | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "inc", 4 + REG_DWORD_OFFSET, 0, 0}, /* 0x44 */ { 0, INS_INC, OP_REG | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "inc", 5 + REG_DWORD_OFFSET, 0, 0}, /* 0x45 */ { 0, INS_INC, OP_REG | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "inc", 6 + REG_DWORD_OFFSET, 0, 0}, /* 0x46 */ { 0, INS_INC, OP_REG | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "inc", 7 + REG_DWORD_OFFSET, 0, 0}, /* 0x47 */ { 0, INS_DEC, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "dec", 0 + REG_DWORD_OFFSET, 0, 0}, /* 0x48 */ { 0, INS_DEC, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "dec", 1 + REG_DWORD_OFFSET, 0, 0}, /* 0x49 */ { 0, INS_DEC, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "dec", 2 + REG_DWORD_OFFSET, 0, 0}, /* 0x4A */ { 0, INS_DEC, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "dec", 3 + REG_DWORD_OFFSET, 0, 0}, /* 0x4B */ { 0, INS_DEC, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "dec", 4 + REG_DWORD_OFFSET, 0, 0}, /* 0x4C */ { 0, INS_DEC, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "dec", 5 + REG_DWORD_OFFSET, 0, 0}, /* 0x4D */ { 0, INS_DEC, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "dec", 6 + REG_DWORD_OFFSET, 0, 0}, /* 0x4E */ { 0, INS_DEC, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "dec", 7 + REG_DWORD_OFFSET, 0, 0}, /* 0x4F */ { 0, INS_PUSH, OP_REG | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "push", 0 + REG_DWORD_OFFSET, 0, 0}, /* 0x50 */ { 0, INS_PUSH, OP_REG | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "push", 1 + REG_DWORD_OFFSET, 0, 0}, /* 0x51 */ { 0, INS_PUSH, OP_REG | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "push", 2 + REG_DWORD_OFFSET, 0, 0}, /* 0x52 */ { 0, INS_PUSH, OP_REG | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "push", 3 + REG_DWORD_OFFSET, 0, 0}, /* 0x53 */ { 0, INS_PUSH, OP_REG | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "push", 4 + REG_DWORD_OFFSET, 0, 0}, /* 0x54 */ { 0, INS_PUSH, OP_REG | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "push", 5 + REG_DWORD_OFFSET, 0, 0}, /* 0x55 */ { 0, INS_PUSH, OP_REG | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "push", 6 + REG_DWORD_OFFSET, 0, 0}, /* 0x56 */ { 0, INS_PUSH, OP_REG | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "push", 7 + REG_DWORD_OFFSET, 0, 0}, /* 0x57 */ { 0, INS_POP, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "pop", 0 + REG_DWORD_OFFSET, 0, 0}, /* 0x58 */ { 0, INS_POP, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "pop", 1 + REG_DWORD_OFFSET, 0, 0}, /* 0x59 */ { 0, INS_POP, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "pop", 2 + REG_DWORD_OFFSET, 0, 0}, /* 0x5A */ { 0, INS_POP, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "pop", 3 + REG_DWORD_OFFSET, 0, 0}, /* 0x5B */ { 0, INS_POP, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "pop", 4 + REG_DWORD_OFFSET, 0, 0}, /* 0x5C */ { 0, INS_POP, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "pop", 5 + REG_DWORD_OFFSET, 0, 0}, /* 0x5D */ { 0, INS_POP, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "pop", 6 + REG_DWORD_OFFSET, 0, 0}, /* 0x5E */ { 0, INS_POP, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "pop", 7 + REG_DWORD_OFFSET, 0, 0}, /* 0x5F */ { 0, INS_PUSHREGS, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "pushad", 0, 0, 0}, /* 0x60 */ { 0, INS_POPREGS, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "popad", 0, 0, 0}, /* 0x61 */ { 0, INS_BOUNDS, ADDRMETH_G | OPTYPE_v | OP_R, ADDRMETH_M | OPTYPE_a | OP_R, ARG_NONE, cpu_80386, "bound", 0, 0, 0}, /* 0x62 */ { 0, INS_SYSTEM, ADDRMETH_E | OPTYPE_w | OP_R, ADDRMETH_G | OPTYPE_w | OP_R, ARG_NONE, cpu_80386, "arpl", 0, 0, 0}, /* 0x63 */ { 0, INSTR_PREFIX, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0x64 */ { 0, INSTR_PREFIX, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0x65 */ { 0, INSTR_PREFIX, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0x66 */ { 0, INSTR_PREFIX, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0x67 */ { 0, INS_PUSH, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "push", 0, 0, 0}, /* 0x68 */ { 0, INS_MUL, ADDRMETH_G | OPTYPE_v | OP_R, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_I | OP_SIGNED | OP_R, cpu_80386, "imul", 0, 0, 0}, /* 0x69 */ {0, INS_PUSH, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "push", 0, 0, 0}, /* 0x6A */ { 0, INS_MUL, ADDRMETH_G | OPTYPE_v | OP_R, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_I | OP_SIGNED | OP_R, cpu_80386, "imul", 0, 0, 0}, /* 0x6B */ {0, INS_IN, ADDRMETH_Y | OPTYPE_b | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "insb", 0, 2 + REG_DWORD_OFFSET, 0}, /* 0x6C */ {0, INS_IN, ADDRMETH_Y | OPTYPE_v | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "insd", 0, 2 + REG_DWORD_OFFSET, 0}, /* 0x6D */ {0, INS_OUT, OP_REG | OP_W, ADDRMETH_X | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "outsb", 2 + REG_DWORD_OFFSET, 0, 0}, /* 0x6E */ {0, INS_OUT, OP_REG | OP_W, ADDRMETH_X | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "outsb", 2 + REG_DWORD_OFFSET, 0, 0}, /* 0x6F */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jo", 0, 0, 0}, /* 0x70 */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jno", 0, 0, 0}, /* 0x71 */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jc", 0, 0, 0}, /* 0x72 */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jnc", 0, 0, 0}, /* 0x73 */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jz", 0, 0, 0}, /* 0x74 */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jnz", 0, 0, 0}, /* 0x75 */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jbe", 0, 0, 0}, /* 0x76 */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "ja", 0, 0, 0}, /* 0x77 */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "js", 0, 0, 0}, /* 0x78 */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jns", 0, 0, 0}, /* 0x79 */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jpe", 0, 0, 0}, /* 0x7A */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jpo", 0, 0, 0}, /* 0x7B */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jl", 0, 0, 0}, /* 0x7C */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jge", 0, 0, 0}, /* 0x7D */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jle", 0, 0, 0}, /* 0x7E */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jg", 0, 0, 0}, /* 0x7F */ {2, 0, ADDRMETH_E | OPTYPE_b, ADDRMETH_I | OPTYPE_b, ARG_NONE,cpu_80386, 0, 0, 0, 0}, /* 0x80 */ {3, 0, ADDRMETH_E | OPTYPE_v, ADDRMETH_I | OPTYPE_v, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0x81 */ {4, 0, ADDRMETH_E | OPTYPE_v, ADDRMETH_I | OPTYPE_b, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0x82 */ {5, 0, ADDRMETH_E | OPTYPE_v, ADDRMETH_I | OPTYPE_b, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0x83 */ { 0, INS_TEST, ADDRMETH_E | OPTYPE_b | OP_R, ADDRMETH_G | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "test", 0, 0, 0}, /* 0x84 */ { 0, INS_TEST, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "test", 0, 0, 0}, /* 0x85 */ { 0, INS_XCHG, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_G | OPTYPE_b | OP_W, ARG_NONE, cpu_80386, "xchg", 0, 0, 0}, /* 0x86 */ { 0, INS_XCHG, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_G | OPTYPE_v | OP_W, ARG_NONE, cpu_80386, "xchg", 0, 0, 0}, /* 0x87 */ { 0, INS_MOV, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_G | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "mov", 0, 0, 0}, /* 0x88 */ { 0, INS_MOV, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "mov", 0, 0, 0}, /* 0x89 */ { 0, INS_MOV, ADDRMETH_G | OPTYPE_b | OP_W, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "mov", 0, 0, 0}, /* 0x8A */ { 0, INS_MOV, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "mov", 0, 0, 0}, /* 0x8B */ { 0, INS_MOV, ADDRMETH_E | OPTYPE_w | OP_W, ADDRMETH_S | OPTYPE_w | OP_R, ARG_NONE, cpu_80386, "mov", 0, 0, 0}, /* 0x8C */ { 0, INS_MOV, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_M | OPTYPE_m | OP_R, ARG_NONE, cpu_80386, "lea", 0, 0, 0}, /* 0x8D */ { 0, INS_MOV, ADDRMETH_S | OPTYPE_w | OP_W, ADDRMETH_E | OPTYPE_w | OP_R, ARG_NONE, cpu_80386, "mov", 0, 0, 0}, /* 0x8E */ { 0, INS_POP, ADDRMETH_E | OPTYPE_v | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "pop", 0, 0, 0}, /* 0x8F */ {0, INS_NOP, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "nop", 0, 0, 0}, /* 0x90 */ { 0, INS_XCHG, OP_REG | OP_W, OP_REG | OP_W, ARG_NONE, cpu_80386, "xchg", 0 + REG_DWORD_OFFSET, 1 + REG_DWORD_OFFSET, 0}, /* 0x91 */ { 0, INS_XCHG, OP_REG | OP_W, OP_REG | OP_W, ARG_NONE, cpu_80386, "xchg", 0 + REG_DWORD_OFFSET, 2 + REG_DWORD_OFFSET, 0}, /* 0x92 */ { 0, INS_XCHG, OP_REG | OP_W, OP_REG | OP_W, ARG_NONE, cpu_80386, "xchg", 0 + REG_DWORD_OFFSET, 3 + REG_DWORD_OFFSET, 0}, /* 0x93 */ { 0, INS_XCHG, OP_REG | OP_W, OP_REG | OP_W, ARG_NONE, cpu_80386, "xchg", 0 + REG_DWORD_OFFSET, 4 + REG_DWORD_OFFSET, 0}, /* 0x94 */ { 0, INS_XCHG, OP_REG | OP_W, OP_REG | OP_W, ARG_NONE, cpu_80386, "xchg", 0 + REG_DWORD_OFFSET, 5 + REG_DWORD_OFFSET, 0}, /* 0x95 */ { 0, INS_XCHG, OP_REG | OP_W, OP_REG | OP_W, ARG_NONE, cpu_80386, "xchg", 0 + REG_DWORD_OFFSET, 6 + REG_DWORD_OFFSET, 0}, /* 0x96 */ { 0, INS_XCHG, OP_REG | OP_W, OP_REG | OP_W, ARG_NONE, cpu_80386, "xchg", 0 + REG_DWORD_OFFSET, 7 + REG_DWORD_OFFSET, 0}, /* 0x97 */ { 0, INS_SZCONV, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "cwde", 0, 0, 0}, /* 0x98 */ { 0, INS_SZCONV, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "cdq", 0, 0, 0}, /* 0x99 */ { 0, INS_CALL, ADDRMETH_A | OPTYPE_p | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "callf", 0, 0, 0}, /* 0x9A */ {0, INS_SYSTEM, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "wait", 0, 0, 0}, /* 0x9B */ { 0, INS_PUSHFLAGS, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "pushfd", 0, 0, 0}, /* 0x9C */ { 0, INS_POPFLAGS, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "popfd", 0, 0, 0}, /* 0x9D */ {0, INS_MOV, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "sahf", 0, 0, 0}, /* 0x9E */ {0, INS_MOV, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "lahf", 0, 0, 0}, /* 0x9F */ { 0, INS_MOV, OP_REG | OP_W, ADDRMETH_O | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "mov", 0 + REG_BYTE_OFFSET, 0, 0}, /* 0xA0 */ { 0, INS_MOV, OP_REG | OP_W, ADDRMETH_O | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "mov", 0 + REG_DWORD_OFFSET, 0, 0}, /* 0xA1 */ { 0, INS_MOV, ADDRMETH_O | OPTYPE_b | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "mov", 0, 0 + REG_BYTE_OFFSET, 0}, /* 0xA2 */ { 0, INS_MOV, ADDRMETH_O | OPTYPE_v | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "mov", 0, 0 + REG_DWORD_OFFSET, 0}, /* 0xA3 */ {0, INS_STRMOV, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "movsb", 0, 0, 0}, /* 0xA4 */ { 0, INS_STRMOV, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "movsd", 0, 0, 0}, /* 0xA5 */ {0, INS_STRCMP, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "cmpsb", 0, 0, 0}, /* 0xA6 */ { 0, INS_STRCMP, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "cmpsd", 0, 0, 0}, /* 0xA7 */ { 0, INS_TEST, OP_REG | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "test", 0 + REG_BYTE_OFFSET, 0, 0}, /* 0xA8 */ { 0, INS_TEST, OP_REG | OP_R, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "test", 0 + REG_DWORD_OFFSET, 0, 0}, /* 0xA9 */ {0, INS_STRSTOR, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "stosb", 0, 0, 0}, /* 0xAA */ { 0, INS_STRSTOR, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "stosd", 0, 0, 0}, /* 0xAB */ {0, INS_STRLOAD, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "lodsb", 0, 0, 0}, /* 0xAC */ { 0, INS_STRLOAD, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "lodsd", 0, 0, 0}, /* 0xAD */ {0, INS_STRCMP, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "scasb", 0, 0, 0}, /* 0xAE */ { 0, INS_STRCMP, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "scasd", 0, 0, 0}, /* 0xAF */ { 0, INS_MOV, OP_REG | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "mov", 0 + REG_BYTE_OFFSET, 0, 0}, /* 0xB0 */ { 0, INS_MOV, OP_REG | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "mov", 1 + REG_BYTE_OFFSET, 0, 0}, /* 0xB1 */ { 0, INS_MOV, OP_REG | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "mov", 2 + REG_BYTE_OFFSET, 0, 0}, /* 0xB2 */ { 0, INS_MOV, OP_REG | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "mov", 3 + REG_BYTE_OFFSET, 0, 0}, /* 0xB3 */ { 0, INS_MOV, OP_REG | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "mov", 4 + REG_BYTE_OFFSET, 0, 0}, /* 0xB4 */ { 0, INS_MOV, OP_REG | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "mov", 5 + REG_BYTE_OFFSET, 0, 0}, /* 0xB5 */ { 0, INS_MOV, OP_REG | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "mov", 6 + REG_BYTE_OFFSET, 0, 0}, /* 0xB6 */ { 0, INS_MOV, OP_REG | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "mov", 7 + REG_BYTE_OFFSET, 0, 0}, /* 0xB7 */ { 0, INS_MOV, OP_REG | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "mov", 0 + REG_DWORD_OFFSET, 0, 0}, /* 0xB8 */ { 0, INS_MOV, OP_REG | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "mov", 1 + REG_DWORD_OFFSET, 0, 0}, /* 0xB9 */ { 0, INS_MOV, OP_REG | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "mov", 2 + REG_DWORD_OFFSET, 0, 0}, /* 0xBA */ { 0, INS_MOV, OP_REG | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "mov", 3 + REG_DWORD_OFFSET, 0, 0}, /* 0xBB */ { 0, INS_MOV, OP_REG | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "mov", 4 + REG_DWORD_OFFSET, 0, 0}, /* 0xBC */ { 0, INS_MOV, OP_REG | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "mov", 5 + REG_DWORD_OFFSET, 0, 0}, /* 0xBD */ { 0, INS_MOV, OP_REG | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "mov", 6 + REG_DWORD_OFFSET, 0, 0}, /* 0xBE */ { 0, INS_MOV, OP_REG | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "mov", 7 + REG_DWORD_OFFSET, 0, 0}, /* 0xBF */ {6, 0, ADDRMETH_E | OPTYPE_b, ADDRMETH_I | OPTYPE_b, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0xC0 */ {7, 0, ADDRMETH_E | OPTYPE_v, ADDRMETH_I | OPTYPE_b, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0xC1 */ { 0, INS_RET, ADDRMETH_I | OPTYPE_w | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "ret", 0, 0, 0}, /* 0xC2 */ { 0, INS_RET, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "ret", 0, 0, 0}, /* 0xC3 */ { 0, INS_MOV, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_M | OPTYPE_p | OP_R, ARG_NONE, cpu_80386, "les", 0, 0, 0}, /* 0xC4 */ { 0, INS_MOV, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_M | OPTYPE_p | OP_R, ARG_NONE, cpu_80386, "lds", 0, 0, 0}, /* 0xC5 */ { 0, INS_MOV, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "mov", 0, 0, 0}, /* 0xC6 */ { 0, INS_MOV, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "mov", 0, 0, 0}, /* 0xC7 */ { 0, INS_ENTER, ADDRMETH_I | OPTYPE_w | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "enter", 0, 0, 0}, /* 0xC8 */ {0, INS_LEAVE, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "leave", 0, 0, 0}, /* 0xC9 */ { 0, INS_RET, ADDRMETH_I | OPTYPE_w | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "retf", 0, 0, 0}, /* 0xCA */ { 0, INS_RET, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "retf", 0, 0, 0}, /* 0xCB */ {0, INS_DEBUG, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "int3", 0, 0, 0}, /* 0xCC */ { 0, INS_TRAP, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "int", 0, 0, 0}, /* 0xCD */ {0, INS_OFLOW, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "into", 0, 0, 0}, /* 0xCE */ { 0, INS_TRET, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "iret", 0, 0, 0}, /* 0xCF */ {8, 0, ADDRMETH_E | OPTYPE_b, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 1, 0}, /* 0xD0 */ {9, 0, ADDRMETH_E | OPTYPE_v, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 1, 0}, /* 0xD1 */ {10, 0, ADDRMETH_E | OPTYPE_b, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, REG_BYTE_OFFSET + 1, 0}, /* 0xD2 */ {11, 0, ADDRMETH_E | OPTYPE_v, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, REG_BYTE_OFFSET + 1, 0}, /* 0xD3 */ { 0, INS_BCDCONV, ADDRMETH_I | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "aam", 0, 0, 0}, /* 0xD4 */ { 0, INS_BCDCONV, ADDRMETH_I | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "aad", 0, 0, 0}, /* 0xD5 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0xD6 */ {0, INS_XLAT, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "xlat", 0, 0, 0}, /* 0xD7 */ {26, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0xD8 */ {28, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0xD9 */ {30, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0xDA */ {32, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0xDB */ {34, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0xDC */ {36, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0xDD */ {38, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0xDE */ {40, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0xDF */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "loopnz", 0, 0, 0}, /* 0xE0 */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "loopz", 0, 0, 0}, /* 0xE1 */ { 0, INS_BRANCH, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "loop", 0, 0, 0}, /* 0xE2 */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jcxz", 0, 0, 0}, /* 0xE3 */ { 0, INS_IN, OP_REG | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "in", 0 + REG_BYTE_OFFSET, 0, 0}, /* 0xE4 */ { 0, INS_IN, OP_REG | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "in", 0 + REG_DWORD_OFFSET, 0, 0}, /* 0xE5 */ { 0, INS_OUT, ADDRMETH_I | OPTYPE_b | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "out", 0, 0 + REG_BYTE_OFFSET, 0}, /* 0xE6 */ { 0, INS_OUT, ADDRMETH_I | OPTYPE_b | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "out", 0, 0 + REG_DWORD_OFFSET, 0}, /* 0xE7 */ { 0, INS_CALL, ADDRMETH_J | OPTYPE_v | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "call", 0, 0, 0}, /* 0xE8 */ { 0, INS_BRANCH, ADDRMETH_J | OPTYPE_v | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jmp", 0, 0, 0}, /* 0xE9 */ { 0, INS_BRANCH, ADDRMETH_A | OPTYPE_p | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jmp", 0, 0, 0}, /* 0xEA */ { 0, INS_BRANCH, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jmp", 0, 0, 0}, /* 0xEB */ {0, INS_IN, OP_REG | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "in", 0 + REG_BYTE_OFFSET, 2 + REG_WORD_OFFSET, 0}, /* 0xEC */ { 0, INS_IN, OP_REG | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "in", 0 + REG_DWORD_OFFSET, 2 + REG_WORD_OFFSET, 0}, /* 0xED */ {0, INS_OUT, OP_REG | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "out", 2 + REG_WORD_OFFSET, 0 + REG_BYTE_OFFSET, 0}, /* 0xEE */ { 0, INS_OUT, OP_REG | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "out", 2 + REG_WORD_OFFSET, 0 + REG_DWORD_OFFSET, 0}, /* 0xEF */ { 0, INSTR_PREFIX, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "lock:", 0, 0, 0}, /* 0xF0 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0xF1 */ { 0, INSTR_PREFIX, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "repne:", 0, 0, 0}, /* 0xF2 */ { 0, INSTR_PREFIX, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "rep:", 0, 0, 0}, /* 0xF3 */ {0, INS_HALT, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "hlt", 0, 0, 0}, /* 0xF4 */ {0, INS_TOGCF, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "cmc", 0, 0, 0}, /* 0xF5 */ {12, 0, ADDRMETH_E | OPTYPE_b, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0xF6 */ {13, 0, ADDRMETH_E | OPTYPE_v, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0xF7 */ {0, INS_CLEARCF, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "clc", 0, 0, 0}, /* 0xF8 */ {0, INS_SETCF, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "stc", 0, 0, 0}, /* 0xF9 */ {0, INS_SYSTEM, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "cli", 0, 0, 0}, /* 0xFA */ {0, INS_SYSTEM, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "sti", 0, 0, 0}, /* 0xFB */ {0, INS_CLEARDF, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "cld", 0, 0, 0}, /* 0xFC */ {0, INS_SETDF, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "std", 0, 0, 0}, /* 0xFD */ {14, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0xFE */ {15, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0 } /* 0xFF */, }; instr tbl_0F[] = { {16, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0x0 */ {17, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0x1 */ { 0, INS_SYSTEM, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_w | OP_R, ARG_NONE, cpu_80386, "lar", 0, 0, 0}, /* 0x2 */ { 0, INS_SYSTEM, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_w | OP_R, ARG_NONE, cpu_80386, "lsl", 0, 0, 0}, /* 0x3 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x4 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x5 */ { 0, INS_SYSTEM, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "clts", 0, 0, 0}, /* 0x6 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x7 */ {0, INS_SYSTEM, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80486, "invd", 0, 0, 0}, /* 0x8 */ {0, INS_SYSTEM, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80486, "wbinvd", 0, 0, 0}, /* 0x9 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0xA */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "ud2", 0, 0, 0}, /* 0xB */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0xC */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0xD */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0xE */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0xF */ { 0, INS_MOV, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2, "movups", 0, 0, 0}, /* 0x10 */ { 0, INS_MOV, ADDRMETH_W | OPTYPE_ps | OP_W, ADDRMETH_V | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2, "movups", 0, 0, 0}, /* 0x11 */ { 0, INS_MOV, ADDRMETH_W | OPTYPE_q | OP_W, ADDRMETH_V | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2, "movlps", 0, 0, 0}, /* 0x12 */ { 0, INS_MOV, ADDRMETH_V | OPTYPE_q | OP_W, ADDRMETH_W | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2, "movlps", 0, 0, 0}, /* 0x13 */ { 0, INS_OTHER, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2, "unpcklps", 0, 0, 0}, /* 0x14 */ { 0, INS_OTHER, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2, "unpckhps", 0, 0, 0}, /* 0x15 */ { 0, INS_OTHER, ADDRMETH_V | OPTYPE_q | OP_W, ADDRMETH_W | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2, "movhps", 0, 0, 0}, /* 0x16 */ { 0, INS_OTHER, ADDRMETH_W | OPTYPE_q | OP_W, ADDRMETH_V | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2, "movhps", 0, 0, 0}, /* 0x17 */ {18, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0x18 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x19 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x1A */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x1B */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x1C */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x1D */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x1E */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x1F */ { 0, INS_MOV, ADDRMETH_R | OPTYPE_d | OP_W, ADDRMETH_C | OPTYPE_d | OP_R, ARG_NONE, cpu_80386, "mov", 0, 0, 0}, /* 0x20 */ { 0, INS_MOV, ADDRMETH_R | OPTYPE_d | OP_W, ADDRMETH_D | OPTYPE_d | OP_R, ARG_NONE, cpu_80386, "mov", 0, 0, 0}, /* 0x21 */ { 0, INS_MOV, ADDRMETH_C | OPTYPE_d | OP_W, ADDRMETH_R | OPTYPE_d | OP_R, ARG_NONE, cpu_80386, "mov", 0, 0, 0}, /* 0x22 */ { 0, INS_MOV, ADDRMETH_D | OPTYPE_d | OP_W, ADDRMETH_R | OPTYPE_d | OP_R, ARG_NONE, cpu_80386, "mov", 0, 0, 0}, /* 0x23 */ { 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x24 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x25 */ { 0, INS_MOV, ADDRMETH_I | OP_W, ADDRMETH_I | OP_R, ARG_NONE, cpu_80386|cpu_80486, "mov", 0, 0, 0}, /* 0x26 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x27 */ { 0, INS_MOV, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2, "movaps", 0, 0, 0}, /* 0x28 */ { 0, INS_MOV, ADDRMETH_W | OPTYPE_ps | OP_W, ADDRMETH_V | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2, "movaps", 0, 0, 0}, /* 0x29 */ { 0, INS_OTHER, ADDRMETH_V | OPTYPE_ps | OP_R, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2, "cvtpi2ps", 0, 0, 0}, /* 0x2A */ { 0, INS_MOV, ADDRMETH_W | OPTYPE_ps | OP_W, ADDRMETH_V | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2, "movntps", 0, 0, 0}, /* 0x2B */ { 0, INS_OTHER, ADDRMETH_Q | OPTYPE_q | OP_R, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2, "cvttps2pi", 0, 0, 0}, /* 0x2C */ { 0, INS_OTHER, ADDRMETH_Q | OPTYPE_q | OP_R, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2, "cvtps2pi", 0, 0, 0}, /* 0x2D */ { 0, INS_OTHER, ADDRMETH_V | OPTYPE_ss | OP_W, ADDRMETH_W | OPTYPE_ss | OP_R, ARG_NONE, cpu_PENTIUM2, "ucomiss", 0, 0, 0}, /* 0x2E */ { 0, INS_OTHER, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ss | OP_W, ARG_NONE, cpu_PENTIUM2, "comiss", 0, 0, 0}, /* 0x2F */ {0, INS_SYSTEM, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM, "wrmsr", 0, 0, 0}, /* 0x30 */ {0, INS_SYSTEM, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM, "rdtsc", 0, 0, 0}, /* 0x31 */ {0, INS_SYSTEM, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM, "rdmsr", 0, 0, 0}, /* 0x32 */ {0, INS_OTHER, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTPRO, "rdpmc", 0, 0, 0}, /* 0x33 */ {0, INS_SYSTEM, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM2, "sysenter", 0, 0, 0}, /* 0x34 */ {0, INS_SYSTEM, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM2, "sysexit", 0, 0, 0}, /* 0x35 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x36 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x37 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x38 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x39 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x3A */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x3B */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x3C */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x3D */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x3E */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x3F */ { 0, INS_MOVCC, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO, "cmovo", 0, 0, 0}, /* 0x40 */ { 0, INS_MOVCC, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO, "cmovno", 0, 0, 0}, /* 0x41 */ { 0, INS_MOVCC, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO, "cmovc", 0, 0, 0}, /* 0x42 */ { 0, INS_MOVCC, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO, "cmovnc", 0, 0, 0}, /* 0x43 */ { 0, INS_MOVCC, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO, "cmovz", 0, 0, 0}, /* 0x44 */ { 0, INS_MOVCC, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO, "cmovnz", 0, 0, 0}, /* 0x45 */ { 0, INS_MOVCC, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO, "cmovbe", 0, 0, 0}, /* 0x46 */ { 0, INS_MOVCC, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO, "cmova", 0, 0, 0}, /* 0x47 */ { 0, INS_MOVCC, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO, "cmovs", 0, 0, 0}, /* 0x48 */ { 0, INS_MOVCC, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO, "cmovns", 0, 0, 0}, /* 0x49 */ { 0, INS_MOVCC, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO, "cmovpe", 0, 0, 0}, /* 0x4A */ { 0, INS_MOVCC, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO, "cmovpo", 0, 0, 0}, /* 0x4B */ { 0, INS_MOVCC, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO, "cmovl", 0, 0, 0}, /* 0x4C */ { 0, INS_MOVCC, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO, "cmovge", 0, 0, 0}, /* 0x4D */ { 0, INS_MOVCC, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO, "cmovle", 0, 0, 0}, /* 0x4E */ { 0, INS_MOVCC, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO, "cmovg", 0, 0, 0}, /* 0x4F */ { 0, INS_MOV, ADDRMETH_E | OPTYPE_d | OP_W, ADDRMETH_V | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2, "movmskps", 0, 0, 0}, /* 0x50 */ { 0, INS_ARITH, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2, "sqrtps", 0, 0, 0}, /* 0x51 */ { 0, INS_ARITH, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2, "rsqrtps", 0, 0, 0}, /* 0x52 */ { 0, INS_OTHER, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2, "rcpps", 0, 0, 0}, /* 0x53 */ { 0, INS_AND, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2, "andps", 0, 0, 0}, /* 0x54 */ { 0, INS_AND, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2, "andnps", 0, 0, 0}, /* 0x55 */ { 0, INS_OR, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2, "orps", 0, 0, 0}, /* 0x56 */ { 0, INS_XOR, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2, "xorps", 0, 0, 0}, /* 0x57 */ { 0, INS_ADD, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2, "addps", 0, 0, 0}, /* 0x58 */ { 0, INS_MUL, ADDRMETH_V | OPTYPE_ps | OP_R, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2, "mulps", 0, 0, 0}, /* 0x59 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x5A */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x5B */ { 0, INS_SUB, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2, "subps", 0, 0, 0}, /* 0x5C */ { 0, INS_ARITH, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2, "minps", 0, 0, 0}, /* 0x5D */ { 0, INS_DIV, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2, "divps", 0, 0, 0}, /* 0x5E */ { 0, INS_ARITH, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2, "maxps", 0, 0, 0}, /* 0x5F */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTMMX, "punpcklbw", 0, 0, 0}, /* 0x60 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTMMX, "punpcklwd", 0, 0, 0}, /* 0x61 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTMMX, "punpckldq", 0, 0, 0}, /* 0x62 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTMMX, "packsswb", 0, 0, 0}, /* 0x63 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTMMX, "pcmpgtb", 0, 0, 0}, /* 0x64 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTMMX, "pcmpgtw", 0, 0, 0}, /* 0x65 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTMMX, "pcmpgtd", 0, 0, 0}, /* 0x66 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTMMX, "packuswb", 0, 0, 0}, /* 0x67 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTMMX, "punpckhbw", 0, 0, 0}, /* 0x68 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTMMX, "punpckhwd", 0, 0, 0}, /* 0x69 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTMMX, "punpckhdq", 0, 0, 0}, /* 0x6A */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTMMX, "packssdw", 0, 0, 0}, /* 0x6B */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x6C */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x6D */ { 0, INS_MOV, ADDRMETH_P | OPTYPE_d | OP_W, ADDRMETH_E | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTMMX, "movd", 0, 0, 0}, /* 0x6E */ { 0, INS_MOV, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTMMX, "movq", 0, 0, 0}, /* 0x6F */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, cpu_PENTIUM2, "pshuf", 0, 0, 0}, /* 0x70 */ {19, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTMMX, 0, 0, 0, 0}, /* 0x71 */ {20, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTMMX, 0, 0, 0, 0}, /* 0x72 */ {21, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTMMX, 0, 0, 0, 0}, /* 0x73 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "pcmpeqb", 0, 0, 0}, /* 0x74 */ { 0, INS_CMP, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "pcmpeqw", 0, 0, 0}, /* 0x75 */ { 0, INS_CMP, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "pcmpeqd", 0, 0, 0}, /* 0x76 */ {0, INS_OTHER, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTMMX, "emms", 0, 0, 0}, /* 0x77 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x78 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x79 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x7A */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x7B */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x7C */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x7D */ { 0, INS_MOV, ADDRMETH_E | OPTYPE_d | OP_W, ADDRMETH_P | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTMMX, "movd", 0, 0, 0}, /* 0x7E */ { 0, INS_MOV, ADDRMETH_Q | OPTYPE_q | OP_W, ADDRMETH_P | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "movq", 0, 0, 0}, /* 0x7F */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_v | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jo", 0, 0, 0}, /* 0x80 */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_v | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jno", 0, 0, 0}, /* 0x81 */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_v | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jc", 0, 0, 0}, /* 0x82 */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_v | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jnc", 0, 0, 0}, /* 0x83 */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_v | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jz", 0, 0, 0}, /* 0x84 */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_v | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jnz", 0, 0, 0}, /* 0x85 */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_v | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jbe", 0, 0, 0}, /* 0x86 */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_v | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "ja", 0, 0, 0}, /* 0x87 */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_v | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "js", 0, 0, 0}, /* 0x88 */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_v | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jns", 0, 0, 0}, /* 0x89 */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_v | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jpe", 0, 0, 0}, /* 0x8A */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_v | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jpo", 0, 0, 0}, /* 0x8B */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_v | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jl", 0, 0, 0}, /* 0x8C */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_v | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jge", 0, 0, 0}, /* 0x8D */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_v | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jle", 0, 0, 0}, /* 0x8E */ { 0, INS_BRANCHCC, ADDRMETH_J | OPTYPE_v | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jg", 0, 0, 0}, /* 0x8F */ { 0, INS_MOVCC, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "seto", 0, 0, 0}, /* 0x90 */ { 0, INS_MOVCC, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "setno", 0, 0, 0}, /* 0x91 */ { 0, INS_MOVCC, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "setc", 0, 0, 0}, /* 0x92 */ { 0, INS_MOVCC, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "setnc", 0, 0, 0}, /* 0x93 */ { 0, INS_MOVCC, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "setz", 0, 0, 0}, /* 0x94 */ { 0, INS_MOVCC, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "setnz", 0, 0, 0}, /* 0x95 */ { 0, INS_MOVCC, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "setbe", 0, 0, 0}, /* 0x96 */ { 0, INS_MOVCC, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "seta", 0, 0, 0}, /* 0x97 */ { 0, INS_MOVCC, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "sets", 0, 0, 0}, /* 0x98 */ { 0, INS_MOVCC, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "setns", 0, 0, 0}, /* 0x99 */ { 0, INS_MOVCC, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "setpe", 0, 0, 0}, /* 0x9A */ { 0, INS_MOVCC, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "setpo", 0, 0, 0}, /* 0x9B */ { 0, INS_MOVCC, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "setl", 0, 0, 0}, /* 0x9C */ { 0, INS_MOVCC, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "setge", 0, 0, 0}, /* 0x9D */ { 0, INS_MOVCC, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "setle", 0, 0, 0}, /* 0x9E */ { 0, INS_MOVCC, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "setg", 0, 0, 0}, /* 0x9F */ {0, INS_PUSH, OP_REG | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "push", 4 + REG_SEG_OFFSET, 0, 0}, /* 0xA0 */ {0, INS_POP, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "pop", 4 + REG_SEG_OFFSET, 0, 0}, /* 0xA1 */ {0, INS_CPUID, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80486, "cpuid", 0, 0, 0}, /* 0xA2 */ { 0, INS_BITTEST, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "bt", 0, 0, 0}, /* 0xA3 */ { 0, INS_SHL, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_G | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, cpu_80386, "shld", 0, 0, 0}, /* 0xA4 */ { 0, INS_SHL, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_G | OPTYPE_v | OP_R, ADDRMETH_I | OP_R | OP_REG, cpu_80386, "shld", 0, 0, 1 + REG_BYTE_OFFSET}, /* 0xA5 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0xA6 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0xA7 */ {0, INS_PUSH, OP_REG | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "push", 5 + REG_SEG_OFFSET, 0, 0}, /* 0xA8 */ {0, INS_POP, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "pop", 5 + REG_SEG_OFFSET, 0, 0}, /* 0xA9 */ {0, INS_SYSTEM, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "rsm", 0, 0, 0}, /* 0xAA */ { 0, INS_BITTEST, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "bts", 0, 0, 0}, /* 0xAB */ { 0, INS_SHR, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_G | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, cpu_80386, "shrd", 0, 0, 0}, /* 0xAC */ { 0, INS_SHR, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_G | OPTYPE_v | OP_R, ADDRMETH_I | OP_R | OP_REG, cpu_80386, "shrd", 0, 0, 1 + REG_BYTE_OFFSET}, /* 0xAD */ {22, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM2, 0, 0, 0, 0}, /* 0xAE */ { 0, INS_MUL, ADDRMETH_G | OPTYPE_v | OP_R, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "imul", 0, 0, 0}, /* 0xAF */ { 0, INS_XCHGCC, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_G | OPTYPE_b | OP_W, ARG_NONE, cpu_80486, "cmpxchg", 0, 0, 0}, /* 0xB0 */ { 0, INS_XCHGCC, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_G | OPTYPE_v | OP_W, ARG_NONE, cpu_80486, "cmpxchg", 0, 0, 0}, /* 0xB1 */ { 0, INS_MOV, ADDRMETH_M | OPTYPE_p | OP_W, ADDRMETH_I | OP_R, ARG_NONE, cpu_80386, "lss", 0, 0, 0}, /* 0xB2 */ { 0, INS_BITTEST, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "btr", 0, 0, 0}, /* 0xB3 */ { 0, INS_MOV, ADDRMETH_M | OPTYPE_p | OP_W, ADDRMETH_I | OP_R, ARG_NONE, cpu_80386, "lfs", 0, 0, 0}, /* 0xB4 */ { 0, INS_MOV, ADDRMETH_M | OPTYPE_p | OP_W, ADDRMETH_I | OP_R, ARG_NONE, cpu_80386, "lgs", 0, 0, 0}, /* 0xB5 */ { 0, INS_MOV, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "movzx", 0, 0, 0}, /* 0xB6 */ { 0, INS_MOV, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_w | OP_R, ARG_NONE, cpu_80386, "movzx", 0, 0, 0}, /* 0xB7 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0xB8 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, "ud1", 0, 0, 0}, /* 0xB9 */ {23, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386, 0, 0, 0, 0}, /* 0xBA */ { 0, INS_BITTEST, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "btc", 0, 0, 0}, /* 0xBB */ { 0, INS_BITTEST, ADDRMETH_G | OPTYPE_v | OP_R | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "bsf", 0, 0, 0}, /* 0xBC */ { 0, INS_BITTEST, ADDRMETH_G | OPTYPE_v | OP_R | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "bsr", 0, 0, 0}, /* 0xBD */ { 0, INS_MOV, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "movsx", 0, 0, 0}, /* 0xBE */ { 0, INS_MOV, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_w | OP_R, ARG_NONE, cpu_80386, "movsx", 0, 0, 0}, /* 0xBF */ { 0, INS_ADD, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_G | OPTYPE_b | OP_W, ARG_NONE, cpu_80486, "xadd", 0, 0, 0}, /* 0xC0 */ { 0, INS_ADD, ADDRMETH_E | OPTYPE_v | OP_W, ARG_NONE, ARG_NONE, cpu_80486, "xadd", 0, 0, 0}, /* 0xC1 */ {24, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM2, 0, 0, 0, 0}, /* 0xC2 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0xC3 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_E | OPTYPE_d | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, cpu_PENTIUM2, "pinsrw", 0, 0, 0}, /* 0xC4 */ { 0, INS_OTHER, ADDRMETH_G | OPTYPE_d | OP_W, ADDRMETH_P | OPTYPE_q | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, cpu_PENTIUM2, "pextrw", 0, 0, 0}, /* 0xC5 */ { 0, INS_OTHER, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, cpu_PENTIUM2, "shufps", 0, 0, 0}, /* 0xC6 */ {25, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTMMX, 0, 0, 0, 0}, /* 0xC7 */ { 0, INS_XCHG, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80486, "bswap", 0 + REG_DWORD_OFFSET, 0, 0}, /* 0xC8 */ { 0, INS_XCHG, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80486, "bswap", 1 + REG_DWORD_OFFSET, 0, 0}, /* 0xC9 */ { 0, INS_XCHG, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80486, "bswap", 2 + REG_DWORD_OFFSET, 0, 0}, /* 0xCA */ { 0, INS_XCHG, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80486, "bswap", 3 + REG_DWORD_OFFSET, 0, 0}, /* 0xCB */ { 0, INS_XCHG, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80486, "bswap", 4 + REG_DWORD_OFFSET, 0, 0}, /* 0xCC */ { 0, INS_XCHG, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80486, "bswap", 5 + REG_DWORD_OFFSET, 0, 0}, /* 0xCD */ { 0, INS_XCHG, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80486, "bswap", 6 + REG_DWORD_OFFSET, 0, 0}, /* 0xCE */ { 0, INS_XCHG, OP_REG | OP_W, ARG_NONE, ARG_NONE, cpu_80486, "bswap", 7 + REG_DWORD_OFFSET, 0, 0}, /* 0xCF */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0xD0 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "psrlw", 0, 0, 0}, /* 0xD1 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "psrld", 0, 0, 0}, /* 0xD2 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "psrlq", 0, 0, 0}, /* 0xD3 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0xD4 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "pmullw", 0, 0, 0}, /* 0xD5 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0xD6 */ { 0, INS_OTHER, ADDRMETH_G | OPTYPE_d | OP_W, ADDRMETH_P | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2, "pmovmskb", 0, 0, 0}, /* 0xD7 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "psubusb", 0, 0, 0}, /* 0xD8 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "psubusw", 0, 0, 0}, /* 0xD9 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2, "pminub", 0, 0, 0}, /* 0xDA */ { 0, INS_AND, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "pand", 0, 0, 0}, /* 0xDB */ { 0, INS_ADD, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "paddusb", 0, 0, 0}, /* 0xDC */ { 0, INS_ADD, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "paddusw", 0, 0, 0}, /* 0xDD */ { 0, INS_ARITH, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2, "pmaxub", 0, 0, 0}, /* 0xDE */ { 0, INS_AND, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "pandn", 0, 0, 0}, /* 0xDF */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2, "pavgb", 0, 0, 0}, /* 0xE0 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "psraw", 0, 0, 0}, /* 0xE1 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "psrad", 0, 0, 0}, /* 0xE2 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2, "pavgw", 0, 0, 0}, /* 0xE3 */ { 0, INS_MUL, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2, "pmulhuw", 0, 0, 0}, /* 0xE4 */ { 0, INS_MUL, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "pmulhw", 0, 0, 0}, /* 0xE5 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0xE6 */ { 0, INS_MOV, ADDRMETH_W | OPTYPE_q | OP_W, ADDRMETH_V | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2, "movntq", 0, 0, 0}, /* 0xE7 */ { 0, INS_SUB, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "psubsb", 0, 0, 0}, /* 0xE8 */ { 0, INS_SUB, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "psubsw", 0, 0, 0}, /* 0xE9 */ { 0, INS_ARITH, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2, "pminsw", 0, 0, 0}, /* 0xEA */ { 0, INS_OR, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "por", 0, 0, 0}, /* 0xEB */ { 0, INS_ADD, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "paddsb", 0, 0, 0}, /* 0xEC */ { 0, INS_ADD, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "paddsw", 0, 0, 0}, /* 0xED */ { 0, INS_ARITH, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2, "pmaxsw", 0, 0, 0}, /* 0xEE */ { 0, INS_XOR, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "pxor", 0, 0, 0}, /* 0xEF */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0xF0 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "psllw", 0, 0, 0}, /* 0xF1 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "pslld", 0, 0, 0}, /* 0xF2 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "psllq", 0, 0, 0}, /* 0xF3 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0xF4 */ { 0, INS_ADD, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "pmaddwd", 0, 0, 0}, /* 0xF5 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2, "psadbw", 0, 0, 0}, /* 0xF6 */ { 0, INS_MOV, ADDRMETH_P | OPTYPE_pi | OP_W, ADDRMETH_Q | OPTYPE_pi | OP_R, ARG_NONE, cpu_PENTIUM2, "maskmovq", 0, 0, 0}, /* 0xF7 */ { 0, INS_SUB, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "psubb", 0, 0, 0}, /* 0xF8 */ { 0, INS_SUB, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "psubw", 0, 0, 0}, /* 0xF9 */ { 0, INS_SUB, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "psubd", 0, 0, 0}, /* 0xFA */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0xFB */ { 0, INS_ADD, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "paddb", 0, 0, 0}, /* 0xFC */ { 0, INS_ADD, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "paddw", 0, 0, 0}, /* 0xFD */ { 0, INS_ADD, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTMMX, "paddd", 0, 0, 0}, /* 0xFE */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0 } /* 0xFF */, }; instr tbl_0F00[] = { { 0, INS_SYSTEM, ADDRMETH_E | OPTYPE_w | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "sldt", 0, 0, 0}, /* 0x0 */ { 0, INS_SYSTEM, ADDRMETH_E | OPTYPE_w | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "str", 0, 0, 0}, /* 0x1 */ { 0, INS_SYSTEM, ADDRMETH_E | OPTYPE_w | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "lldt", 0, 0, 0}, /* 0x2 */ { 0, INS_SYSTEM, ADDRMETH_E | OPTYPE_w | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "ltr", 0, 0, 0}, /* 0x3 */ { 0, INS_SYSTEM, ADDRMETH_E | OPTYPE_w | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "verr", 0, 0, 0}, /* 0x4 */ { 0, INS_SYSTEM, ADDRMETH_E | OPTYPE_w | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "verw", 0, 0, 0}, /* 0x5 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x6 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0 } /* 0x7 */, }; instr tbl_0F01[] = { { 0, INS_SYSTEM, ADDRMETH_M | OPTYPE_s | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "sgdt", 0, 0, 0}, /* 0x0 */ { 0, INS_SYSTEM, ADDRMETH_M | OPTYPE_s | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "sidt", 0, 0, 0}, /* 0x1 */ { 0, INS_SYSTEM, ADDRMETH_M | OPTYPE_s | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "lgdt", 0, 0, 0}, /* 0x2 */ { 0, INS_SYSTEM, ADDRMETH_M | OPTYPE_s | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "lidt", 0, 0, 0}, /* 0x3 */ { 0, INS_SYSTEM, ADDRMETH_E | OPTYPE_w | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "smsw", 0, 0, 0}, /* 0x4 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x5 */ { 0, INS_SYSTEM, ADDRMETH_E | OPTYPE_w | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "lmsw", 0, 0, 0}, /* 0x6 */ { 0, INS_SYSTEM, ADDRMETH_M | OPTYPE_b | OP_R, ARG_NONE, ARG_NONE, cpu_80486, "invlpg", 0, 0, 0 } /* 0x7 */, }; instr tbl_0F18[] = { { 0, INS_SYSTEM, OP_W | ADDRMETH_M, ARG_NONE, ARG_NONE, cpu_PENTIUM2, "prefetch", 0, 0, 0}, /* 0x0 */ { 0, INS_SYSTEM, OP_REG | OP_W | ADDRMETH_M, ARG_NONE, ARG_NONE, cpu_PENTIUM2, "prefetch", 0 + REG_TEST_OFFSET, 0, 0}, /* 0x1 */ { 0, INS_SYSTEM, OP_REG | OP_W | ADDRMETH_M, ARG_NONE, ARG_NONE, cpu_PENTIUM2, "prefetch", 1 + REG_TEST_OFFSET, 0, 0}, /* 0x2 */ { 0, INS_SYSTEM, OP_REG | OP_W | ADDRMETH_M, ARG_NONE, ARG_NONE, cpu_PENTIUM2, "prefetch", 2 + REG_TEST_OFFSET, 0, 0}, /* 0x3 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x4 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x5 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x6 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0 } /* 0x7 */, }; instr tbl_0F71[] = { {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x0 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x1 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTMMX, "psrlw", 0, 0, 0}, /* 0x2 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x3 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTMMX, "psraw", 0, 0, 0}, /* 0x4 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x5 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTMMX, "psllw", 0, 0, 0}, /* 0x6 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0 } /* 0x7 */, }; instr tbl_0F72[] = { {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x0 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x1 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTMMX, "psrld", 0, 0, 0}, /* 0x2 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x3 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTMMX, "psrad", 0, 0, 0}, /* 0x4 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0}, /* 0x5 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTMMX, "pslld", 0, 0, 0}, /* 0x6 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0 } /* 0x7 */, }; instr tbl_0F73[] = { { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTMMX, "psrlq", 0, 0, 0}, /* 0x0 */ { 0, INS_OTHER, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTMMX, "psllq", 0, 0, 0 } /* 0x1 */, }; instr tbl_0FAE[] = { { 0, INS_FPU, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTMMX, "fxsave", 0, 0, 0}, /* 0x0 */ { 0, INS_FPU, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTMMX, "fxrstor", 0, 0, 0}, /* 0x1 */ { 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM2, "ldmxcsr", 0, 0, 0}, /* 0x2 */ { 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM2, "stmxcsr", 0, 0, 0}, /* 0x3 */ { 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM2, "sfence", 0, 0, 0 } /* 0x4 */, }; instr tbl_0FBA[] = { { 0, INS_BITTEST, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "bt", 0, 0, 0}, /* 0x0 */ { 0, INS_BITTEST, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "bts", 0, 0, 0}, /* 0x1 */ { 0, INS_BITTEST, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "btr", 0, 0, 0}, /* 0x2 */ { 0, INS_BITTEST, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "btc", 0, 0, 0 } /* 0x3 */, }; instr tbl_0FC7[] = { { 0, INS_XCHGCC, ADDRMETH_M | OPTYPE_q | OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM, "cmpxch8b", 0, 0, 0 } /* 0x0 */, }; instr tbl_80[] = { { 0, INS_ADD, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "add", 0, 0, 0}, /* 0x0 */ { 0, INS_OR, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "or", 0, 0, 0}, /* 0x1 */ { 0, INS_ADD, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "adc", 0, 0, 0}, /* 0x2 */ { 0, INS_SUB, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "sbb", 0, 0, 0}, /* 0x3 */ { 0, INS_AND, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "and", 0, 0, 0}, /* 0x4 */ { 0, INS_SUB, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "sub", 0, 0, 0}, /* 0x5 */ { 0, INS_XOR, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "xor", 0, 0, 0}, /* 0x6 */ { 0, INS_CMP, ADDRMETH_E | OPTYPE_b | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "cmp", 0, 0, 0 } /* 0x7 */, }; instr tbl_81[] = { { 0, INS_ADD, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "add", 0, 0, 0}, /* 0x0 */ { 0, INS_OR, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "or", 0, 0, 0}, /* 0x1 */ { 0, INS_ADD, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "adc", 0, 0, 0}, /* 0x2 */ { 0, INS_SUB, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "sbb", 0, 0, 0}, /* 0x3 */ { 0, INS_AND, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "and", 0, 0, 0}, /* 0x4 */ { 0, INS_SUB, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "sub", 0, 0, 0}, /* 0x5 */ { 0, INS_XOR, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "xor", 0, 0, 0}, /* 0x6 */ { 0, INS_CMP, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "cmp", 0, 0, 0 } /* 0x7 */, }; instr tbl_82[] = { { 0, INS_ADD, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "add", 0, 0, 0}, /* 0x0 */ { 0, INS_OR, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "or", 0, 0, 0}, /* 0x1 */ { 0, INS_ADD, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "adc", 0, 0, 0}, /* 0x2 */ { 0, INS_SUB, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "sbb", 0, 0, 0}, /* 0x3 */ { 0, INS_AND, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "and", 0, 0, 0}, /* 0x4 */ { 0, INS_SUB, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "sub", 0, 0, 0}, /* 0x5 */ { 0, INS_XOR, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "xor", 0, 0, 0}, /* 0x6 */ { 0, INS_CMP, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "cmp", 0, 0, 0 } /* 0x7 */, }; instr tbl_83[] = { { 0, INS_ADD, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "add", 0, 0, 0}, /* 0x0 */ { 0, INS_OR, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "or", 0, 0, 0}, /* 0x1 */ { 0, INS_ADD, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "adc", 0, 0, 0}, /* 0x2 */ { 0, INS_SUB, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "sbb", 0, 0, 0}, /* 0x3 */ { 0, INS_AND, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "and", 0, 0, 0}, /* 0x4 */ { 0, INS_SUB, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "sub", 0, 0, 0}, /* 0x5 */ { 0, INS_XOR, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "xor", 0, 0, 0}, /* 0x6 */ { 0, INS_CMP, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "cmp", 0, 0, 0 } /* 0x7 */, }; instr tbl_C0[] = { { 0, INS_ROL, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "rol", 0, 0, 0}, /* 0x0 */ { 0, INS_ROR, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "ror", 0, 0, 0}, /* 0x1 */ { 0, INS_ROL, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "rcl", 0, 0, 0}, /* 0x2 */ { 0, INS_ROR, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "rcr", 0, 0, 0}, /* 0x3 */ { 0, INS_SHL, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "shl", 0, 0, 0}, /* 0x4 */ { 0, INS_SHR, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "shr", 0, 0, 0}, /* 0x5 */ { 0, INS_SHL, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "sal", 0, 0, 0}, /* 0x6 */ { 0, INS_SHR, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "sar", 0, 0, 0 } /* 0x7 */, }; instr tbl_C1[] = { { 0, INS_ROL, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "rol", 0, 0, 0}, /* 0x0 */ { 0, INS_ROR, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "ror", 0, 0, 0}, /* 0x1 */ { 0, INS_ROL, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "rcl", 0, 0, 0}, /* 0x2 */ { 0, INS_ROR, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "rcr", 0, 0, 0}, /* 0x3 */ { 0, INS_SHL, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "shl", 0, 0, 0}, /* 0x4 */ { 0, INS_SHR, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "shr", 0, 0, 0}, /* 0x5 */ { 0, INS_SHL, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "sal", 0, 0, 0}, /* 0x6 */ { 0, INS_SHR, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "sar", 0, 0, 0 } /* 0x7 */, }; instr tbl_D0[] = { { 0, INS_ROL, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OP_IMM | OP_R, ARG_NONE, cpu_80386, "rol", 0, 1, 0}, /* 0x0 */ { 0, INS_ROR, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OP_IMM | OP_R, ARG_NONE, cpu_80386, "ror", 0, 1, 0}, /* 0x1 */ { 0, INS_ROL, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OP_IMM | OP_R, ARG_NONE, cpu_80386, "rcl", 0, 1, 0}, /* 0x2 */ { 0, INS_ROR, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OP_IMM | OP_R, ARG_NONE, cpu_80386, "rcr", 0, 1, 0}, /* 0x3 */ { 0, INS_SHL, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OP_IMM | OP_R, ARG_NONE, cpu_80386, "shl", 0, 1, 0}, /* 0x4 */ { 0, INS_SHR, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OP_IMM | OP_R, ARG_NONE, cpu_80386, "shr", 0, 1, 0}, /* 0x5 */ { 0, INS_SHL, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OP_IMM | OP_R, ARG_NONE, cpu_80386, "sal", 0, 1, 0}, /* 0x6 */ { 0, INS_SHR, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OP_IMM | OP_R, ARG_NONE, cpu_80386, "sar", 0, 1, 0 } /* 0x7 */, }; instr tbl_D1[] = { { 0, INS_ROL, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OP_IMM | OP_R, ARG_NONE, cpu_80386, "rol", 0, 1, 0}, /* 0x0 */ { 0, INS_ROR, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OP_IMM | OP_R, ARG_NONE, cpu_80386, "ror", 0, 1, 0}, /* 0x1 */ { 0, INS_ROL, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OP_IMM | OP_R, ARG_NONE, cpu_80386, "rcl", 0, 1, 0}, /* 0x2 */ { 0, INS_ROR, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OP_IMM | OP_R, ARG_NONE, cpu_80386, "rcr", 0, 1, 0}, /* 0x3 */ { 0, INS_SHL, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OP_IMM | OP_R, ARG_NONE, cpu_80386, "shl", 0, 1, 0}, /* 0x4 */ { 0, INS_SHR, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OP_IMM | OP_R, ARG_NONE, cpu_80386, "shr", 0, 1, 0}, /* 0x5 */ { 0, INS_SHL, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OP_IMM | OP_R, ARG_NONE, cpu_80386, "sal", 0, 1, 0}, /* 0x6 */ { 0, INS_SHR, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OP_IMM | OP_R, ARG_NONE, cpu_80386, "sar", 0, 1, 0 } /* 0x7 */, }; instr tbl_D2[] = { { 0, INS_ROL, ADDRMETH_E | OPTYPE_b | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "rol", 0, 1 + REG_BYTE_OFFSET, 0}, /* 0x0 */ { 0, INS_ROR, ADDRMETH_E | OPTYPE_b | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "ror", 0, 1 + REG_BYTE_OFFSET, 0}, /* 0x1 */ { 0, INS_ROL, ADDRMETH_E | OPTYPE_b | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "rcl", 0, 1 + REG_BYTE_OFFSET, 0}, /* 0x2 */ { 0, INS_ROR, ADDRMETH_E | OPTYPE_b | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "rcr", 0, 1 + REG_BYTE_OFFSET, 0}, /* 0x3 */ { 0, INS_SHL, ADDRMETH_E | OPTYPE_b | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "shl", 0, 1 + REG_BYTE_OFFSET, 0}, /* 0x4 */ { 0, INS_SHR, ADDRMETH_E | OPTYPE_b | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "shr", 0, 1 + REG_BYTE_OFFSET, 0}, /* 0x5 */ { 0, INS_SHL, ADDRMETH_E | OPTYPE_b | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "sal", 0, 1 + REG_BYTE_OFFSET, 0}, /* 0x6 */ { 0, INS_SHR, ADDRMETH_E | OPTYPE_b | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "sar", 0, 1 + REG_BYTE_OFFSET, 0 } /* 0x7 */, }; instr tbl_D3[] = { { 0, INS_ROL, ADDRMETH_E | OPTYPE_v | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "rol", 0, 1 + REG_BYTE_OFFSET, 0}, /* 0x0 */ { 0, INS_ROR, ADDRMETH_E | OPTYPE_v | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "ror", 0, 1 + REG_BYTE_OFFSET, 0}, /* 0x1 */ { 0, INS_ROL, ADDRMETH_E | OPTYPE_v | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "rcl", 0, 1 + REG_BYTE_OFFSET, 0}, /* 0x2 */ { 0, INS_ROR, ADDRMETH_E | OPTYPE_v | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "rcr", 0, 1 + REG_BYTE_OFFSET, 0}, /* 0x3 */ { 0, INS_SHL, ADDRMETH_E | OPTYPE_v | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "shl", 0, 1 + REG_BYTE_OFFSET, 0}, /* 0x4 */ { 0, INS_SHR, ADDRMETH_E | OPTYPE_v | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "shr", 0, 1 + REG_BYTE_OFFSET, 0}, /* 0x5 */ { 0, INS_SHL, ADDRMETH_E | OPTYPE_v | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "sal", 0, 1 + REG_BYTE_OFFSET, 0}, /* 0x6 */ { 0, INS_SHR, ADDRMETH_E | OPTYPE_v | OP_W, OP_REG | OP_R, ARG_NONE, cpu_80386, "sar", 0, 1 + REG_BYTE_OFFSET, 0 } /* 0x7 */, }; instr tbl_F6[] = { { 0, INS_TEST, ADDRMETH_E | OPTYPE_b | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "test", 0, 0, 0}, /* 0x0 */ { 0, INS_TEST, ADDRMETH_E | OPTYPE_b | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "test", 0, 0, 0}, /* 0x1 */ { 0, INS_NOT, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "not", 0, 0, 0}, /* 0x2 */ { 0, INS_NEG, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "neg", 0, 0, 0}, /* 0x3 */ { 0, INS_MUL, OP_REG | OP_W, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "mul", 0 + REG_BYTE_OFFSET, 0, 0}, /* 0x4 */ { 0, INS_MUL, OP_REG | OP_W, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "imul", 0 + REG_BYTE_OFFSET, 0, 0}, /* 0x5 */ { 0, INS_DIV, OP_REG | OP_W, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "div", 0 + REG_BYTE_OFFSET, 0, 0}, /* 0x6 */ { 0, INS_DIV, OP_REG | OP_W, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386, "idiv", 0 + REG_BYTE_OFFSET, 0, 0 } /* 0x7 */, }; instr tbl_F7[] = { { 0, INS_TEST, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "test", 0, 0, 0}, /* 0x0 */ { 0, INS_TEST, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386, "test", 0, 0, 0}, /* 0x1 */ { 0, INS_NOT, ADDRMETH_E | OPTYPE_v | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "not", 0, 0, 0}, /* 0x2 */ { 0, INS_NEG, ADDRMETH_E | OPTYPE_v | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "neg", 0, 0, 0}, /* 0x3 */ { 0, INS_MUL, OP_REG | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "mul", 0 + REG_DWORD_OFFSET, 0, 0}, /* 0x4 */ { 0, INS_MUL, OP_REG | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "imul", 0 + REG_DWORD_OFFSET, 0, 0}, /* 0x5 */ { 0, INS_DIV, OP_REG | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "div", 0 + REG_DWORD_OFFSET, 0, 0}, /* 0x6 */ { 0, INS_DIV, OP_REG | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386, "idiv", 0 + REG_DWORD_OFFSET, 0, 0} /* 0x7 */, }; instr tbl_FE[] = { { 0, INS_INC, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "inc", 0, 0, 0}, /* 0x0 */ { 0, INS_DEC, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "dec", 0, 0, 0 } /* 0x1 */, }; instr tbl_FF[] = { { 0, INS_INC, ADDRMETH_E | OPTYPE_v | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "inc", 0, 0, 0}, /* 0x0 */ { 0, INS_DEC, ADDRMETH_E | OPTYPE_v | OP_W, ARG_NONE, ARG_NONE, cpu_80386, "dec", 0, 0, 0}, /* 0x1 */ { 0, INS_CALL, ADDRMETH_E | OPTYPE_v | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "call", 0, 0, 0}, /* 0x2 */ { 0, INS_CALL, ADDRMETH_E | OPTYPE_p | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "call", 0, 0, 0}, /* 0x3 */ { 0, INS_BRANCH, ADDRMETH_E | OPTYPE_v | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jmp", 0, 0, 0}, /* 0x4 */ { 0, INS_BRANCH, ADDRMETH_E | OPTYPE_p | OP_X, ARG_NONE, ARG_NONE, cpu_80386, "jmp", 0, 0, 0}, /* 0x5 */ { 0, INS_PUSH, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, ARG_NONE, cpu_80386, "push", 0, 0, 0}, /* 0x6 */ {0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, 0, 0, 0, 0 } /* 0x7 */, }; instr tbl_fpuD8_00BF[] = { { 0,INS_FPU,ADDRMETH_M|OPTYPE_fs|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fadd",0,0,0 }, /*0x0*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fs|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fmul",0,0,0 }, /*0x1*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fs|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fcom",0,0,0 }, /*0x2*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fs|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fcomp",0,0,0 }, /*0x3*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fs|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fsub",0,0,0 }, /*0x4*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fs|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fsubr",0,0,0 }, /*0x5*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fs|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fdiv",0,0,0 }, /*0x6*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fs|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fdivr",0,0,0 /*0x7*/ }, }; instr tbl_fpuD8_rest[] = { { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fadd",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xC0*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fadd",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 1,0 }, /*0xC1*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fadd",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 2,0 }, /*0xC2*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fadd",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 3,0 }, /*0xC3*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fadd",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 4,0 }, /*0xC4*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fadd",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 5,0 }, /*0xC5*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fadd",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 6,0 }, /*0xC6*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fadd",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 7,0 }, /*0xC7*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmul",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xC8*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmul",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 1,0 }, /*0xC9*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmul",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 2,0 }, /*0xCA*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmul",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 3,0 }, /*0xCB*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmul",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 4,0 }, /*0xCC*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmul",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 5,0 }, /*0xCD*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmul",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 6,0 }, /*0xCE*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmul",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 7,0 }, /*0xCF*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcom",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xD0*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcom",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 1,0 }, /*0xD1*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcom",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 2,0 }, /*0xD2*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcom",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 3,0 }, /*0xD3*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcom",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 4,0 }, /*0xD4*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcom",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 5,0 }, /*0xD5*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcom",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 6,0 }, /*0xD6*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcom",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 7,0 }, /*0xD7*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomp",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xD8*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomp",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 1,0 }, /*0xD9*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomp",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 2,0 }, /*0xDA*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomp",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 3,0 }, /*0xDB*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomp",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 4,0 }, /*0xDC*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomp",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 5,0 }, /*0xDD*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomp",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 6,0 }, /*0xDE*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomp",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 7,0 }, /*0xDF*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsub",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xE0*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsub",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 1,0 }, /*0xE1*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsub",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 2,0 }, /*0xE2*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsub",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 3,0 }, /*0xE3*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsub",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 4,0 }, /*0xE4*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsub",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 5,0 }, /*0xE5*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsub",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 6,0 }, /*0xE6*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsub",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 7,0 }, /*0xE7*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubr",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xE8*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubr",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 1,0 }, /*0xE9*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubr",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 2,0 }, /*0xEA*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubr",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 3,0 }, /*0xEB*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubr",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 4,0 }, /*0xEC*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubr",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 5,0 }, /*0xED*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubr",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 6,0 }, /*0xEE*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubr",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 7,0 }, /*0xEF*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdiv",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xF0*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdiv",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 1,0 }, /*0xF1*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdiv",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 2,0 }, /*0xF2*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdiv",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 3,0 }, /*0xF3*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdiv",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 4,0 }, /*0xF4*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdiv",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 5,0 }, /*0xF5*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdiv",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 6,0 }, /*0xF6*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdiv",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 7,0 }, /*0xF7*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivr",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xF8*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivr",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 1,0 }, /*0xF9*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivr",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 2,0 }, /*0xFA*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivr",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 3,0 }, /*0xFB*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivr",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 4,0 }, /*0xFC*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivr",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 5,0 }, /*0xFD*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivr",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 6,0 }, /*0xFE*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivr",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 7,0 }, /*0xFF*/ }; instr tbl_fpuD9_00BF[] = { { 0,INS_FPU,ADDRMETH_M|OPTYPE_fs|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fld",0,0,0 }, /*0x0*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0x1*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fs|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fst",0,0,0 }, /*0x2*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fs|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fstp",0,0,0 }, /*0x3*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fv|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fldenv",0,0,0 }, /*0x4*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_w|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fldcw",0,0,0 }, /*0x5*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fv|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fstenv",0,0,0 }, /*0x6*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_w|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fstcw",0,0,0 /*0x7*/ }, }; instr tbl_fpuD9_rest[] = { { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fld",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xC0*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fld",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 1,0 }, /*0xC1*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fld",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 2,0 }, /*0xC2*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fld",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 3,0 }, /*0xC3*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fld",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 4,0 }, /*0xC4*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fld",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 5,0 }, /*0xC5*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fld",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 6,0 }, /*0xC6*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fld",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 7,0 }, /*0xC7*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fxch",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xC8*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fxch",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 1,0 }, /*0xC9*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fxch",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 2,0 }, /*0xCA*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fxch",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 3,0 }, /*0xCB*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fxch",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 4,0 }, /*0xCC*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fxch",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 5,0 }, /*0xCD*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fxch",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 6,0 }, /*0xCE*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fxch",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 7,0 }, /*0xCF*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fnop",0,0,0 }, /*0xD0*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD1*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD2*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD3*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD4*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD5*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD6*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD7*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD8*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD9*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDA*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDB*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDC*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDD*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDE*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDF*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fchs",0,0,0 }, /*0xE0*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fabs",0,0,0 }, /*0xE1*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE2*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE3*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"ftst",0,0,0 }, /*0xE4*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fxam",0,0,0 }, /*0xE5*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE6*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE7*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fld1",0,0,0 }, /*0xE8*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fld2t",0,0,0 }, /*0xE9*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fld2t",0,0,0 }, /*0xEA*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fldpi",0,0,0 }, /*0xEB*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fldlg2",0,0,0 }, /*0xEC*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fldln2",0,0,0 }, /*0xED*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fldz",0,0,0 }, /*0xEE*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xEF*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"f2xm1",0,0,0 }, /*0xF0*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fyl2x",0,0,0 }, /*0xF1*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fptan",0,0,0 }, /*0xF2*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fpatan",0,0,0 }, /*0xF3*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fxtract",0,0,0 }, /*0xF4*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fprem1",0,0,0 }, /*0xF5*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fdecstp",0,0,0 }, /*0xF6*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fincstp",0,0,0 }, /*0xF7*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fprem",0,0,0 }, /*0xF8*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fyl2xp1",0,0,0 }, /*0xF9*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fsqrt",0,0,0 }, /*0xFA*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fsincos",0,0,0 }, /*0xFB*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"frndint",0,0,0 }, /*0xFC*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fscale",0,0,0 }, /*0xFD*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fsin",0,0,0 }, /*0xFE*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fcos",0,0,0 }, /*0xFF*/ }; instr tbl_fpuDA_00BF[] = { { 0,INS_FPU,ADDRMETH_M|OPTYPE_d|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fiadd",0,0,0 }, /*0x0*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_d|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fimul",0,0,0 }, /*0x1*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_d|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"ficom",0,0,0 }, /*0x2*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_d|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"ficomp",0,0,0 }, /*0x3*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_d|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fisub",0,0,0 }, /*0x4*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_d|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fisubr",0,0,0 }, /*0x5*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_d|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fidiv",0,0,0 }, /*0x6*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_d|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fidivr",0,0,0 /*0x7*/ }, }; instr tbl_fpuDA_rest[] = { { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovb",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xC0*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovb",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 1,0 }, /*0xC1*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovb",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 2,0 }, /*0xC2*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovb",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 3,0 }, /*0xC3*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovb",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 4,0 }, /*0xC4*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovb",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 5,0 }, /*0xC5*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovb",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 6,0 }, /*0xC6*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovb",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 7,0 }, /*0xC7*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmove",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xC8*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmove",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 1,0 }, /*0xC9*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmove",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 2,0 }, /*0xCA*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmove",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 3,0 }, /*0xCB*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmove",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 4,0 }, /*0xCC*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmove",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 5,0 }, /*0xCD*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmove",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 6,0 }, /*0xCE*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmove",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 7,0 }, /*0xCF*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovbe",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xD0*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovbe",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 1,0 }, /*0xD1*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovbe",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 2,0 }, /*0xD2*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovbe",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 3,0 }, /*0xD3*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovbe",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 4,0 }, /*0xD4*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovbe",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 5,0 }, /*0xD5*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovbe",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 6,0 }, /*0xD6*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovbe",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 7,0 }, /*0xD7*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovu",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xD8*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovu",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 1,0 }, /*0xD9*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovu",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 2,0 }, /*0xDA*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovu",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 3,0 }, /*0xDB*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovu",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 4,0 }, /*0xDC*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovu",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 5,0 }, /*0xDD*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovu",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 6,0 }, /*0xDE*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovu",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 7,0 }, /*0xDF*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE0*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE1*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE2*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE3*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE4*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE5*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE6*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE7*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE8*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fucompp",0,0,0 }, /*0xE9*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xEA*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xEB*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xEC*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xED*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xEE*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xEF*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF0*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF1*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF2*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF3*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF4*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF5*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF6*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF7*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF8*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF9*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFA*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFB*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFC*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFD*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFE*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFF*/ }; instr tbl_fpuDB_00BF[] = { { 0,INS_FPU,ADDRMETH_M|OPTYPE_d|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fild",0,0,0 }, /*0x0*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0x1*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_d|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fist",0,0,0 }, /*0x2*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_d|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fistp",0,0,0 }, /*0x3*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0x4*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fe|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fld",0,0,0 }, /*0x5*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0x6*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fe|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fstp",0,0,0 /*0x7*/ }, }; instr tbl_fpuDB_rest[] = { { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnb",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xC0*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnb",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 1,0 }, /*0xC1*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnb",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 2,0 }, /*0xC2*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnb",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 3,0 }, /*0xC3*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnb",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 4,0 }, /*0xC4*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnb",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 5,0 }, /*0xC5*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnb",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 6,0 }, /*0xC6*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnb",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 7,0 }, /*0xC7*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovne",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xC8*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovne",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 1,0 }, /*0xC9*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovne",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 2,0 }, /*0xCA*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovne",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 3,0 }, /*0xCB*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovne",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 4,0 }, /*0xCC*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovne",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 5,0 }, /*0xCD*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovne",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 6,0 }, /*0xCE*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovne",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 7,0 }, /*0xCF*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnbe",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xD0*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnbe",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 1,0 }, /*0xD1*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnbe",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 2,0 }, /*0xD2*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnbe",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 3,0 }, /*0xD3*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnbe",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 4,0 }, /*0xD4*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnbe",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 5,0 }, /*0xD5*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnbe",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 6,0 }, /*0xD6*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnbe",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 7,0 }, /*0xD7*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnu",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xD8*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnu",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 1,0 }, /*0xD9*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnu",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 2,0 }, /*0xDA*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnu",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 3,0 }, /*0xDB*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnu",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 4,0 }, /*0xDC*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnu",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 5,0 }, /*0xDD*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnu",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 6,0 }, /*0xDE*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcmovnu",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 7,0 }, /*0xDF*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE0*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE1*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fclex",0,0,0 }, /*0xE2*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"finit",0,0,0 }, /*0xE3*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE4*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE5*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE6*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE7*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucomi",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xE8*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucomi",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 1,0 }, /*0xE9*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucomi",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 2,0 }, /*0xEA*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucomi",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 3,0 }, /*0xEB*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucomi",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 4,0 }, /*0xEC*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucomi",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 5,0 }, /*0xED*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucomi",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 6,0 }, /*0xEE*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucomi",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 7,0 }, /*0xEF*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomi",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xF0*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomi",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 1,0 }, /*0xF1*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomi",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 2,0 }, /*0xF2*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomi",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 3,0 }, /*0xF3*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomi",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 4,0 }, /*0xF4*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomi",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 5,0 }, /*0xF5*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomi",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 6,0 }, /*0xF6*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomi",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 7,0 }, /*0xF7*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF8*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF9*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFA*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFB*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFC*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFD*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFE*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFF*/ }; instr tbl_fpuDC_00BF[] = { { 0,INS_FPU,ADDRMETH_M|OPTYPE_fd|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fadd",0,0,0 }, /*0x0*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fd|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fmul",0,0,0 }, /*0x1*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fd|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fcom",0,0,0 }, /*0x2*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fd|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fcomp",0,0,0 }, /*0x3*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fd|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fsub",0,0,0 }, /*0x4*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fd|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fsubr",0,0,0 }, /*0x5*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fd|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fdiv",0,0,0 }, /*0x6*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fd|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fdivr",0,0,0 /*0x7*/ }, }; instr tbl_fpuDC_rest[] = { { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fadd",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xC0*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fadd",REG_FPU_OFFSET + 1,REG_FPU_OFFSET + 0,0 }, /*0xC1*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fadd",REG_FPU_OFFSET + 2,REG_FPU_OFFSET + 0,0 }, /*0xC2*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fadd",REG_FPU_OFFSET + 3,REG_FPU_OFFSET + 0,0 }, /*0xC3*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fadd",REG_FPU_OFFSET + 4,REG_FPU_OFFSET + 0,0 }, /*0xC4*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fadd",REG_FPU_OFFSET + 5,REG_FPU_OFFSET + 0,0 }, /*0xC5*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fadd",REG_FPU_OFFSET + 6,REG_FPU_OFFSET + 0,0 }, /*0xC6*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fadd",REG_FPU_OFFSET + 7,REG_FPU_OFFSET + 0,0 }, /*0xC7*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmul",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xC8*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmul",REG_FPU_OFFSET + 1,REG_FPU_OFFSET + 0,0 }, /*0xC9*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmul",REG_FPU_OFFSET + 2,REG_FPU_OFFSET + 0,0 }, /*0xCA*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmul",REG_FPU_OFFSET + 3,REG_FPU_OFFSET + 0,0 }, /*0xCB*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmul",REG_FPU_OFFSET + 4,REG_FPU_OFFSET + 0,0 }, /*0xCC*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmul",REG_FPU_OFFSET + 5,REG_FPU_OFFSET + 0,0 }, /*0xCD*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmul",REG_FPU_OFFSET + 6,REG_FPU_OFFSET + 0,0 }, /*0xCE*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmul",REG_FPU_OFFSET + 7,REG_FPU_OFFSET + 0,0 }, /*0xCF*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD0*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD1*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD2*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD3*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD4*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD5*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD6*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD7*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD8*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD9*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDA*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDB*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDC*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDD*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDE*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDF*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubr",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xE0*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubr",REG_FPU_OFFSET + 1,REG_FPU_OFFSET + 0,0 }, /*0xE1*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubr",REG_FPU_OFFSET + 2,REG_FPU_OFFSET + 0,0 }, /*0xE2*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubr",REG_FPU_OFFSET + 3,REG_FPU_OFFSET + 0,0 }, /*0xE3*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubr",REG_FPU_OFFSET + 4,REG_FPU_OFFSET + 0,0 }, /*0xE4*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubr",REG_FPU_OFFSET + 5,REG_FPU_OFFSET + 0,0 }, /*0xE5*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubr",REG_FPU_OFFSET + 6,REG_FPU_OFFSET + 0,0 }, /*0xE6*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubr",REG_FPU_OFFSET + 7,REG_FPU_OFFSET + 0,0 }, /*0xE7*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsub",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xE8*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsub",REG_FPU_OFFSET + 1,REG_FPU_OFFSET + 0,0 }, /*0xE9*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsub",REG_FPU_OFFSET + 2,REG_FPU_OFFSET + 0,0 }, /*0xEA*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsub",REG_FPU_OFFSET + 3,REG_FPU_OFFSET + 0,0 }, /*0xEB*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsub",REG_FPU_OFFSET + 4,REG_FPU_OFFSET + 0,0 }, /*0xEC*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsub",REG_FPU_OFFSET + 5,REG_FPU_OFFSET + 0,0 }, /*0xED*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsub",REG_FPU_OFFSET + 6,REG_FPU_OFFSET + 0,0 }, /*0xEE*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsub",REG_FPU_OFFSET + 7,REG_FPU_OFFSET + 0,0 }, /*0xEF*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivr",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xF0*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivr",REG_FPU_OFFSET + 1,REG_FPU_OFFSET + 0,0 }, /*0xF1*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivr",REG_FPU_OFFSET + 2,REG_FPU_OFFSET + 0,0 }, /*0xF2*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivr",REG_FPU_OFFSET + 3,REG_FPU_OFFSET + 0,0 }, /*0xF3*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivr",REG_FPU_OFFSET + 4,REG_FPU_OFFSET + 0,0 }, /*0xF4*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivr",REG_FPU_OFFSET + 5,REG_FPU_OFFSET + 0,0 }, /*0xF5*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivr",REG_FPU_OFFSET + 6,REG_FPU_OFFSET + 0,0 }, /*0xF6*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivr",REG_FPU_OFFSET + 7,REG_FPU_OFFSET + 0,0 }, /*0xF7*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdiv",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xF8*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdiv",REG_FPU_OFFSET + 1,REG_FPU_OFFSET + 0,0 }, /*0xF9*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdiv",REG_FPU_OFFSET + 2,REG_FPU_OFFSET + 0,0 }, /*0xFA*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdiv",REG_FPU_OFFSET + 3,REG_FPU_OFFSET + 0,0 }, /*0xFB*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdiv",REG_FPU_OFFSET + 4,REG_FPU_OFFSET + 0,0 }, /*0xFC*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdiv",REG_FPU_OFFSET + 5,REG_FPU_OFFSET + 0,0 }, /*0xFD*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdiv",REG_FPU_OFFSET + 6,REG_FPU_OFFSET + 0,0 }, /*0xFE*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdiv",REG_FPU_OFFSET + 7,REG_FPU_OFFSET + 0,0 }, /*0xFF*/ }; instr tbl_fpuDD_00BF[] = { { 0,INS_FPU,ADDRMETH_M|OPTYPE_fd|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fld",0,0,0 }, /*0x0*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0x1*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fd|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fst",0,0,0 }, /*0x2*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fd|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fstp",0,0,0 }, /*0x3*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fv|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"frstor",0,0,0 }, /*0x4*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0x5*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fv|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fsave",0,0,0 }, /*0x6*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_w|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fstsw",0,0,0 /*0x7*/ }, }; instr tbl_fpuDD_rest[] = { { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"ffree",REG_FPU_OFFSET + 0,0,0 }, /*0xC0*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"ffree",REG_FPU_OFFSET + 1,0,0 }, /*0xC1*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"ffree",REG_FPU_OFFSET + 2,0,0 }, /*0xC2*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"ffree",REG_FPU_OFFSET + 3,0,0 }, /*0xC3*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"ffree",REG_FPU_OFFSET + 4,0,0 }, /*0xC4*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"ffree",REG_FPU_OFFSET + 5,0,0 }, /*0xC5*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"ffree",REG_FPU_OFFSET + 6,0,0 }, /*0xC6*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"ffree",REG_FPU_OFFSET + 7,0,0 }, /*0xC7*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xC8*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xC9*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xCA*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xCB*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xCC*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xCD*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xCE*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xCF*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fst",REG_FPU_OFFSET + 0,0,0 }, /*0xD0*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fst",REG_FPU_OFFSET + 1,0,0 }, /*0xD1*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fst",REG_FPU_OFFSET + 2,0,0 }, /*0xD2*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fst",REG_FPU_OFFSET + 3,0,0 }, /*0xD3*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fst",REG_FPU_OFFSET + 4,0,0 }, /*0xD4*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fst",REG_FPU_OFFSET + 5,0,0 }, /*0xD5*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fst",REG_FPU_OFFSET + 6,0,0 }, /*0xD6*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fst",REG_FPU_OFFSET + 7,0,0 }, /*0xD7*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fstp",REG_FPU_OFFSET + 0,0,0 }, /*0xD8*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fstp",REG_FPU_OFFSET + 1,0,0 }, /*0xD9*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fstp",REG_FPU_OFFSET + 2,0,0 }, /*0xDA*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fstp",REG_FPU_OFFSET + 3,0,0 }, /*0xDB*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fstp",REG_FPU_OFFSET + 4,0,0 }, /*0xDC*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fstp",REG_FPU_OFFSET + 5,0,0 }, /*0xDD*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fstp",REG_FPU_OFFSET + 6,0,0 }, /*0xDE*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fstp",REG_FPU_OFFSET + 7,0,0 }, /*0xDF*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucom",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xE0*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucom",REG_FPU_OFFSET + 1,REG_FPU_OFFSET + 0,0 }, /*0xE1*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucom",REG_FPU_OFFSET + 2,REG_FPU_OFFSET + 0,0 }, /*0xE2*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucom",REG_FPU_OFFSET + 3,REG_FPU_OFFSET + 0,0 }, /*0xE3*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucom",REG_FPU_OFFSET + 4,REG_FPU_OFFSET + 0,0 }, /*0xE4*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucom",REG_FPU_OFFSET + 5,REG_FPU_OFFSET + 0,0 }, /*0xE5*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucom",REG_FPU_OFFSET + 6,REG_FPU_OFFSET + 0,0 }, /*0xE6*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucom",REG_FPU_OFFSET + 7,REG_FPU_OFFSET + 0,0 }, /*0xE7*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fucomp",REG_FPU_OFFSET + 0,0,0 }, /*0xE8*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fucomp",REG_FPU_OFFSET + 1,0,0 }, /*0xE9*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fucomp",REG_FPU_OFFSET + 2,0,0 }, /*0xEA*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fucomp",REG_FPU_OFFSET + 3,0,0 }, /*0xEB*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fucomp",REG_FPU_OFFSET + 4,0,0 }, /*0xEC*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fucomp",REG_FPU_OFFSET + 5,0,0 }, /*0xED*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fucomp",REG_FPU_OFFSET + 6,0,0 }, /*0xEE*/ { 0,INS_FPU,OP_REG | OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fucomp",REG_FPU_OFFSET + 7,0,0 }, /*0xEF*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF0*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF1*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF2*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF3*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF4*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF5*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF6*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF7*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF8*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF9*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFA*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFB*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFC*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFD*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFE*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFF*/ }; instr tbl_fpuDE_00BF[] = { { 0,INS_FPU,ADDRMETH_M|OPTYPE_w|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fiadd",0,0,0 }, /*0x0*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_w|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fimul",0,0,0 }, /*0x1*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_w|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"ficom",0,0,0 }, /*0x2*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_w|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"ficomp",0,0,0 }, /*0x3*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_w|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fisub",0,0,0 }, /*0x4*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_w|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fisubr",0,0,0 }, /*0x5*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_w|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fidiv",0,0,0 }, /*0x6*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_w|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fidivr",0,0,0 /*0x7*/ }, }; instr tbl_fpuDE_rest[] = { { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"faddp",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xC0*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"faddp",REG_FPU_OFFSET + 1,REG_FPU_OFFSET + 0,0 }, /*0xC1*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"faddp",REG_FPU_OFFSET + 2,REG_FPU_OFFSET + 0,0 }, /*0xC2*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"faddp",REG_FPU_OFFSET + 3,REG_FPU_OFFSET + 0,0 }, /*0xC3*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"faddp",REG_FPU_OFFSET + 4,REG_FPU_OFFSET + 0,0 }, /*0xC4*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"faddp",REG_FPU_OFFSET + 5,REG_FPU_OFFSET + 0,0 }, /*0xC5*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"faddp",REG_FPU_OFFSET + 6,REG_FPU_OFFSET + 0,0 }, /*0xC6*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"faddp",REG_FPU_OFFSET + 7,REG_FPU_OFFSET + 0,0 }, /*0xC7*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmulp",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xC8*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmulp",REG_FPU_OFFSET + 1,REG_FPU_OFFSET + 0,0 }, /*0xC9*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmulp",REG_FPU_OFFSET + 2,REG_FPU_OFFSET + 0,0 }, /*0xCA*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmulp",REG_FPU_OFFSET + 3,REG_FPU_OFFSET + 0,0 }, /*0xCB*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmulp",REG_FPU_OFFSET + 4,REG_FPU_OFFSET + 0,0 }, /*0xCC*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmulp",REG_FPU_OFFSET + 5,REG_FPU_OFFSET + 0,0 }, /*0xCD*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmulp",REG_FPU_OFFSET + 6,REG_FPU_OFFSET + 0,0 }, /*0xCE*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fmulp",REG_FPU_OFFSET + 7,REG_FPU_OFFSET + 0,0 }, /*0xCF*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD0*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD1*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD2*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD3*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD4*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD5*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD6*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD7*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD8*/ { 0,INS_FPU,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,"fcompp",0,0,0 }, /*0xD9*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDA*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDB*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDC*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDD*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDE*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDF*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubrp",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xE0*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubrp",REG_FPU_OFFSET + 1,REG_FPU_OFFSET + 0,0 }, /*0xE1*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubrp",REG_FPU_OFFSET + 2,REG_FPU_OFFSET + 0,0 }, /*0xE2*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubrp",REG_FPU_OFFSET + 3,REG_FPU_OFFSET + 0,0 }, /*0xE3*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubrp",REG_FPU_OFFSET + 4,REG_FPU_OFFSET + 0,0 }, /*0xE4*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubrp",REG_FPU_OFFSET + 5,REG_FPU_OFFSET + 0,0 }, /*0xE5*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubrp",REG_FPU_OFFSET + 6,REG_FPU_OFFSET + 0,0 }, /*0xE6*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubrp",REG_FPU_OFFSET + 7,REG_FPU_OFFSET + 0,0 }, /*0xE7*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubp",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xE8*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubp",REG_FPU_OFFSET + 1,REG_FPU_OFFSET + 0,0 }, /*0xE9*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubp",REG_FPU_OFFSET + 2,REG_FPU_OFFSET + 0,0 }, /*0xEA*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubp",REG_FPU_OFFSET + 3,REG_FPU_OFFSET + 0,0 }, /*0xEB*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubp",REG_FPU_OFFSET + 4,REG_FPU_OFFSET + 0,0 }, /*0xEC*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubp",REG_FPU_OFFSET + 5,REG_FPU_OFFSET + 0,0 }, /*0xED*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubp",REG_FPU_OFFSET + 6,REG_FPU_OFFSET + 0,0 }, /*0xEE*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fsubp",REG_FPU_OFFSET + 7,REG_FPU_OFFSET + 0,0 }, /*0xEF*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivrp",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xF0*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivrp",REG_FPU_OFFSET + 1,REG_FPU_OFFSET + 0,0 }, /*0xF1*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivrp",REG_FPU_OFFSET + 2,REG_FPU_OFFSET + 0,0 }, /*0xF2*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivrp",REG_FPU_OFFSET + 3,REG_FPU_OFFSET + 0,0 }, /*0xF3*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivrp",REG_FPU_OFFSET + 4,REG_FPU_OFFSET + 0,0 }, /*0xF4*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivrp",REG_FPU_OFFSET + 5,REG_FPU_OFFSET + 0,0 }, /*0xF5*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivrp",REG_FPU_OFFSET + 6,REG_FPU_OFFSET + 0,0 }, /*0xF6*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivrp",REG_FPU_OFFSET + 7,REG_FPU_OFFSET + 0,0 }, /*0xF7*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivp",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xF8*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivp",REG_FPU_OFFSET + 1,REG_FPU_OFFSET + 0,0 }, /*0xF9*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivp",REG_FPU_OFFSET + 2,REG_FPU_OFFSET + 0,0 }, /*0xFA*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivp",REG_FPU_OFFSET + 3,REG_FPU_OFFSET + 0,0 }, /*0xFB*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivp",REG_FPU_OFFSET + 4,REG_FPU_OFFSET + 0,0 }, /*0xFC*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivp",REG_FPU_OFFSET + 5,REG_FPU_OFFSET + 0,0 }, /*0xFD*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivp",REG_FPU_OFFSET + 6,REG_FPU_OFFSET + 0,0 }, /*0xFE*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fdivp",REG_FPU_OFFSET + 7,REG_FPU_OFFSET + 0,0 }, /*0xFF*/ }; instr tbl_fpuDF_00BF[] = { { 0,INS_FPU,ADDRMETH_M|OPTYPE_w|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fild",0,0,0 }, /*0x0*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0x1*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_w|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fist",0,0,0 }, /*0x2*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_w|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fistp",0,0,0 }, /*0x3*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fb|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fbld",0,0,0 }, /*0x4*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_q|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fild",0,0,0 }, /*0x5*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_fb|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fbstp",0,0,0 }, /*0x6*/ { 0,INS_FPU,ADDRMETH_M|OPTYPE_q|OP_W,ARG_NONE,ARG_NONE,cpu_80387,"fistp",0,0,0 /*0x7*/ }, }; instr tbl_fpuDF_rest[] = { { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xC0*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xC1*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xC2*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xC3*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xC4*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xC5*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xC6*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xC7*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xC8*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xC9*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xCA*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xCB*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xCC*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xCD*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xCE*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xCF*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD0*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD1*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD2*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD3*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD4*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD5*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD6*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD7*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD8*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xD9*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDA*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDB*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDC*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDD*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDE*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xDF*/ { 0,INS_FPU,OP_REG,ARG_NONE,ARG_NONE,cpu_80387,"fstsw",REG_WORD_OFFSET + 0,0,0 }, /*0xE0*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE1*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE2*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE3*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE4*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE5*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE6*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xE7*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucomip",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xE8*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucomip",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 1,0 }, /*0xE9*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucomip",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 2,0 }, /*0xEA*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucomip",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 3,0 }, /*0xEB*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucomip",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 4,0 }, /*0xEC*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucomip",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 5,0 }, /*0xED*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucomip",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 6,0 }, /*0xEE*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fucomip",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 7,0 }, /*0xEF*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomip",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 0,0 }, /*0xF0*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomip",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 1,0 }, /*0xF1*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomip",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 2,0 }, /*0xF2*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomip",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 3,0 }, /*0xF3*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomip",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 4,0 }, /*0xF4*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomip",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 5,0 }, /*0xF5*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomip",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 6,0 }, /*0xF6*/ { 0,INS_FPU,OP_REG | OP_W,OP_REG | OP_R,ARG_NONE,cpu_80387,"fcomip",REG_FPU_OFFSET + 0,REG_FPU_OFFSET + 7,0 }, /*0xF7*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF8*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xF9*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFA*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFB*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFC*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFD*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFE*/ { 0,0,ARG_NONE,ARG_NONE,ARG_NONE,cpu_80387,0,0,0,0 }, /*0xFF*/ }; /* ====================================== TABLES OF TABLES ================ */ asmtable tables86[]={ {tbl_Main,0,0xff,0,0xff}, /* 0 */ {tbl_0F,0,0xff,0,0xff}, {tbl_80,3,0x07,0,0xff}, {tbl_81,3,0x07,0,0xff}, {tbl_82,3,0x07,0,0xff}, {tbl_83,3,0x07,0,0xff}, /* 5 */ {tbl_C0,3,0x07,0,0xff}, {tbl_C1,3,0x07,0,0xff}, {tbl_D0,3,0x07,0,0xff}, {tbl_D1,3,0x07,0,0xff}, {tbl_D2,3,0x07,0,0xff}, /* 10 */ {tbl_D3,3,0x07,0,0xff}, {tbl_F6,3,0x07,0,0xff}, {tbl_F7,3,0x07,0,0xff}, {tbl_FE,3,0x07,0,0xff}, {tbl_FF,3,0x07,0,0xff}, /* 15 */ {tbl_0F00,3,0x07,0,0xff}, {tbl_0F01,3,0x07,0,0xff}, {tbl_0F18,3,0x07,0,0xff}, {tbl_0F71,3,0x07,0,0xff}, {tbl_0F72,3,0x07,0,0xff}, /* 20 */ {tbl_0F73,3,0x07,0,0xff}, {tbl_0FAE,3,0x07,0,0xff}, {tbl_0FBA,3,0x07,0,0xff}, {tbl_0FC7,3,0x07,0,0xff}, {tbl_0FC7,3,0x07,0,0xff}, /* 25 */ {tbl_fpuD8_00BF,3,0x07,0,0xbf}, /* CoProc Tables */ {tbl_fpuD8_rest,0,0xff,0xc0,0xff}, {tbl_fpuD9_00BF,3,0x07,0,0xbf}, {tbl_fpuD9_rest,0,0xff,0xc0,0xff}, {tbl_fpuDA_00BF,3,0x07,0,0xbf}, /* 30 */ {tbl_fpuDA_rest,0,0xff,0xc0,0xff}, {tbl_fpuDB_00BF,3,0x07,0,0xbf}, {tbl_fpuDB_rest,0,0xff,0xc0,0xff}, {tbl_fpuDC_00BF,3,0x07,0,0xbf}, {tbl_fpuDC_rest,0,0xff,0xc0,0xff}, /* 35 */ {tbl_fpuDD_00BF,3,0x07,0,0xbf}, {tbl_fpuDD_rest,0,0xff,0xc0,0xff}, {tbl_fpuDE_00BF,3,0x07,0,0xbf}, {tbl_fpuDE_rest,0,0xff,0xc0,0xff}, {tbl_fpuDF_00BF,3,0x07,0,0xbf}, /* 40 */ {tbl_fpuDF_rest,0,0xff,0xc0,0xff} };