diff options
author | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2003-03-19 00:00:28 +0000 |
---|---|---|
committer | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2003-03-19 00:00:28 +0000 |
commit | dc99065b5f97cc0410f88e3f90c7440531a55f9f (patch) | |
tree | a0566030175ea990f8aeeec662b3fa2e6b704bcf | |
parent | ca735206e0f223d75894260fb98c0c605f590817 (diff) |
added flags computation optimization
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@34 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | TODO | 8 | ||||
-rw-r--r-- | dis-asm.h | 237 | ||||
-rw-r--r-- | dis-buf.c | 79 | ||||
-rw-r--r-- | dyngen.c | 210 | ||||
-rw-r--r-- | exec-i386.c | 2 | ||||
-rw-r--r-- | gen-i386.h | 8 | ||||
-rw-r--r-- | i386-dis.c | 2299 | ||||
-rw-r--r-- | linux-user/syscall.c | 2 | ||||
-rw-r--r-- | op-i386.c | 54 | ||||
-rw-r--r-- | opc-i386.h | 518 | ||||
-rw-r--r-- | ops_template.h | 49 | ||||
-rw-r--r-- | translate-i386.c | 387 |
13 files changed, 3767 insertions, 88 deletions
@@ -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 @@ -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 index 0000000000..bd7e47844c --- /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; + + +/* 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 *)); + + +/* 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 index 0000000000..cdb8e9b190 --- /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; +} @@ -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; } diff --git a/exec-i386.c b/exec-i386.c index 8144add7ba..538ebe0d63 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -19,7 +19,7 @@ */ #include "exec-i386.h" -#define DEBUG_EXEC +//#define DEBUG_EXEC #define DEBUG_FLUSH /* main execution loop */ diff --git a/gen-i386.h b/gen-i386.h index a5d7f59898..e69de29bb2 100644 --- a/gen-i386.h +++ b/gen-i386.h @@ -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 index 0000000000..0a63294f72 --- /dev/null +++ b/i386-dis.c @@ -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; + + +/* + * 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; +} diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1e7dcedbdd..e6f04a8408 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -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; } @@ -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 index 0000000000..aae289419c --- /dev/null +++ b/opc-i386.h @@ -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) diff --git a/ops_template.h b/ops_template.h index 8905d90846..f8cd5e54ca 100644 --- a/ops_template.h +++ b/ops_template.h @@ -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) diff --git a/translate-i386.c b/translate-i386.c index 9bf7f5607e..f02c5ea677 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -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; } |