added flags computation optimization
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Wed, 19 Mar 2003 00:00:28 +0000 (00:00 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Wed, 19 Mar 2003 00:00:28 +0000 (00:00 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@34 c046a42c-6fe2-441c-8c8c-71466251a162

13 files changed:
Makefile
TODO
dis-asm.h [new file with mode: 0644]
dis-buf.c [new file with mode: 0644]
dyngen.c
exec-i386.c
gen-i386.h
i386-dis.c [new file with mode: 0644]
linux-user/syscall.c
op-i386.c
opc-i386.h [new file with mode: 0644]
ops_template.h
translate-i386.c

index f922a3e..8b92f0e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -33,7 +33,7 @@ LIBS+=-ldl -lm
 # profiling code
 ifdef TARGET_GPROF
 LDFLAGS+=-p
-CFLAGS+=-p
+main.o: CFLAGS+=-p
 endif
 
 OBJS= elfload.o main.o thunk.o syscall.o
diff --git a/TODO b/TODO
index 1a7bac5..ad3c765 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,9 +1,7 @@
-- optimize translated cache chaining (DLL PLT like system)
-- improved 16 bit support 
-- optimize inverse flags propagation (easy by generating intermediate
-  micro operation array).
+- optimize translated cache chaining (DLL PLT-like system)
+- 64 bit syscalls
 - signals
 - threads
 - make it self runnable (use same trick as ld.so : include its own relocator and libc)
+- improved 16 bit support 
 - fix FPU exceptions (in particular: gen_op_fpush not before mem load)
-- tests
diff --git a/dis-asm.h b/dis-asm.h
new file mode 100644 (file)
index 0000000..bd7e478
--- /dev/null
+++ b/dis-asm.h
@@ -0,0 +1,237 @@
+/* Interface between the opcode library and its callers.
+   Written by Cygnus Support, 1993.
+
+   The opcode library (libopcodes.a) provides instruction decoders for
+   a large variety of instruction sets, callable with an identical
+   interface, for making instruction-processing programs more independent
+   of the instruction set being processed.  */
+
+#ifndef DIS_ASM_H
+#define DIS_ASM_H
+
+#include <stdio.h>
+#include "bfd.h"
+
+typedef int (*fprintf_ftype) PARAMS((FILE*, const char*, ...));
+
+enum dis_insn_type {
+  dis_noninsn,                 /* Not a valid instruction */
+  dis_nonbranch,               /* Not a branch instruction */
+  dis_branch,                  /* Unconditional branch */
+  dis_condbranch,              /* Conditional branch */
+  dis_jsr,                     /* Jump to subroutine */
+  dis_condjsr,                 /* Conditional jump to subroutine */
+  dis_dref,                    /* Data reference instruction */
+  dis_dref2                    /* Two data references in instruction */
+};
+
+/* This struct is passed into the instruction decoding routine, 
+   and is passed back out into each callback.  The various fields are used
+   for conveying information from your main routine into your callbacks,
+   for passing information into the instruction decoders (such as the
+   addresses of the callback functions), or for passing information
+   back from the instruction decoders to their callers.
+
+   It must be initialized before it is first passed; this can be done
+   by hand, or using one of the initialization macros below.  */
+
+typedef struct disassemble_info {
+  fprintf_ftype fprintf_func;
+  FILE *stream;
+  PTR application_data;
+
+  /* Target description.  We could replace this with a pointer to the bfd,
+     but that would require one.  There currently isn't any such requirement
+     so to avoid introducing one we record these explicitly.  */
+  /* The bfd_flavour.  This can be bfd_target_unknown_flavour.  */
+  enum bfd_flavour flavour;
+  /* The bfd_arch value.  */
+  enum bfd_architecture arch;
+  /* The bfd_mach value.  */
+  unsigned long mach;
+  /* Endianness (for bi-endian cpus).  Mono-endian cpus can ignore this.  */
+  enum bfd_endian endian;
+
+  /* An array of pointers to symbols either at the location being disassembled
+     or at the start of the function being disassembled.  The array is sorted
+     so that the first symbol is intended to be the one used.  The others are
+     present for any misc. purposes.  This is not set reliably, but if it is
+     not NULL, it is correct.  */
+  asymbol **symbols;
+  /* Number of symbols in array.  */
+  int num_symbols;
+
+  /* For use by the disassembler.
+     The top 16 bits are reserved for public use (and are documented here).
+     The bottom 16 bits are for the internal use of the disassembler.  */
+  unsigned long flags;
+#define INSN_HAS_RELOC 0x80000000
+  PTR private_data;
+
+  /* Function used to get bytes to disassemble.  MEMADDR is the
+     address of the stuff to be disassembled, MYADDR is the address to
+     put the bytes in, and LENGTH is the number of bytes to read.
+     INFO is a pointer to this struct.
+     Returns an errno value or 0 for success.  */
+  int (*read_memory_func)
+    PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, int length,
+            struct disassemble_info *info));
+
+  /* Function which should be called if we get an error that we can't
+     recover from.  STATUS is the errno value from read_memory_func and
+     MEMADDR is the address that we were trying to read.  INFO is a
+     pointer to this struct.  */
+  void (*memory_error_func)
+    PARAMS ((int status, bfd_vma memaddr, struct disassemble_info *info));
+
+  /* Function called to print ADDR.  */
+  void (*print_address_func)
+    PARAMS ((bfd_vma addr, struct disassemble_info *info));
+
+  /* Function called to determine if there is a symbol at the given ADDR.
+     If there is, the function returns 1, otherwise it returns 0.
+     This is used by ports which support an overlay manager where
+     the overlay number is held in the top part of an address.  In
+     some circumstances we want to include the overlay number in the
+     address, (normally because there is a symbol associated with
+     that address), but sometimes we want to mask out the overlay bits.  */
+  int (* symbol_at_address_func)
+    PARAMS ((bfd_vma addr, struct disassemble_info * info));
+
+  /* These are for buffer_read_memory.  */
+  bfd_byte *buffer;
+  bfd_vma buffer_vma;
+  int buffer_length;
+
+  /* This variable may be set by the instruction decoder.  It suggests
+      the number of bytes objdump should display on a single line.  If
+      the instruction decoder sets this, it should always set it to
+      the same value in order to get reasonable looking output.  */
+  int bytes_per_line;
+
+  /* the next two variables control the way objdump displays the raw data */
+  /* For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the */
+  /* output will look like this:
+     00:   00000000 00000000
+     with the chunks displayed according to "display_endian". */
+  int bytes_per_chunk;
+  enum bfd_endian display_endian;
+
+  /* Results from instruction decoders.  Not all decoders yet support
+     this information.  This info is set each time an instruction is
+     decoded, and is only valid for the last such instruction.
+
+     To determine whether this decoder supports this information, set
+     insn_info_valid to 0, decode an instruction, then check it.  */
+
+  char insn_info_valid;                /* Branch info has been set. */
+  char branch_delay_insns;     /* How many sequential insn's will run before
+                                  a branch takes effect.  (0 = normal) */
+  char data_size;              /* Size of data reference in insn, in bytes */
+  enum dis_insn_type insn_type;        /* Type of instruction */
+  bfd_vma target;              /* Target address of branch or dref, if known;
+                                  zero if unknown.  */
+  bfd_vma target2;             /* Second target address for dref2 */
+
+} disassemble_info;
+
+\f
+/* Standard disassemblers.  Disassemble one instruction at the given
+   target address.  Return number of bytes processed.  */
+typedef int (*disassembler_ftype)
+     PARAMS((bfd_vma, disassemble_info *));
+
+extern int print_insn_big_mips         PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_little_mips      PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_i386             PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_m68k             PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_z8001            PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_z8002            PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_h8300            PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_h8300h           PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_h8300s           PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_h8500            PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_alpha            PARAMS ((bfd_vma, disassemble_info*));
+extern disassembler_ftype arc_get_disassembler PARAMS ((int, int));
+extern int print_insn_big_arm          PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_little_arm       PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_sparc            PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_big_a29k         PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_little_a29k      PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_i960             PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_sh               PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_shl              PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_hppa             PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_m32r             PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_m88k             PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_mn10200          PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_mn10300          PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_ns32k            PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_big_powerpc      PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_little_powerpc   PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_rs6000           PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_w65              PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_d10v             PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_v850             PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_tic30            PARAMS ((bfd_vma, disassemble_info*));
+
+/* Fetch the disassembler for a given BFD, if that support is available.  */
+extern disassembler_ftype disassembler PARAMS ((bfd *));
+
+\f
+/* This block of definitions is for particular callers who read instructions
+   into a buffer before calling the instruction decoder.  */
+
+/* Here is a function which callers may wish to use for read_memory_func.
+   It gets bytes from a buffer.  */
+extern int buffer_read_memory
+  PARAMS ((bfd_vma, bfd_byte *, int, struct disassemble_info *));
+
+/* This function goes with buffer_read_memory.
+   It prints a message using info->fprintf_func and info->stream.  */
+extern void perror_memory PARAMS ((int, bfd_vma, struct disassemble_info *));
+
+
+/* Just print the address in hex.  This is included for completeness even
+   though both GDB and objdump provide their own (to print symbolic
+   addresses).  */
+extern void generic_print_address
+  PARAMS ((bfd_vma, struct disassemble_info *));
+
+/* Always true.  */
+extern int generic_symbol_at_address
+  PARAMS ((bfd_vma, struct disassemble_info *));
+
+/* Macro to initialize a disassemble_info struct.  This should be called
+   by all applications creating such a struct.  */
+#define INIT_DISASSEMBLE_INFO(INFO, STREAM, FPRINTF_FUNC) \
+  (INFO).flavour = bfd_target_unknown_flavour, \
+  (INFO).arch = bfd_arch_unknown, \
+  (INFO).mach = 0, \
+  (INFO).endian = BFD_ENDIAN_UNKNOWN, \
+  INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC)
+
+/* Call this macro to initialize only the internal variables for the
+   disassembler.  Architecture dependent things such as byte order, or machine
+   variant are not touched by this macro.  This makes things much easier for
+   GDB which must initialize these things seperatly.  */
+
+#define INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) \
+  (INFO).fprintf_func = (FPRINTF_FUNC), \
+  (INFO).stream = (STREAM), \
+  (INFO).symbols = NULL, \
+  (INFO).num_symbols = 0, \
+  (INFO).buffer = NULL, \
+  (INFO).buffer_vma = 0, \
+  (INFO).buffer_length = 0, \
+  (INFO).read_memory_func = buffer_read_memory, \
+  (INFO).memory_error_func = perror_memory, \
+  (INFO).print_address_func = generic_print_address, \
+  (INFO).symbol_at_address_func = generic_symbol_at_address, \
+  (INFO).flags = 0, \
+  (INFO).bytes_per_line = 0, \
+  (INFO).bytes_per_chunk = 0, \
+  (INFO).display_endian = BFD_ENDIAN_UNKNOWN, \
+  (INFO).insn_info_valid = 0
+
+#endif /* ! defined (DIS_ASM_H) */
diff --git a/dis-buf.c b/dis-buf.c
new file mode 100644 (file)
index 0000000..cdb8e9b
--- /dev/null
+++ b/dis-buf.c
@@ -0,0 +1,79 @@
+/* Disassemble from a buffer, for GNU.
+   Copyright (C) 1993, 1994 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "dis-asm.h"
+#include <errno.h>
+
+/* Get LENGTH bytes from info's buffer, at target address memaddr.
+   Transfer them to myaddr.  */
+int
+buffer_read_memory (memaddr, myaddr, length, info)
+     bfd_vma memaddr;
+     bfd_byte *myaddr;
+     int length;
+     struct disassemble_info *info;
+{
+  if (memaddr < info->buffer_vma
+      || memaddr + length > info->buffer_vma + info->buffer_length)
+    /* Out of bounds.  Use EIO because GDB uses it.  */
+    return EIO;
+  memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
+  return 0;
+}
+
+/* Print an error message.  We can assume that this is in response to
+   an error return from buffer_read_memory.  */
+void
+perror_memory (status, memaddr, info)
+     int status;
+     bfd_vma memaddr;
+     struct disassemble_info *info;
+{
+  if (status != EIO)
+    /* Can't happen.  */
+    (*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
+  else
+    /* Actually, address between memaddr and memaddr + len was
+       out of bounds.  */
+    (*info->fprintf_func) (info->stream,
+                          "Address 0x%x is out of bounds.\n", memaddr);
+}
+
+/* This could be in a separate file, to save miniscule amounts of space
+   in statically linked executables.  */
+
+/* Just print the address is hex.  This is included for completeness even
+   though both GDB and objdump provide their own (to print symbolic
+   addresses).  */
+
+void
+generic_print_address (addr, info)
+     bfd_vma addr;
+     struct disassemble_info *info;
+{
+  (*info->fprintf_func) (info->stream, "0x%x", addr);
+}
+
+/* Just return the given address.  */
+
+int
+generic_symbol_at_address (addr, info)
+     bfd_vma addr;
+     struct disassemble_info * info;
+{
+  return 1;
+}
index 40a7fc6..9b2889b 100644 (file)
--- a/dyngen.c
+++ b/dyngen.c
@@ -28,7 +28,7 @@
 #include "thunk.h"
 
 /* all dynamically generated functions begin with this code */
-#define OP_PREFIX "op"
+#define OP_PREFIX "op_"
 
 int elf_must_swap(Elf32_Ehdr *h)
 {
@@ -201,7 +201,7 @@ int strstart(const char *str, const char *val, const char **ptr)
 /* generate op code */
 void gen_code(const char *name, unsigned long offset, unsigned long size, 
               FILE *outfile, uint8_t *text, void *relocs, int nb_relocs, int reloc_sh_type,
-              Elf32_Sym *symtab, char *strtab)
+              Elf32_Sym *symtab, char *strtab, int gen_switch)
 {
     int copy_size = 0;
     uint8_t *p_start, *p_end;
@@ -258,8 +258,6 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
                     if (n >= MAX_ARGS)
                         error("too many arguments in %s", name);
                     args_present[n - 1] = 1;
-                } else {
-                    fprintf(outfile, "extern char %s;\n", sym_name);
                 }
             }
         }
@@ -274,8 +272,6 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
                     if (n >= MAX_ARGS)
                         error("too many arguments in %s", name);
                     args_present[n - 1] = 1;
-                } else {
-                    fprintf(outfile, "extern char %s;\n", sym_name);
                 }
             }
         }
@@ -289,33 +285,59 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
             error("inconsistent argument numbering in %s", name);
     }
 
-    /* output C code */
-    fprintf(outfile, "extern void %s();\n", name);
-    fprintf(outfile, "static inline void gen_%s(", name);
-    if (nb_args == 0) {
-        fprintf(outfile, "void");
-    } else {
-        for(i = 0; i < nb_args; i++) {
-            if (i != 0)
-                fprintf(outfile, ", ");
-            fprintf(outfile, "long param%d", i + 1);
+    if (gen_switch) {
+
+        /* output C code */
+        fprintf(outfile, "case INDEX_%s: {\n", name);
+        if (nb_args > 0) {
+            fprintf(outfile, "    long ");
+            for(i = 0; i < nb_args; i++) {
+                if (i != 0)
+                    fprintf(outfile, ", ");
+                fprintf(outfile, "param%d", i + 1);
+            }
+            fprintf(outfile, ";\n");
         }
-    }
-    fprintf(outfile, ")\n");
-    fprintf(outfile, "{\n");
-    fprintf(outfile, "    memcpy(gen_code_ptr, &%s, %d);\n", name, copy_size);
-    
-    /* patch relocations */
-    switch(e_machine) {
-    case EM_386:
-        {
+        fprintf(outfile, "    extern void %s();\n", name);
+
+        if (reloc_sh_type == SHT_REL) {
             Elf32_Rel *rel;
-            char name[256];
-            int type;
-            long addend;
             for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
                 if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
                     sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
+                    if (!strstart(sym_name, "__op_param", &p)) {
+                        fprintf(outfile, "extern char %s;\n", sym_name);
+                    }
+                }
+            }
+        } else {
+            Elf32_Rela *rel;
+            for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+                if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
+                    sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
+                    if (!strstart(sym_name, "__op_param", &p)) {
+                        fprintf(outfile, "extern char %s;\n", sym_name);
+                    }
+                }
+            }
+        }
+
+        fprintf(outfile, "    memcpy(gen_code_ptr, &%s, %d);\n", name, copy_size);
+        for(i = 0; i < nb_args; i++) {
+            fprintf(outfile, "    param%d = *opparam_ptr++;\n", i + 1);
+        }
+
+        /* patch relocations */
+        switch(e_machine) {
+        case EM_386:
+            {
+                Elf32_Rel *rel;
+                char name[256];
+                int type;
+                long addend;
+                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+                if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
+                    sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
                     if (strstart(sym_name, "__op_param", &p)) {
                         snprintf(name, sizeof(name), "param%s", p);
                     } else {
@@ -336,20 +358,38 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
                         error("unsupported i386 relocation (%d)", type);
                     }
                 }
+                }
+            }
+            break;
+        default:
+            error("unsupported CPU for relocations (%d)", e_machine);
+        }
+        fprintf(outfile, "    gen_code_ptr += %d;\n", copy_size);
+        fprintf(outfile, "}\n");
+        fprintf(outfile, "break;\n\n");
+    } else {
+        fprintf(outfile, "static inline void gen_%s(", name);
+        if (nb_args == 0) {
+            fprintf(outfile, "void");
+        } else {
+            for(i = 0; i < nb_args; i++) {
+                if (i != 0)
+                    fprintf(outfile, ", ");
+                fprintf(outfile, "long param%d", i + 1);
             }
         }
-        break;
-    default:
-        error("unsupported CPU for relocations (%d)", e_machine);
+        fprintf(outfile, ")\n");
+        fprintf(outfile, "{\n");
+        for(i = 0; i < nb_args; i++) {
+            fprintf(outfile, "    *gen_opparam_ptr++ = param%d;\n", i + 1);
+        }
+        fprintf(outfile, "    *gen_opc_ptr++ = INDEX_%s;\n", name);
+        fprintf(outfile, "}\n\n");
     }
-
-
-    fprintf(outfile, "    gen_code_ptr += %d;\n", copy_size);
-    fprintf(outfile, "}\n\n");
 }
 
 /* load an elf object file */
-int load_elf(const char *filename, FILE *outfile)
+int load_elf(const char *filename, FILE *outfile, int do_print_enum)
 {
     int fd;
     Elf32_Ehdr ehdr;
@@ -476,23 +516,77 @@ int load_elf(const char *filename, FILE *outfile)
         error("unsupported CPU (e_machine=%d)", e_machine);
     }
 
-    fprintf(outfile, "#include \"gen-%s.h\"\n\n", cpu_name);
+    if (do_print_enum) {
+        fprintf(outfile, "DEF(end)\n");
+        for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
+            const char *name, *p;
+            name = strtab + sym->st_name;
+            if (strstart(name, OP_PREFIX, &p)) {
+                fprintf(outfile, "DEF(%s)\n", p);
+            }
+        }
+    } else {
+        /* generate big code generation switch */
+fprintf(outfile,
+"int dyngen_code(uint8_t *gen_code_buf,\n"
+"                const uint16_t *opc_buf, const uint32_t *opparam_buf)\n"
+"{\n"
+"    uint8_t *gen_code_ptr;\n"
+"    const uint16_t *opc_ptr;\n"
+"    const uint32_t *opparam_ptr;\n"
+"    gen_code_ptr = gen_code_buf;\n"
+"    opc_ptr = opc_buf;\n"
+"    opparam_ptr = opparam_buf;\n"
+"    for(;;) {\n"
+"        switch(*opc_ptr++) {\n"
+);
 
-    for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
-        const char *name;
-        name = strtab + sym->st_name;
-        if (strstart(name, "op_", NULL) ||
-            strstart(name, "op1_", NULL) ||
-            strstart(name, "op2_", NULL) ||
-            strstart(name, "op3_", NULL)) {
+        for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
+            const char *name;
+            name = strtab + sym->st_name;
+            if (strstart(name, OP_PREFIX, NULL)) {
 #if 0
-            printf("%4d: %s pos=0x%08x len=%d\n", 
-                   i, name, sym->st_value, sym->st_size);
+                printf("%4d: %s pos=0x%08x len=%d\n", 
+                       i, name, sym->st_value, sym->st_size);
 #endif
-            if (sym->st_shndx != (text_sec - shdr))
-                error("invalid section for opcode (0x%x)", sym->st_shndx);
-            gen_code(name, sym->st_value, sym->st_size, outfile, 
-                     text, relocs, nb_relocs, reloc_sh_type, symtab, strtab);
+                if (sym->st_shndx != (text_sec - shdr))
+                    error("invalid section for opcode (0x%x)", sym->st_shndx);
+                gen_code(name, sym->st_value, sym->st_size, outfile, 
+                         text, relocs, nb_relocs, reloc_sh_type, symtab, strtab, 1);
+            }
+        }
+
+fprintf(outfile,
+"        default:\n"
+"            goto the_end;\n"
+"        }\n"
+"    }\n"
+" the_end:\n"
+);
+
+/* generate a return */ 
+    switch(e_machine) {
+    case EM_386:
+        fprintf(outfile, "*gen_code_ptr++ = 0xc3; /* ret */\n");
+        break;
+    default:
+        error("no return generation for cpu '%s'", cpu_name);
+    }
+    
+    fprintf(outfile, "return gen_code_ptr -  gen_code_buf;\n");
+    fprintf(outfile, "}\n\n");
+
+/* generate gen_xxx functions */
+/* XXX: suppress the use of these functions to simplify code */
+        for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
+            const char *name;
+            name = strtab + sym->st_name;
+            if (strstart(name, OP_PREFIX, NULL)) {
+                if (sym->st_shndx != (text_sec - shdr))
+                    error("invalid section for opcode (0x%x)", sym->st_shndx);
+                gen_code(name, sym->st_value, sym->st_size, outfile, 
+                         text, relocs, nb_relocs, reloc_sh_type, symtab, strtab, 0);
+            }
         }
     }
 
@@ -503,20 +597,23 @@ int load_elf(const char *filename, FILE *outfile)
 void usage(void)
 {
     printf("dyngen (c) 2003 Fabrice Bellard\n"
-           "usage: dyngen [-o outfile] objfile\n"
-           "Generate a dynamic code generator from an object file\n");
+           "usage: dyngen [-o outfile] [-c] objfile\n"
+           "Generate a dynamic code generator from an object file\n"
+           "-c     output enum of operations\n"
+           );
     exit(1);
 }
 
 int main(int argc, char **argv)
 {
-    int c;
+    int c, do_print_enum;
     const char *filename, *outfilename;
     FILE *outfile;
 
     outfilename = "out.c";
+    do_print_enum = 0;
     for(;;) {
-        c = getopt(argc, argv, "ho:");
+        c = getopt(argc, argv, "ho:c");
         if (c == -1)
             break;
         switch(c) {
@@ -526,6 +623,9 @@ int main(int argc, char **argv)
         case 'o':
             outfilename = optarg;
             break;
+        case 'c':
+            do_print_enum = 1;
+            break;
         }
     }
     if (optind >= argc)
@@ -534,7 +634,7 @@ int main(int argc, char **argv)
     outfile = fopen(outfilename, "w");
     if (!outfile)
         error("could not open '%s'", outfilename);
-    load_elf(filename, outfile);
+    load_elf(filename, outfile, do_print_enum);
     fclose(outfile);
     return 0;
 }
index 8144add..538ebe0 100644 (file)
@@ -19,7 +19,7 @@
  */
 #include "exec-i386.h"
 
-#define DEBUG_EXEC
+//#define DEBUG_EXEC
 #define DEBUG_FLUSH
 
 /* main execution loop */
index a5d7f59..e69de29 100644 (file)
@@ -1,8 +0,0 @@
-static inline void gen_start(void)
-{
-}
-
-static inline void gen_end(void)
-{
-    *gen_code_ptr++ = 0xc3; /* ret */
-}
diff --git a/i386-dis.c b/i386-dis.c
new file mode 100644 (file)
index 0000000..0a63294
--- /dev/null
@@ -0,0 +1,2299 @@
+/* Print i386 instructions for GDB, the GNU debugger.
+   Copyright (C) 1988, 89, 91, 93, 94, 95, 96, 97, 1998
+   Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/*
+ * 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu)
+ * July 1988
+ *  modified by John Hassey (hassey@dg-rtp.dg.com)
+ */
+
+/*
+ * The main tables describing the instructions is essentially a copy
+ * of the "Opcode Map" chapter (Appendix A) of the Intel 80386
+ * Programmers Manual.  Usually, there is a capital letter, followed
+ * by a small letter.  The capital letter tell the addressing mode,
+ * and the small letter tells about the operand size.  Refer to 
+ * the Intel manual for details.
+ */
+
+#include "dis-asm.h"
+
+#define MAXLEN 20
+
+#include <setjmp.h>
+
+static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *));
+
+struct dis_private
+{
+  /* Points to first byte not fetched.  */
+  bfd_byte *max_fetched;
+  bfd_byte the_buffer[MAXLEN];
+  bfd_vma insn_start;
+  jmp_buf bailout;
+};
+
+/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
+   to ADDR (exclusive) are valid.  Returns 1 for success, longjmps
+   on error.  */
+#define FETCH_DATA(info, addr) \
+  ((addr) <= ((struct dis_private *)(info->private_data))->max_fetched \
+   ? 1 : fetch_data ((info), (addr)))
+
+static int
+fetch_data (info, addr)
+     struct disassemble_info *info;
+     bfd_byte *addr;
+{
+  int status;
+  struct dis_private *priv = (struct dis_private *)info->private_data;
+  bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer);
+
+  status = (*info->read_memory_func) (start,
+                                     priv->max_fetched,
+                                     addr - priv->max_fetched,
+                                     info);
+  if (status != 0)
+    {
+      (*info->memory_error_func) (status, start, info);
+      longjmp (priv->bailout, 1);
+    }
+  else
+    priv->max_fetched = addr;
+  return 1;
+}
+
+#define Eb OP_E, b_mode
+#define indirEb OP_indirE, b_mode
+#define Gb OP_G, b_mode
+#define Ev OP_E, v_mode
+#define indirEv OP_indirE, v_mode
+#define Ew OP_E, w_mode
+#define Ma OP_E, v_mode
+#define M OP_E, 0
+#define Mp OP_E, 0             /* ? */
+#define Gv OP_G, v_mode
+#define Gw OP_G, w_mode
+#define Rw OP_rm, w_mode
+#define Rd OP_rm, d_mode
+#define Ib OP_I, b_mode
+#define sIb OP_sI, b_mode      /* sign extened byte */
+#define Iv OP_I, v_mode
+#define Iw OP_I, w_mode
+#define Jb OP_J, b_mode
+#define Jv OP_J, v_mode
+#if 0
+#define ONE OP_ONE, 0
+#endif
+#define Cd OP_C, d_mode
+#define Dd OP_D, d_mode
+#define Td OP_T, d_mode
+
+#define eAX OP_REG, eAX_reg
+#define eBX OP_REG, eBX_reg
+#define eCX OP_REG, eCX_reg
+#define eDX OP_REG, eDX_reg
+#define eSP OP_REG, eSP_reg
+#define eBP OP_REG, eBP_reg
+#define eSI OP_REG, eSI_reg
+#define eDI OP_REG, eDI_reg
+#define AL OP_REG, al_reg
+#define CL OP_REG, cl_reg
+#define DL OP_REG, dl_reg
+#define BL OP_REG, bl_reg
+#define AH OP_REG, ah_reg
+#define CH OP_REG, ch_reg
+#define DH OP_REG, dh_reg
+#define BH OP_REG, bh_reg
+#define AX OP_REG, ax_reg
+#define DX OP_REG, dx_reg
+#define indirDX OP_REG, indir_dx_reg
+
+#define Sw OP_SEG, w_mode
+#define Ap OP_DIR, lptr
+#define Av OP_DIR, v_mode
+#define Ob OP_OFF, b_mode
+#define Ov OP_OFF, v_mode
+#define Xb OP_DSSI, b_mode
+#define Xv OP_DSSI, v_mode
+#define Yb OP_ESDI, b_mode
+#define Yv OP_ESDI, v_mode
+
+#define es OP_REG, es_reg
+#define ss OP_REG, ss_reg
+#define cs OP_REG, cs_reg
+#define ds OP_REG, ds_reg
+#define fs OP_REG, fs_reg
+#define gs OP_REG, gs_reg
+
+#define MX OP_MMX, 0
+#define EM OP_EM, v_mode
+#define MS OP_MS, b_mode
+
+typedef int (*op_rtn) PARAMS ((int bytemode, int aflag, int dflag));
+
+static int OP_E PARAMS ((int, int, int));
+static int OP_G PARAMS ((int, int, int));
+static int OP_I PARAMS ((int, int, int));
+static int OP_indirE PARAMS ((int, int, int));
+static int OP_sI PARAMS ((int, int, int));
+static int OP_REG PARAMS ((int, int, int));
+static int OP_J PARAMS ((int, int, int));
+static int OP_DIR PARAMS ((int, int, int));
+static int OP_OFF PARAMS ((int, int, int));
+static int OP_ESDI PARAMS ((int, int, int));
+static int OP_DSSI PARAMS ((int, int, int));
+static int OP_SEG PARAMS ((int, int, int));
+static int OP_C PARAMS ((int, int, int));
+static int OP_D PARAMS ((int, int, int));
+static int OP_T PARAMS ((int, int, int));
+static int OP_rm PARAMS ((int, int, int));
+static int OP_ST PARAMS ((int, int, int));
+static int OP_STi  PARAMS ((int, int, int));
+#if 0
+static int OP_ONE PARAMS ((int, int, int));
+#endif
+static int OP_MMX PARAMS ((int, int, int));
+static int OP_EM PARAMS ((int, int, int));
+static int OP_MS PARAMS ((int, int, int));
+
+static void append_prefix PARAMS ((void));
+static void set_op PARAMS ((int op));
+static void putop PARAMS ((char *template, int aflag, int dflag));
+static void dofloat PARAMS ((int aflag, int dflag));
+static int get16 PARAMS ((void));
+static int get32 PARAMS ((void));
+static void ckprefix PARAMS ((void));
+
+#define b_mode 1
+#define v_mode 2
+#define w_mode 3
+#define d_mode 4
+
+#define es_reg 100
+#define cs_reg 101
+#define ss_reg 102
+#define ds_reg 103
+#define fs_reg 104
+#define gs_reg 105
+#define eAX_reg 107
+#define eCX_reg 108
+#define eDX_reg 109
+#define eBX_reg 110
+#define eSP_reg 111
+#define eBP_reg 112
+#define eSI_reg 113
+#define eDI_reg 114
+
+#define lptr 115
+
+#define al_reg 116
+#define cl_reg 117
+#define dl_reg 118
+#define bl_reg 119
+#define ah_reg 120
+#define ch_reg 121
+#define dh_reg 122
+#define bh_reg 123
+
+#define ax_reg 124
+#define cx_reg 125
+#define dx_reg 126
+#define bx_reg 127
+#define sp_reg 128
+#define bp_reg 129
+#define si_reg 130
+#define di_reg 131
+
+#define indir_dx_reg 150
+
+#define GRP1b NULL, NULL, 0
+#define GRP1S NULL, NULL, 1
+#define GRP1Ss NULL, NULL, 2
+#define GRP2b NULL, NULL, 3
+#define GRP2S NULL, NULL, 4
+#define GRP2b_one NULL, NULL, 5
+#define GRP2S_one NULL, NULL, 6
+#define GRP2b_cl NULL, NULL, 7
+#define GRP2S_cl NULL, NULL, 8
+#define GRP3b NULL, NULL, 9
+#define GRP3S NULL, NULL, 10
+#define GRP4  NULL, NULL, 11
+#define GRP5  NULL, NULL, 12
+#define GRP6  NULL, NULL, 13
+#define GRP7 NULL, NULL, 14
+#define GRP8 NULL, NULL, 15
+#define GRP9 NULL, NULL, 16
+#define GRP10 NULL, NULL, 17
+#define GRP11 NULL, NULL, 18
+#define GRP12 NULL, NULL, 19
+
+#define FLOATCODE 50
+#define FLOAT NULL, NULL, FLOATCODE
+
+struct dis386 {
+  char *name;
+  op_rtn op1;
+  int bytemode1;
+  op_rtn op2;
+  int bytemode2;
+  op_rtn op3;
+  int bytemode3;
+};
+
+static struct dis386 dis386[] = {
+  /* 00 */
+  { "addb",    Eb, Gb },
+  { "addS",    Ev, Gv },
+  { "addb",    Gb, Eb },
+  { "addS",    Gv, Ev },
+  { "addb",    AL, Ib },
+  { "addS",    eAX, Iv },
+  { "pushS",   es },
+  { "popS",    es },
+  /* 08 */
+  { "orb",     Eb, Gb },
+  { "orS",     Ev, Gv },
+  { "orb",     Gb, Eb },
+  { "orS",     Gv, Ev },
+  { "orb",     AL, Ib },
+  { "orS",     eAX, Iv },
+  { "pushS",   cs },
+  { "(bad)" }, /* 0x0f extended opcode escape */
+  /* 10 */
+  { "adcb",    Eb, Gb },
+  { "adcS",    Ev, Gv },
+  { "adcb",    Gb, Eb },
+  { "adcS",    Gv, Ev },
+  { "adcb",    AL, Ib },
+  { "adcS",    eAX, Iv },
+  { "pushS",   ss },
+  { "popS",    ss },
+  /* 18 */
+  { "sbbb",    Eb, Gb },
+  { "sbbS",    Ev, Gv },
+  { "sbbb",    Gb, Eb },
+  { "sbbS",    Gv, Ev },
+  { "sbbb",    AL, Ib },
+  { "sbbS",    eAX, Iv },
+  { "pushS",   ds },
+  { "popS",    ds },
+  /* 20 */
+  { "andb",    Eb, Gb },
+  { "andS",    Ev, Gv },
+  { "andb",    Gb, Eb },
+  { "andS",    Gv, Ev },
+  { "andb",    AL, Ib },
+  { "andS",    eAX, Iv },
+  { "(bad)" },                 /* SEG ES prefix */
+  { "daa" },
+  /* 28 */
+  { "subb",    Eb, Gb },
+  { "subS",    Ev, Gv },
+  { "subb",    Gb, Eb },
+  { "subS",    Gv, Ev },
+  { "subb",    AL, Ib },
+  { "subS",    eAX, Iv },
+  { "(bad)" },                 /* SEG CS prefix */
+  { "das" },
+  /* 30 */
+  { "xorb",    Eb, Gb },
+  { "xorS",    Ev, Gv },
+  { "xorb",    Gb, Eb },
+  { "xorS",    Gv, Ev },
+  { "xorb",    AL, Ib },
+  { "xorS",    eAX, Iv },
+  { "(bad)" },                 /* SEG SS prefix */
+  { "aaa" },
+  /* 38 */
+  { "cmpb",    Eb, Gb },
+  { "cmpS",    Ev, Gv },
+  { "cmpb",    Gb, Eb },
+  { "cmpS",    Gv, Ev },
+  { "cmpb",    AL, Ib },
+  { "cmpS",    eAX, Iv },
+  { "(bad)" },                 /* SEG DS prefix */
+  { "aas" },
+  /* 40 */
+  { "incS",    eAX },
+  { "incS",    eCX },
+  { "incS",    eDX },
+  { "incS",    eBX },
+  { "incS",    eSP },
+  { "incS",    eBP },
+  { "incS",    eSI },
+  { "incS",    eDI },
+  /* 48 */
+  { "decS",    eAX },
+  { "decS",    eCX },
+  { "decS",    eDX },
+  { "decS",    eBX },
+  { "decS",    eSP },
+  { "decS",    eBP },
+  { "decS",    eSI },
+  { "decS",    eDI },
+  /* 50 */
+  { "pushS",   eAX },
+  { "pushS",   eCX },
+  { "pushS",   eDX },
+  { "pushS",   eBX },
+  { "pushS",   eSP },
+  { "pushS",   eBP },
+  { "pushS",   eSI },
+  { "pushS",   eDI },
+  /* 58 */
+  { "popS",    eAX },
+  { "popS",    eCX },
+  { "popS",    eDX },
+  { "popS",    eBX },
+  { "popS",    eSP },
+  { "popS",    eBP },
+  { "popS",    eSI },
+  { "popS",    eDI },
+  /* 60 */
+  { "pusha" },
+  { "popa" },
+  { "boundS",  Gv, Ma },
+  { "arpl",    Ew, Gw },
+  { "(bad)" },                 /* seg fs */
+  { "(bad)" },                 /* seg gs */
+  { "(bad)" },                 /* op size prefix */
+  { "(bad)" },                 /* adr size prefix */
+  /* 68 */
+  { "pushS",   Iv },           /* 386 book wrong */
+  { "imulS",   Gv, Ev, Iv },
+  { "pushS",   sIb },          /* push of byte really pushes 2 or 4 bytes */
+  { "imulS",   Gv, Ev, Ib },
+  { "insb",    Yb, indirDX },
+  { "insS",    Yv, indirDX },
+  { "outsb",   indirDX, Xb },
+  { "outsS",   indirDX, Xv },
+  /* 70 */
+  { "jo",      Jb },
+  { "jno",     Jb },
+  { "jb",      Jb },
+  { "jae",     Jb },
+  { "je",      Jb },
+  { "jne",     Jb },
+  { "jbe",     Jb },
+  { "ja",      Jb },
+  /* 78 */
+  { "js",      Jb },
+  { "jns",     Jb },
+  { "jp",      Jb },
+  { "jnp",     Jb },
+  { "jl",      Jb },
+  { "jnl",     Jb },
+  { "jle",     Jb },
+  { "jg",      Jb },
+  /* 80 */
+  { GRP1b },
+  { GRP1S },
+  { "(bad)" },
+  { GRP1Ss },
+  { "testb",   Eb, Gb },
+  { "testS",   Ev, Gv },
+  { "xchgb",   Eb, Gb },
+  { "xchgS",   Ev, Gv },
+  /* 88 */
+  { "movb",    Eb, Gb },
+  { "movS",    Ev, Gv },
+  { "movb",    Gb, Eb },
+  { "movS",    Gv, Ev },
+  { "movS",    Ev, Sw },
+  { "leaS",    Gv, M },
+  { "movS",    Sw, Ev },
+  { "popS",    Ev },
+  /* 90 */
+  { "nop" },
+  { "xchgS",   eCX, eAX },
+  { "xchgS",   eDX, eAX },
+  { "xchgS",   eBX, eAX },
+  { "xchgS",   eSP, eAX },
+  { "xchgS",   eBP, eAX },
+  { "xchgS",   eSI, eAX },
+  { "xchgS",   eDI, eAX },
+  /* 98 */
+  { "cWtS" },
+  { "cStd" },
+  { "lcall",   Ap },
+  { "(bad)" },         /* fwait */
+  { "pushf" },
+  { "popf" },
+  { "sahf" },
+  { "lahf" },
+  /* a0 */
+  { "movb",    AL, Ob },
+  { "movS",    eAX, Ov },
+  { "movb",    Ob, AL },
+  { "movS",    Ov, eAX },
+  { "movsb",   Yb, Xb },
+  { "movsS",   Yv, Xv },
+  { "cmpsb",   Yb, Xb },
+  { "cmpsS",   Yv, Xv },
+  /* a8 */
+  { "testb",   AL, Ib },
+  { "testS",   eAX, Iv },
+  { "stosb",   Yb, AL },
+  { "stosS",   Yv, eAX },
+  { "lodsb",   AL, Xb },
+  { "lodsS",   eAX, Xv },
+  { "scasb",   AL, Yb },
+  { "scasS",   eAX, Yv },
+  /* b0 */
+  { "movb",    AL, Ib },
+  { "movb",    CL, Ib },
+  { "movb",    DL, Ib },
+  { "movb",    BL, Ib },
+  { "movb",    AH, Ib },
+  { "movb",    CH, Ib },
+  { "movb",    DH, Ib },
+  { "movb",    BH, Ib },
+  /* b8 */
+  { "movS",    eAX, Iv },
+  { "movS",    eCX, Iv },
+  { "movS",    eDX, Iv },
+  { "movS",    eBX, Iv },
+  { "movS",    eSP, Iv },
+  { "movS",    eBP, Iv },
+  { "movS",    eSI, Iv },
+  { "movS",    eDI, Iv },
+  /* c0 */
+  { GRP2b },
+  { GRP2S },
+  { "ret",     Iw },
+  { "ret" },
+  { "lesS",    Gv, Mp },
+  { "ldsS",    Gv, Mp },
+  { "movb",    Eb, Ib },
+  { "movS",    Ev, Iv },
+  /* c8 */
+  { "enter",   Iw, Ib },
+  { "leave" },
+  { "lret",    Iw },
+  { "lret" },
+  { "int3" },
+  { "int",     Ib },
+  { "into" },
+  { "iret" },
+  /* d0 */
+  { GRP2b_one },
+  { GRP2S_one },
+  { GRP2b_cl },
+  { GRP2S_cl },
+  { "aam",     Ib },
+  { "aad",     Ib },
+  { "(bad)" },
+  { "xlat" },
+  /* d8 */
+  { FLOAT },
+  { FLOAT },
+  { FLOAT },
+  { FLOAT },
+  { FLOAT },
+  { FLOAT },
+  { FLOAT },
+  { FLOAT },
+  /* e0 */
+  { "loopne",  Jb },
+  { "loope",   Jb },
+  { "loop",    Jb },
+  { "jCcxz",   Jb },
+  { "inb",     AL, Ib },
+  { "inS",     eAX, Ib },
+  { "outb",    Ib, AL },
+  { "outS",    Ib, eAX },
+  /* e8 */
+  { "call",    Av },
+  { "jmp",     Jv },
+  { "ljmp",    Ap },
+  { "jmp",     Jb },
+  { "inb",     AL, indirDX },
+  { "inS",     eAX, indirDX },
+  { "outb",    indirDX, AL },
+  { "outS",    indirDX, eAX },
+  /* f0 */
+  { "(bad)" },                 /* lock prefix */
+  { "(bad)" },
+  { "(bad)" },                 /* repne */
+  { "(bad)" },                 /* repz */
+  { "hlt" },
+  { "cmc" },
+  { GRP3b },
+  { GRP3S },
+  /* f8 */
+  { "clc" },
+  { "stc" },
+  { "cli" },
+  { "sti" },
+  { "cld" },
+  { "std" },
+  { GRP4 },
+  { GRP5 },
+};
+
+static struct dis386 dis386_twobyte[] = {
+  /* 00 */
+  { GRP6 },
+  { GRP7 },
+  { "larS", Gv, Ew },
+  { "lslS", Gv, Ew },  
+  { "(bad)" },
+  { "(bad)" },
+  { "clts" },
+  { "(bad)" },  
+  /* 08 */
+  { "invd" },
+  { "wbinvd" },
+  { "(bad)" },  { "ud2a" },  
+  { "(bad)" },  { "(bad)" },  { "(bad)" },  { "(bad)" },  
+  /* 10 */
+  { "(bad)" },  { "(bad)" },  { "(bad)" },  { "(bad)" },  
+  { "(bad)" },  { "(bad)" },  { "(bad)" },  { "(bad)" },  
+  /* 18 */
+  { "(bad)" },  { "(bad)" },  { "(bad)" },  { "(bad)" },  
+  { "(bad)" },  { "(bad)" },  { "(bad)" },  { "(bad)" },  
+  /* 20 */
+  /* these are all backward in appendix A of the intel book */
+  { "movl", Rd, Cd },
+  { "movl", Rd, Dd },
+  { "movl", Cd, Rd },
+  { "movl", Dd, Rd },  
+  { "movl", Rd, Td },
+  { "(bad)" },
+  { "movl", Td, Rd },
+  { "(bad)" },  
+  /* 28 */
+  { "(bad)" },  { "(bad)" },  { "(bad)" },  { "(bad)" },  
+  { "(bad)" },  { "(bad)" },  { "(bad)" },  { "(bad)" },  
+  /* 30 */
+  { "wrmsr" },  { "rdtsc" },  { "rdmsr" },  { "rdpmc" },  
+  { "(bad)" },  { "(bad)" },  { "(bad)" },  { "(bad)" },  
+  /* 38 */
+  { "(bad)" },  { "(bad)" },  { "(bad)" },  { "(bad)" },  
+  { "(bad)" },  { "(bad)" },  { "(bad)" },  { "(bad)" },  
+  /* 40 */
+  { "cmovo", Gv,Ev }, { "cmovno", Gv,Ev }, { "cmovb", Gv,Ev }, { "cmovae", Gv,Ev },
+  { "cmove", Gv,Ev }, { "cmovne", Gv,Ev }, { "cmovbe", Gv,Ev }, { "cmova", Gv,Ev },
+  /* 48 */
+  { "cmovs", Gv,Ev }, { "cmovns", Gv,Ev }, { "cmovp", Gv,Ev }, { "cmovnp", Gv,Ev },
+  { "cmovl", Gv,Ev }, { "cmovge", Gv,Ev }, { "cmovle", Gv,Ev }, { "cmovg", Gv,Ev },  
+  /* 50 */
+  { "(bad)" },  { "(bad)" },  { "(bad)" },  { "(bad)" },  
+  { "(bad)" },  { "(bad)" },  { "(bad)" },  { "(bad)" },  
+  /* 58 */
+  { "(bad)" },  { "(bad)" },  { "(bad)" },  { "(bad)" },  
+  { "(bad)" },  { "(bad)" },  { "(bad)" },  { "(bad)" },  
+  /* 60 */
+  { "punpcklbw", MX, EM },
+  { "punpcklwd", MX, EM },
+  { "punpckldq", MX, EM },
+  { "packsswb", MX, EM },
+  { "pcmpgtb", MX, EM },
+  { "pcmpgtw", MX, EM },
+  { "pcmpgtd", MX, EM },
+  { "packuswb", MX, EM },
+  /* 68 */
+  { "punpckhbw", MX, EM },
+  { "punpckhwd", MX, EM },
+  { "punpckhdq", MX, EM },
+  { "packssdw", MX, EM },
+  { "(bad)" },  { "(bad)" },
+  { "movd", MX, Ev },
+  { "movq", MX, EM },
+  /* 70 */
+  { "(bad)" },
+  { GRP10 },
+  { GRP11 },
+  { GRP12 },
+  { "pcmpeqb", MX, EM },
+  { "pcmpeqw", MX, EM },
+  { "pcmpeqd", MX, EM },
+  { "emms" },
+  /* 78 */
+  { "(bad)" },  { "(bad)" },  { "(bad)" },  { "(bad)" },  
+  { "(bad)" },  { "(bad)" },
+  { "movd", Ev, MX },
+  { "movq", EM, MX },
+  /* 80 */
+  { "jo", Jv },
+  { "jno", Jv },
+  { "jb", Jv },
+  { "jae", Jv },  
+  { "je", Jv },
+  { "jne", Jv },
+  { "jbe", Jv },
+  { "ja", Jv },  
+  /* 88 */
+  { "js", Jv },
+  { "jns", Jv },
+  { "jp", Jv },
+  { "jnp", Jv },  
+  { "jl", Jv },
+  { "jge", Jv },
+  { "jle", Jv },
+  { "jg", Jv },  
+  /* 90 */
+  { "seto", Eb },
+  { "setno", Eb },
+  { "setb", Eb },
+  { "setae", Eb },
+  { "sete", Eb },
+  { "setne", Eb },
+  { "setbe", Eb },
+  { "seta", Eb },
+  /* 98 */
+  { "sets", Eb },
+  { "setns", Eb },
+  { "setp", Eb },
+  { "setnp", Eb },
+  { "setl", Eb },
+  { "setge", Eb },
+  { "setle", Eb },
+  { "setg", Eb },  
+  /* a0 */
+  { "pushS", fs },
+  { "popS", fs },
+  { "cpuid" },
+  { "btS", Ev, Gv },  
+  { "shldS", Ev, Gv, Ib },
+  { "shldS", Ev, Gv, CL },
+  { "(bad)" },
+  { "(bad)" },  
+  /* a8 */
+  { "pushS", gs },
+  { "popS", gs },
+  { "rsm" },
+  { "btsS", Ev, Gv },  
+  { "shrdS", Ev, Gv, Ib },
+  { "shrdS", Ev, Gv, CL },
+  { "(bad)" },
+  { "imulS", Gv, Ev },  
+  /* b0 */
+  { "cmpxchgb", Eb, Gb },
+  { "cmpxchgS", Ev, Gv },
+  { "lssS", Gv, Mp },  /* 386 lists only Mp */
+  { "btrS", Ev, Gv },  
+  { "lfsS", Gv, Mp },  /* 386 lists only Mp */
+  { "lgsS", Gv, Mp },  /* 386 lists only Mp */
+  { "movzbS", Gv, Eb },
+  { "movzwS", Gv, Ew },  
+  /* b8 */
+  { "ud2b" },
+  { "(bad)" },
+  { GRP8 },
+  { "btcS", Ev, Gv },  
+  { "bsfS", Gv, Ev },
+  { "bsrS", Gv, Ev },
+  { "movsbS", Gv, Eb },
+  { "movswS", Gv, Ew },  
+  /* c0 */
+  { "xaddb", Eb, Gb },
+  { "xaddS", Ev, Gv },
+  { "(bad)" },
+  { "(bad)" },  
+  { "(bad)" },
+  { "(bad)" },
+  { "(bad)" },
+  { GRP9 },  
+  /* c8 */
+  { "bswap", eAX },
+  { "bswap", eCX },
+  { "bswap", eDX },
+  { "bswap", eBX },
+  { "bswap", eSP },
+  { "bswap", eBP },
+  { "bswap", eSI },
+  { "bswap", eDI },
+  /* d0 */
+  { "(bad)" },
+  { "psrlw", MX, EM },
+  { "psrld", MX, EM },
+  { "psrlq", MX, EM },
+  { "(bad)" },
+  { "pmullw", MX, EM },
+  { "(bad)" },  { "(bad)" },  
+  /* d8 */
+  { "psubusb", MX, EM },
+  { "psubusw", MX, EM },
+  { "(bad)" },
+  { "pand", MX, EM },
+  { "paddusb", MX, EM },
+  { "paddusw", MX, EM },
+  { "(bad)" },
+  { "pandn", MX, EM },
+  /* e0 */
+  { "(bad)" },
+  { "psraw", MX, EM },
+  { "psrad", MX, EM },
+  { "(bad)" },
+  { "(bad)" },
+  { "pmulhw", MX, EM },
+  { "(bad)" },  { "(bad)" },  
+  /* e8 */
+  { "psubsb", MX, EM },
+  { "psubsw", MX, EM },
+  { "(bad)" },
+  { "por", MX, EM },
+  { "paddsb", MX, EM },
+  { "paddsw", MX, EM },
+  { "(bad)" },
+  { "pxor", MX, EM },
+  /* f0 */
+  { "(bad)" },
+  { "psllw", MX, EM },
+  { "pslld", MX, EM },
+  { "psllq", MX, EM },
+  { "(bad)" },
+  { "pmaddwd", MX, EM },
+  { "(bad)" },  { "(bad)" },  
+  /* f8 */
+  { "psubb", MX, EM },
+  { "psubw", MX, EM },
+  { "psubd", MX, EM },
+  { "(bad)" },  
+  { "paddb", MX, EM },
+  { "paddw", MX, EM },
+  { "paddd", MX, EM },
+  { "(bad)" }
+};
+
+static const unsigned char onebyte_has_modrm[256] = {
+  1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,
+  1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,
+  1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,
+  1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,
+  1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1
+};
+
+static const unsigned char twobyte_has_modrm[256] = {
+  /* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */
+  /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */
+  /* 20 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* 2f */
+  /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */
+  /* 40 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4f */
+  /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */
+  /* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1, /* 6f */
+  /* 70 */ 0,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1, /* 7f */
+  /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
+  /* 90 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 9f */
+  /* a0 */ 0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1, /* af */
+  /* b0 */ 1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1, /* bf */
+  /* c0 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* cf */
+  /* d0 */ 0,1,1,1,0,1,0,0,1,1,0,1,1,1,0,1, /* df */
+  /* e0 */ 0,1,1,0,0,1,0,0,1,1,0,1,1,1,0,1, /* ef */
+  /* f0 */ 0,1,1,1,0,1,0,0,1,1,1,0,1,1,1,0  /* ff */
+};
+
+static char obuf[100];
+static char *obufp;
+static char scratchbuf[100];
+static unsigned char *start_codep;
+static unsigned char *codep;
+static disassemble_info *the_info;
+static int mod;
+static int rm;
+static int reg;
+static void oappend PARAMS ((char *s));
+
+static char *names32[]={
+  "%eax","%ecx","%edx","%ebx", "%esp","%ebp","%esi","%edi",
+};
+static char *names16[] = {
+  "%ax","%cx","%dx","%bx","%sp","%bp","%si","%di",
+};
+static char *names8[] = {
+  "%al","%cl","%dl","%bl","%ah","%ch","%dh","%bh",
+};
+static char *names_seg[] = {
+  "%es","%cs","%ss","%ds","%fs","%gs","%?","%?",
+};
+static char *index16[] = {
+  "bx+si","bx+di","bp+si","bp+di","si","di","bp","bx"
+};
+
+static struct dis386 grps[][8] = {
+  /* GRP1b */
+  {
+    { "addb",  Eb, Ib },
+    { "orb",   Eb, Ib },
+    { "adcb",  Eb, Ib },
+    { "sbbb",  Eb, Ib },
+    { "andb",  Eb, Ib },
+    { "subb",  Eb, Ib },
+    { "xorb",  Eb, Ib },
+    { "cmpb",  Eb, Ib }
+  },
+  /* GRP1S */
+  {
+    { "addS",  Ev, Iv },
+    { "orS",   Ev, Iv },
+    { "adcS",  Ev, Iv },
+    { "sbbS",  Ev, Iv },
+    { "andS",  Ev, Iv },
+    { "subS",  Ev, Iv },
+    { "xorS",  Ev, Iv },
+    { "cmpS",  Ev, Iv }
+  },
+  /* GRP1Ss */
+  {
+    { "addS",  Ev, sIb },
+    { "orS",   Ev, sIb },
+    { "adcS",  Ev, sIb },
+    { "sbbS",  Ev, sIb },
+    { "andS",  Ev, sIb },
+    { "subS",  Ev, sIb },
+    { "xorS",  Ev, sIb },
+    { "cmpS",  Ev, sIb }
+  },
+  /* GRP2b */
+  {
+    { "rolb",  Eb, Ib },
+    { "rorb",  Eb, Ib },
+    { "rclb",  Eb, Ib },
+    { "rcrb",  Eb, Ib },
+    { "shlb",  Eb, Ib },
+    { "shrb",  Eb, Ib },
+    { "(bad)" },
+    { "sarb",  Eb, Ib },
+  },
+  /* GRP2S */
+  {
+    { "rolS",  Ev, Ib },
+    { "rorS",  Ev, Ib },
+    { "rclS",  Ev, Ib },
+    { "rcrS",  Ev, Ib },
+    { "shlS",  Ev, Ib },
+    { "shrS",  Ev, Ib },
+    { "(bad)" },
+    { "sarS",  Ev, Ib },
+  },
+  /* GRP2b_one */
+  {
+    { "rolb",  Eb },
+    { "rorb",  Eb },
+    { "rclb",  Eb },
+    { "rcrb",  Eb },
+    { "shlb",  Eb },
+    { "shrb",  Eb },
+    { "(bad)" },
+    { "sarb",  Eb },
+  },
+  /* GRP2S_one */
+  {
+    { "rolS",  Ev },
+    { "rorS",  Ev },
+    { "rclS",  Ev },
+    { "rcrS",  Ev },
+    { "shlS",  Ev },
+    { "shrS",  Ev },
+    { "(bad)" },
+    { "sarS",  Ev },
+  },
+  /* GRP2b_cl */
+  {
+    { "rolb",  Eb, CL },
+    { "rorb",  Eb, CL },
+    { "rclb",  Eb, CL },
+    { "rcrb",  Eb, CL },
+    { "shlb",  Eb, CL },
+    { "shrb",  Eb, CL },
+    { "(bad)" },
+    { "sarb",  Eb, CL },
+  },
+  /* GRP2S_cl */
+  {
+    { "rolS",  Ev, CL },
+    { "rorS",  Ev, CL },
+    { "rclS",  Ev, CL },
+    { "rcrS",  Ev, CL },
+    { "shlS",  Ev, CL },
+    { "shrS",  Ev, CL },
+    { "(bad)" },
+    { "sarS",  Ev, CL }
+  },
+  /* GRP3b */
+  {
+    { "testb", Eb, Ib },
+    { "(bad)", Eb },
+    { "notb",  Eb },
+    { "negb",  Eb },
+    { "mulb",  AL, Eb },
+    { "imulb", AL, Eb },
+    { "divb",  AL, Eb },
+    { "idivb", AL, Eb }
+  },
+  /* GRP3S */
+  {
+    { "testS", Ev, Iv },
+    { "(bad)" },
+    { "notS",  Ev },
+    { "negS",  Ev },
+    { "mulS",  eAX, Ev },
+    { "imulS", eAX, Ev },
+    { "divS",  eAX, Ev },
+    { "idivS", eAX, Ev },
+  },
+  /* GRP4 */
+  {
+    { "incb", Eb },
+    { "decb", Eb },
+    { "(bad)" },
+    { "(bad)" },
+    { "(bad)" },
+    { "(bad)" },
+    { "(bad)" },
+    { "(bad)" },
+  },
+  /* GRP5 */
+  {
+    { "incS",  Ev },
+    { "decS",  Ev },
+    { "call",  indirEv },
+    { "lcall", indirEv },
+    { "jmp",   indirEv },
+    { "ljmp",  indirEv },
+    { "pushS", Ev },
+    { "(bad)" },
+  },
+  /* GRP6 */
+  {
+    { "sldt",  Ew },
+    { "str",   Ew },
+    { "lldt",  Ew },
+    { "ltr",   Ew },
+    { "verr",  Ew },
+    { "verw",  Ew },
+    { "(bad)" },
+    { "(bad)" }
+  },
+  /* GRP7 */
+  {
+    { "sgdt", Ew },
+    { "sidt", Ew },
+    { "lgdt", Ew },
+    { "lidt", Ew },
+    { "smsw", Ew },
+    { "(bad)" },
+    { "lmsw", Ew },
+    { "invlpg", Ew },
+  },
+  /* GRP8 */
+  {
+    { "(bad)" },
+    { "(bad)" },
+    { "(bad)" },
+    { "(bad)" },
+    { "btS",   Ev, Ib },
+    { "btsS",  Ev, Ib },
+    { "btrS",  Ev, Ib },
+    { "btcS",  Ev, Ib },
+  },
+  /* GRP9 */
+  {
+    { "(bad)" },
+    { "cmpxchg8b", Ev },
+    { "(bad)" },
+    { "(bad)" },
+    { "(bad)" },
+    { "(bad)" },
+    { "(bad)" },
+    { "(bad)" },
+  },
+  /* GRP10 */
+  {
+    { "(bad)" },
+    { "(bad)" },
+    { "psrlw", MS, Ib },
+    { "(bad)" },
+    { "psraw", MS, Ib },
+    { "(bad)" },
+    { "psllw", MS, Ib },
+    { "(bad)" },
+  },
+  /* GRP11 */
+  {
+    { "(bad)" },
+    { "(bad)" },
+    { "psrld", MS, Ib },
+    { "(bad)" },
+    { "psrad", MS, Ib },
+    { "(bad)" },
+    { "pslld", MS, Ib },
+    { "(bad)" },
+  },
+  /* GRP12 */
+  {
+    { "(bad)" },
+    { "(bad)" },
+    { "psrlq", MS, Ib },
+    { "(bad)" },
+    { "(bad)" },
+    { "(bad)" },
+    { "psllq", MS, Ib },
+    { "(bad)" },
+  }
+};
+
+#define PREFIX_REPZ 1
+#define PREFIX_REPNZ 2
+#define PREFIX_LOCK 4
+#define PREFIX_CS 8
+#define PREFIX_SS 0x10
+#define PREFIX_DS 0x20
+#define PREFIX_ES 0x40
+#define PREFIX_FS 0x80
+#define PREFIX_GS 0x100
+#define PREFIX_DATA 0x200
+#define PREFIX_ADR 0x400
+#define PREFIX_FWAIT 0x800
+
+static int prefixes;
+
+static void
+ckprefix ()
+{
+  prefixes = 0;
+  while (1)
+    {
+      FETCH_DATA (the_info, codep + 1);
+      switch (*codep)
+       {
+       case 0xf3:
+         prefixes |= PREFIX_REPZ;
+         break;
+       case 0xf2:
+         prefixes |= PREFIX_REPNZ;
+         break;
+       case 0xf0:
+         prefixes |= PREFIX_LOCK;
+         break;
+       case 0x2e:
+         prefixes |= PREFIX_CS;
+         break;
+       case 0x36:
+         prefixes |= PREFIX_SS;
+         break;
+       case 0x3e:
+         prefixes |= PREFIX_DS;
+         break;
+       case 0x26:
+         prefixes |= PREFIX_ES;
+         break;
+       case 0x64:
+         prefixes |= PREFIX_FS;
+         break;
+       case 0x65:
+         prefixes |= PREFIX_GS;
+         break;
+       case 0x66:
+         prefixes |= PREFIX_DATA;
+         break;
+       case 0x67:
+         prefixes |= PREFIX_ADR;
+         break;
+       case 0x9b:
+         prefixes |= PREFIX_FWAIT;
+         break;
+       default:
+         return;
+       }
+      codep++;
+    }
+}
+
+static char op1out[100], op2out[100], op3out[100];
+static int op_address[3], op_ad, op_index[3];
+static int start_pc;
+
+\f
+/*
+ *   On the 386's of 1988, the maximum length of an instruction is 15 bytes.
+ *   (see topic "Redundant prefixes" in the "Differences from 8086"
+ *   section of the "Virtual 8086 Mode" chapter.)
+ * 'pc' should be the address of this instruction, it will
+ *   be used to print the target address if this is a relative jump or call
+ * The function returns the length of this instruction in bytes.
+ */
+
+int print_insn_x86 PARAMS ((bfd_vma pc, disassemble_info *info, int aflag,
+                           int dflag));
+int
+print_insn_i386 (pc, info)
+     bfd_vma pc;
+     disassemble_info *info;
+{
+  if (info->mach == bfd_mach_i386_i386)
+    return print_insn_x86 (pc, info, 1, 1);
+  else if (info->mach == bfd_mach_i386_i8086)
+    return print_insn_x86 (pc, info, 0, 0);
+  else
+    abort ();
+}
+
+int
+print_insn_x86 (pc, info, aflag, dflag)
+     bfd_vma pc;
+     disassemble_info *info;
+     int aflag;
+     int dflag;
+{
+  struct dis386 *dp;
+  int i;
+  int enter_instruction;
+  char *first, *second, *third;
+  int needcomma;
+  unsigned char need_modrm;
+
+  struct dis_private priv;
+  bfd_byte *inbuf = priv.the_buffer;
+
+  /* The output looks better if we put 5 bytes on a line, since that
+     puts long word instructions on a single line.  */
+  info->bytes_per_line = 5;
+
+  info->private_data = (PTR) &priv;
+  priv.max_fetched = priv.the_buffer;
+  priv.insn_start = pc;
+  if (setjmp (priv.bailout) != 0)
+    /* Error return.  */
+    return -1;
+
+  obuf[0] = 0;
+  op1out[0] = 0;
+  op2out[0] = 0;
+  op3out[0] = 0;
+
+  op_index[0] = op_index[1] = op_index[2] = -1;
+
+  the_info = info;
+  start_pc = pc;
+  start_codep = inbuf;
+  codep = inbuf;
+  
+  ckprefix ();
+
+  FETCH_DATA (info, codep + 1);
+  if (*codep == 0xc8)
+    enter_instruction = 1;
+  else
+    enter_instruction = 0;
+  
+  obufp = obuf;
+  
+  if (prefixes & PREFIX_REPZ)
+    oappend ("repz ");
+  if (prefixes & PREFIX_REPNZ)
+    oappend ("repnz ");
+  if (prefixes & PREFIX_LOCK)
+    oappend ("lock ");
+  
+  if ((prefixes & PREFIX_FWAIT)
+      && ((*codep < 0xd8) || (*codep > 0xdf)))
+    {
+      /* fwait not followed by floating point instruction */
+      (*info->fprintf_func) (info->stream, "fwait");
+      return (1);
+    }
+  
+  if (prefixes & PREFIX_DATA)
+    dflag ^= 1;
+  
+  if (prefixes & PREFIX_ADR)
+    {
+      aflag ^= 1;
+      if (aflag)
+        oappend ("addr32 ");
+      else
+       oappend ("addr16 ");
+    }
+  
+  if (*codep == 0x0f)
+    {
+      FETCH_DATA (info, codep + 2);
+      dp = &dis386_twobyte[*++codep];
+      need_modrm = twobyte_has_modrm[*codep];
+    }
+  else
+    {
+      dp = &dis386[*codep];
+      need_modrm = onebyte_has_modrm[*codep];
+    }
+  codep++;
+
+  if (need_modrm)
+    {
+      FETCH_DATA (info, codep + 1);
+      mod = (*codep >> 6) & 3;
+      reg = (*codep >> 3) & 7;
+      rm = *codep & 7;
+    }
+
+  if (dp->name == NULL && dp->bytemode1 == FLOATCODE)
+    {
+      dofloat (aflag, dflag);
+    }
+  else
+    {
+      if (dp->name == NULL)
+       dp = &grps[dp->bytemode1][reg];
+      
+      putop (dp->name, aflag, dflag);
+      
+      obufp = op1out;
+      op_ad = 2;
+      if (dp->op1)
+       (*dp->op1)(dp->bytemode1, aflag, dflag);
+      
+      obufp = op2out;
+      op_ad = 1;
+      if (dp->op2)
+       (*dp->op2)(dp->bytemode2, aflag, dflag);
+      
+      obufp = op3out;
+      op_ad = 0;
+      if (dp->op3)
+       (*dp->op3)(dp->bytemode3, aflag, dflag);
+    }
+  
+  obufp = obuf + strlen (obuf);
+  for (i = strlen (obuf); i < 6; i++)
+    oappend (" ");
+  oappend (" ");
+  (*info->fprintf_func) (info->stream, "%s", obuf);
+  
+  /* enter instruction is printed with operands in the
+   * same order as the intel book; everything else
+   * is printed in reverse order 
+   */
+  if (enter_instruction)
+    {
+      first = op1out;
+      second = op2out;
+      third = op3out;
+      op_ad = op_index[0];
+      op_index[0] = op_index[2];
+      op_index[2] = op_ad;
+    }
+  else
+    {
+      first = op3out;
+      second = op2out;
+      third = op1out;
+    }
+  needcomma = 0;
+  if (*first)
+    {
+      if (op_index[0] != -1)
+       (*info->print_address_func) (op_address[op_index[0]], info);
+      else
+       (*info->fprintf_func) (info->stream, "%s", first);
+      needcomma = 1;
+    }
+  if (*second)
+    {
+      if (needcomma)
+       (*info->fprintf_func) (info->stream, ",");
+      if (op_index[1] != -1)
+       (*info->print_address_func) (op_address[op_index[1]], info);
+      else
+       (*info->fprintf_func) (info->stream, "%s", second);
+      needcomma = 1;
+    }
+  if (*third)
+    {
+      if (needcomma)
+       (*info->fprintf_func) (info->stream, ",");
+      if (op_index[2] != -1)
+       (*info->print_address_func) (op_address[op_index[2]], info);
+      else
+       (*info->fprintf_func) (info->stream, "%s", third);
+    }
+  return (codep - inbuf);
+}
+
+static char *float_mem[] = {
+  /* d8 */
+  "fadds",
+  "fmuls",
+  "fcoms",
+  "fcomps",
+  "fsubs",
+  "fsubrs",
+  "fdivs",
+  "fdivrs",
+  /*  d9 */
+  "flds",
+  "(bad)",
+  "fsts",
+  "fstps",
+  "fldenv",
+  "fldcw",
+  "fNstenv",
+  "fNstcw",
+  /* da */
+  "fiaddl",
+  "fimull",
+  "ficoml",
+  "ficompl",
+  "fisubl",
+  "fisubrl",
+  "fidivl",
+  "fidivrl",
+  /* db */
+  "fildl",
+  "(bad)",
+  "fistl",
+  "fistpl",
+  "(bad)",
+  "fldt",
+  "(bad)",
+  "fstpt",
+  /* dc */
+  "faddl",
+  "fmull",
+  "fcoml",
+  "fcompl",
+  "fsubl",
+  "fsubrl",
+  "fdivl",
+  "fdivrl",
+  /* dd */
+  "fldl",
+  "(bad)",
+  "fstl",
+  "fstpl",
+  "frstor",
+  "(bad)",
+  "fNsave",
+  "fNstsw",
+  /* de */
+  "fiadd",
+  "fimul",
+  "ficom",
+  "ficomp",
+  "fisub",
+  "fisubr",
+  "fidiv",
+  "fidivr",
+  /* df */
+  "fild",
+  "(bad)",
+  "fist",
+  "fistp",
+  "fbld",
+  "fildll",
+  "fbstp",
+  "fistpll",
+};
+
+#define ST OP_ST, 0
+#define STi OP_STi, 0
+
+#define FGRPd9_2 NULL, NULL, 0
+#define FGRPd9_4 NULL, NULL, 1
+#define FGRPd9_5 NULL, NULL, 2
+#define FGRPd9_6 NULL, NULL, 3
+#define FGRPd9_7 NULL, NULL, 4
+#define FGRPda_5 NULL, NULL, 5
+#define FGRPdb_4 NULL, NULL, 6
+#define FGRPde_3 NULL, NULL, 7
+#define FGRPdf_4 NULL, NULL, 8
+
+static struct dis386 float_reg[][8] = {
+  /* d8 */
+  {
+    { "fadd",  ST, STi },
+    { "fmul",  ST, STi },
+    { "fcom",  STi },
+    { "fcomp", STi },
+    { "fsub",  ST, STi },
+    { "fsubr", ST, STi },
+    { "fdiv",  ST, STi },
+    { "fdivr", ST, STi },
+  },
+  /* d9 */
+  {
+    { "fld",   STi },
+    { "fxch",  STi },
+    { FGRPd9_2 },
+    { "(bad)" },
+    { FGRPd9_4 },
+    { FGRPd9_5 },
+    { FGRPd9_6 },
+    { FGRPd9_7 },
+  },
+  /* da */
+  {
+    { "fcmovb",        ST, STi },
+    { "fcmove",        ST, STi },
+    { "fcmovbe",ST, STi },
+    { "fcmovu",        ST, STi },
+    { "(bad)" },
+    { FGRPda_5 },
+    { "(bad)" },
+    { "(bad)" },
+  },
+  /* db */
+  {
+    { "fcmovnb",ST, STi },
+    { "fcmovne",ST, STi },
+    { "fcmovnbe",ST, STi },
+    { "fcmovnu",ST, STi },
+    { FGRPdb_4 },
+    { "fucomi",        ST, STi },
+    { "fcomi", ST, STi },
+    { "(bad)" },
+  },
+  /* dc */
+  {
+    { "fadd",  STi, ST },
+    { "fmul",  STi, ST },
+    { "(bad)" },
+    { "(bad)" },
+    { "fsub",  STi, ST },
+    { "fsubr", STi, ST },
+    { "fdiv",  STi, ST },
+    { "fdivr", STi, ST },
+  },
+  /* dd */
+  {
+    { "ffree", STi },
+    { "(bad)" },
+    { "fst",   STi },
+    { "fstp",  STi },
+    { "fucom", STi },
+    { "fucomp",        STi },
+    { "(bad)" },
+    { "(bad)" },
+  },
+  /* de */
+  {
+    { "faddp", STi, ST },
+    { "fmulp", STi, ST },
+    { "(bad)" },
+    { FGRPde_3 },
+    { "fsubp", STi, ST },
+    { "fsubrp",        STi, ST },
+    { "fdivp", STi, ST },
+    { "fdivrp",        STi, ST },
+  },
+  /* df */
+  {
+    { "(bad)" },
+    { "(bad)" },
+    { "(bad)" },
+    { "(bad)" },
+    { FGRPdf_4 },
+    { "fucomip",ST, STi },
+    { "fcomip", ST, STi },
+    { "(bad)" },
+  },
+};
+
+
+static char *fgrps[][8] = {
+  /* d9_2  0 */
+  {
+    "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+  },
+
+  /* d9_4  1 */
+  {
+    "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)",
+  },
+
+  /* d9_5  2 */
+  {
+    "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)",
+  },
+
+  /* d9_6  3 */
+  {
+    "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp",
+  },
+
+  /* d9_7  4 */
+  {
+    "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos",
+  },
+
+  /* da_5  5 */
+  {
+    "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+  },
+
+  /* db_4  6 */
+  {
+    "feni(287 only)","fdisi(287 only)","fNclex","fNinit",
+    "fNsetpm(287 only)","(bad)","(bad)","(bad)",
+  },
+
+  /* de_3  7 */
+  {
+    "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+  },
+
+  /* df_4  8 */
+  {
+    "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+  },
+};
+
+static void
+dofloat (aflag, dflag)
+     int aflag;
+     int dflag;
+{
+  struct dis386 *dp;
+  unsigned char floatop;
+  
+  floatop = codep[-1];
+  
+  if (mod != 3)
+    {
+      putop (float_mem[(floatop - 0xd8) * 8 + reg], aflag, dflag);
+      obufp = op1out;
+      OP_E (v_mode, aflag, dflag);
+      return;
+    }
+  codep++;
+  
+  dp = &float_reg[floatop - 0xd8][reg];
+  if (dp->name == NULL)
+    {
+      putop (fgrps[dp->bytemode1][rm], aflag, dflag);
+      /* instruction fnstsw is only one with strange arg */
+      if (floatop == 0xdf
+         && FETCH_DATA (the_info, codep + 1)
+         && *codep == 0xe0)
+       strcpy (op1out, "%eax");
+    }
+  else
+    {
+      putop (dp->name, aflag, dflag);
+      obufp = op1out;
+      if (dp->op1)
+       (*dp->op1)(dp->bytemode1, aflag, dflag);
+      obufp = op2out;
+      if (dp->op2)
+       (*dp->op2)(dp->bytemode2, aflag, dflag);
+    }
+}
+
+/* ARGSUSED */
+static int
+OP_ST (ignore, aflag, dflag)
+     int ignore;
+     int aflag;
+     int dflag;
+{
+  oappend ("%st");
+  return (0);
+}
+
+/* ARGSUSED */
+static int
+OP_STi (ignore, aflag, dflag)
+     int ignore;
+     int aflag;
+     int dflag;
+{
+  sprintf (scratchbuf, "%%st(%d)", rm);
+  oappend (scratchbuf);
+  return (0);
+}
+
+
+/* capital letters in template are macros */
+static void
+putop (template, aflag, dflag)
+     char *template;
+     int aflag;
+     int dflag;
+{
+  char *p;
+  
+  for (p = template; *p; p++)
+    {
+      switch (*p)
+       {
+       default:
+         *obufp++ = *p;
+         break;
+       case 'C':               /* For jcxz/jecxz */
+         if (aflag)
+           *obufp++ = 'e';
+         break;
+       case 'N':
+         if ((prefixes & PREFIX_FWAIT) == 0)
+           *obufp++ = 'n';
+         break;
+       case 'S':
+         /* operand size flag */
+         if (dflag)
+           *obufp++ = 'l';
+         else
+           *obufp++ = 'w';
+         break;
+       case 'W':
+         /* operand size flag for cwtl, cbtw */
+         if (dflag)
+           *obufp++ = 'w';
+         else
+           *obufp++ = 'b';
+         break;
+       }
+    }
+  *obufp = 0;
+}
+
+static void
+oappend (s)
+     char *s;
+{
+  strcpy (obufp, s);
+  obufp += strlen (s);
+  *obufp = 0;
+}
+
+static void
+append_prefix ()
+{
+  if (prefixes & PREFIX_CS)
+    oappend ("%cs:");
+  if (prefixes & PREFIX_DS)
+    oappend ("%ds:");
+  if (prefixes & PREFIX_SS)
+    oappend ("%ss:");
+  if (prefixes & PREFIX_ES)
+    oappend ("%es:");
+  if (prefixes & PREFIX_FS)
+    oappend ("%fs:");
+  if (prefixes & PREFIX_GS)
+    oappend ("%gs:");
+}
+
+static int
+OP_indirE (bytemode, aflag, dflag)
+     int bytemode;
+     int aflag;
+     int dflag;
+{
+  oappend ("*");
+  return OP_E (bytemode, aflag, dflag);
+}
+
+static int
+OP_E (bytemode, aflag, dflag)
+     int bytemode;
+     int aflag;
+     int dflag;
+{
+  int disp;
+
+  /* skip mod/rm byte */
+  codep++;
+
+  if (mod == 3)
+    {
+      switch (bytemode)
+       {
+       case b_mode:
+         oappend (names8[rm]);
+         break;
+       case w_mode:
+         oappend (names16[rm]);
+         break;
+       case v_mode:
+         if (dflag)
+           oappend (names32[rm]);
+         else
+           oappend (names16[rm]);
+         break;
+       default:
+         oappend ("<bad dis table>");
+         break;
+       }
+      return 0;
+    }
+
+  disp = 0;
+  append_prefix ();
+
+  if (aflag) /* 32 bit address mode */
+    {
+      int havesib;
+      int havebase;
+      int base;
+      int index = 0;
+      int scale = 0;
+
+      havesib = 0;
+      havebase = 1;
+      base = rm;
+
+      if (base == 4)
+       {
+         havesib = 1;
+         FETCH_DATA (the_info, codep + 1);
+         scale = (*codep >> 6) & 3;
+         index = (*codep >> 3) & 7;
+         base = *codep & 7;
+         codep++;
+       }
+
+      switch (mod)
+       {
+       case 0:
+         if (base == 5)
+           {
+             havebase = 0;
+             disp = get32 ();
+           }
+         break;
+       case 1:
+         FETCH_DATA (the_info, codep + 1);
+         disp = *codep++;
+         if ((disp & 0x80) != 0)
+           disp -= 0x100;
+         break;
+       case 2:
+         disp = get32 ();
+         break;
+       }
+
+      if (mod != 0 || base == 5)
+       {
+         sprintf (scratchbuf, "0x%x", disp);
+         oappend (scratchbuf);
+       }
+
+      if (havebase || (havesib && (index != 4 || scale != 0)))
+       {
+         oappend ("(");
+         if (havebase)
+           oappend (names32[base]);
+         if (havesib)
+           {
+             if (index != 4)
+               {
+                 sprintf (scratchbuf, ",%s", names32[index]);
+                 oappend (scratchbuf);
+               }
+             sprintf (scratchbuf, ",%d", 1 << scale);
+             oappend (scratchbuf);
+           }
+         oappend (")");
+       }
+    }
+  else
+    { /* 16 bit address mode */
+      switch (mod)
+       {
+       case 0:
+         if (rm == 6)
+           {
+             disp = get16 ();
+             if ((disp & 0x8000) != 0)
+               disp -= 0x10000;
+           }
+         break;
+       case 1:
+         FETCH_DATA (the_info, codep + 1);
+         disp = *codep++;
+         if ((disp & 0x80) != 0)
+           disp -= 0x100;
+         break;
+       case 2:
+         disp = get16 ();
+         if ((disp & 0x8000) != 0)
+           disp -= 0x10000;
+         break;
+       }
+
+      if (mod != 0 || rm == 6)
+       {
+         sprintf (scratchbuf, "0x%x", disp);
+         oappend (scratchbuf);
+       }
+
+      if (mod != 0 || rm != 6)
+       {
+         oappend ("(");
+         oappend (index16[rm]);
+         oappend (")");
+       }
+    }
+  return 0;
+}
+
+static int
+OP_G (bytemode, aflag, dflag)
+     int bytemode;
+     int aflag;
+     int dflag;
+{
+  switch (bytemode) 
+    {
+    case b_mode:
+      oappend (names8[reg]);
+      break;
+    case w_mode:
+      oappend (names16[reg]);
+      break;
+    case d_mode:
+      oappend (names32[reg]);
+      break;
+    case v_mode:
+      if (dflag)
+       oappend (names32[reg]);
+      else
+       oappend (names16[reg]);
+      break;
+    default:
+      oappend ("<internal disassembler error>");
+      break;
+    }
+  return (0);
+}
+
+static int
+get32 ()
+{
+  int x = 0;
+
+  FETCH_DATA (the_info, codep + 4);
+  x = *codep++ & 0xff;
+  x |= (*codep++ & 0xff) << 8;
+  x |= (*codep++ & 0xff) << 16;
+  x |= (*codep++ & 0xff) << 24;
+  return (x);
+}
+
+static int
+get16 ()
+{
+  int x = 0;
+
+  FETCH_DATA (the_info, codep + 2);
+  x = *codep++ & 0xff;
+  x |= (*codep++ & 0xff) << 8;
+  return (x);
+}
+
+static void
+set_op (op)
+     int op;
+{
+  op_index[op_ad] = op_ad;
+  op_address[op_ad] = op;
+}
+
+static int
+OP_REG (code, aflag, dflag)
+     int code;
+     int aflag;
+     int dflag;
+{
+  char *s;
+  
+  switch (code) 
+    {
+    case indir_dx_reg: s = "(%dx)"; break;
+       case ax_reg: case cx_reg: case dx_reg: case bx_reg:
+       case sp_reg: case bp_reg: case si_reg: case di_reg:
+               s = names16[code - ax_reg];
+               break;
+       case es_reg: case ss_reg: case cs_reg:
+       case ds_reg: case fs_reg: case gs_reg:
+               s = names_seg[code - es_reg];
+               break;
+       case al_reg: case ah_reg: case cl_reg: case ch_reg:
+       case dl_reg: case dh_reg: case bl_reg: case bh_reg:
+               s = names8[code - al_reg];
+               break;
+       case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg:
+       case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg:
+      if (dflag)
+       s = names32[code - eAX_reg];
+      else
+       s = names16[code - eAX_reg];
+      break;
+    default:
+      s = "<internal disassembler error>";
+      break;
+    }
+  oappend (s);
+  return (0);
+}
+
+static int
+OP_I (bytemode, aflag, dflag)
+     int bytemode;
+     int aflag;
+     int dflag;
+{
+  int op;
+  
+  switch (bytemode) 
+    {
+    case b_mode:
+      FETCH_DATA (the_info, codep + 1);
+      op = *codep++ & 0xff;
+      break;
+    case v_mode:
+      if (dflag)
+       op = get32 ();
+      else
+       op = get16 ();
+      break;
+    case w_mode:
+      op = get16 ();
+      break;
+    default:
+      oappend ("<internal disassembler error>");
+      return (0);
+    }
+  sprintf (scratchbuf, "$0x%x", op);
+  oappend (scratchbuf);
+  return (0);
+}
+
+static int
+OP_sI (bytemode, aflag, dflag)
+     int bytemode;
+     int aflag;
+     int dflag;
+{
+  int op;
+  
+  switch (bytemode) 
+    {
+    case b_mode:
+      FETCH_DATA (the_info, codep + 1);
+      op = *codep++;
+      if ((op & 0x80) != 0)
+       op -= 0x100;
+      break;
+    case v_mode:
+      if (dflag)
+       op = get32 ();
+      else
+       {
+         op = get16();
+         if ((op & 0x8000) != 0)
+           op -= 0x10000;
+       }
+      break;
+    case w_mode:
+      op = get16 ();
+      if ((op & 0x8000) != 0)
+       op -= 0x10000;
+      break;
+    default:
+      oappend ("<internal disassembler error>");
+      return (0);
+    }
+  sprintf (scratchbuf, "$0x%x", op);
+  oappend (scratchbuf);
+  return (0);
+}
+
+static int
+OP_J (bytemode, aflag, dflag)
+     int bytemode;
+     int aflag;
+     int dflag;
+{
+  int disp;
+  int mask = -1;
+  
+  switch (bytemode) 
+    {
+    case b_mode:
+      FETCH_DATA (the_info, codep + 1);
+      disp = *codep++;
+      if ((disp & 0x80) != 0)
+       disp -= 0x100;
+      break;
+    case v_mode:
+      if (dflag)
+       disp = get32 ();
+      else
+       {
+         disp = get16 ();
+         if ((disp & 0x8000) != 0)
+           disp -= 0x10000;
+         /* for some reason, a data16 prefix on a jump instruction
+            means that the pc is masked to 16 bits after the
+            displacement is added!  */
+         mask = 0xffff;
+       }
+      break;
+    default:
+      oappend ("<internal disassembler error>");
+      return (0);
+    }
+  disp = (start_pc + codep - start_codep + disp) & mask;
+  set_op (disp);
+  sprintf (scratchbuf, "0x%x", disp);
+  oappend (scratchbuf);
+  return (0);
+}
+
+/* ARGSUSED */
+static int
+OP_SEG (dummy, aflag, dflag)
+     int dummy;
+     int aflag;
+     int dflag;
+{
+  static char *sreg[] = {
+    "%es","%cs","%ss","%ds","%fs","%gs","%?","%?",
+  };
+
+  oappend (sreg[reg]);
+  return (0);
+}
+
+static int
+OP_DIR (size, aflag, dflag)
+     int size;
+     int aflag;
+     int dflag;
+{
+  int seg, offset;
+  
+  switch (size) 
+    {
+    case lptr:
+      if (aflag) 
+       {
+         offset = get32 ();
+         seg = get16 ();
+       } 
+      else 
+       {
+         offset = get16 ();
+         seg = get16 ();
+       }
+      sprintf (scratchbuf, "0x%x,0x%x", seg, offset);
+      oappend (scratchbuf);
+      break;
+    case v_mode:
+      if (aflag)
+       offset = get32 ();
+      else
+       {
+         offset = get16 ();
+         if ((offset & 0x8000) != 0)
+           offset -= 0x10000;
+       }
+      
+      offset = start_pc + codep - start_codep + offset;
+      set_op (offset);
+      sprintf (scratchbuf, "0x%x", offset);
+      oappend (scratchbuf);
+      break;
+    default:
+      oappend ("<internal disassembler error>");
+      break;
+    }
+  return (0);
+}
+
+/* ARGSUSED */
+static int
+OP_OFF (bytemode, aflag, dflag)
+     int bytemode;
+     int aflag;
+     int dflag;
+{
+  int off;
+
+  append_prefix ();
+
+  if (aflag)
+    off = get32 ();
+  else
+    off = get16 ();
+  
+  sprintf (scratchbuf, "0x%x", off);
+  oappend (scratchbuf);
+  return (0);
+}
+
+/* ARGSUSED */
+static int
+OP_ESDI (dummy, aflag, dflag)
+     int dummy;
+     int aflag;
+     int dflag;
+{
+  oappend ("%es:(");
+  oappend (aflag ? "%edi" : "%di");
+  oappend (")");
+  return (0);
+}
+
+/* ARGSUSED */
+static int
+OP_DSSI (dummy, aflag, dflag)
+     int dummy;
+     int aflag;
+     int dflag;
+{
+  if ((prefixes
+       & (PREFIX_CS
+         | PREFIX_DS
+         | PREFIX_SS
+         | PREFIX_ES
+         | PREFIX_FS
+         | PREFIX_GS)) == 0)
+    prefixes |= PREFIX_DS;
+  append_prefix ();
+  oappend ("(");
+  oappend (aflag ? "%esi" : "%si");
+  oappend (")");
+  return (0);
+}
+
+#if 0
+/* Not used.  */
+
+/* ARGSUSED */
+static int
+OP_ONE (dummy, aflag, dflag)
+     int dummy;
+     int aflag;
+     int dflag;
+{
+  oappend ("1");
+  return (0);
+}
+
+#endif
+
+/* ARGSUSED */
+static int
+OP_C (dummy, aflag, dflag)
+     int dummy;
+     int aflag;
+     int dflag;
+{
+  codep++; /* skip mod/rm */
+  sprintf (scratchbuf, "%%cr%d", reg);
+  oappend (scratchbuf);
+  return (0);
+}
+
+/* ARGSUSED */
+static int
+OP_D (dummy, aflag, dflag)
+     int dummy;
+     int aflag;
+     int dflag;
+{
+  codep++; /* skip mod/rm */
+  sprintf (scratchbuf, "%%db%d", reg);
+  oappend (scratchbuf);
+  return (0);
+}
+
+/* ARGSUSED */
+static int
+OP_T (dummy, aflag, dflag)
+     int dummy;
+     int aflag;
+     int dflag;
+{
+  codep++; /* skip mod/rm */
+  sprintf (scratchbuf, "%%tr%d", reg);
+  oappend (scratchbuf);
+  return (0);
+}
+
+static int
+OP_rm (bytemode, aflag, dflag)
+     int bytemode;
+     int aflag;
+     int dflag;
+{
+  switch (bytemode) 
+    {
+    case d_mode:
+      oappend (names32[rm]);
+      break;
+    case w_mode:
+      oappend (names16[rm]);
+      break;
+    }
+  return (0);
+}
+
+static int
+OP_MMX (bytemode, aflag, dflag)
+     int bytemode;
+     int aflag;
+     int dflag;
+{
+  sprintf (scratchbuf, "%%mm%d", reg);
+  oappend (scratchbuf);
+  return 0;
+}
+
+static int
+OP_EM (bytemode, aflag, dflag)
+     int bytemode;
+     int aflag;
+     int dflag;
+{
+  if (mod != 3)
+    return OP_E (bytemode, aflag, dflag);
+
+  codep++;
+  sprintf (scratchbuf, "%%mm%d", rm);
+  oappend (scratchbuf);
+  return 0;
+}
+
+static int
+OP_MS (bytemode, aflag, dflag)
+     int bytemode;
+     int aflag;
+     int dflag;
+{
+  ++codep;
+  sprintf (scratchbuf, "%%mm%d", rm);
+  oappend (scratchbuf);
+  return 0;
+}
index 1e7dced..e6f04a8 100644 (file)
@@ -1000,7 +1000,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
         ret = get_errno(setsid());
         break;
     case TARGET_NR_sigaction:
-#if 1
+#if 0
         {
             ret = 0;
         }
index f8188e3..002ce96 100644 (file)
--- a/op-i386.c
+++ b/op-i386.c
@@ -177,7 +177,7 @@ void raise_exception(int exception_index)
 #undef REG
 #undef REGNAME
 
-/* operations */
+/* operations with flags */
 
 void OPPROTO op_addl_T0_T1_cc(void)
 {
@@ -217,11 +217,6 @@ void OPPROTO op_cmpl_T0_T1_cc(void)
     CC_DST = T0 - T1;
 }
 
-void OPPROTO op_notl_T0(void)
-{
-    T0 = ~T0;
-}
-
 void OPPROTO op_negl_T0_cc(void)
 {
     CC_SRC = 0;
@@ -248,6 +243,53 @@ void OPPROTO op_testl_T0_T1_cc(void)
     CC_DST = T0 & T1;
 }
 
+/* operations without flags */
+
+void OPPROTO op_addl_T0_T1(void)
+{
+    T0 += T1;
+}
+
+void OPPROTO op_orl_T0_T1(void)
+{
+    T0 |= T1;
+}
+
+void OPPROTO op_andl_T0_T1(void)
+{
+    T0 &= T1;
+}
+
+void OPPROTO op_subl_T0_T1(void)
+{
+    T0 -= T1;
+}
+
+void OPPROTO op_xorl_T0_T1(void)
+{
+    T0 ^= T1;
+}
+
+void OPPROTO op_negl_T0(void)
+{
+    T0 = -T0;
+}
+
+void OPPROTO op_incl_T0(void)
+{
+    T0++;
+}
+
+void OPPROTO op_decl_T0(void)
+{
+    T0--;
+}
+
+void OPPROTO op_notl_T0(void)
+{
+    T0 = ~T0;
+}
+
 void OPPROTO op_bswapl_T0(void)
 {
     T0 = bswap32(T0);
diff --git a/opc-i386.h b/opc-i386.h
new file mode 100644 (file)
index 0000000..aae2894
--- /dev/null
@@ -0,0 +1,518 @@
+DEF(end)
+DEF(movl_A0_EAX)
+DEF(addl_A0_EAX)
+DEF(addl_A0_EAX_s1)
+DEF(addl_A0_EAX_s2)
+DEF(addl_A0_EAX_s3)
+DEF(movl_T0_EAX)
+DEF(movl_T1_EAX)
+DEF(movh_T0_EAX)
+DEF(movh_T1_EAX)
+DEF(movl_EAX_T0)
+DEF(movl_EAX_T1)
+DEF(movl_EAX_A0)
+DEF(cmovw_EAX_T1_T0)
+DEF(cmovl_EAX_T1_T0)
+DEF(movw_EAX_T0)
+DEF(movw_EAX_T1)
+DEF(movw_EAX_A0)
+DEF(movb_EAX_T0)
+DEF(movh_EAX_T0)
+DEF(movb_EAX_T1)
+DEF(movh_EAX_T1)
+DEF(movl_A0_ECX)
+DEF(addl_A0_ECX)
+DEF(addl_A0_ECX_s1)
+DEF(addl_A0_ECX_s2)
+DEF(addl_A0_ECX_s3)
+DEF(movl_T0_ECX)
+DEF(movl_T1_ECX)
+DEF(movh_T0_ECX)
+DEF(movh_T1_ECX)
+DEF(movl_ECX_T0)
+DEF(movl_ECX_T1)
+DEF(movl_ECX_A0)
+DEF(cmovw_ECX_T1_T0)
+DEF(cmovl_ECX_T1_T0)
+DEF(movw_ECX_T0)
+DEF(movw_ECX_T1)
+DEF(movw_ECX_A0)
+DEF(movb_ECX_T0)
+DEF(movh_ECX_T0)
+DEF(movb_ECX_T1)
+DEF(movh_ECX_T1)
+DEF(movl_A0_EDX)
+DEF(addl_A0_EDX)
+DEF(addl_A0_EDX_s1)
+DEF(addl_A0_EDX_s2)
+DEF(addl_A0_EDX_s3)
+DEF(movl_T0_EDX)
+DEF(movl_T1_EDX)
+DEF(movh_T0_EDX)
+DEF(movh_T1_EDX)
+DEF(movl_EDX_T0)
+DEF(movl_EDX_T1)
+DEF(movl_EDX_A0)
+DEF(cmovw_EDX_T1_T0)
+DEF(cmovl_EDX_T1_T0)
+DEF(movw_EDX_T0)
+DEF(movw_EDX_T1)
+DEF(movw_EDX_A0)
+DEF(movb_EDX_T0)
+DEF(movh_EDX_T0)
+DEF(movb_EDX_T1)
+DEF(movh_EDX_T1)
+DEF(movl_A0_EBX)
+DEF(addl_A0_EBX)
+DEF(addl_A0_EBX_s1)
+DEF(addl_A0_EBX_s2)
+DEF(addl_A0_EBX_s3)
+DEF(movl_T0_EBX)
+DEF(movl_T1_EBX)
+DEF(movh_T0_EBX)
+DEF(movh_T1_EBX)
+DEF(movl_EBX_T0)
+DEF(movl_EBX_T1)
+DEF(movl_EBX_A0)
+DEF(cmovw_EBX_T1_T0)
+DEF(cmovl_EBX_T1_T0)
+DEF(movw_EBX_T0)
+DEF(movw_EBX_T1)
+DEF(movw_EBX_A0)
+DEF(movb_EBX_T0)
+DEF(movh_EBX_T0)
+DEF(movb_EBX_T1)
+DEF(movh_EBX_T1)
+DEF(movl_A0_ESP)
+DEF(addl_A0_ESP)
+DEF(addl_A0_ESP_s1)
+DEF(addl_A0_ESP_s2)
+DEF(addl_A0_ESP_s3)
+DEF(movl_T0_ESP)
+DEF(movl_T1_ESP)
+DEF(movh_T0_ESP)
+DEF(movh_T1_ESP)
+DEF(movl_ESP_T0)
+DEF(movl_ESP_T1)
+DEF(movl_ESP_A0)
+DEF(cmovw_ESP_T1_T0)
+DEF(cmovl_ESP_T1_T0)
+DEF(movw_ESP_T0)
+DEF(movw_ESP_T1)
+DEF(movw_ESP_A0)
+DEF(movb_ESP_T0)
+DEF(movh_ESP_T0)
+DEF(movb_ESP_T1)
+DEF(movh_ESP_T1)
+DEF(movl_A0_EBP)
+DEF(addl_A0_EBP)
+DEF(addl_A0_EBP_s1)
+DEF(addl_A0_EBP_s2)
+DEF(addl_A0_EBP_s3)
+DEF(movl_T0_EBP)
+DEF(movl_T1_EBP)
+DEF(movh_T0_EBP)
+DEF(movh_T1_EBP)
+DEF(movl_EBP_T0)
+DEF(movl_EBP_T1)
+DEF(movl_EBP_A0)
+DEF(cmovw_EBP_T1_T0)
+DEF(cmovl_EBP_T1_T0)
+DEF(movw_EBP_T0)
+DEF(movw_EBP_T1)
+DEF(movw_EBP_A0)
+DEF(movb_EBP_T0)
+DEF(movh_EBP_T0)
+DEF(movb_EBP_T1)
+DEF(movh_EBP_T1)
+DEF(movl_A0_ESI)
+DEF(addl_A0_ESI)
+DEF(addl_A0_ESI_s1)
+DEF(addl_A0_ESI_s2)
+DEF(addl_A0_ESI_s3)
+DEF(movl_T0_ESI)
+DEF(movl_T1_ESI)
+DEF(movh_T0_ESI)
+DEF(movh_T1_ESI)
+DEF(movl_ESI_T0)
+DEF(movl_ESI_T1)
+DEF(movl_ESI_A0)
+DEF(cmovw_ESI_T1_T0)
+DEF(cmovl_ESI_T1_T0)
+DEF(movw_ESI_T0)
+DEF(movw_ESI_T1)
+DEF(movw_ESI_A0)
+DEF(movb_ESI_T0)
+DEF(movh_ESI_T0)
+DEF(movb_ESI_T1)
+DEF(movh_ESI_T1)
+DEF(movl_A0_EDI)
+DEF(addl_A0_EDI)
+DEF(addl_A0_EDI_s1)
+DEF(addl_A0_EDI_s2)
+DEF(addl_A0_EDI_s3)
+DEF(movl_T0_EDI)
+DEF(movl_T1_EDI)
+DEF(movh_T0_EDI)
+DEF(movh_T1_EDI)
+DEF(movl_EDI_T0)
+DEF(movl_EDI_T1)
+DEF(movl_EDI_A0)
+DEF(cmovw_EDI_T1_T0)
+DEF(cmovl_EDI_T1_T0)
+DEF(movw_EDI_T0)
+DEF(movw_EDI_T1)
+DEF(movw_EDI_A0)
+DEF(movb_EDI_T0)
+DEF(movh_EDI_T0)
+DEF(movb_EDI_T1)
+DEF(movh_EDI_T1)
+DEF(addl_T0_T1_cc)
+DEF(orl_T0_T1_cc)
+DEF(andl_T0_T1_cc)
+DEF(subl_T0_T1_cc)
+DEF(xorl_T0_T1_cc)
+DEF(cmpl_T0_T1_cc)
+DEF(negl_T0_cc)
+DEF(incl_T0_cc)
+DEF(decl_T0_cc)
+DEF(testl_T0_T1_cc)
+DEF(addl_T0_T1)
+DEF(orl_T0_T1)
+DEF(andl_T0_T1)
+DEF(subl_T0_T1)
+DEF(xorl_T0_T1)
+DEF(negl_T0)
+DEF(incl_T0)
+DEF(decl_T0)
+DEF(notl_T0)
+DEF(bswapl_T0)
+DEF(mulb_AL_T0)
+DEF(imulb_AL_T0)
+DEF(mulw_AX_T0)
+DEF(imulw_AX_T0)
+DEF(mull_EAX_T0)
+DEF(imull_EAX_T0)
+DEF(imulw_T0_T1)
+DEF(imull_T0_T1)
+DEF(divb_AL_T0)
+DEF(idivb_AL_T0)
+DEF(divw_AX_T0)
+DEF(idivw_AX_T0)
+DEF(divl_EAX_T0)
+DEF(idivl_EAX_T0)
+DEF(movl_T0_im)
+DEF(movl_T1_im)
+DEF(movl_A0_im)
+DEF(addl_A0_im)
+DEF(andl_A0_ffff)
+DEF(ldub_T0_A0)
+DEF(ldsb_T0_A0)
+DEF(lduw_T0_A0)
+DEF(ldsw_T0_A0)
+DEF(ldl_T0_A0)
+DEF(ldub_T1_A0)
+DEF(ldsb_T1_A0)
+DEF(lduw_T1_A0)
+DEF(ldsw_T1_A0)
+DEF(ldl_T1_A0)
+DEF(stb_T0_A0)
+DEF(stw_T0_A0)
+DEF(stl_T0_A0)
+DEF(add_bitw_A0_T1)
+DEF(add_bitl_A0_T1)
+DEF(jmp_T0)
+DEF(jmp_im)
+DEF(int_im)
+DEF(int3)
+DEF(into)
+DEF(jb_subb)
+DEF(jz_subb)
+DEF(jbe_subb)
+DEF(js_subb)
+DEF(jl_subb)
+DEF(jle_subb)
+DEF(setb_T0_subb)
+DEF(setz_T0_subb)
+DEF(setbe_T0_subb)
+DEF(sets_T0_subb)
+DEF(setl_T0_subb)
+DEF(setle_T0_subb)
+DEF(rolb_T0_T1_cc)
+DEF(rolb_T0_T1)
+DEF(rorb_T0_T1_cc)
+DEF(rorb_T0_T1)
+DEF(rclb_T0_T1_cc)
+DEF(rcrb_T0_T1_cc)
+DEF(shlb_T0_T1_cc)
+DEF(shlb_T0_T1)
+DEF(shrb_T0_T1_cc)
+DEF(shrb_T0_T1)
+DEF(sarb_T0_T1_cc)
+DEF(sarb_T0_T1)
+DEF(adcb_T0_T1_cc)
+DEF(sbbb_T0_T1_cc)
+DEF(cmpxchgb_T0_T1_EAX_cc)
+DEF(movsb)
+DEF(rep_movsb)
+DEF(stosb)
+DEF(rep_stosb)
+DEF(lodsb)
+DEF(rep_lodsb)
+DEF(scasb)
+DEF(repz_scasb)
+DEF(repnz_scasb)
+DEF(cmpsb)
+DEF(repz_cmpsb)
+DEF(repnz_cmpsb)
+DEF(outsb)
+DEF(rep_outsb)
+DEF(insb)
+DEF(rep_insb)
+DEF(outb_T0_T1)
+DEF(inb_T0_T1)
+DEF(jb_subw)
+DEF(jz_subw)
+DEF(jbe_subw)
+DEF(js_subw)
+DEF(jl_subw)
+DEF(jle_subw)
+DEF(loopnzw)
+DEF(loopzw)
+DEF(loopw)
+DEF(jecxzw)
+DEF(setb_T0_subw)
+DEF(setz_T0_subw)
+DEF(setbe_T0_subw)
+DEF(sets_T0_subw)
+DEF(setl_T0_subw)
+DEF(setle_T0_subw)
+DEF(rolw_T0_T1_cc)
+DEF(rolw_T0_T1)
+DEF(rorw_T0_T1_cc)
+DEF(rorw_T0_T1)
+DEF(rclw_T0_T1_cc)
+DEF(rcrw_T0_T1_cc)
+DEF(shlw_T0_T1_cc)
+DEF(shlw_T0_T1)
+DEF(shrw_T0_T1_cc)
+DEF(shrw_T0_T1)
+DEF(sarw_T0_T1_cc)
+DEF(sarw_T0_T1)
+DEF(shldw_T0_T1_im_cc)
+DEF(shldw_T0_T1_ECX_cc)
+DEF(shrdw_T0_T1_im_cc)
+DEF(shrdw_T0_T1_ECX_cc)
+DEF(adcw_T0_T1_cc)
+DEF(sbbw_T0_T1_cc)
+DEF(cmpxchgw_T0_T1_EAX_cc)
+DEF(btw_T0_T1_cc)
+DEF(btsw_T0_T1_cc)
+DEF(btrw_T0_T1_cc)
+DEF(btcw_T0_T1_cc)
+DEF(bsfw_T0_cc)
+DEF(bsrw_T0_cc)
+DEF(movsw)
+DEF(rep_movsw)
+DEF(stosw)
+DEF(rep_stosw)
+DEF(lodsw)
+DEF(rep_lodsw)
+DEF(scasw)
+DEF(repz_scasw)
+DEF(repnz_scasw)
+DEF(cmpsw)
+DEF(repz_cmpsw)
+DEF(repnz_cmpsw)
+DEF(outsw)
+DEF(rep_outsw)
+DEF(insw)
+DEF(rep_insw)
+DEF(outw_T0_T1)
+DEF(inw_T0_T1)
+DEF(jb_subl)
+DEF(jz_subl)
+DEF(jbe_subl)
+DEF(js_subl)
+DEF(jl_subl)
+DEF(jle_subl)
+DEF(loopnzl)
+DEF(loopzl)
+DEF(loopl)
+DEF(jecxzl)
+DEF(setb_T0_subl)
+DEF(setz_T0_subl)
+DEF(setbe_T0_subl)
+DEF(sets_T0_subl)
+DEF(setl_T0_subl)
+DEF(setle_T0_subl)
+DEF(roll_T0_T1_cc)
+DEF(roll_T0_T1)
+DEF(rorl_T0_T1_cc)
+DEF(rorl_T0_T1)
+DEF(rcll_T0_T1_cc)
+DEF(rcrl_T0_T1_cc)
+DEF(shll_T0_T1_cc)
+DEF(shll_T0_T1)
+DEF(shrl_T0_T1_cc)
+DEF(shrl_T0_T1)
+DEF(sarl_T0_T1_cc)
+DEF(sarl_T0_T1)
+DEF(shldl_T0_T1_im_cc)
+DEF(shldl_T0_T1_ECX_cc)
+DEF(shrdl_T0_T1_im_cc)
+DEF(shrdl_T0_T1_ECX_cc)
+DEF(adcl_T0_T1_cc)
+DEF(sbbl_T0_T1_cc)
+DEF(cmpxchgl_T0_T1_EAX_cc)
+DEF(btl_T0_T1_cc)
+DEF(btsl_T0_T1_cc)
+DEF(btrl_T0_T1_cc)
+DEF(btcl_T0_T1_cc)
+DEF(bsfl_T0_cc)
+DEF(bsrl_T0_cc)
+DEF(movsl)
+DEF(rep_movsl)
+DEF(stosl)
+DEF(rep_stosl)
+DEF(lodsl)
+DEF(rep_lodsl)
+DEF(scasl)
+DEF(repz_scasl)
+DEF(repnz_scasl)
+DEF(cmpsl)
+DEF(repz_cmpsl)
+DEF(repnz_cmpsl)
+DEF(outsl)
+DEF(rep_outsl)
+DEF(insl)
+DEF(rep_insl)
+DEF(outl_T0_T1)
+DEF(inl_T0_T1)
+DEF(movsbl_T0_T0)
+DEF(movzbl_T0_T0)
+DEF(movswl_T0_T0)
+DEF(movzwl_T0_T0)
+DEF(movswl_EAX_AX)
+DEF(movsbw_AX_AL)
+DEF(movslq_EDX_EAX)
+DEF(movswl_DX_AX)
+DEF(pushl_T0)
+DEF(pushl_T1)
+DEF(popl_T0)
+DEF(addl_ESP_im)
+DEF(pushal)
+DEF(pushaw)
+DEF(popal)
+DEF(popaw)
+DEF(enterl)
+DEF(rdtsc)
+DEF(aam)
+DEF(aad)
+DEF(aaa)
+DEF(aas)
+DEF(daa)
+DEF(das)
+DEF(movl_seg_T0)
+DEF(movl_T0_seg)
+DEF(addl_A0_seg)
+DEF(jo_cc)
+DEF(jb_cc)
+DEF(jz_cc)
+DEF(jbe_cc)
+DEF(js_cc)
+DEF(jp_cc)
+DEF(jl_cc)
+DEF(jle_cc)
+DEF(seto_T0_cc)
+DEF(setb_T0_cc)
+DEF(setz_T0_cc)
+DEF(setbe_T0_cc)
+DEF(sets_T0_cc)
+DEF(setp_T0_cc)
+DEF(setl_T0_cc)
+DEF(setle_T0_cc)
+DEF(xor_T0_1)
+DEF(set_cc_op)
+DEF(movl_eflags_T0)
+DEF(movb_eflags_T0)
+DEF(movl_T0_eflags)
+DEF(cld)
+DEF(std)
+DEF(clc)
+DEF(stc)
+DEF(cmc)
+DEF(salc)
+DEF(flds_FT0_A0)
+DEF(fldl_FT0_A0)
+DEF(fild_FT0_A0)
+DEF(fildl_FT0_A0)
+DEF(fildll_FT0_A0)
+DEF(flds_ST0_A0)
+DEF(fldl_ST0_A0)
+DEF(fldt_ST0_A0)
+DEF(fild_ST0_A0)
+DEF(fildl_ST0_A0)
+DEF(fildll_ST0_A0)
+DEF(fsts_ST0_A0)
+DEF(fstl_ST0_A0)
+DEF(fstt_ST0_A0)
+DEF(fist_ST0_A0)
+DEF(fistl_ST0_A0)
+DEF(fistll_ST0_A0)
+DEF(fbld_ST0_A0)
+DEF(fbst_ST0_A0)
+DEF(fpush)
+DEF(fpop)
+DEF(fdecstp)
+DEF(fincstp)
+DEF(fmov_ST0_FT0)
+DEF(fmov_FT0_STN)
+DEF(fmov_ST0_STN)
+DEF(fmov_STN_ST0)
+DEF(fxchg_ST0_STN)
+DEF(fcom_ST0_FT0)
+DEF(fucom_ST0_FT0)
+DEF(fadd_ST0_FT0)
+DEF(fmul_ST0_FT0)
+DEF(fsub_ST0_FT0)
+DEF(fsubr_ST0_FT0)
+DEF(fdiv_ST0_FT0)
+DEF(fdivr_ST0_FT0)
+DEF(fadd_STN_ST0)
+DEF(fmul_STN_ST0)
+DEF(fsub_STN_ST0)
+DEF(fsubr_STN_ST0)
+DEF(fdiv_STN_ST0)
+DEF(fdivr_STN_ST0)
+DEF(fchs_ST0)
+DEF(fabs_ST0)
+DEF(fxam_ST0)
+DEF(fld1_ST0)
+DEF(fldl2t_ST0)
+DEF(fldl2e_ST0)
+DEF(fldpi_ST0)
+DEF(fldlg2_ST0)
+DEF(fldln2_ST0)
+DEF(fldz_ST0)
+DEF(fldz_FT0)
+DEF(f2xm1)
+DEF(fyl2x)
+DEF(fptan)
+DEF(fpatan)
+DEF(fxtract)
+DEF(fprem1)
+DEF(fprem)
+DEF(fyl2xp1)
+DEF(fsqrt)
+DEF(fsincos)
+DEF(frndint)
+DEF(fscale)
+DEF(fsin)
+DEF(fcos)
+DEF(fnstsw_A0)
+DEF(fnstsw_EAX)
+DEF(fnstcw_A0)
+DEF(fldcw_A0)
+DEF(fclex)
+DEF(fninit)
index 8905d90..f8cd5e5 100644 (file)
@@ -385,7 +385,6 @@ void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void)
 void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1_cc)(void)
 {
     int count, src;
-    /* XXX: testing */
     count = T1 & SHIFT_MASK;
     if (count) {
         CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C);
@@ -399,6 +398,17 @@ void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1_cc)(void)
     FORCE_RET();
 }
 
+void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1)(void)
+{
+    int count;
+    count = T1 & SHIFT_MASK;
+    if (count) {
+        T0 &= DATA_MASK;
+        T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
+    }
+    FORCE_RET();
+}
+
 void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1_cc)(void)
 {
     int count, src;
@@ -415,6 +425,17 @@ void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1_cc)(void)
     FORCE_RET();
 }
 
+void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1)(void)
+{
+    int count;
+    count = T1 & SHIFT_MASK;
+    if (count) {
+        T0 &= DATA_MASK;
+        T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
+    }
+    FORCE_RET();
+}
+
 void OPPROTO glue(glue(op_rcl, SUFFIX), _T0_T1_cc)(void)
 {
     int count, res, eflags;
@@ -482,6 +503,14 @@ void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1_cc)(void)
     FORCE_RET();
 }
 
+void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void)
+{
+    int count;
+    count = T1 & 0x1f;
+    T0 = T0 << count;
+    FORCE_RET();
+}
+
 void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1_cc)(void)
 {
     int count;
@@ -496,6 +525,15 @@ void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1_cc)(void)
     FORCE_RET();
 }
 
+void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void)
+{
+    int count;
+    count = T1 & 0x1f;
+    T0 &= DATA_MASK;
+    T0 = T0 >> count;
+    FORCE_RET();
+}
+
 void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void)
 {
     int count, src;
@@ -510,6 +548,15 @@ void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void)
     FORCE_RET();
 }
 
+void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void)
+{
+    int count, src;
+    count = T1 & 0x1f;
+    src = (DATA_STYPE)T0;
+    T0 = src >> count;
+    FORCE_RET();
+}
+
 #if DATA_BITS == 16
 /* XXX: overflow flag might be incorrect in some cases in shldw */
 void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_im_cc)(void)
index 9bf7f56..f02c5ea 100644 (file)
@@ -38,7 +38,8 @@
 #define offsetof(type, field) ((size_t) &((type *)0)->field)
 #endif
 
-static uint8_t *gen_code_ptr;
+static uint16_t *gen_opc_ptr;
+static uint32_t *gen_opparam_ptr;
 int __op_param1, __op_param2, __op_param3;
 
 extern FILE *logfile;
@@ -95,6 +96,13 @@ enum {
     OP_SAR = 7,
 };
 
+enum {
+#define DEF(s) INDEX_op_ ## s,
+#include "opc-i386.h"
+#undef DEF
+    NB_OPS,
+};
+
 #include "op-i386.h"
 
 /* operand size */
@@ -1922,7 +1930,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         if (mod == 3)
             goto illegal_op;
         gen_op_ld_T1_A0[ot]();
-        op_addl_A0_im(1 << (ot - OT_WORD + 1));
+        gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
         /* load the segment first to handle exceptions properly */
         gen_op_lduw_T0_A0();
         gen_movl_seg_T0(s, op);
@@ -2842,24 +2850,350 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
     return -1;
 }
 
+#define CC_OSZAPC (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C)
+#define CC_OSZAP (CC_O | CC_S | CC_Z | CC_A | CC_P)
+
+/* flags read by an operation */
+static uint16_t opc_read_flags[NB_OPS] = { 
+    [INDEX_op_aas] = CC_A,
+    [INDEX_op_aaa] = CC_A,
+    [INDEX_op_das] = CC_A | CC_C,
+    [INDEX_op_daa] = CC_A | CC_C,
+
+    [INDEX_op_adcb_T0_T1_cc] = CC_C,
+    [INDEX_op_adcw_T0_T1_cc] = CC_C,
+    [INDEX_op_adcl_T0_T1_cc] = CC_C,
+    [INDEX_op_sbbb_T0_T1_cc] = CC_C,
+    [INDEX_op_sbbw_T0_T1_cc] = CC_C,
+    [INDEX_op_sbbl_T0_T1_cc] = CC_C,
+
+    [INDEX_op_into] = CC_O,
+
+    [INDEX_op_jo_cc] = CC_O,
+    [INDEX_op_jb_cc] = CC_C,
+    [INDEX_op_jz_cc] = CC_Z,
+    [INDEX_op_jbe_cc] = CC_Z | CC_C,
+    [INDEX_op_js_cc] = CC_S,
+    [INDEX_op_jp_cc] = CC_P,
+    [INDEX_op_jl_cc] = CC_O | CC_S,
+    [INDEX_op_jle_cc] = CC_O | CC_S | CC_Z,
+
+    [INDEX_op_jb_subb] = CC_C,
+    [INDEX_op_jb_subw] = CC_C,
+    [INDEX_op_jb_subl] = CC_C,
+
+    [INDEX_op_jz_subb] = CC_Z,
+    [INDEX_op_jz_subw] = CC_Z,
+    [INDEX_op_jz_subl] = CC_Z,
+
+    [INDEX_op_jbe_subb] = CC_Z | CC_C,
+    [INDEX_op_jbe_subw] = CC_Z | CC_C,
+    [INDEX_op_jbe_subl] = CC_Z | CC_C,
+
+    [INDEX_op_js_subb] = CC_S,
+    [INDEX_op_js_subw] = CC_S,
+    [INDEX_op_js_subl] = CC_S,
+
+    [INDEX_op_jl_subb] = CC_O | CC_S,
+    [INDEX_op_jl_subw] = CC_O | CC_S,
+    [INDEX_op_jl_subl] = CC_O | CC_S,
+
+    [INDEX_op_jle_subb] = CC_O | CC_S | CC_Z,
+    [INDEX_op_jle_subw] = CC_O | CC_S | CC_Z,
+    [INDEX_op_jle_subl] = CC_O | CC_S | CC_Z,
+
+    [INDEX_op_loopnzw] = CC_Z,
+    [INDEX_op_loopnzl] = CC_Z,
+    [INDEX_op_loopzw] = CC_Z,
+    [INDEX_op_loopzl] = CC_Z,
+
+    [INDEX_op_seto_T0_cc] = CC_O,
+    [INDEX_op_setb_T0_cc] = CC_C,
+    [INDEX_op_setz_T0_cc] = CC_Z,
+    [INDEX_op_setbe_T0_cc] = CC_Z | CC_C,
+    [INDEX_op_sets_T0_cc] = CC_S,
+    [INDEX_op_setp_T0_cc] = CC_P,
+    [INDEX_op_setl_T0_cc] = CC_O | CC_S,
+    [INDEX_op_setle_T0_cc] = CC_O | CC_S | CC_Z,
+
+    [INDEX_op_setb_T0_subb] = CC_C,
+    [INDEX_op_setb_T0_subw] = CC_C,
+    [INDEX_op_setb_T0_subl] = CC_C,
+
+    [INDEX_op_setz_T0_subb] = CC_Z,
+    [INDEX_op_setz_T0_subw] = CC_Z,
+    [INDEX_op_setz_T0_subl] = CC_Z,
+
+    [INDEX_op_setbe_T0_subb] = CC_Z | CC_C,
+    [INDEX_op_setbe_T0_subw] = CC_Z | CC_C,
+    [INDEX_op_setbe_T0_subl] = CC_Z | CC_C,
+
+    [INDEX_op_sets_T0_subb] = CC_S,
+    [INDEX_op_sets_T0_subw] = CC_S,
+    [INDEX_op_sets_T0_subl] = CC_S,
+
+    [INDEX_op_setl_T0_subb] = CC_O | CC_S,
+    [INDEX_op_setl_T0_subw] = CC_O | CC_S,
+    [INDEX_op_setl_T0_subl] = CC_O | CC_S,
+
+    [INDEX_op_setle_T0_subb] = CC_O | CC_S | CC_Z,
+    [INDEX_op_setle_T0_subw] = CC_O | CC_S | CC_Z,
+    [INDEX_op_setle_T0_subl] = CC_O | CC_S | CC_Z,
+
+    [INDEX_op_movl_T0_eflags] = CC_OSZAPC,
+    [INDEX_op_cmc] = CC_C,
+    [INDEX_op_salc] = CC_C,
+
+    [INDEX_op_rclb_T0_T1_cc] = CC_C,
+    [INDEX_op_rclw_T0_T1_cc] = CC_C,
+    [INDEX_op_rcll_T0_T1_cc] = CC_C,
+    [INDEX_op_rcrb_T0_T1_cc] = CC_C,
+    [INDEX_op_rcrw_T0_T1_cc] = CC_C,
+    [INDEX_op_rcrl_T0_T1_cc] = CC_C,
+};
+
+/* flags written by an operation */
+static uint16_t opc_write_flags[NB_OPS] = { 
+    [INDEX_op_addl_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_orl_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_adcb_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_adcw_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_adcl_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_sbbb_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_sbbw_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_sbbl_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_andl_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_subl_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_xorl_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_negl_T0_cc] = CC_OSZAPC,
+    [INDEX_op_incl_T0_cc] = CC_OSZAP,
+    [INDEX_op_decl_T0_cc] = CC_OSZAP,
+    [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC,
+
+    [INDEX_op_mulb_AL_T0] = CC_OSZAPC,
+    [INDEX_op_imulb_AL_T0] = CC_OSZAPC,
+    [INDEX_op_mulw_AX_T0] = CC_OSZAPC,
+    [INDEX_op_imulw_AX_T0] = CC_OSZAPC,
+    [INDEX_op_mull_EAX_T0] = CC_OSZAPC,
+    [INDEX_op_imull_EAX_T0] = CC_OSZAPC,
+    [INDEX_op_imulw_T0_T1] = CC_OSZAPC,
+    [INDEX_op_imull_T0_T1] = CC_OSZAPC,
+    
+    /* bcd */
+    [INDEX_op_aam] = CC_OSZAPC,
+    [INDEX_op_aad] = CC_OSZAPC,
+    [INDEX_op_aas] = CC_OSZAPC,
+    [INDEX_op_aaa] = CC_OSZAPC,
+    [INDEX_op_das] = CC_OSZAPC,
+    [INDEX_op_daa] = CC_OSZAPC,
+
+    [INDEX_op_movb_eflags_T0] = CC_S | CC_Z | CC_A | CC_P | CC_C,
+    [INDEX_op_movl_eflags_T0] = CC_OSZAPC,
+    [INDEX_op_clc] = CC_C,
+    [INDEX_op_stc] = CC_C,
+    [INDEX_op_cmc] = CC_C,
+
+    [INDEX_op_rolb_T0_T1_cc] = CC_O | CC_C,
+    [INDEX_op_rolw_T0_T1_cc] = CC_O | CC_C,
+    [INDEX_op_roll_T0_T1_cc] = CC_O | CC_C,
+    [INDEX_op_rorb_T0_T1_cc] = CC_O | CC_C,
+    [INDEX_op_rorw_T0_T1_cc] = CC_O | CC_C,
+    [INDEX_op_rorl_T0_T1_cc] = CC_O | CC_C,
+
+    [INDEX_op_rclb_T0_T1_cc] = CC_O | CC_C,
+    [INDEX_op_rclw_T0_T1_cc] = CC_O | CC_C,
+    [INDEX_op_rcll_T0_T1_cc] = CC_O | CC_C,
+    [INDEX_op_rcrb_T0_T1_cc] = CC_O | CC_C,
+    [INDEX_op_rcrw_T0_T1_cc] = CC_O | CC_C,
+    [INDEX_op_rcrl_T0_T1_cc] = CC_O | CC_C,
+
+    [INDEX_op_shlb_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_shlw_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_shll_T0_T1_cc] = CC_OSZAPC,
+
+    [INDEX_op_shrb_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_shrw_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_shrl_T0_T1_cc] = CC_OSZAPC,
+
+    [INDEX_op_sarb_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_sarw_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_sarl_T0_T1_cc] = CC_OSZAPC,
+
+    [INDEX_op_shldw_T0_T1_ECX_cc] = CC_OSZAPC,
+    [INDEX_op_shldl_T0_T1_ECX_cc] = CC_OSZAPC,
+    [INDEX_op_shldw_T0_T1_im_cc] = CC_OSZAPC,
+    [INDEX_op_shldl_T0_T1_im_cc] = CC_OSZAPC,
+
+    [INDEX_op_shrdw_T0_T1_ECX_cc] = CC_OSZAPC,
+    [INDEX_op_shrdl_T0_T1_ECX_cc] = CC_OSZAPC,
+    [INDEX_op_shrdw_T0_T1_im_cc] = CC_OSZAPC,
+    [INDEX_op_shrdl_T0_T1_im_cc] = CC_OSZAPC,
+
+    [INDEX_op_btw_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_btl_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_btsw_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_btsl_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_btrw_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_btrl_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_btcw_T0_T1_cc] = CC_OSZAPC,
+    [INDEX_op_btcl_T0_T1_cc] = CC_OSZAPC,
+
+    [INDEX_op_bsfw_T0_cc] = CC_OSZAPC,
+    [INDEX_op_bsfl_T0_cc] = CC_OSZAPC,
+    [INDEX_op_bsrw_T0_cc] = CC_OSZAPC,
+    [INDEX_op_bsrl_T0_cc] = CC_OSZAPC,
+
+    [INDEX_op_scasb] = CC_OSZAPC,
+    [INDEX_op_scasw] = CC_OSZAPC,
+    [INDEX_op_scasl] = CC_OSZAPC,
+    [INDEX_op_repz_scasb] = CC_OSZAPC,
+    [INDEX_op_repz_scasw] = CC_OSZAPC,
+    [INDEX_op_repz_scasl] = CC_OSZAPC,
+    [INDEX_op_repnz_scasb] = CC_OSZAPC,
+    [INDEX_op_repnz_scasw] = CC_OSZAPC,
+    [INDEX_op_repnz_scasl] = CC_OSZAPC,
+
+    [INDEX_op_cmpsb] = CC_OSZAPC,
+    [INDEX_op_cmpsw] = CC_OSZAPC,
+    [INDEX_op_cmpsl] = CC_OSZAPC,
+    [INDEX_op_repz_cmpsb] = CC_OSZAPC,
+    [INDEX_op_repz_cmpsw] = CC_OSZAPC,
+    [INDEX_op_repz_cmpsl] = CC_OSZAPC,
+    [INDEX_op_repnz_cmpsb] = CC_OSZAPC,
+    [INDEX_op_repnz_cmpsw] = CC_OSZAPC,
+    [INDEX_op_repnz_cmpsl] = CC_OSZAPC,
+
+    [INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC,
+    [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC,
+};
+
+/* simpler form of an operation if no flags need to be generated */
+static uint16_t opc_simpler[NB_OPS] = { 
+    [INDEX_op_addl_T0_T1_cc] = INDEX_op_addl_T0_T1,
+    [INDEX_op_orl_T0_T1_cc] = INDEX_op_orl_T0_T1,
+    [INDEX_op_andl_T0_T1_cc] = INDEX_op_andl_T0_T1,
+    [INDEX_op_subl_T0_T1_cc] = INDEX_op_subl_T0_T1,
+    [INDEX_op_xorl_T0_T1_cc] = INDEX_op_xorl_T0_T1,
+    [INDEX_op_negl_T0_cc] = INDEX_op_negl_T0,
+    [INDEX_op_incl_T0_cc] = INDEX_op_incl_T0,
+    [INDEX_op_decl_T0_cc] = INDEX_op_decl_T0,
+
+    [INDEX_op_rolb_T0_T1_cc] = INDEX_op_rolb_T0_T1,
+    [INDEX_op_rolw_T0_T1_cc] = INDEX_op_rolw_T0_T1,
+    [INDEX_op_roll_T0_T1_cc] = INDEX_op_roll_T0_T1,
+
+    [INDEX_op_rorb_T0_T1_cc] = INDEX_op_rorb_T0_T1,
+    [INDEX_op_rorw_T0_T1_cc] = INDEX_op_rorw_T0_T1,
+    [INDEX_op_rorl_T0_T1_cc] = INDEX_op_rorl_T0_T1,
+
+    [INDEX_op_shlb_T0_T1_cc] = INDEX_op_shlb_T0_T1,
+    [INDEX_op_shlw_T0_T1_cc] = INDEX_op_shlw_T0_T1,
+    [INDEX_op_shll_T0_T1_cc] = INDEX_op_shll_T0_T1,
+
+    [INDEX_op_shrb_T0_T1_cc] = INDEX_op_shrb_T0_T1,
+    [INDEX_op_shrw_T0_T1_cc] = INDEX_op_shrw_T0_T1,
+    [INDEX_op_shrl_T0_T1_cc] = INDEX_op_shrl_T0_T1,
+
+    [INDEX_op_sarb_T0_T1_cc] = INDEX_op_sarb_T0_T1,
+    [INDEX_op_sarw_T0_T1_cc] = INDEX_op_sarw_T0_T1,
+    [INDEX_op_sarl_T0_T1_cc] = INDEX_op_sarl_T0_T1,
+};
+
+static void optimize_flags_init(void)
+{
+    int i;
+    /* put default values in arrays */
+    for(i = 0; i < NB_OPS; i++) {
+        if (opc_simpler[i] == 0)
+            opc_simpler[i] = i;
+    }
+}
+
+/* CPU flags computation optimization: we move backward thru the
+   generated code to see which flags are needed. The operation is
+   modified if suitable */
+static void optimize_flags(uint16_t *opc_buf, int opc_buf_len)
+{
+    uint16_t *opc_ptr;
+    int live_flags, write_flags, op;
+
+    opc_ptr = opc_buf + opc_buf_len;
+    /* live_flags contains the flags needed by the next instructions
+       in the code. At the end of the bloc, we consider that all the
+       flags are live. */
+    live_flags = CC_OSZAPC;
+    while (opc_ptr > opc_buf) {
+        op = *--opc_ptr;
+        /* if none of the flags written by the instruction is used,
+           then we can try to find a simpler instruction */
+        write_flags = opc_write_flags[op];
+        if ((live_flags & write_flags) == 0) {
+            *opc_ptr = opc_simpler[op];
+        }
+        /* compute the live flags before the instruction */
+        live_flags &= ~write_flags;
+        live_flags |= opc_read_flags[op];
+    }
+}
+
+
+#ifdef DEBUG_DISAS
+static const char *op_str[] = {
+#define DEF(s) #s,
+#include "opc-i386.h"
+#undef DEF
+};
+
+static void dump_ops(const uint16_t *opc_buf)
+{
+    const uint16_t *opc_ptr;
+    int c;
+    opc_ptr = opc_buf;
+    for(;;) {
+        c = *opc_ptr++;
+        fprintf(logfile, "0x%04x: %s\n", opc_ptr - opc_buf - 1, op_str[c]);
+        if (c == INDEX_op_end)
+            break;
+    }
+}
+
+#endif
+
+/* XXX: make this buffer thread safe */
+/* XXX: make safe guess about sizes */
+#define MAX_OP_PER_INSTR 32
+#define OPC_BUF_SIZE 512
+#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR)
+
+#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * 3)
+
+static uint16_t gen_opc_buf[OPC_BUF_SIZE];
+static uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
+
 /* return the next pc */
 int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, 
                      int *gen_code_size_ptr, uint8_t *pc_start, 
                      int flags)
 {
     DisasContext dc1, *dc = &dc1;
-    uint8_t *gen_code_end, *pc_ptr;
+    uint8_t *pc_ptr;
+    uint16_t *gen_opc_end;
     long ret;
 #ifdef DEBUG_DISAS
     struct disassemble_info disasm_info;
 #endif
+    
+    /* generate intermediate code */
+
     dc->code32 = (flags >> GEN_FLAG_CODE32_SHIFT) & 1;
     dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1;
     dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7;
     dc->cc_op = CC_OP_DYNAMIC;
-    gen_code_ptr = gen_code_buf;
-    gen_code_end = gen_code_buf + max_code_size - 4096;
-    gen_start();
+
+    gen_opc_ptr = gen_opc_buf;
+    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+    gen_opparam_ptr = gen_opparam_buf;
 
     dc->is_jmp = 0;
     pc_ptr = pc_start;
@@ -2871,7 +3205,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
             abort();
         }
         pc_ptr = (void *)ret;
-    } while (!dc->is_jmp && gen_code_ptr < gen_code_end);
+    } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end);
     /* we must store the eflags state if it is not already done */
     if (dc->cc_op != CC_OP_DYNAMIC)
         gen_op_set_cc_op(dc->cc_op);
@@ -2879,9 +3213,9 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
         /* we add an additionnal jmp to update the simulated PC */
         gen_op_jmp_im(ret);
     }
-    gen_end();
-    *gen_code_size_ptr = gen_code_ptr - gen_code_buf;
+    *gen_opc_ptr = INDEX_op_end;
 
+    /* optimize flag computations */
 #ifdef DEBUG_DISAS
     if (loglevel) {
         uint8_t *pc;
@@ -2898,6 +3232,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
 #else
         disasm_info.endian = BFD_ENDIAN_LITTLE;
 #endif        
+        fprintf(logfile, "----------------\n");
         fprintf(logfile, "IN:\n");
         disasm_info.buffer = pc_start;
         disasm_info.buffer_vma = (unsigned long)pc_start;
@@ -2911,12 +3246,37 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
         }
         fprintf(logfile, "\n");
         
+        fprintf(logfile, "OP:\n");
+        dump_ops(gen_opc_buf);
+        fprintf(logfile, "\n");
+    }
+#endif
+
+    /* optimize flag computations */
+    optimize_flags(gen_opc_buf, gen_opc_ptr - gen_opc_buf);
+
+#ifdef DEBUG_DISAS
+    if (loglevel) {
+        fprintf(logfile, "AFTER FLAGS OPT:\n");
+        dump_ops(gen_opc_buf);
+        fprintf(logfile, "\n");
+    }
+#endif
+
+    /* generate machine code */
+    *gen_code_size_ptr = dyngen_code(gen_code_buf, gen_opc_buf, gen_opparam_buf);
+
+#ifdef DEBUG_DISAS
+    if (loglevel) {
+        uint8_t *pc;
+        int count;
+
         pc = gen_code_buf;
         disasm_info.buffer = pc;
         disasm_info.buffer_vma = (unsigned long)pc;
         disasm_info.buffer_length = *gen_code_size_ptr;
         fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr);
-        while (pc < gen_code_ptr) {
+        while (pc < gen_code_buf + *gen_code_size_ptr) {
             fprintf(logfile, "0x%08lx:  ", (long)pc);
             count = print_insn_i386((unsigned long)pc, &disasm_info);
             fprintf(logfile, "\n");
@@ -2932,6 +3292,7 @@ CPUX86State *cpu_x86_init(void)
 {
     CPUX86State *env;
     int i;
+    static int inited;
 
     cpu_x86_tblocks_init();
 
@@ -2946,6 +3307,12 @@ CPUX86State *cpu_x86_init(void)
     /* flags setup */
     env->cc_op = CC_OP_EFLAGS;
     env->df = 1;
+
+    /* init various static tables */
+    if (!inited) {
+        inited = 1;
+        optimize_flags_init();
+    }
     return env;
 }