===============================================================================
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<invalid instruction>\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 ( <OPCODES> ) {
		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<invalid instruction>\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}
};
