From bc51c5c989c12b3936b78c5772a3308629a7484c Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 17 Mar 2004 23:46:04 +0000 Subject: [PATCH] initial x86-64 host support (Gwenole Beauchesne) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@670 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + Makefile.target | 11 + amd64.ld | 342 ++++ bswap.h | 2 +- configure | 6 + cpu-exec.c | 15 + dis-asm.h | 5 + disas.c | 5 +- dyngen-exec.h | 11 + dyngen.c | 43 + dyngen.h | 6 + exec-all.h | 14 + i386-dis.c | 4475 +++++++++++++++++++++++++++++------------- linux-user/mmap.c | 2 +- linux-user/syscall.c | 2 +- target-i386/cpu.h | 2 +- target-i386/helper.c | 4 +- 17 files changed, 3623 insertions(+), 1323 deletions(-) create mode 100644 amd64.ld diff --git a/Changelog b/Changelog index e7b2aca4d1..321f5fd65d 100644 --- a/Changelog +++ b/Changelog @@ -18,6 +18,7 @@ version 0.5.3: - generic removable device support - support of CD-ROM change - multiple network interface support + - initial x86-64 host support (Gwenole Beauchesne) version 0.5.2: diff --git a/Makefile.target b/Makefile.target index 769237ac96..f869aad5c1 100644 --- a/Makefile.target +++ b/Makefile.target @@ -80,6 +80,11 @@ LDFLAGS+=-Wl,-shared endif endif +ifeq ($(ARCH),amd64) +OP_CFLAGS=$(CFLAGS) -falign-functions=0 +LDFLAGS+=-Wl,-T,$(SRC_PATH)/amd64.ld +endif + ifeq ($(ARCH),ppc) OP_CFLAGS=$(CFLAGS) LDFLAGS+=-Wl,-T,$(SRC_PATH)/ppc.ld @@ -174,6 +179,12 @@ endif # NOTE: the disassembler code is only needed for debugging LIBOBJS+=disas.o ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386) +USE_I386_DIS=y +endif +ifeq ($(findstring amd64, $(TARGET_ARCH) $(ARCH)),amd64) +USE_I386_DIS=y +endif +ifdef USE_I386_DIS LIBOBJS+=i386-dis.o endif ifeq ($(findstring alpha, $(TARGET_ARCH) $(ARCH)),alpha) diff --git a/amd64.ld b/amd64.ld new file mode 100644 index 0000000000..c52a625598 --- /dev/null +++ b/amd64.ld @@ -0,0 +1,342 @@ +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_start) +SEARCH_DIR("/lib64"); SEARCH_DIR("/usr/lib64"); SEARCH_DIR("/usr/local/lib64"); +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x90909090 + .plt : { *(.plt) } + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x90909090 + .fini : + { + KEEP (*(.fini)) + } =0x90909090 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN (0x100000) - ((0x100000 - .) & (0x100000 - 1)); . = DATA_SEGMENT_ALIGN (0x100000, 0x1000); + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(64 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table) } + .dynamic : { *(.dynamic) } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .got : { *(.got.plt) *(.got) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(64 / 8); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_start) +SEARCH_DIR("/lib64"); SEARCH_DIR("/usr/lib64"); SEARCH_DIR("/usr/local/lib64"); +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x90909090 + .plt : { *(.plt) } + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x90909090 + .fini : + { + KEEP (*(.fini)) + } =0x90909090 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN (0x100000) - ((0x100000 - .) & (0x100000 - 1)); . = DATA_SEGMENT_ALIGN (0x100000, 0x1000); + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(64 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table) } + .dynamic : { *(.dynamic) } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .got : { *(.got.plt) *(.got) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(64 / 8); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/bswap.h b/bswap.h index 0632a9d9af..c52933e493 100644 --- a/bswap.h +++ b/bswap.h @@ -43,7 +43,7 @@ #endif /* !HAVE_BYTESWAP_H */ -#if defined(__alpha__) || defined (__ia64__) +#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) #define HOST_LONG_BITS 64 #else #define HOST_LONG_BITS 32 diff --git a/configure b/configure index be8c8bcbc6..f3f68b6171 100755 --- a/configure +++ b/configure @@ -59,6 +59,9 @@ case "$cpu" in m68k) cpu="m68k" ;; + x86_64|amd64) + cpu="amd64" + ;; *) cpu="unknown" ;; @@ -253,6 +256,9 @@ echo "LDFLAGS=$LDFLAGS" >> $config_mak if test "$cpu" = "i386" ; then echo "ARCH=i386" >> $config_mak echo "#define HOST_I386 1" >> $config_h +elif test "$cpu" = "amd64" ; then + echo "ARCH=amd64" >> $config_mak + echo "#define HOST_AMD64 1" >> $config_h elif test "$cpu" = "armv4l" ; then echo "ARCH=arm" >> $config_mak echo "#define HOST_ARM 1" >> $config_h diff --git a/cpu-exec.c b/cpu-exec.c index c6f52f2780..b6f3de1bb8 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -785,6 +785,21 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, &uc->uc_sigmask, puc); } +#elif defined(__x86_64__) + +int cpu_signal_handler(int host_signum, struct siginfo *info, + void *puc) +{ + struct ucontext *uc = puc; + unsigned long pc; + + pc = uc->uc_mcontext.gregs[REG_RIP]; + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ? + (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0, + &uc->uc_sigmask, puc); +} + #elif defined(__powerpc) int cpu_signal_handler(int host_signum, struct siginfo *info, diff --git a/dis-asm.h b/dis-asm.h index 3e6982f230..ebfb2993a5 100644 --- a/dis-asm.h +++ b/dis-asm.h @@ -16,7 +16,9 @@ #define PARAMS(x) x typedef void *PTR; typedef uint64_t bfd_vma; +typedef int64_t bfd_signed_vma; typedef uint8_t bfd_byte; +#define sprintf_vma(s,x) sprintf (s, "%0" PRIx64, x) enum bfd_flavour { bfd_target_unknown_flavour, @@ -105,6 +107,9 @@ enum bfd_architecture bfd_arch_i386, /* Intel 386 */ #define bfd_mach_i386_i386 0 #define bfd_mach_i386_i8086 1 +#define bfd_mach_i386_i386_intel_syntax 2 +#define bfd_mach_x86_64 3 +#define bfd_mach_x86_64_intel_syntax 4 bfd_arch_we32k, /* AT&T WE32xxx */ bfd_arch_tahoe, /* CCI/Harris Tahoe */ bfd_arch_i860, /* Intel 860 */ diff --git a/disas.c b/disas.c index f274ac52d1..f048348f5c 100644 --- a/disas.c +++ b/disas.c @@ -140,9 +140,12 @@ void disas(FILE *out, void *code, unsigned long size, int is_host, int flags) #else disasm_info.endian = BFD_ENDIAN_LITTLE; #endif -#ifdef __i386__ +#if defined(__i386__) disasm_info.mach = bfd_mach_i386_i386; print_insn = print_insn_i386; +#elif defined(__x86_64__) + disasm_info.mach = bfd_mach_x86_64; + print_insn = print_insn_i386; #elif defined(__powerpc__) print_insn = print_insn_ppc; #elif defined(__alpha__) diff --git a/dyngen-exec.h b/dyngen-exec.h index da23e0e6a6..5e9bab6f9a 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -68,6 +68,14 @@ extern int printf(const char *, ...); #define AREG2 "esi" #define AREG3 "edi" #endif +#ifdef __x86_64__ +#define AREG0 "rbp" +#define AREG1 "rbx" +#define AREG2 "r12" +#define AREG3 "r13" +#define AREG4 "r14" +#define AREG5 "r15" +#endif #ifdef __powerpc__ #define AREG0 "r27" #define AREG1 "r24" @@ -188,6 +196,9 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; #ifdef __i386__ #define EXIT_TB() asm volatile ("ret") #endif +#ifdef __x86_64__ +#define EXIT_TB() asm volatile ("ret") +#endif #ifdef __powerpc__ #define EXIT_TB() asm volatile ("blr") #endif diff --git a/dyngen.c b/dyngen.c index 89e98245b6..7c1c0e8aed 100644 --- a/dyngen.c +++ b/dyngen.c @@ -37,6 +37,13 @@ #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) ) #undef ELF_USES_RELOCA +#elif defined(HOST_AMD64) + +#define ELF_CLASS ELFCLASS64 +#define ELF_ARCH EM_X86_64 +#define elf_check_arch(x) ((x) == EM_X86_64) +#define ELF_USES_RELOCA + #elif defined(HOST_PPC) #define ELF_CLASS ELFCLASS32 @@ -446,6 +453,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, start_offset = offset; switch(ELF_ARCH) { case EM_386: + case EM_X86_64: { int len; len = p_end - p_start; @@ -766,6 +774,41 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } } +#elif defined(HOST_AMD64) + { + char name[256]; + int type; + int addend; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= start_offset && + rel->r_offset < start_offset + copy_size) { + sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; + if (strstart(sym_name, "__op_param", &p)) { + snprintf(name, sizeof(name), "param%s", p); + } else { + snprintf(name, sizeof(name), "(long)(&%s)", sym_name); + } + type = ELF32_R_TYPE(rel->r_info); + addend = rel->r_addend; + switch(type) { + case R_X86_64_32: + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n", + rel->r_offset - start_offset, name, addend); + break; + case R_X86_64_32S: + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n", + rel->r_offset - start_offset, name, addend); + break; + case R_X86_64_PC32: + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", + rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend); + break; + default: + error("unsupported AMD64 relocation (%d)", type); + } + } + } + } #elif defined(HOST_PPC) { char name[256]; diff --git a/dyngen.h b/dyngen.h index f7f1d3aabb..a00ded775e 100644 --- a/dyngen.h +++ b/dyngen.h @@ -27,6 +27,12 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop) } #endif +#ifdef __x86_64__ +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ +} +#endif + #ifdef __s390__ static inline void flush_icache_range(unsigned long start, unsigned long stop) { diff --git a/exec-all.h b/exec-all.h index 3c79eca917..9ecf2dca7f 100644 --- a/exec-all.h +++ b/exec-all.h @@ -400,6 +400,20 @@ static inline int testandset (int *p) } #endif +#ifdef __x86_64__ +static inline int testandset (int *p) +{ + char ret; + int readval; + + __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0" + : "=q" (ret), "=m" (*p), "=a" (readval) + : "r" (1), "m" (*p), "a" (0) + : "memory"); + return ret; +} +#endif + #ifdef __s390__ static inline int testandset (int *p) { diff --git a/i386-dis.c b/i386-dis.c index f9e9072981..372f0a441b 100644 --- a/i386-dis.c +++ b/i386-dis.c @@ -1,5 +1,6 @@ /* Print i386 instructions for GDB, the GNU debugger. - Copyright (C) 1988, 89, 91, 93, 94, 95, 96, 97, 1998 + Copyright 1988, 1989, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2001 Free Software Foundation, Inc. This file is part of GDB. @@ -22,6 +23,7 @@ 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) + * x86-64 support added by Jan Hubicka (jh@suse.cz) */ /* @@ -29,33 +31,132 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ * 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 + * and the small letter tells about the operand size. Refer to * the Intel manual for details. */ #include -#include - #include "dis-asm.h" #define MAXLEN 20 -static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *)); +#include -struct dis_private -{ +#ifndef UNIXWARE_COMPAT +/* Set non-zero for broken, compatible instructions. Set to zero for + non-broken opcodes. */ +#define UNIXWARE_COMPAT 1 +#endif + +static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *)); +static void ckprefix PARAMS ((void)); +static const char *prefix_name PARAMS ((int, int)); +static int print_insn PARAMS ((bfd_vma, disassemble_info *)); +static void dofloat PARAMS ((int)); +static void OP_ST PARAMS ((int, int)); +static void OP_STi PARAMS ((int, int)); +static int putop PARAMS ((const char *, int)); +static void oappend PARAMS ((const char *)); +static void append_seg PARAMS ((void)); +static void OP_indirE PARAMS ((int, int)); +static void print_operand_value PARAMS ((char *, int, bfd_vma)); +static void OP_E PARAMS ((int, int)); +static void OP_G PARAMS ((int, int)); +static bfd_vma get64 PARAMS ((void)); +static bfd_signed_vma get32 PARAMS ((void)); +static bfd_signed_vma get32s PARAMS ((void)); +static int get16 PARAMS ((void)); +static void set_op PARAMS ((bfd_vma, int)); +static void OP_REG PARAMS ((int, int)); +static void OP_IMREG PARAMS ((int, int)); +static void OP_I PARAMS ((int, int)); +static void OP_I64 PARAMS ((int, int)); +static void OP_sI PARAMS ((int, int)); +static void OP_J PARAMS ((int, int)); +static void OP_SEG PARAMS ((int, int)); +static void OP_DIR PARAMS ((int, int)); +static void OP_OFF PARAMS ((int, int)); +static void OP_OFF64 PARAMS ((int, int)); +static void ptr_reg PARAMS ((int, int)); +static void OP_ESreg PARAMS ((int, int)); +static void OP_DSreg PARAMS ((int, int)); +static void OP_C PARAMS ((int, int)); +static void OP_D PARAMS ((int, int)); +static void OP_T PARAMS ((int, int)); +static void OP_Rd PARAMS ((int, int)); +static void OP_MMX PARAMS ((int, int)); +static void OP_XMM PARAMS ((int, int)); +static void OP_EM PARAMS ((int, int)); +static void OP_EX PARAMS ((int, int)); +static void OP_MS PARAMS ((int, int)); +static void OP_XS PARAMS ((int, int)); +static void OP_3DNowSuffix PARAMS ((int, int)); +static void OP_SIMD_Suffix PARAMS ((int, int)); +static void SIMD_Fixup PARAMS ((int, int)); +static void BadOp PARAMS ((void)); + +struct dis_private { /* Points to first byte not fetched. */ bfd_byte *max_fetched; bfd_byte the_buffer[MAXLEN]; bfd_vma insn_start; + int orig_sizeflag; jmp_buf bailout; }; +/* The opcode for the fwait instruction, which we treat as a prefix + when we can. */ +#define FWAIT_OPCODE (0x9b) + +/* Set to 1 for 64bit mode disassembly. */ +static int mode_64bit; + +/* Flags for the prefixes for the current instruction. See below. */ +static int prefixes; + +/* REX prefix the current instruction. See below. */ +static int rex; +/* Bits of REX we've already used. */ +static int rex_used; +#define REX_MODE64 8 +#define REX_EXTX 4 +#define REX_EXTY 2 +#define REX_EXTZ 1 +/* Mark parts used in the REX prefix. When we are testing for + empty prefix (for 8bit register REX extension), just mask it + out. Otherwise test for REX bit is excuse for existence of REX + only in case value is nonzero. */ +#define USED_REX(value) \ + { \ + if (value) \ + rex_used |= (rex & value) ? (value) | 0x40 : 0; \ + else \ + rex_used |= 0x40; \ + } + +/* Flags for prefixes which we somehow handled when printing the + current instruction. */ +static int used_prefixes; + +/* Flags stored in PREFIXES. */ +#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_ADDR 0x400 +#define PREFIX_FWAIT 0x800 + /* 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 \ + ((addr) <= ((struct dis_private *) (info->private_data))->max_fetched \ ? 1 : fetch_data ((info), (addr))) static int @@ -64,7 +165,7 @@ fetch_data (info, addr) bfd_byte *addr; { int status; - struct dis_private *priv = (struct dis_private *)info->private_data; + 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, @@ -73,7 +174,12 @@ fetch_data (info, addr) info); if (status != 0) { - (*info->memory_error_func) (status, start, info); + /* If we did manage to read at least one byte, then + print_insn_i386 will do something sensible. Otherwise, print + an error. We do that here because this is where we know + STATUS. */ + if (priv->max_fetched == priv->the_buffer) + (*info->memory_error_func) (status, start, info); longjmp (priv->bailout, 1); } else @@ -81,61 +187,95 @@ fetch_data (info, addr) return 1; } +#define XX NULL, 0 + #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 Ed OP_E, d_mode +#define indirEb OP_indirE, b_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 M OP_E, 0 /* lea, lgdt, etc. */ +#define Mp OP_E, 0 /* 32 or 48 bit memory operand for LDS, LES etc */ +#define Gb OP_G, b_mode #define Gv OP_G, v_mode +#define Gd OP_G, d_mode #define Gw OP_G, w_mode -#define Rw OP_rm, w_mode -#define Rd OP_rm, d_mode +#define Rd OP_Rd, d_mode +#define Rm OP_Rd, m_mode #define Ib OP_I, b_mode #define sIb OP_sI, b_mode /* sign extened byte */ #define Iv OP_I, v_mode +#define Iq OP_I, q_mode +#define Iv64 OP_I64, 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 Cm OP_C, m_mode +#define Dm OP_D, m_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 RMeAX OP_REG, eAX_reg +#define RMeBX OP_REG, eBX_reg +#define RMeCX OP_REG, eCX_reg +#define RMeDX OP_REG, eDX_reg +#define RMeSP OP_REG, eSP_reg +#define RMeBP OP_REG, eBP_reg +#define RMeSI OP_REG, eSI_reg +#define RMeDI OP_REG, eDI_reg +#define RMrAX OP_REG, rAX_reg +#define RMrBX OP_REG, rBX_reg +#define RMrCX OP_REG, rCX_reg +#define RMrDX OP_REG, rDX_reg +#define RMrSP OP_REG, rSP_reg +#define RMrBP OP_REG, rBP_reg +#define RMrSI OP_REG, rSI_reg +#define RMrDI OP_REG, rDI_reg +#define RMAL OP_REG, al_reg +#define RMAL OP_REG, al_reg +#define RMCL OP_REG, cl_reg +#define RMDL OP_REG, dl_reg +#define RMBL OP_REG, bl_reg +#define RMAH OP_REG, ah_reg +#define RMCH OP_REG, ch_reg +#define RMDH OP_REG, dh_reg +#define RMBH OP_REG, bh_reg +#define RMAX OP_REG, ax_reg +#define RMDX OP_REG, dx_reg + +#define eAX OP_IMREG, eAX_reg +#define eBX OP_IMREG, eBX_reg +#define eCX OP_IMREG, eCX_reg +#define eDX OP_IMREG, eDX_reg +#define eSP OP_IMREG, eSP_reg +#define eBP OP_IMREG, eBP_reg +#define eSI OP_IMREG, eSI_reg +#define eDI OP_IMREG, eDI_reg +#define AL OP_IMREG, al_reg +#define AL OP_IMREG, al_reg +#define CL OP_IMREG, cl_reg +#define DL OP_IMREG, dl_reg +#define BL OP_IMREG, bl_reg +#define AH OP_IMREG, ah_reg +#define CH OP_IMREG, ch_reg +#define DH OP_IMREG, dh_reg +#define BH OP_IMREG, bh_reg +#define AX OP_IMREG, ax_reg +#define DX OP_IMREG, dx_reg +#define indirDX OP_IMREG, indir_dx_reg #define Sw OP_SEG, w_mode -#define Ap OP_DIR, lptr -#define Av OP_DIR, v_mode +#define Ap OP_DIR, 0 #define Ob OP_OFF, b_mode +#define Ob64 OP_OFF64, 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 Ov64 OP_OFF64, v_mode +#define Xb OP_DSreg, eSI_reg +#define Xv OP_DSreg, eSI_reg +#define Yb OP_ESreg, eDI_reg +#define Yv OP_ESreg, eDI_reg +#define DSBX OP_DSreg, eBX_reg #define es OP_REG, es_reg #define ss OP_REG, ss_reg @@ -145,48 +285,32 @@ fetch_data (info, addr) #define gs OP_REG, gs_reg #define MX OP_MMX, 0 +#define XM OP_XMM, 0 #define EM OP_EM, v_mode -#define MS OP_MS, b_mode +#define EX OP_EX, v_mode +#define MS OP_MS, v_mode +#define XS OP_XS, v_mode +#define None OP_E, 0 +#define OPSUF OP_3DNowSuffix, 0 +#define OPSIMD OP_SIMD_Suffix, 0 -typedef int (*op_rtn) PARAMS ((int bytemode, int aflag, int dflag)); +#define cond_jump_flag NULL, cond_jump_mode +#define loop_jcxz_flag NULL, loop_jcxz_mode -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)); +/* bits in sizeflag */ +#define SUFFIX_ALWAYS 4 +#define AFLAG 2 +#define DFLAG 1 -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 b_mode 1 /* byte operand */ +#define v_mode 2 /* operand size depends on prefixes */ +#define w_mode 3 /* word operand */ +#define d_mode 4 /* double word operand */ +#define q_mode 5 /* quad word operand */ +#define x_mode 6 +#define m_mode 7 /* d_mode in 32bit, q_mode in 64bit mode. */ +#define cond_jump_mode 8 +#define loop_jcxz_mode 9 #define es_reg 100 #define cs_reg 101 @@ -194,16 +318,15 @@ static void ckprefix PARAMS ((void)); #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 eAX_reg 108 +#define eCX_reg 109 +#define eDX_reg 110 +#define eBX_reg 111 +#define eSP_reg 112 +#define eBP_reg 113 +#define eSI_reg 114 +#define eDI_reg 115 #define al_reg 116 #define cl_reg 117 @@ -223,34 +346,82 @@ static void ckprefix PARAMS ((void)); #define si_reg 130 #define di_reg 131 +#define rAX_reg 132 +#define rCX_reg 133 +#define rDX_reg 134 +#define rBX_reg 135 +#define rSP_reg 136 +#define rBP_reg 137 +#define rSI_reg 138 +#define rDI_reg 139 + #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 1 +#define USE_GROUPS 2 +#define USE_PREFIX_USER_TABLE 3 +#define X86_64_SPECIAL 4 -#define FLOATCODE 50 -#define FLOAT NULL, NULL, FLOATCODE +#define FLOAT NULL, NULL, FLOATCODE, NULL, 0, NULL, 0 + +#define GRP1b NULL, NULL, USE_GROUPS, NULL, 0, NULL, 0 +#define GRP1S NULL, NULL, USE_GROUPS, NULL, 1, NULL, 0 +#define GRP1Ss NULL, NULL, USE_GROUPS, NULL, 2, NULL, 0 +#define GRP2b NULL, NULL, USE_GROUPS, NULL, 3, NULL, 0 +#define GRP2S NULL, NULL, USE_GROUPS, NULL, 4, NULL, 0 +#define GRP2b_one NULL, NULL, USE_GROUPS, NULL, 5, NULL, 0 +#define GRP2S_one NULL, NULL, USE_GROUPS, NULL, 6, NULL, 0 +#define GRP2b_cl NULL, NULL, USE_GROUPS, NULL, 7, NULL, 0 +#define GRP2S_cl NULL, NULL, USE_GROUPS, NULL, 8, NULL, 0 +#define GRP3b NULL, NULL, USE_GROUPS, NULL, 9, NULL, 0 +#define GRP3S NULL, NULL, USE_GROUPS, NULL, 10, NULL, 0 +#define GRP4 NULL, NULL, USE_GROUPS, NULL, 11, NULL, 0 +#define GRP5 NULL, NULL, USE_GROUPS, NULL, 12, NULL, 0 +#define GRP6 NULL, NULL, USE_GROUPS, NULL, 13, NULL, 0 +#define GRP7 NULL, NULL, USE_GROUPS, NULL, 14, NULL, 0 +#define GRP8 NULL, NULL, USE_GROUPS, NULL, 15, NULL, 0 +#define GRP9 NULL, NULL, USE_GROUPS, NULL, 16, NULL, 0 +#define GRP10 NULL, NULL, USE_GROUPS, NULL, 17, NULL, 0 +#define GRP11 NULL, NULL, USE_GROUPS, NULL, 18, NULL, 0 +#define GRP12 NULL, NULL, USE_GROUPS, NULL, 19, NULL, 0 +#define GRP13 NULL, NULL, USE_GROUPS, NULL, 20, NULL, 0 +#define GRP14 NULL, NULL, USE_GROUPS, NULL, 21, NULL, 0 +#define GRPAMD NULL, NULL, USE_GROUPS, NULL, 22, NULL, 0 + +#define PREGRP0 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 0, NULL, 0 +#define PREGRP1 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 1, NULL, 0 +#define PREGRP2 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 2, NULL, 0 +#define PREGRP3 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 3, NULL, 0 +#define PREGRP4 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 4, NULL, 0 +#define PREGRP5 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 5, NULL, 0 +#define PREGRP6 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 6, NULL, 0 +#define PREGRP7 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 7, NULL, 0 +#define PREGRP8 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 8, NULL, 0 +#define PREGRP9 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 9, NULL, 0 +#define PREGRP10 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 10, NULL, 0 +#define PREGRP11 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 11, NULL, 0 +#define PREGRP12 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 12, NULL, 0 +#define PREGRP13 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 13, NULL, 0 +#define PREGRP14 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 14, NULL, 0 +#define PREGRP15 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 15, NULL, 0 +#define PREGRP16 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 16, NULL, 0 +#define PREGRP17 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 17, NULL, 0 +#define PREGRP18 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 18, NULL, 0 +#define PREGRP19 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 19, NULL, 0 +#define PREGRP20 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 20, NULL, 0 +#define PREGRP21 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 21, NULL, 0 +#define PREGRP22 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 22, NULL, 0 +#define PREGRP23 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 23, NULL, 0 +#define PREGRP24 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 24, NULL, 0 +#define PREGRP25 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 25, NULL, 0 +#define PREGRP26 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 26, NULL, 0 + +#define X86_64_0 NULL, NULL, X86_64_SPECIAL, NULL, 0, NULL, 0 + +typedef void (*op_rtn) PARAMS ((int bytemode, int sizeflag)); struct dis386 { - char *name; + const char *name; op_rtn op1; int bytemode1; op_rtn op2; @@ -259,250 +430,281 @@ struct dis386 { int bytemode3; }; -static struct dis386 dis386[] = { +/* Upper case letters in the instruction names here are macros. + 'A' => print 'b' if no register operands or suffix_always is true + 'B' => print 'b' if suffix_always is true + 'E' => print 'e' if 32-bit form of jcxz + 'F' => print 'w' or 'l' depending on address size prefix (loop insns) + 'H' => print ",pt" or ",pn" branch hint + 'L' => print 'l' if suffix_always is true + 'N' => print 'n' if instruction has no wait "prefix" + 'O' => print 'd', or 'o' + 'P' => print 'w', 'l' or 'q' if instruction has an operand size prefix, + . or suffix_always is true. print 'q' if rex prefix is present. + 'Q' => print 'w', 'l' or 'q' if no register operands or suffix_always + . is true + 'R' => print 'w', 'l' or 'q' ("wd" or "dq" in intel mode) + 'S' => print 'w', 'l' or 'q' if suffix_always is true + 'T' => print 'q' in 64bit mode and behave as 'P' otherwise + 'U' => print 'q' in 64bit mode and behave as 'Q' otherwise + 'X' => print 's', 'd' depending on data16 prefix (for XMM) + 'W' => print 'b' or 'w' ("w" or "de" in intel mode) + 'Y' => 'q' if instruction has an REX 64bit overwrite prefix + + Many of the above letters print nothing in Intel mode. See "putop" + for the details. + + Braces '{' and '}', and vertical bars '|', indicate alternative + mnemonic strings for AT&T, Intel, X86_64 AT&T, and X86_64 Intel + modes. In cases where there are only two alternatives, the X86_64 + instruction is reserved, and "(bad)" is printed. +*/ + +static const 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 }, + { "addB", Eb, Gb, XX }, + { "addS", Ev, Gv, XX }, + { "addB", Gb, Eb, XX }, + { "addS", Gv, Ev, XX }, + { "addB", AL, Ib, XX }, + { "addS", eAX, Iv, XX }, + { "push{T|}", es, XX, XX }, + { "pop{T|}", es, XX, XX }, /* 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 */ + { "orB", Eb, Gb, XX }, + { "orS", Ev, Gv, XX }, + { "orB", Gb, Eb, XX }, + { "orS", Gv, Ev, XX }, + { "orB", AL, Ib, XX }, + { "orS", eAX, Iv, XX }, + { "push{T|}", cs, XX, XX }, + { "(bad)", XX, XX, XX }, /* 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 }, + { "adcB", Eb, Gb, XX }, + { "adcS", Ev, Gv, XX }, + { "adcB", Gb, Eb, XX }, + { "adcS", Gv, Ev, XX }, + { "adcB", AL, Ib, XX }, + { "adcS", eAX, Iv, XX }, + { "push{T|}", ss, XX, XX }, + { "popT|}", ss, XX, XX }, /* 18 */ - { "sbbb", Eb, Gb }, - { "sbbS", Ev, Gv }, - { "sbbb", Gb, Eb }, - { "sbbS", Gv, Ev }, - { "sbbb", AL, Ib }, - { "sbbS", eAX, Iv }, - { "pushS", ds }, - { "popS", ds }, + { "sbbB", Eb, Gb, XX }, + { "sbbS", Ev, Gv, XX }, + { "sbbB", Gb, Eb, XX }, + { "sbbS", Gv, Ev, XX }, + { "sbbB", AL, Ib, XX }, + { "sbbS", eAX, Iv, XX }, + { "push{T|}", ds, XX, XX }, + { "pop{T|}", ds, XX, XX }, /* 20 */ - { "andb", Eb, Gb }, - { "andS", Ev, Gv }, - { "andb", Gb, Eb }, - { "andS", Gv, Ev }, - { "andb", AL, Ib }, - { "andS", eAX, Iv }, - { "(bad)" }, /* SEG ES prefix */ - { "daa" }, + { "andB", Eb, Gb, XX }, + { "andS", Ev, Gv, XX }, + { "andB", Gb, Eb, XX }, + { "andS", Gv, Ev, XX }, + { "andB", AL, Ib, XX }, + { "andS", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG ES prefix */ + { "daa{|}", XX, XX, XX }, /* 28 */ - { "subb", Eb, Gb }, - { "subS", Ev, Gv }, - { "subb", Gb, Eb }, - { "subS", Gv, Ev }, - { "subb", AL, Ib }, - { "subS", eAX, Iv }, - { "(bad)" }, /* SEG CS prefix */ - { "das" }, + { "subB", Eb, Gb, XX }, + { "subS", Ev, Gv, XX }, + { "subB", Gb, Eb, XX }, + { "subS", Gv, Ev, XX }, + { "subB", AL, Ib, XX }, + { "subS", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG CS prefix */ + { "das{|}", XX, XX, XX }, /* 30 */ - { "xorb", Eb, Gb }, - { "xorS", Ev, Gv }, - { "xorb", Gb, Eb }, - { "xorS", Gv, Ev }, - { "xorb", AL, Ib }, - { "xorS", eAX, Iv }, - { "(bad)" }, /* SEG SS prefix */ - { "aaa" }, + { "xorB", Eb, Gb, XX }, + { "xorS", Ev, Gv, XX }, + { "xorB", Gb, Eb, XX }, + { "xorS", Gv, Ev, XX }, + { "xorB", AL, Ib, XX }, + { "xorS", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG SS prefix */ + { "aaa{|}", XX, XX, XX }, /* 38 */ - { "cmpb", Eb, Gb }, - { "cmpS", Ev, Gv }, - { "cmpb", Gb, Eb }, - { "cmpS", Gv, Ev }, - { "cmpb", AL, Ib }, - { "cmpS", eAX, Iv }, - { "(bad)" }, /* SEG DS prefix */ - { "aas" }, + { "cmpB", Eb, Gb, XX }, + { "cmpS", Ev, Gv, XX }, + { "cmpB", Gb, Eb, XX }, + { "cmpS", Gv, Ev, XX }, + { "cmpB", AL, Ib, XX }, + { "cmpS", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG DS prefix */ + { "aas{|}", XX, XX, XX }, /* 40 */ - { "incS", eAX }, - { "incS", eCX }, - { "incS", eDX }, - { "incS", eBX }, - { "incS", eSP }, - { "incS", eBP }, - { "incS", eSI }, - { "incS", eDI }, + { "inc{S|}", RMeAX, XX, XX }, + { "inc{S|}", RMeCX, XX, XX }, + { "inc{S|}", RMeDX, XX, XX }, + { "inc{S|}", RMeBX, XX, XX }, + { "inc{S|}", RMeSP, XX, XX }, + { "inc{S|}", RMeBP, XX, XX }, + { "inc{S|}", RMeSI, XX, XX }, + { "inc{S|}", RMeDI, XX, XX }, /* 48 */ - { "decS", eAX }, - { "decS", eCX }, - { "decS", eDX }, - { "decS", eBX }, - { "decS", eSP }, - { "decS", eBP }, - { "decS", eSI }, - { "decS", eDI }, + { "dec{S|}", RMeAX, XX, XX }, + { "dec{S|}", RMeCX, XX, XX }, + { "dec{S|}", RMeDX, XX, XX }, + { "dec{S|}", RMeBX, XX, XX }, + { "dec{S|}", RMeSP, XX, XX }, + { "dec{S|}", RMeBP, XX, XX }, + { "dec{S|}", RMeSI, XX, XX }, + { "dec{S|}", RMeDI, XX, XX }, /* 50 */ - { "pushS", eAX }, - { "pushS", eCX }, - { "pushS", eDX }, - { "pushS", eBX }, - { "pushS", eSP }, - { "pushS", eBP }, - { "pushS", eSI }, - { "pushS", eDI }, + { "pushS", RMrAX, XX, XX }, + { "pushS", RMrCX, XX, XX }, + { "pushS", RMrDX, XX, XX }, + { "pushS", RMrBX, XX, XX }, + { "pushS", RMrSP, XX, XX }, + { "pushS", RMrBP, XX, XX }, + { "pushS", RMrSI, XX, XX }, + { "pushS", RMrDI, XX, XX }, /* 58 */ - { "popS", eAX }, - { "popS", eCX }, - { "popS", eDX }, - { "popS", eBX }, - { "popS", eSP }, - { "popS", eBP }, - { "popS", eSI }, - { "popS", eDI }, + { "popS", RMrAX, XX, XX }, + { "popS", RMrCX, XX, XX }, + { "popS", RMrDX, XX, XX }, + { "popS", RMrBX, XX, XX }, + { "popS", RMrSP, XX, XX }, + { "popS", RMrBP, XX, XX }, + { "popS", RMrSI, XX, XX }, + { "popS", RMrDI, XX, XX }, /* 60 */ - { "pusha" }, - { "popa" }, - { "boundS", Gv, Ma }, - { "arpl", Ew, Gw }, - { "(bad)" }, /* seg fs */ - { "(bad)" }, /* seg gs */ - { "(bad)" }, /* op size prefix */ - { "(bad)" }, /* adr size prefix */ + { "pusha{P|}", XX, XX, XX }, + { "popa{P|}", XX, XX, XX }, + { "bound{S|}", Gv, Ma, XX }, + { X86_64_0 }, + { "(bad)", XX, XX, XX }, /* seg fs */ + { "(bad)", XX, XX, XX }, /* seg gs */ + { "(bad)", XX, XX, XX }, /* op size prefix */ + { "(bad)", XX, XX, XX }, /* 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 }, + { "pushT", Iq, XX, XX }, + { "imulS", Gv, Ev, Iv }, + { "pushT", sIb, XX, XX }, + { "imulS", Gv, Ev, sIb }, + { "ins{b||b|}", Yb, indirDX, XX }, + { "ins{R||R|}", Yv, indirDX, XX }, + { "outs{b||b|}", indirDX, Xb, XX }, + { "outs{R||R|}", indirDX, Xv, XX }, /* 70 */ - { "jo", Jb }, - { "jno", Jb }, - { "jb", Jb }, - { "jae", Jb }, - { "je", Jb }, - { "jne", Jb }, - { "jbe", Jb }, - { "ja", Jb }, + { "joH", Jb, XX, cond_jump_flag }, + { "jnoH", Jb, XX, cond_jump_flag }, + { "jbH", Jb, XX, cond_jump_flag }, + { "jaeH", Jb, XX, cond_jump_flag }, + { "jeH", Jb, XX, cond_jump_flag }, + { "jneH", Jb, XX, cond_jump_flag }, + { "jbeH", Jb, XX, cond_jump_flag }, + { "jaH", Jb, XX, cond_jump_flag }, /* 78 */ - { "js", Jb }, - { "jns", Jb }, - { "jp", Jb }, - { "jnp", Jb }, - { "jl", Jb }, - { "jnl", Jb }, - { "jle", Jb }, - { "jg", Jb }, + { "jsH", Jb, XX, cond_jump_flag }, + { "jnsH", Jb, XX, cond_jump_flag }, + { "jpH", Jb, XX, cond_jump_flag }, + { "jnpH", Jb, XX, cond_jump_flag }, + { "jlH", Jb, XX, cond_jump_flag }, + { "jgeH", Jb, XX, cond_jump_flag }, + { "jleH", Jb, XX, cond_jump_flag }, + { "jgH", Jb, XX, cond_jump_flag }, /* 80 */ { GRP1b }, { GRP1S }, - { "(bad)" }, + { "(bad)", XX, XX, XX }, { GRP1Ss }, - { "testb", Eb, Gb }, - { "testS", Ev, Gv }, - { "xchgb", Eb, Gb }, - { "xchgS", Ev, Gv }, + { "testB", Eb, Gb, XX }, + { "testS", Ev, Gv, XX }, + { "xchgB", Eb, Gb, XX }, + { "xchgS", Ev, Gv, XX }, /* 88 */ - { "movb", Eb, Gb }, - { "movS", Ev, Gv }, - { "movb", Gb, Eb }, - { "movS", Gv, Ev }, - { "movS", Ev, Sw }, - { "leaS", Gv, M }, - { "movS", Sw, Ev }, - { "popS", Ev }, + { "movB", Eb, Gb, XX }, + { "movS", Ev, Gv, XX }, + { "movB", Gb, Eb, XX }, + { "movS", Gv, Ev, XX }, + { "movQ", Ev, Sw, XX }, + { "leaS", Gv, M, XX }, + { "movQ", Sw, Ev, XX }, + { "popU", Ev, XX, XX }, /* 90 */ - { "nop" }, - { "xchgS", eCX, eAX }, - { "xchgS", eDX, eAX }, - { "xchgS", eBX, eAX }, - { "xchgS", eSP, eAX }, - { "xchgS", eBP, eAX }, - { "xchgS", eSI, eAX }, - { "xchgS", eDI, eAX }, + { "nop", XX, XX, XX }, + /* FIXME: NOP with REPz prefix is called PAUSE. */ + { "xchgS", RMeCX, eAX, XX }, + { "xchgS", RMeDX, eAX, XX }, + { "xchgS", RMeBX, eAX, XX }, + { "xchgS", RMeSP, eAX, XX }, + { "xchgS", RMeBP, eAX, XX }, + { "xchgS", RMeSI, eAX, XX }, + { "xchgS", RMeDI, eAX, XX }, /* 98 */ - { "cWtS" }, - { "cStd" }, - { "lcall", Ap }, - { "(bad)" }, /* fwait */ - { "pushf" }, - { "popf" }, - { "sahf" }, - { "lahf" }, + { "cW{tR||tR|}", XX, XX, XX }, + { "cR{tO||tO|}", XX, XX, XX }, + { "lcall{T|}", Ap, XX, XX }, + { "(bad)", XX, XX, XX }, /* fwait */ + { "pushfT", XX, XX, XX }, + { "popfT", XX, XX, XX }, + { "sahf{|}", XX, XX, XX }, + { "lahf{|}", XX, XX, XX }, /* 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 }, + { "movB", AL, Ob64, XX }, + { "movS", eAX, Ov64, XX }, + { "movB", Ob64, AL, XX }, + { "movS", Ov64, eAX, XX }, + { "movs{b||b|}", Yb, Xb, XX }, + { "movs{R||R|}", Yv, Xv, XX }, + { "cmps{b||b|}", Xb, Yb, XX }, + { "cmps{R||R|}", Xv, Yv, XX }, /* 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 }, + { "testB", AL, Ib, XX }, + { "testS", eAX, Iv, XX }, + { "stosB", Yb, AL, XX }, + { "stosS", Yv, eAX, XX }, + { "lodsB", AL, Xb, XX }, + { "lodsS", eAX, Xv, XX }, + { "scasB", AL, Yb, XX }, + { "scasS", eAX, Yv, XX }, /* 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 }, + { "movB", RMAL, Ib, XX }, + { "movB", RMCL, Ib, XX }, + { "movB", RMDL, Ib, XX }, + { "movB", RMBL, Ib, XX }, + { "movB", RMAH, Ib, XX }, + { "movB", RMCH, Ib, XX }, + { "movB", RMDH, Ib, XX }, + { "movB", RMBH, Ib, XX }, /* 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 }, + { "movS", RMeAX, Iv64, XX }, + { "movS", RMeCX, Iv64, XX }, + { "movS", RMeDX, Iv64, XX }, + { "movS", RMeBX, Iv64, XX }, + { "movS", RMeSP, Iv64, XX }, + { "movS", RMeBP, Iv64, XX }, + { "movS", RMeSI, Iv64, XX }, + { "movS", RMeDI, Iv64, XX }, /* c0 */ { GRP2b }, { GRP2S }, - { "ret", Iw }, - { "ret" }, - { "lesS", Gv, Mp }, - { "ldsS", Gv, Mp }, - { "movb", Eb, Ib }, - { "movS", Ev, Iv }, + { "retT", Iw, XX, XX }, + { "retT", XX, XX, XX }, + { "les{S|}", Gv, Mp, XX }, + { "ldsS", Gv, Mp, XX }, + { "movA", Eb, Ib, XX }, + { "movQ", Ev, Iv, XX }, /* c8 */ - { "enter", Iw, Ib }, - { "leave" }, - { "lret", Iw }, - { "lret" }, - { "int3" }, - { "int", Ib }, - { "into" }, - { "iret" }, + { "enterT", Iw, Ib, XX }, + { "leaveT", XX, XX, XX }, + { "lretP", Iw, XX, XX }, + { "lretP", XX, XX, XX }, + { "int3", XX, XX, XX }, + { "int", Ib, XX, XX }, + { "into{|}", XX, XX, XX }, + { "iretP", XX, XX, XX }, /* d0 */ { GRP2b_one }, { GRP2S_one }, { GRP2b_cl }, { GRP2S_cl }, - { "aam", Ib }, - { "aad", Ib }, - { "(bad)" }, - { "xlat" }, + { "aam{|}", sIb, XX, XX }, + { "aad{|}", sIb, XX, XX }, + { "(bad)", XX, XX, XX }, + { "xlat", DSBX, XX, XX }, /* d8 */ { FLOAT }, { FLOAT }, @@ -513,581 +715,974 @@ static struct dis386 dis386[] = { { FLOAT }, { FLOAT }, /* e0 */ - { "loopne", Jb }, - { "loope", Jb }, - { "loop", Jb }, - { "jCcxz", Jb }, - { "inb", AL, Ib }, - { "inS", eAX, Ib }, - { "outb", Ib, AL }, - { "outS", Ib, eAX }, + { "loopneFH", Jb, XX, loop_jcxz_flag }, + { "loopeFH", Jb, XX, loop_jcxz_flag }, + { "loopFH", Jb, XX, loop_jcxz_flag }, + { "jEcxzH", Jb, XX, loop_jcxz_flag }, + { "inB", AL, Ib, XX }, + { "inS", eAX, Ib, XX }, + { "outB", Ib, AL, XX }, + { "outS", Ib, eAX, XX }, /* e8 */ - { "call", Av }, - { "jmp", Jv }, - { "ljmp", Ap }, - { "jmp", Jb }, - { "inb", AL, indirDX }, - { "inS", eAX, indirDX }, - { "outb", indirDX, AL }, - { "outS", indirDX, eAX }, + { "callT", Jv, XX, XX }, + { "jmpT", Jv, XX, XX }, + { "ljmp{T|}", Ap, XX, XX }, + { "jmp", Jb, XX, XX }, + { "inB", AL, indirDX, XX }, + { "inS", eAX, indirDX, XX }, + { "outB", indirDX, AL, XX }, + { "outS", indirDX, eAX, XX }, /* f0 */ - { "(bad)" }, /* lock prefix */ - { "(bad)" }, - { "(bad)" }, /* repne */ - { "(bad)" }, /* repz */ - { "hlt" }, - { "cmc" }, + { "(bad)", XX, XX, XX }, /* lock prefix */ + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, /* repne */ + { "(bad)", XX, XX, XX }, /* repz */ + { "hlt", XX, XX, XX }, + { "cmc", XX, XX, XX }, { GRP3b }, { GRP3S }, /* f8 */ - { "clc" }, - { "stc" }, - { "cli" }, - { "sti" }, - { "cld" }, - { "std" }, + { "clc", XX, XX, XX }, + { "stc", XX, XX, XX }, + { "cli", XX, XX, XX }, + { "sti", XX, XX, XX }, + { "cld", XX, XX, XX }, + { "std", XX, XX, XX }, { GRP4 }, { GRP5 }, }; -static struct dis386 dis386_twobyte[] = { +static const struct dis386 dis386_twobyte[] = { /* 00 */ { GRP6 }, { GRP7 }, - { "larS", Gv, Ew }, - { "lslS", Gv, Ew }, - { "(bad)" }, - { "(bad)" }, - { "clts" }, - { "(bad)" }, + { "larS", Gv, Ew, XX }, + { "lslS", Gv, Ew, XX }, + { "(bad)", XX, XX, XX }, + { "syscall", XX, XX, XX }, + { "clts", XX, XX, XX }, + { "sysretP", XX, XX, XX }, /* 08 */ - { "invd" }, - { "wbinvd" }, - { "(bad)" }, { "ud2a" }, - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "invd", XX, XX, XX }, + { "wbinvd", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "ud2a", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { GRPAMD }, + { "femms", XX, XX, XX }, + { "", MX, EM, OPSUF }, /* See OP_3DNowSuffix. */ /* 10 */ - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { PREGRP8 }, + { PREGRP9 }, + { "movlpX", XM, EX, SIMD_Fixup, 'h' }, /* really only 2 operands */ + { "movlpX", EX, XM, SIMD_Fixup, 'h' }, + { "unpcklpX", XM, EX, XX }, + { "unpckhpX", XM, EX, XX }, + { "movhpX", XM, EX, SIMD_Fixup, 'l' }, + { "movhpX", EX, XM, SIMD_Fixup, 'l' }, /* 18 */ - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { GRP14 }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, /* 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)" }, + { "movL", Rm, Cm, XX }, + { "movL", Rm, Dm, XX }, + { "movL", Cm, Rm, XX }, + { "movL", Dm, Rm, XX }, + { "movL", Rd, Td, XX }, + { "(bad)", XX, XX, XX }, + { "movL", Td, Rd, XX }, + { "(bad)", XX, XX, XX }, /* 28 */ - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "movapX", XM, EX, XX }, + { "movapX", EX, XM, XX }, + { PREGRP2 }, + { "movntpX", Ev, XM, XX }, + { PREGRP4 }, + { PREGRP3 }, + { "ucomisX", XM,EX, XX }, + { "comisX", XM,EX, XX }, /* 30 */ - { "wrmsr" }, { "rdtsc" }, { "rdmsr" }, { "rdpmc" }, - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "wrmsr", XX, XX, XX }, + { "rdtsc", XX, XX, XX }, + { "rdmsr", XX, XX, XX }, + { "rdpmc", XX, XX, XX }, + { "sysenter", XX, XX, XX }, + { "sysexit", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, /* 38 */ - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, /* 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 }, + { "cmovo", Gv, Ev, XX }, + { "cmovno", Gv, Ev, XX }, + { "cmovb", Gv, Ev, XX }, + { "cmovae", Gv, Ev, XX }, + { "cmove", Gv, Ev, XX }, + { "cmovne", Gv, Ev, XX }, + { "cmovbe", Gv, Ev, XX }, + { "cmova", Gv, Ev, XX }, /* 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 }, + { "cmovs", Gv, Ev, XX }, + { "cmovns", Gv, Ev, XX }, + { "cmovp", Gv, Ev, XX }, + { "cmovnp", Gv, Ev, XX }, + { "cmovl", Gv, Ev, XX }, + { "cmovge", Gv, Ev, XX }, + { "cmovle", Gv, Ev, XX }, + { "cmovg", Gv, Ev, XX }, /* 50 */ - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "movmskpX", Gd, XS, XX }, + { PREGRP13 }, + { PREGRP12 }, + { PREGRP11 }, + { "andpX", XM, EX, XX }, + { "andnpX", XM, EX, XX }, + { "orpX", XM, EX, XX }, + { "xorpX", XM, EX, XX }, /* 58 */ - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { PREGRP0 }, + { PREGRP10 }, + { PREGRP17 }, + { PREGRP16 }, + { PREGRP14 }, + { PREGRP7 }, + { PREGRP5 }, + { PREGRP6 }, /* 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 }, + { "punpcklbw", MX, EM, XX }, + { "punpcklwd", MX, EM, XX }, + { "punpckldq", MX, EM, XX }, + { "packsswb", MX, EM, XX }, + { "pcmpgtb", MX, EM, XX }, + { "pcmpgtw", MX, EM, XX }, + { "pcmpgtd", MX, EM, XX }, + { "packuswb", MX, EM, XX }, /* 68 */ - { "punpckhbw", MX, EM }, - { "punpckhwd", MX, EM }, - { "punpckhdq", MX, EM }, - { "packssdw", MX, EM }, - { "(bad)" }, { "(bad)" }, - { "movd", MX, Ev }, - { "movq", MX, EM }, + { "punpckhbw", MX, EM, XX }, + { "punpckhwd", MX, EM, XX }, + { "punpckhdq", MX, EM, XX }, + { "packssdw", MX, EM, XX }, + { PREGRP26 }, + { PREGRP24 }, + { "movd", MX, Ed, XX }, + { PREGRP19 }, /* 70 */ - { "(bad)" }, + { PREGRP22 }, { GRP10 }, { GRP11 }, { GRP12 }, - { "pcmpeqb", MX, EM }, - { "pcmpeqw", MX, EM }, - { "pcmpeqd", MX, EM }, - { "emms" }, + { "pcmpeqb", MX, EM, XX }, + { "pcmpeqw", MX, EM, XX }, + { "pcmpeqd", MX, EM, XX }, + { "emms", XX, XX, XX }, /* 78 */ - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, - { "(bad)" }, { "(bad)" }, - { "movd", Ev, MX }, - { "movq", EM, MX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { PREGRP23 }, + { PREGRP20 }, /* 80 */ - { "jo", Jv }, - { "jno", Jv }, - { "jb", Jv }, - { "jae", Jv }, - { "je", Jv }, - { "jne", Jv }, - { "jbe", Jv }, - { "ja", Jv }, + { "joH", Jv, XX, cond_jump_flag }, + { "jnoH", Jv, XX, cond_jump_flag }, + { "jbH", Jv, XX, cond_jump_flag }, + { "jaeH", Jv, XX, cond_jump_flag }, + { "jeH", Jv, XX, cond_jump_flag }, + { "jneH", Jv, XX, cond_jump_flag }, + { "jbeH", Jv, XX, cond_jump_flag }, + { "jaH", Jv, XX, cond_jump_flag }, /* 88 */ - { "js", Jv }, - { "jns", Jv }, - { "jp", Jv }, - { "jnp", Jv }, - { "jl", Jv }, - { "jge", Jv }, - { "jle", Jv }, - { "jg", Jv }, + { "jsH", Jv, XX, cond_jump_flag }, + { "jnsH", Jv, XX, cond_jump_flag }, + { "jpH", Jv, XX, cond_jump_flag }, + { "jnpH", Jv, XX, cond_jump_flag }, + { "jlH", Jv, XX, cond_jump_flag }, + { "jgeH", Jv, XX, cond_jump_flag }, + { "jleH", Jv, XX, cond_jump_flag }, + { "jgH", Jv, XX, cond_jump_flag }, /* 90 */ - { "seto", Eb }, - { "setno", Eb }, - { "setb", Eb }, - { "setae", Eb }, - { "sete", Eb }, - { "setne", Eb }, - { "setbe", Eb }, - { "seta", Eb }, + { "seto", Eb, XX, XX }, + { "setno", Eb, XX, XX }, + { "setb", Eb, XX, XX }, + { "setae", Eb, XX, XX }, + { "sete", Eb, XX, XX }, + { "setne", Eb, XX, XX }, + { "setbe", Eb, XX, XX }, + { "seta", Eb, XX, XX }, /* 98 */ - { "sets", Eb }, - { "setns", Eb }, - { "setp", Eb }, - { "setnp", Eb }, - { "setl", Eb }, - { "setge", Eb }, - { "setle", Eb }, - { "setg", Eb }, + { "sets", Eb, XX, XX }, + { "setns", Eb, XX, XX }, + { "setp", Eb, XX, XX }, + { "setnp", Eb, XX, XX }, + { "setl", Eb, XX, XX }, + { "setge", Eb, XX, XX }, + { "setle", Eb, XX, XX }, + { "setg", Eb, XX, XX }, /* a0 */ - { "pushS", fs }, - { "popS", fs }, - { "cpuid" }, - { "btS", Ev, Gv }, - { "shldS", Ev, Gv, Ib }, - { "shldS", Ev, Gv, CL }, - { "(bad)" }, - { "(bad)" }, + { "pushT", fs, XX, XX }, + { "popT", fs, XX, XX }, + { "cpuid", XX, XX, XX }, + { "btS", Ev, Gv, XX }, + { "shldS", Ev, Gv, Ib }, + { "shldS", Ev, Gv, CL }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, /* a8 */ - { "pushS", gs }, - { "popS", gs }, - { "rsm" }, - { "btsS", Ev, Gv }, - { "shrdS", Ev, Gv, Ib }, - { "shrdS", Ev, Gv, CL }, - { "(bad)" }, - { "imulS", Gv, Ev }, + { "pushT", gs, XX, XX }, + { "popT", gs, XX, XX }, + { "rsm", XX, XX, XX }, + { "btsS", Ev, Gv, XX }, + { "shrdS", Ev, Gv, Ib }, + { "shrdS", Ev, Gv, CL }, + { GRP13 }, + { "imulS", Gv, Ev, XX }, /* 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 }, + { "cmpxchgB", Eb, Gb, XX }, + { "cmpxchgS", Ev, Gv, XX }, + { "lssS", Gv, Mp, XX }, + { "btrS", Ev, Gv, XX }, + { "lfsS", Gv, Mp, XX }, + { "lgsS", Gv, Mp, XX }, + { "movz{bR|x|bR|x}", Gv, Eb, XX }, + { "movz{wR|x|wR|x}", Gv, Ew, XX }, /* yes, there really is movzww ! */ /* b8 */ - { "ud2b" }, - { "(bad)" }, + { "(bad)", XX, XX, XX }, + { "ud2b", XX, XX, XX }, { GRP8 }, - { "btcS", Ev, Gv }, - { "bsfS", Gv, Ev }, - { "bsrS", Gv, Ev }, - { "movsbS", Gv, Eb }, - { "movswS", Gv, Ew }, + { "btcS", Ev, Gv, XX }, + { "bsfS", Gv, Ev, XX }, + { "bsrS", Gv, Ev, XX }, + { "movs{bR|x|bR|x}", Gv, Eb, XX }, + { "movs{wR|x|wR|x}", Gv, Ew, XX }, /* yes, there really is movsww ! */ /* c0 */ - { "xaddb", Eb, Gb }, - { "xaddS", Ev, Gv }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { GRP9 }, + { "xaddB", Eb, Gb, XX }, + { "xaddS", Ev, Gv, XX }, + { PREGRP1 }, + { "movntiS", Ev, Gv, XX }, + { "pinsrw", MX, Ed, Ib }, + { "pextrw", Gd, MS, Ib }, + { "shufpX", XM, EX, Ib }, + { GRP9 }, /* c8 */ - { "bswap", eAX }, - { "bswap", eCX }, - { "bswap", eDX }, - { "bswap", eBX }, - { "bswap", eSP }, - { "bswap", eBP }, - { "bswap", eSI }, - { "bswap", eDI }, + { "bswap", RMeAX, XX, XX }, + { "bswap", RMeCX, XX, XX }, + { "bswap", RMeDX, XX, XX }, + { "bswap", RMeBX, XX, XX }, + { "bswap", RMeSP, XX, XX }, + { "bswap", RMeBP, XX, XX }, + { "bswap", RMeSI, XX, XX }, + { "bswap", RMeDI, XX, XX }, /* d0 */ - { "(bad)" }, - { "psrlw", MX, EM }, - { "psrld", MX, EM }, - { "psrlq", MX, EM }, - { "(bad)" }, - { "pmullw", MX, EM }, - { "(bad)" }, { "(bad)" }, + { "(bad)", XX, XX, XX }, + { "psrlw", MX, EM, XX }, + { "psrld", MX, EM, XX }, + { "psrlq", MX, EM, XX }, + { "paddq", MX, EM, XX }, + { "pmullw", MX, EM, XX }, + { PREGRP21 }, + { "pmovmskb", Gd, MS, XX }, /* d8 */ - { "psubusb", MX, EM }, - { "psubusw", MX, EM }, - { "(bad)" }, - { "pand", MX, EM }, - { "paddusb", MX, EM }, - { "paddusw", MX, EM }, - { "(bad)" }, - { "pandn", MX, EM }, + { "psubusb", MX, EM, XX }, + { "psubusw", MX, EM, XX }, + { "pminub", MX, EM, XX }, + { "pand", MX, EM, XX }, + { "paddusb", MX, EM, XX }, + { "paddusw", MX, EM, XX }, + { "pmaxub", MX, EM, XX }, + { "pandn", MX, EM, XX }, /* e0 */ - { "(bad)" }, - { "psraw", MX, EM }, - { "psrad", MX, EM }, - { "(bad)" }, - { "(bad)" }, - { "pmulhw", MX, EM }, - { "(bad)" }, { "(bad)" }, + { "pavgb", MX, EM, XX }, + { "psraw", MX, EM, XX }, + { "psrad", MX, EM, XX }, + { "pavgw", MX, EM, XX }, + { "pmulhuw", MX, EM, XX }, + { "pmulhw", MX, EM, XX }, + { PREGRP15 }, + { PREGRP25 }, /* e8 */ - { "psubsb", MX, EM }, - { "psubsw", MX, EM }, - { "(bad)" }, - { "por", MX, EM }, - { "paddsb", MX, EM }, - { "paddsw", MX, EM }, - { "(bad)" }, - { "pxor", MX, EM }, + { "psubsb", MX, EM, XX }, + { "psubsw", MX, EM, XX }, + { "pminsw", MX, EM, XX }, + { "por", MX, EM, XX }, + { "paddsb", MX, EM, XX }, + { "paddsw", MX, EM, XX }, + { "pmaxsw", MX, EM, XX }, + { "pxor", MX, EM, XX }, /* f0 */ - { "(bad)" }, - { "psllw", MX, EM }, - { "pslld", MX, EM }, - { "psllq", MX, EM }, - { "(bad)" }, - { "pmaddwd", MX, EM }, - { "(bad)" }, { "(bad)" }, + { "(bad)", XX, XX, XX }, + { "psllw", MX, EM, XX }, + { "pslld", MX, EM, XX }, + { "psllq", MX, EM, XX }, + { "pmuludq", MX, EM, XX }, + { "pmaddwd", MX, EM, XX }, + { "psadbw", MX, EM, XX }, + { PREGRP18 }, /* f8 */ - { "psubb", MX, EM }, - { "psubw", MX, EM }, - { "psubd", MX, EM }, - { "(bad)" }, - { "paddb", MX, EM }, - { "paddw", MX, EM }, - { "paddd", MX, EM }, - { "(bad)" } + { "psubb", MX, EM, XX }, + { "psubw", MX, EM, XX }, + { "psubd", MX, EM, XX }, + { "psubq", MX, EM, XX }, + { "paddb", MX, EM, XX }, + { "paddw", MX, EM, XX }, + { "paddd", MX, EM, XX }, + { "(bad)", XX, XX, XX } }; 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 + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 00 */ + /* 10 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 10 */ + /* 20 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 20 */ + /* 30 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 30 */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40 */ + /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */ + /* 60 */ 0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0, /* 60 */ + /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */ + /* 80 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 80 */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 90 */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* a0 */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* b0 */ + /* c0 */ 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* c0 */ + /* d0 */ 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* d0 */ + /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* e0 */ + /* f0 */ 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1 /* f0 */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ }; 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 */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,1, /* 0f */ + /* 10 */ 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1, /* 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 */ + /* 50 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 5f */ + /* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6f */ + /* 70 */ 1,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 */ + /* a0 */ 0,0,0,1,1,1,0,0,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 */ + /* d0 */ 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* df */ + /* e0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* ef */ + /* f0 */ 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +static const unsigned char twobyte_uses_SSE_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* 5f */ + /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1, /* 6f */ + /* 70 */ 1,0,0,0,0,0,0,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 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ }; static char obuf[100]; static char *obufp; static char scratchbuf[100]; static unsigned char *start_codep; +static unsigned char *insn_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 unsigned char need_modrm; -static char *names32[]={ - "%eax","%ecx","%edx","%ebx", "%esp","%ebp","%esi","%edi", +/* If we are accessing mod/rm/reg without need_modrm set, then the + values are stale. Hitting this abort likely indicates that you + need to update onebyte_has_modrm or twobyte_has_modrm. */ +#define MODRM_CHECK if (!need_modrm) abort () + +static const char **names64; +static const char **names32; +static const char **names16; +static const char **names8; +static const char **names8rex; +static const char **names_seg; +static const char **index16; + +static const char *intel_names64[] = { + "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" }; -static char *names16[] = { - "%ax","%cx","%dx","%bx","%sp","%bp","%si","%di", +static const char *intel_names32[] = { + "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", + "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" }; -static char *names8[] = { - "%al","%cl","%dl","%bl","%ah","%ch","%dh","%bh", +static const char *intel_names16[] = { + "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", + "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" }; -static char *names_seg[] = { - "%es","%cs","%ss","%ds","%fs","%gs","%?","%?", +static const char *intel_names8[] = { + "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", }; -static char *index16[] = { - "bx+si","bx+di","bp+si","bp+di","si","di","bp","bx" +static const char *intel_names8rex[] = { + "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", + "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" +}; +static const char *intel_names_seg[] = { + "es", "cs", "ss", "ds", "fs", "gs", "?", "?", +}; +static const char *intel_index16[] = { + "bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx" }; -static struct dis386 grps[][8] = { +static const char *att_names64[] = { + "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi", + "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" +}; +static const char *att_names32[] = { + "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi", + "%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d" +}; +static const char *att_names16[] = { + "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di", + "%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w" +}; +static const char *att_names8[] = { + "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh", +}; +static const char *att_names8rex[] = { + "%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil", + "%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b" +}; +static const char *att_names_seg[] = { + "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "%?", "%?", +}; +static const char *att_index16[] = { + "%bx,%si", "%bx,%di", "%bp,%si", "%bp,%di", "%si", "%di", "%bp", "%bx" +}; + +static const 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 } + { "addA", Eb, Ib, XX }, + { "orA", Eb, Ib, XX }, + { "adcA", Eb, Ib, XX }, + { "sbbA", Eb, Ib, XX }, + { "andA", Eb, Ib, XX }, + { "subA", Eb, Ib, XX }, + { "xorA", Eb, Ib, XX }, + { "cmpA", Eb, Ib, XX } }, /* 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 } + { "addQ", Ev, Iv, XX }, + { "orQ", Ev, Iv, XX }, + { "adcQ", Ev, Iv, XX }, + { "sbbQ", Ev, Iv, XX }, + { "andQ", Ev, Iv, XX }, + { "subQ", Ev, Iv, XX }, + { "xorQ", Ev, Iv, XX }, + { "cmpQ", Ev, Iv, XX } }, /* 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 } + { "addQ", Ev, sIb, XX }, + { "orQ", Ev, sIb, XX }, + { "adcQ", Ev, sIb, XX }, + { "sbbQ", Ev, sIb, XX }, + { "andQ", Ev, sIb, XX }, + { "subQ", Ev, sIb, XX }, + { "xorQ", Ev, sIb, XX }, + { "cmpQ", Ev, sIb, XX } }, /* GRP2b */ { - { "rolb", Eb, Ib }, - { "rorb", Eb, Ib }, - { "rclb", Eb, Ib }, - { "rcrb", Eb, Ib }, - { "shlb", Eb, Ib }, - { "shrb", Eb, Ib }, - { "(bad)" }, - { "sarb", Eb, Ib }, + { "rolA", Eb, Ib, XX }, + { "rorA", Eb, Ib, XX }, + { "rclA", Eb, Ib, XX }, + { "rcrA", Eb, Ib, XX }, + { "shlA", Eb, Ib, XX }, + { "shrA", Eb, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "sarA", Eb, Ib, XX }, }, /* GRP2S */ { - { "rolS", Ev, Ib }, - { "rorS", Ev, Ib }, - { "rclS", Ev, Ib }, - { "rcrS", Ev, Ib }, - { "shlS", Ev, Ib }, - { "shrS", Ev, Ib }, - { "(bad)" }, - { "sarS", Ev, Ib }, + { "rolQ", Ev, Ib, XX }, + { "rorQ", Ev, Ib, XX }, + { "rclQ", Ev, Ib, XX }, + { "rcrQ", Ev, Ib, XX }, + { "shlQ", Ev, Ib, XX }, + { "shrQ", Ev, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "sarQ", Ev, Ib, XX }, }, /* GRP2b_one */ { - { "rolb", Eb }, - { "rorb", Eb }, - { "rclb", Eb }, - { "rcrb", Eb }, - { "shlb", Eb }, - { "shrb", Eb }, - { "(bad)" }, - { "sarb", Eb }, + { "rolA", Eb, XX, XX }, + { "rorA", Eb, XX, XX }, + { "rclA", Eb, XX, XX }, + { "rcrA", Eb, XX, XX }, + { "shlA", Eb, XX, XX }, + { "shrA", Eb, XX, XX }, + { "(bad)", XX, XX, XX }, + { "sarA", Eb, XX, XX }, }, /* GRP2S_one */ { - { "rolS", Ev }, - { "rorS", Ev }, - { "rclS", Ev }, - { "rcrS", Ev }, - { "shlS", Ev }, - { "shrS", Ev }, - { "(bad)" }, - { "sarS", Ev }, + { "rolQ", Ev, XX, XX }, + { "rorQ", Ev, XX, XX }, + { "rclQ", Ev, XX, XX }, + { "rcrQ", Ev, XX, XX }, + { "shlQ", Ev, XX, XX }, + { "shrQ", Ev, XX, XX }, + { "(bad)", XX, XX, XX}, + { "sarQ", Ev, XX, XX }, }, /* GRP2b_cl */ { - { "rolb", Eb, CL }, - { "rorb", Eb, CL }, - { "rclb", Eb, CL }, - { "rcrb", Eb, CL }, - { "shlb", Eb, CL }, - { "shrb", Eb, CL }, - { "(bad)" }, - { "sarb", Eb, CL }, + { "rolA", Eb, CL, XX }, + { "rorA", Eb, CL, XX }, + { "rclA", Eb, CL, XX }, + { "rcrA", Eb, CL, XX }, + { "shlA", Eb, CL, XX }, + { "shrA", Eb, CL, XX }, + { "(bad)", XX, XX, XX }, + { "sarA", Eb, CL, XX }, }, /* GRP2S_cl */ { - { "rolS", Ev, CL }, - { "rorS", Ev, CL }, - { "rclS", Ev, CL }, - { "rcrS", Ev, CL }, - { "shlS", Ev, CL }, - { "shrS", Ev, CL }, - { "(bad)" }, - { "sarS", Ev, CL } + { "rolQ", Ev, CL, XX }, + { "rorQ", Ev, CL, XX }, + { "rclQ", Ev, CL, XX }, + { "rcrQ", Ev, CL, XX }, + { "shlQ", Ev, CL, XX }, + { "shrQ", Ev, CL, XX }, + { "(bad)", XX, XX, XX }, + { "sarQ", Ev, CL, XX } }, /* GRP3b */ { - { "testb", Eb, Ib }, - { "(bad)", Eb }, - { "notb", Eb }, - { "negb", Eb }, - { "mulb", AL, Eb }, - { "imulb", AL, Eb }, - { "divb", AL, Eb }, - { "idivb", AL, Eb } + { "testA", Eb, Ib, XX }, + { "(bad)", Eb, XX, XX }, + { "notA", Eb, XX, XX }, + { "negA", Eb, XX, XX }, + { "mulA", Eb, XX, XX }, /* Don't print the implicit %al register, */ + { "imulA", Eb, XX, XX }, /* to distinguish these opcodes from other */ + { "divA", Eb, XX, XX }, /* mul/imul opcodes. Do the same for div */ + { "idivA", Eb, XX, XX } /* and idiv for consistency. */ }, /* GRP3S */ { - { "testS", Ev, Iv }, - { "(bad)" }, - { "notS", Ev }, - { "negS", Ev }, - { "mulS", eAX, Ev }, - { "imulS", eAX, Ev }, - { "divS", eAX, Ev }, - { "idivS", eAX, Ev }, + { "testQ", Ev, Iv, XX }, + { "(bad)", XX, XX, XX }, + { "notQ", Ev, XX, XX }, + { "negQ", Ev, XX, XX }, + { "mulQ", Ev, XX, XX }, /* Don't print the implicit register. */ + { "imulQ", Ev, XX, XX }, + { "divQ", Ev, XX, XX }, + { "idivQ", Ev, XX, XX }, }, /* GRP4 */ { - { "incb", Eb }, - { "decb", Eb }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, + { "incA", Eb, XX, XX }, + { "decA", Eb, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, }, /* GRP5 */ { - { "incS", Ev }, - { "decS", Ev }, - { "call", indirEv }, - { "lcall", indirEv }, - { "jmp", indirEv }, - { "ljmp", indirEv }, - { "pushS", Ev }, - { "(bad)" }, + { "incQ", Ev, XX, XX }, + { "decQ", Ev, XX, XX }, + { "callT", indirEv, XX, XX }, + { "lcallT", indirEv, XX, XX }, + { "jmpT", indirEv, XX, XX }, + { "ljmpT", indirEv, XX, XX }, + { "pushU", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, }, /* GRP6 */ { - { "sldt", Ew }, - { "str", Ew }, - { "lldt", Ew }, - { "ltr", Ew }, - { "verr", Ew }, - { "verw", Ew }, - { "(bad)" }, - { "(bad)" } + { "sldtQ", Ev, XX, XX }, + { "strQ", Ev, XX, XX }, + { "lldt", Ew, XX, XX }, + { "ltr", Ew, XX, XX }, + { "verr", Ew, XX, XX }, + { "verw", Ew, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX } }, /* GRP7 */ { - { "sgdt", Ew }, - { "sidt", Ew }, - { "lgdt", Ew }, - { "lidt", Ew }, - { "smsw", Ew }, - { "(bad)" }, - { "lmsw", Ew }, - { "invlpg", Ew }, + { "sgdtQ", M, XX, XX }, + { "sidtQ", M, XX, XX }, + { "lgdtQ", M, XX, XX }, + { "lidtQ", M, XX, XX }, + { "smswQ", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, + { "lmsw", Ew, XX, XX }, + { "invlpg", Ew, XX, XX }, }, /* GRP8 */ { - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "btS", Ev, Ib }, - { "btsS", Ev, Ib }, - { "btrS", Ev, Ib }, - { "btcS", Ev, Ib }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "btQ", Ev, Ib, XX }, + { "btsQ", Ev, Ib, XX }, + { "btrQ", Ev, Ib, XX }, + { "btcQ", Ev, Ib, XX }, }, /* GRP9 */ { - { "(bad)" }, - { "cmpxchg8b", Ev }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, + { "(bad)", XX, XX, XX }, + { "cmpxchg8b", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, }, /* GRP10 */ { - { "(bad)" }, - { "(bad)" }, - { "psrlw", MS, Ib }, - { "(bad)" }, - { "psraw", MS, Ib }, - { "(bad)" }, - { "psllw", MS, Ib }, - { "(bad)" }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "psrlw", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "psraw", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "psllw", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, }, /* GRP11 */ { - { "(bad)" }, - { "(bad)" }, - { "psrld", MS, Ib }, - { "(bad)" }, - { "psrad", MS, Ib }, - { "(bad)" }, - { "pslld", MS, Ib }, - { "(bad)" }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "psrld", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "psrad", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "pslld", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, }, /* GRP12 */ { - { "(bad)" }, - { "(bad)" }, - { "psrlq", MS, Ib }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "psllq", MS, Ib }, - { "(bad)" }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "psrlq", MS, Ib, XX }, + { "psrldq", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "psllq", MS, Ib, XX }, + { "pslldq", MS, Ib, XX }, + }, + /* GRP13 */ + { + { "fxsave", Ev, XX, XX }, + { "fxrstor", Ev, XX, XX }, + { "ldmxcsr", Ev, XX, XX }, + { "stmxcsr", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, + { "lfence", None, XX, XX }, + { "mfence", None, XX, XX }, + { "sfence", None, XX, XX }, + /* FIXME: the sfence with memory operand is clflush! */ + }, + /* GRP14 */ + { + { "prefetchnta", Ev, XX, XX }, + { "prefetcht0", Ev, XX, XX }, + { "prefetcht1", Ev, XX, XX }, + { "prefetcht2", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + }, + /* GRPAMD */ + { + { "prefetch", Eb, XX, XX }, + { "prefetchw", Eb, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, } }; -#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 const struct dis386 prefix_user_table[][4] = { + /* PREGRP0 */ + { + { "addps", XM, EX, XX }, + { "addss", XM, EX, XX }, + { "addpd", XM, EX, XX }, + { "addsd", XM, EX, XX }, + }, + /* PREGRP1 */ + { + { "", XM, EX, OPSIMD }, /* See OP_SIMD_SUFFIX. */ + { "", XM, EX, OPSIMD }, + { "", XM, EX, OPSIMD }, + { "", XM, EX, OPSIMD }, + }, + /* PREGRP2 */ + { + { "cvtpi2ps", XM, EM, XX }, + { "cvtsi2ssY", XM, Ev, XX }, + { "cvtpi2pd", XM, EM, XX }, + { "cvtsi2sdY", XM, Ev, XX }, + }, + /* PREGRP3 */ + { + { "cvtps2pi", MX, EX, XX }, + { "cvtss2siY", Gv, EX, XX }, + { "cvtpd2pi", MX, EX, XX }, + { "cvtsd2siY", Gv, EX, XX }, + }, + /* PREGRP4 */ + { + { "cvttps2pi", MX, EX, XX }, + { "cvttss2siY", Gv, EX, XX }, + { "cvttpd2pi", MX, EX, XX }, + { "cvttsd2siY", Gv, EX, XX }, + }, + /* PREGRP5 */ + { + { "divps", XM, EX, XX }, + { "divss", XM, EX, XX }, + { "divpd", XM, EX, XX }, + { "divsd", XM, EX, XX }, + }, + /* PREGRP6 */ + { + { "maxps", XM, EX, XX }, + { "maxss", XM, EX, XX }, + { "maxpd", XM, EX, XX }, + { "maxsd", XM, EX, XX }, + }, + /* PREGRP7 */ + { + { "minps", XM, EX, XX }, + { "minss", XM, EX, XX }, + { "minpd", XM, EX, XX }, + { "minsd", XM, EX, XX }, + }, + /* PREGRP8 */ + { + { "movups", XM, EX, XX }, + { "movss", XM, EX, XX }, + { "movupd", XM, EX, XX }, + { "movsd", XM, EX, XX }, + }, + /* PREGRP9 */ + { + { "movups", EX, XM, XX }, + { "movss", EX, XM, XX }, + { "movupd", EX, XM, XX }, + { "movsd", EX, XM, XX }, + }, + /* PREGRP10 */ + { + { "mulps", XM, EX, XX }, + { "mulss", XM, EX, XX }, + { "mulpd", XM, EX, XX }, + { "mulsd", XM, EX, XX }, + }, + /* PREGRP11 */ + { + { "rcpps", XM, EX, XX }, + { "rcpss", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + }, + /* PREGRP12 */ + { + { "rsqrtps", XM, EX, XX }, + { "rsqrtss", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + }, + /* PREGRP13 */ + { + { "sqrtps", XM, EX, XX }, + { "sqrtss", XM, EX, XX }, + { "sqrtpd", XM, EX, XX }, + { "sqrtsd", XM, EX, XX }, + }, + /* PREGRP14 */ + { + { "subps", XM, EX, XX }, + { "subss", XM, EX, XX }, + { "subpd", XM, EX, XX }, + { "subsd", XM, EX, XX }, + }, + /* PREGRP15 */ + { + { "(bad)", XM, EX, XX }, + { "cvtdq2pd", XM, EX, XX }, + { "cvttpd2dq", XM, EX, XX }, + { "cvtpd2dq", XM, EX, XX }, + }, + /* PREGRP16 */ + { + { "cvtdq2ps", XM, EX, XX }, + { "cvttps2dq",XM, EX, XX }, + { "cvtps2dq",XM, EX, XX }, + { "(bad)", XM, EX, XX }, + }, + /* PREGRP17 */ + { + { "cvtps2pd", XM, EX, XX }, + { "cvtss2sd", XM, EX, XX }, + { "cvtpd2ps", XM, EX, XX }, + { "cvtsd2ss", XM, EX, XX }, + }, + /* PREGRP18 */ + { + { "maskmovq", MX, MS, XX }, + { "(bad)", XM, EX, XX }, + { "maskmovdqu", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + }, + /* PREGRP19 */ + { + { "movq", MX, EM, XX }, + { "movdqu", XM, EX, XX }, + { "movdqa", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + }, + /* PREGRP20 */ + { + { "movq", EM, MX, XX }, + { "movdqu", EX, XM, XX }, + { "movdqa", EX, XM, XX }, + { "(bad)", EX, XM, XX }, + }, + /* PREGRP21 */ + { + { "(bad)", EX, XM, XX }, + { "movq2dq", XM, MS, XX }, + { "movq", EX, XM, XX }, + { "movdq2q", MX, XS, XX }, + }, + /* PREGRP22 */ + { + { "pshufw", MX, EM, Ib }, + { "pshufhw", XM, EX, Ib }, + { "pshufd", XM, EX, Ib }, + { "pshuflw", XM, EX, Ib }, + }, + /* PREGRP23 */ + { + { "movd", Ed, MX, XX }, + { "movq", XM, EX, XX }, + { "movd", Ed, XM, XX }, + { "(bad)", Ed, XM, XX }, + }, + /* PREGRP24 */ + { + { "(bad)", MX, EX, XX }, + { "(bad)", XM, EX, XX }, + { "punpckhqdq", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + }, + /* PREGRP25 */ + { + { "movntq", Ev, MX, XX }, + { "(bad)", Ev, XM, XX }, + { "movntdq", Ev, XM, XX }, + { "(bad)", Ev, XM, XX }, + }, + /* PREGRP26 */ + { + { "(bad)", MX, EX, XX }, + { "(bad)", XM, EX, XX }, + { "punpcklqdq", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + }, +}; -static int prefixes; +static const struct dis386 x86_64_table[][2] = { + { + { "arpl", Ew, Gw, XX }, + { "movs{||lq|xd}", Gv, Ed, XX }, + }, +}; + +#define INTERNAL_DISASSEMBLER_ERROR _("") static void ckprefix () { + int newrex; + rex = 0; prefixes = 0; + used_prefixes = 0; + rex_used = 0; while (1) { FETCH_DATA (the_info, codep + 1); + newrex = 0; switch (*codep) { + /* REX prefixes family. */ + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + if (mode_64bit) + newrex = *codep; + else + return; + break; case 0xf3: prefixes |= PREFIX_REPZ; break; @@ -1119,22 +1714,114 @@ ckprefix () prefixes |= PREFIX_DATA; break; case 0x67: - prefixes |= PREFIX_ADR; + prefixes |= PREFIX_ADDR; break; - case 0x9b: - prefixes |= PREFIX_FWAIT; + case FWAIT_OPCODE: + /* fwait is really an instruction. If there are prefixes + before the fwait, they belong to the fwait, *not* to the + following instruction. */ + if (prefixes) + { + prefixes |= PREFIX_FWAIT; + codep++; + return; + } + prefixes = PREFIX_FWAIT; break; default: return; } + /* Rex is ignored when followed by another prefix. */ + if (rex) + { + oappend (prefix_name (rex, 0)); + oappend (" "); + } + rex = newrex; codep++; } } -static char op1out[100], op2out[100], op3out[100]; -static int op_address[3], op_ad, op_index[3]; -static int start_pc; +/* Return the name of the prefix byte PREF, or NULL if PREF is not a + prefix byte. */ +static const char * +prefix_name (pref, sizeflag) + int pref; + int sizeflag; +{ + switch (pref) + { + /* REX prefixes family. */ + case 0x40: + return "rex"; + case 0x41: + return "rexZ"; + case 0x42: + return "rexY"; + case 0x43: + return "rexYZ"; + case 0x44: + return "rexX"; + case 0x45: + return "rexXZ"; + case 0x46: + return "rexXY"; + case 0x47: + return "rexXYZ"; + case 0x48: + return "rex64"; + case 0x49: + return "rex64Z"; + case 0x4a: + return "rex64Y"; + case 0x4b: + return "rex64YZ"; + case 0x4c: + return "rex64X"; + case 0x4d: + return "rex64XZ"; + case 0x4e: + return "rex64XY"; + case 0x4f: + return "rex64XYZ"; + case 0xf3: + return "repz"; + case 0xf2: + return "repnz"; + case 0xf0: + return "lock"; + case 0x2e: + return "cs"; + case 0x36: + return "ss"; + case 0x3e: + return "ds"; + case 0x26: + return "es"; + case 0x64: + return "fs"; + case 0x65: + return "gs"; + case 0x66: + return (sizeflag & DFLAG) ? "data16" : "data32"; + case 0x67: + if (mode_64bit) + return (sizeflag & AFLAG) ? "addr32" : "addr64"; + else + return ((sizeflag & AFLAG) && !mode_64bit) ? "addr16" : "addr32"; + case FWAIT_OPCODE: + return "fwait"; + default: + return NULL; + } +} + +static char op1out[100], op2out[100], op3out[100]; +static int op_ad, op_index[3]; +static bfd_vma op_address[3]; +static bfd_vma op_riprel[3]; +static bfd_vma start_pc; /* * On the 386's of 1988, the maximum length of an instruction is 15 bytes. @@ -1145,48 +1832,160 @@ static int start_pc; * 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)); +static char intel_syntax; +static char open_char; +static char close_char; +static char separator_char; +static char scale_char; + +/* Here for backwards compatibility. When gdb stops using + print_insn_i386_att and print_insn_i386_intel these functions can + disappear, and print_insn_i386 be merged into print_insn. */ +int +print_insn_i386_att (pc, info) + bfd_vma pc; + disassemble_info *info; +{ + intel_syntax = 0; + + return print_insn (pc, info); +} + +int +print_insn_i386_intel (pc, info) + bfd_vma pc; + disassemble_info *info; +{ + intel_syntax = 1; + + return print_insn (pc, info); +} + 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 (); + intel_syntax = -1; + + return print_insn (pc, info); } -int -print_insn_x86 (pc, info, aflag, dflag) +static int +print_insn (pc, info) bfd_vma pc; disassemble_info *info; - int volatile aflag; - int volatile dflag; { - struct dis386 *dp; + const struct dis386 *dp; int i; - int enter_instruction; + int two_source_ops; char *first, *second, *third; int needcomma; - unsigned char need_modrm; - + unsigned char uses_SSE_prefix; + int sizeflag; + const char *p; 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; + mode_64bit = (info->mach == bfd_mach_x86_64_intel_syntax + || info->mach == bfd_mach_x86_64); + + if (intel_syntax == -1) + intel_syntax = (info->mach == bfd_mach_i386_i386_intel_syntax + || info->mach == bfd_mach_x86_64_intel_syntax); + + if (info->mach == bfd_mach_i386_i386 + || info->mach == bfd_mach_x86_64 + || info->mach == bfd_mach_i386_i386_intel_syntax + || info->mach == bfd_mach_x86_64_intel_syntax) + priv.orig_sizeflag = AFLAG | DFLAG; + else if (info->mach == bfd_mach_i386_i8086) + priv.orig_sizeflag = 0; + else + abort (); + + for (p = info->disassembler_options; p != NULL; ) + { + if (strncmp (p, "x86-64", 6) == 0) + { + mode_64bit = 1; + priv.orig_sizeflag = AFLAG | DFLAG; + } + else if (strncmp (p, "i386", 4) == 0) + { + mode_64bit = 0; + priv.orig_sizeflag = AFLAG | DFLAG; + } + else if (strncmp (p, "i8086", 5) == 0) + { + mode_64bit = 0; + priv.orig_sizeflag = 0; + } + else if (strncmp (p, "intel", 5) == 0) + { + intel_syntax = 1; + } + else if (strncmp (p, "att", 3) == 0) + { + intel_syntax = 0; + } + else if (strncmp (p, "addr", 4) == 0) + { + if (p[4] == '1' && p[5] == '6') + priv.orig_sizeflag &= ~AFLAG; + else if (p[4] == '3' && p[5] == '2') + priv.orig_sizeflag |= AFLAG; + } + else if (strncmp (p, "data", 4) == 0) + { + if (p[4] == '1' && p[5] == '6') + priv.orig_sizeflag &= ~DFLAG; + else if (p[4] == '3' && p[5] == '2') + priv.orig_sizeflag |= DFLAG; + } + else if (strncmp (p, "suffix", 6) == 0) + priv.orig_sizeflag |= SUFFIX_ALWAYS; + + p = strchr (p, ','); + if (p != NULL) + p++; + } + + if (intel_syntax) + { + names64 = intel_names64; + names32 = intel_names32; + names16 = intel_names16; + names8 = intel_names8; + names8rex = intel_names8rex; + names_seg = intel_names_seg; + index16 = intel_index16; + open_char = '['; + close_char = ']'; + separator_char = '+'; + scale_char = '*'; + } + else + { + names64 = att_names64; + names32 = att_names32; + names16 = att_names16; + names8 = att_names8; + names8rex = att_names8rex; + names_seg = att_names_seg; + index16 = att_index16; + open_char = '('; + close_char = ')'; + separator_char = ','; + scale_char = ','; + } + + /* The output looks better if we put 7 bytes on a line, since that + puts most long word instructions on a single line. */ + info->bytes_per_line = 7; 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; @@ -1197,59 +1996,116 @@ print_insn_x86 (pc, info, aflag, dflag) the_info = info; start_pc = pc; - start_codep = inbuf; - codep = inbuf; - + start_codep = priv.the_buffer; + codep = priv.the_buffer; + + if (setjmp (priv.bailout) != 0) + { + const char *name; + + /* Getting here means we tried for data but didn't get it. That + means we have an incomplete instruction of some sort. Just + print the first byte as a prefix or a .byte pseudo-op. */ + if (codep > priv.the_buffer) + { + name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); + if (name != NULL) + (*info->fprintf_func) (info->stream, "%s", name); + else + { + /* Just print the first byte as a .byte instruction. */ + (*info->fprintf_func) (info->stream, ".byte 0x%x", + (unsigned int) priv.the_buffer[0]); + } + + return 1; + } + + return -1; + } + + obufp = obuf; ckprefix (); + insn_codep = codep; + sizeflag = priv.orig_sizeflag; + 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 "); - + two_source_ops = (*codep == 0x62) || (*codep == 0xc8); + if ((prefixes & PREFIX_FWAIT) && ((*codep < 0xd8) || (*codep > 0xdf))) { - /* fwait not followed by floating point instruction */ - (*info->fprintf_func) (info->stream, "fwait"); - return (1); + const char *name; + + /* fwait not followed by floating point instruction. Print the + first prefix, which is probably fwait itself. */ + name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); + if (name == NULL) + name = INTERNAL_DISASSEMBLER_ERROR; + (*info->fprintf_func) (info->stream, "%s", name); + 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]; + uses_SSE_prefix = twobyte_uses_SSE_prefix[*codep]; } else { dp = &dis386[*codep]; need_modrm = onebyte_has_modrm[*codep]; + uses_SSE_prefix = 0; } codep++; + if (!uses_SSE_prefix && (prefixes & PREFIX_REPZ)) + { + oappend ("repz "); + used_prefixes |= PREFIX_REPZ; + } + if (!uses_SSE_prefix && (prefixes & PREFIX_REPNZ)) + { + oappend ("repnz "); + used_prefixes |= PREFIX_REPNZ; + } + if (prefixes & PREFIX_LOCK) + { + oappend ("lock "); + used_prefixes |= PREFIX_LOCK; + } + + if (prefixes & PREFIX_ADDR) + { + sizeflag ^= AFLAG; + if (dp->bytemode3 != loop_jcxz_mode || intel_syntax) + { + if ((sizeflag & AFLAG) || mode_64bit) + oappend ("addr32 "); + else + oappend ("addr16 "); + used_prefixes |= PREFIX_ADDR; + } + } + + if (!uses_SSE_prefix && (prefixes & PREFIX_DATA)) + { + sizeflag ^= DFLAG; + if (dp->bytemode3 == cond_jump_mode + && dp->bytemode1 == v_mode + && !intel_syntax) + { + if (sizeflag & DFLAG) + oappend ("data32 "); + else + oappend ("data16 "); + used_prefixes |= PREFIX_DATA; + } + } + if (need_modrm) { FETCH_DATA (info, codep + 1); @@ -1260,42 +2116,100 @@ print_insn_x86 (pc, info, aflag, dflag) if (dp->name == NULL && dp->bytemode1 == FLOATCODE) { - dofloat (aflag, dflag); + dofloat (sizeflag); } else { + int index; 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); + { + switch (dp->bytemode1) + { + case USE_GROUPS: + dp = &grps[dp->bytemode2][reg]; + break; + + case USE_PREFIX_USER_TABLE: + index = 0; + used_prefixes |= (prefixes & PREFIX_REPZ); + if (prefixes & PREFIX_REPZ) + index = 1; + else + { + used_prefixes |= (prefixes & PREFIX_DATA); + if (prefixes & PREFIX_DATA) + index = 2; + else + { + used_prefixes |= (prefixes & PREFIX_REPNZ); + if (prefixes & PREFIX_REPNZ) + index = 3; + } + } + dp = &prefix_user_table[dp->bytemode2][index]; + break; + + case X86_64_SPECIAL: + dp = &x86_64_table[dp->bytemode2][mode_64bit]; + break; + + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + break; + } + } + + if (putop (dp->name, sizeflag) == 0) + { + obufp = op1out; + op_ad = 2; + if (dp->op1) + (*dp->op1) (dp->bytemode1, sizeflag); + + obufp = op2out; + op_ad = 1; + if (dp->op2) + (*dp->op2) (dp->bytemode2, sizeflag); + + obufp = op3out; + op_ad = 0; + if (dp->op3) + (*dp->op3) (dp->bytemode3, sizeflag); + } } - + + /* See if any prefixes were not used. If so, print the first one + separately. If we don't do this, we'll wind up printing an + instruction stream which does not precisely correspond to the + bytes we are disassembling. */ + if ((prefixes & ~used_prefixes) != 0) + { + const char *name; + + name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); + if (name == NULL) + name = INTERNAL_DISASSEMBLER_ERROR; + (*info->fprintf_func) (info->stream, "%s", name); + return 1; + } + if (rex & ~rex_used) + { + const char *name; + name = prefix_name (rex | 0x40, priv.orig_sizeflag); + if (name == NULL) + name = INTERNAL_DISASSEMBLER_ERROR; + (*info->fprintf_func) (info->stream, "%s ", name); + } + 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) + + /* The enter and bound instructions are printed with operands in the same + order as the intel book; everything else is printed in reverse order. */ + if (intel_syntax || two_source_ops) { first = op1out; second = op2out; @@ -1313,8 +2227,8 @@ print_insn_x86 (pc, info, aflag, dflag) needcomma = 0; if (*first) { - if (op_index[0] != -1) - (*info->print_address_func) (op_address[op_index[0]], info); + if (op_index[0] != -1 && !op_riprel[0]) + (*info->print_address_func) ((bfd_vma) op_address[op_index[0]], info); else (*info->fprintf_func) (info->stream, "%s", first); needcomma = 1; @@ -1323,8 +2237,8 @@ print_insn_x86 (pc, info, aflag, dflag) { if (needcomma) (*info->fprintf_func) (info->stream, ","); - if (op_index[1] != -1) - (*info->print_address_func) (op_address[op_index[1]], info); + if (op_index[1] != -1 && !op_riprel[1]) + (*info->print_address_func) ((bfd_vma) op_address[op_index[1]], info); else (*info->fprintf_func) (info->stream, "%s", second); needcomma = 1; @@ -1333,65 +2247,72 @@ print_insn_x86 (pc, info, aflag, dflag) { if (needcomma) (*info->fprintf_func) (info->stream, ","); - if (op_index[2] != -1) - (*info->print_address_func) (op_address[op_index[2]], info); + if (op_index[2] != -1 && !op_riprel[2]) + (*info->print_address_func) ((bfd_vma) op_address[op_index[2]], info); else (*info->fprintf_func) (info->stream, "%s", third); } - return (codep - inbuf); + for (i = 0; i < 3; i++) + if (op_index[i] != -1 && op_riprel[i]) + { + (*info->fprintf_func) (info->stream, " # "); + (*info->print_address_func) ((bfd_vma) (start_pc + codep - start_codep + + op_address[op_index[i]]), info); + } + return codep - priv.the_buffer; } -static char *float_mem[] = { +static const char *float_mem[] = { /* d8 */ - "fadds", - "fmuls", - "fcoms", - "fcomps", - "fsubs", - "fsubrs", - "fdivs", - "fdivrs", + "fadd{s||s|}", + "fmul{s||s|}", + "fcom{s||s|}", + "fcomp{s||s|}", + "fsub{s||s|}", + "fsubr{s||s|}", + "fdiv{s||s|}", + "fdivr{s||s|}", /* d9 */ - "flds", + "fld{s||s|}", "(bad)", - "fsts", - "fstps", + "fst{s||s|}", + "fstp{s||s|}", "fldenv", "fldcw", "fNstenv", "fNstcw", /* da */ - "fiaddl", - "fimull", - "ficoml", - "ficompl", - "fisubl", - "fisubrl", - "fidivl", - "fidivrl", + "fiadd{l||l|}", + "fimul{l||l|}", + "ficom{l||l|}", + "ficomp{l||l|}", + "fisub{l||l|}", + "fisubr{l||l|}", + "fidiv{l||l|}", + "fidivr{l||l|}", /* db */ - "fildl", + "fild{l||l|}", "(bad)", - "fistl", - "fistpl", + "fist{l||l|}", + "fistp{l||l|}", "(bad)", - "fldt", + "fld{t||t|}", "(bad)", - "fstpt", + "fstp{t||t|}", /* dc */ - "faddl", - "fmull", - "fcoml", - "fcompl", - "fsubl", - "fsubrl", - "fdivl", - "fdivrl", + "fadd{l||l|}", + "fmul{l||l|}", + "fcom{l||l|}", + "fcomp{l||l|}", + "fsub{l||l|}", + "fsubr{l||l|}", + "fdiv{l||l|}", + "fdivr{l||l|}", /* dd */ - "fldl", + "fld{l||l|}", "(bad)", - "fstl", - "fstpl", + "fst{l||l|}", + "fstp{l||l|}", "frstor", "(bad)", "fNsave", @@ -1411,7 +2332,7 @@ static char *float_mem[] = { "fist", "fistp", "fbld", - "fildll", + "fild{ll||ll|}", "fbstp", "fistpll", }; @@ -1419,34 +2340,34 @@ static char *float_mem[] = { #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 +#define FGRPd9_2 NULL, NULL, 0, NULL, 0, NULL, 0 +#define FGRPd9_4 NULL, NULL, 1, NULL, 0, NULL, 0 +#define FGRPd9_5 NULL, NULL, 2, NULL, 0, NULL, 0 +#define FGRPd9_6 NULL, NULL, 3, NULL, 0, NULL, 0 +#define FGRPd9_7 NULL, NULL, 4, NULL, 0, NULL, 0 +#define FGRPda_5 NULL, NULL, 5, NULL, 0, NULL, 0 +#define FGRPdb_4 NULL, NULL, 6, NULL, 0, NULL, 0 +#define FGRPde_3 NULL, NULL, 7, NULL, 0, NULL, 0 +#define FGRPdf_4 NULL, NULL, 8, NULL, 0, NULL, 0 -static struct dis386 float_reg[][8] = { +static const 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 }, + { "fadd", ST, STi, XX }, + { "fmul", ST, STi, XX }, + { "fcom", STi, XX, XX }, + { "fcomp", STi, XX, XX }, + { "fsub", ST, STi, XX }, + { "fsubr", ST, STi, XX }, + { "fdiv", ST, STi, XX }, + { "fdivr", ST, STi, XX }, }, /* d9 */ { - { "fld", STi }, - { "fxch", STi }, + { "fld", STi, XX, XX }, + { "fxch", STi, XX, XX }, { FGRPd9_2 }, - { "(bad)" }, + { "(bad)", XX, XX, XX }, { FGRPd9_4 }, { FGRPd9_5 }, { FGRPd9_6 }, @@ -1454,73 +2375,86 @@ static struct dis386 float_reg[][8] = { }, /* da */ { - { "fcmovb", ST, STi }, - { "fcmove", ST, STi }, - { "fcmovbe",ST, STi }, - { "fcmovu", ST, STi }, - { "(bad)" }, + { "fcmovb", ST, STi, XX }, + { "fcmove", ST, STi, XX }, + { "fcmovbe",ST, STi, XX }, + { "fcmovu", ST, STi, XX }, + { "(bad)", XX, XX, XX }, { FGRPda_5 }, - { "(bad)" }, - { "(bad)" }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, }, /* db */ { - { "fcmovnb",ST, STi }, - { "fcmovne",ST, STi }, - { "fcmovnbe",ST, STi }, - { "fcmovnu",ST, STi }, + { "fcmovnb",ST, STi, XX }, + { "fcmovne",ST, STi, XX }, + { "fcmovnbe",ST, STi, XX }, + { "fcmovnu",ST, STi, XX }, { FGRPdb_4 }, - { "fucomi", ST, STi }, - { "fcomi", ST, STi }, - { "(bad)" }, + { "fucomi", ST, STi, XX }, + { "fcomi", ST, STi, XX }, + { "(bad)", XX, XX, XX }, }, /* dc */ { - { "fadd", STi, ST }, - { "fmul", STi, ST }, - { "(bad)" }, - { "(bad)" }, - { "fsub", STi, ST }, - { "fsubr", STi, ST }, - { "fdiv", STi, ST }, - { "fdivr", STi, ST }, + { "fadd", STi, ST, XX }, + { "fmul", STi, ST, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, +#if UNIXWARE_COMPAT + { "fsub", STi, ST, XX }, + { "fsubr", STi, ST, XX }, + { "fdiv", STi, ST, XX }, + { "fdivr", STi, ST, XX }, +#else + { "fsubr", STi, ST, XX }, + { "fsub", STi, ST, XX }, + { "fdivr", STi, ST, XX }, + { "fdiv", STi, ST, XX }, +#endif }, /* dd */ { - { "ffree", STi }, - { "(bad)" }, - { "fst", STi }, - { "fstp", STi }, - { "fucom", STi }, - { "fucomp", STi }, - { "(bad)" }, - { "(bad)" }, + { "ffree", STi, XX, XX }, + { "(bad)", XX, XX, XX }, + { "fst", STi, XX, XX }, + { "fstp", STi, XX, XX }, + { "fucom", STi, XX, XX }, + { "fucomp", STi, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, }, /* de */ { - { "faddp", STi, ST }, - { "fmulp", STi, ST }, - { "(bad)" }, + { "faddp", STi, ST, XX }, + { "fmulp", STi, ST, XX }, + { "(bad)", XX, XX, XX }, { FGRPde_3 }, - { "fsubp", STi, ST }, - { "fsubrp", STi, ST }, - { "fdivp", STi, ST }, - { "fdivrp", STi, ST }, +#if UNIXWARE_COMPAT + { "fsubp", STi, ST, XX }, + { "fsubrp", STi, ST, XX }, + { "fdivp", STi, ST, XX }, + { "fdivrp", STi, ST, XX }, +#else + { "fsubrp", STi, ST, XX }, + { "fsubp", STi, ST, XX }, + { "fdivrp", STi, ST, XX }, + { "fdivp", STi, ST, XX }, +#endif }, /* df */ { - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, + { "ffreep", STi, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, { FGRPdf_4 }, - { "fucomip",ST, STi }, - { "fcomip", ST, STi }, - { "(bad)" }, + { "fucomip",ST, STi, XX }, + { "fcomip", ST, STi, XX }, + { "(bad)", XX, XX, XX }, }, }; - static char *fgrps[][8] = { /* d9_2 0 */ { @@ -1570,79 +2504,78 @@ static char *fgrps[][8] = { }; static void -dofloat (aflag, dflag) - int aflag; - int dflag; +dofloat (sizeflag) + int sizeflag; { - struct dis386 *dp; + const struct dis386 *dp; unsigned char floatop; - + floatop = codep[-1]; - + if (mod != 3) { - putop (float_mem[(floatop - 0xd8) * 8 + reg], aflag, dflag); + putop (float_mem[(floatop - 0xd8) * 8 + reg], sizeflag); obufp = op1out; - OP_E (v_mode, aflag, dflag); + if (floatop == 0xdb) + OP_E (x_mode, sizeflag); + else if (floatop == 0xdd) + OP_E (d_mode, sizeflag); + else + OP_E (v_mode, sizeflag); return; } + /* Skip mod/rm byte. */ + MODRM_CHECK; 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"); + putop (fgrps[dp->bytemode1][rm], sizeflag); + + /* Instruction fnstsw is only one with strange arg. */ + if (floatop == 0xdf && codep[-1] == 0xe0) + strcpy (op1out, names16[0]); } else { - putop (dp->name, aflag, dflag); + putop (dp->name, sizeflag); + obufp = op1out; if (dp->op1) - (*dp->op1)(dp->bytemode1, aflag, dflag); + (*dp->op1) (dp->bytemode1, sizeflag); obufp = op2out; if (dp->op2) - (*dp->op2)(dp->bytemode2, aflag, dflag); + (*dp->op2) (dp->bytemode2, sizeflag); } } -/* ARGSUSED */ -static int -OP_ST (ignore, aflag, dflag) - int ignore; - int aflag; - int dflag; +static void +OP_ST (bytemode, sizeflag) + int bytemode; + int sizeflag; { oappend ("%st"); - return (0); } -/* ARGSUSED */ -static int -OP_STi (ignore, aflag, dflag) - int ignore; - int aflag; - int dflag; +static void +OP_STi (bytemode, sizeflag) + int bytemode; + int sizeflag; { sprintf (scratchbuf, "%%st(%d)", rm); - oappend (scratchbuf); - return (0); + oappend (scratchbuf + intel_syntax); } - -/* capital letters in template are macros */ -static void -putop (template, aflag, dflag) - char *template; - int aflag; - int dflag; +/* Capital letters in template are macros. */ +static int +putop (template, sizeflag) + const char *template; + int sizeflag; { - char *p; - + const char *p; + int alt; + for (p = template; *p; p++) { switch (*p) @@ -1650,78 +2583,393 @@ putop (template, aflag, dflag) default: *obufp++ = *p; break; - case 'C': /* For jcxz/jecxz */ - if (aflag) - *obufp++ = 'e'; + case '{': + alt = 0; + if (intel_syntax) + alt += 1; + if (mode_64bit) + alt += 2; + while (alt != 0) + { + while (*++p != '|') + { + if (*p == '}') + { + /* Alternative not valid. */ + strcpy (obuf, "(bad)"); + obufp = obuf + 5; + return 1; + } + else if (*p == '\0') + abort (); + } + alt--; + } + break; + case '|': + while (*++p != '}') + { + if (*p == '\0') + abort (); + } + break; + case '}': + break; + case 'A': + if (intel_syntax) + break; + if (mod != 3 || (sizeflag & SUFFIX_ALWAYS)) + *obufp++ = 'b'; + break; + case 'B': + if (intel_syntax) + break; + if (sizeflag & SUFFIX_ALWAYS) + *obufp++ = 'b'; + break; + case 'E': /* For jcxz/jecxz */ + if (mode_64bit) + { + if (sizeflag & AFLAG) + *obufp++ = 'r'; + else + *obufp++ = 'e'; + } + else + if (sizeflag & AFLAG) + *obufp++ = 'e'; + used_prefixes |= (prefixes & PREFIX_ADDR); + break; + case 'F': + if (intel_syntax) + break; + if ((prefixes & PREFIX_ADDR) || (sizeflag & SUFFIX_ALWAYS)) + { + if (sizeflag & AFLAG) + *obufp++ = mode_64bit ? 'q' : 'l'; + else + *obufp++ = mode_64bit ? 'l' : 'w'; + used_prefixes |= (prefixes & PREFIX_ADDR); + } + break; + case 'H': + if (intel_syntax) + break; + if ((prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_CS + || (prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_DS) + { + used_prefixes |= prefixes & (PREFIX_CS | PREFIX_DS); + *obufp++ = ','; + *obufp++ = 'p'; + if (prefixes & PREFIX_DS) + *obufp++ = 't'; + else + *obufp++ = 'n'; + } + break; + case 'L': + if (intel_syntax) + break; + if (sizeflag & SUFFIX_ALWAYS) + *obufp++ = 'l'; break; case 'N': if ((prefixes & PREFIX_FWAIT) == 0) *obufp++ = 'n'; + else + used_prefixes |= PREFIX_FWAIT; + break; + case 'O': + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + *obufp++ = 'o'; + else + *obufp++ = 'd'; + break; + case 'T': + if (intel_syntax) + break; + if (mode_64bit) + { + *obufp++ = 'q'; + break; + } + /* Fall through. */ + case 'P': + if (intel_syntax) + break; + if ((prefixes & PREFIX_DATA) + || (rex & REX_MODE64) + || (sizeflag & SUFFIX_ALWAYS)) + { + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + *obufp++ = 'q'; + else + { + if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + used_prefixes |= (prefixes & PREFIX_DATA); + } + } + break; + case 'U': + if (intel_syntax) + break; + if (mode_64bit) + { + *obufp++ = 'q'; + break; + } + /* Fall through. */ + case 'Q': + if (intel_syntax) + break; + USED_REX (REX_MODE64); + if (mod != 3 || (sizeflag & SUFFIX_ALWAYS)) + { + if (rex & REX_MODE64) + *obufp++ = 'q'; + else + { + if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + used_prefixes |= (prefixes & PREFIX_DATA); + } + } + break; + case 'R': + USED_REX (REX_MODE64); + if (intel_syntax) + { + if (rex & REX_MODE64) + { + *obufp++ = 'q'; + *obufp++ = 't'; + } + else if (sizeflag & DFLAG) + { + *obufp++ = 'd'; + *obufp++ = 'q'; + } + else + { + *obufp++ = 'w'; + *obufp++ = 'd'; + } + } + else + { + if (rex & REX_MODE64) + *obufp++ = 'q'; + else if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + } + if (!(rex & REX_MODE64)) + used_prefixes |= (prefixes & PREFIX_DATA); break; case 'S': - /* operand size flag */ - if (dflag) - *obufp++ = 'l'; - else - *obufp++ = 'w'; + if (intel_syntax) + break; + if (sizeflag & SUFFIX_ALWAYS) + { + if (rex & REX_MODE64) + *obufp++ = 'q'; + else + { + if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + used_prefixes |= (prefixes & PREFIX_DATA); + } + } break; + case 'X': + if (prefixes & PREFIX_DATA) + *obufp++ = 'd'; + else + *obufp++ = 's'; + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case 'Y': + if (intel_syntax) + break; + if (rex & REX_MODE64) + { + USED_REX (REX_MODE64); + *obufp++ = 'q'; + } + break; + /* implicit operand size 'l' for i386 or 'q' for x86-64 */ case 'W': /* operand size flag for cwtl, cbtw */ - if (dflag) + USED_REX (0); + if (rex) + *obufp++ = 'l'; + else if (sizeflag & DFLAG) *obufp++ = 'w'; else *obufp++ = 'b'; + if (intel_syntax) + { + if (rex) + { + *obufp++ = 'q'; + *obufp++ = 'e'; + } + if (sizeflag & DFLAG) + { + *obufp++ = 'd'; + *obufp++ = 'e'; + } + else + { + *obufp++ = 'w'; + } + } + if (!rex) + used_prefixes |= (prefixes & PREFIX_DATA); break; } } *obufp = 0; + return 0; } static void oappend (s) - char *s; + const char *s; { strcpy (obufp, s); obufp += strlen (s); - *obufp = 0; } static void -append_prefix () +append_seg () { if (prefixes & PREFIX_CS) - oappend ("%cs:"); + { + used_prefixes |= PREFIX_CS; + oappend ("%cs:" + intel_syntax); + } if (prefixes & PREFIX_DS) - oappend ("%ds:"); + { + used_prefixes |= PREFIX_DS; + oappend ("%ds:" + intel_syntax); + } if (prefixes & PREFIX_SS) - oappend ("%ss:"); + { + used_prefixes |= PREFIX_SS; + oappend ("%ss:" + intel_syntax); + } if (prefixes & PREFIX_ES) - oappend ("%es:"); + { + used_prefixes |= PREFIX_ES; + oappend ("%es:" + intel_syntax); + } if (prefixes & PREFIX_FS) - oappend ("%fs:"); + { + used_prefixes |= PREFIX_FS; + oappend ("%fs:" + intel_syntax); + } if (prefixes & PREFIX_GS) - oappend ("%gs:"); + { + used_prefixes |= PREFIX_GS; + oappend ("%gs:" + intel_syntax); + } } -static int -OP_indirE (bytemode, aflag, dflag) +static void +OP_indirE (bytemode, sizeflag) int bytemode; - int aflag; - int dflag; + int sizeflag; { - oappend ("*"); - return OP_E (bytemode, aflag, dflag); + if (!intel_syntax) + oappend ("*"); + OP_E (bytemode, sizeflag); } -static int -OP_E (bytemode, aflag, dflag) - int bytemode; - int aflag; - int dflag; +static void +print_operand_value (buf, hex, disp) + char *buf; + int hex; + bfd_vma disp; { - int disp; + if (mode_64bit) + { + if (hex) + { + char tmp[30]; + int i; + buf[0] = '0'; + buf[1] = 'x'; + sprintf_vma (tmp, disp); + for (i = 0; tmp[i] == '0' && tmp[i + 1]; i++); + strcpy (buf + 2, tmp + i); + } + else + { + bfd_signed_vma v = disp; + char tmp[30]; + int i; + if (v < 0) + { + *(buf++) = '-'; + v = -disp; + /* Check for possible overflow on 0x8000000000000000. */ + if (v < 0) + { + strcpy (buf, "9223372036854775808"); + return; + } + } + if (!v) + { + strcpy (buf, "0"); + return; + } - /* skip mod/rm byte */ + i = 0; + tmp[29] = 0; + while (v) + { + tmp[28 - i] = (v % 10) + '0'; + v /= 10; + i++; + } + strcpy (buf, tmp + 29 - i); + } + } + else + { + if (hex) + sprintf (buf, "0x%x", (unsigned int) disp); + else + sprintf (buf, "%d", (int) disp); + } +} + +static void +OP_E (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + bfd_vma disp; + int add = 0; + int riprel = 0; + USED_REX (REX_EXTZ); + if (rex & REX_EXTZ) + add += 8; + + /* Skip mod/rm byte. */ + MODRM_CHECK; codep++; if (mod == 3) @@ -1729,28 +2977,54 @@ OP_E (bytemode, aflag, dflag) switch (bytemode) { case b_mode: - oappend (names8[rm]); + USED_REX (0); + if (rex) + oappend (names8rex[rm + add]); + else + oappend (names8[rm + add]); break; case w_mode: - oappend (names16[rm]); + oappend (names16[rm + add]); + break; + case d_mode: + oappend (names32[rm + add]); + break; + case q_mode: + oappend (names64[rm + add]); + break; + case m_mode: + if (mode_64bit) + oappend (names64[rm + add]); + else + oappend (names32[rm + add]); break; case v_mode: - if (dflag) - oappend (names32[rm]); + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + oappend (names64[rm + add]); + else if (sizeflag & DFLAG) + oappend (names32[rm + add]); else - oappend (names16[rm]); + oappend (names16[rm + add]); + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case 0: + if (!(codep[-2] == 0xAE && codep[-1] == 0xF8 /* sfence */) + && !(codep[-2] == 0xAE && codep[-1] == 0xF0 /* mfence */) + && !(codep[-2] == 0xAE && codep[-1] == 0xe8 /* lfence */)) + BadOp (); /* bad sfence,lea,lds,les,lfs,lgs,lss modrm */ break; default: - oappend (""); + oappend (INTERNAL_DISASSEMBLER_ERROR); break; } - return 0; + return; } disp = 0; - append_prefix (); + append_seg (); - if (aflag) /* 32 bit address mode */ + if ((sizeflag & AFLAG) || mode_64bit) /* 32 bit address mode */ { int havesib; int havebase; @@ -1769,16 +3043,24 @@ OP_E (bytemode, aflag, dflag) scale = (*codep >> 6) & 3; index = (*codep >> 3) & 7; base = *codep & 7; + USED_REX (REX_EXTY); + USED_REX (REX_EXTZ); + if (rex & REX_EXTY) + index += 8; + if (rex & REX_EXTZ) + base += 8; codep++; } switch (mod) { case 0: - if (base == 5) + if ((base & 7) == 5) { havebase = 0; - disp = get32 (); + if (mode_64bit && !havesib && (sizeflag & AFLAG)) + riprel = 1; + disp = get32s (); } break; case 1: @@ -1788,40 +3070,139 @@ OP_E (bytemode, aflag, dflag) disp -= 0x100; break; case 2: - disp = get32 (); + disp = get32s (); break; } - if (mod != 0 || base == 5) - { - sprintf (scratchbuf, "0x%x", disp); - oappend (scratchbuf); - } + if (!intel_syntax) + if (mod != 0 || (base & 7) == 5) + { + print_operand_value (scratchbuf, !riprel, disp); + oappend (scratchbuf); + if (riprel) + { + set_op (disp, 1); + oappend ("(%rip)"); + } + } if (havebase || (havesib && (index != 4 || scale != 0))) { - oappend ("("); + if (intel_syntax) + { + switch (bytemode) + { + case b_mode: + oappend ("BYTE PTR "); + break; + case w_mode: + oappend ("WORD PTR "); + break; + case v_mode: + oappend ("DWORD PTR "); + break; + case d_mode: + oappend ("QWORD PTR "); + break; + case m_mode: + if (mode_64bit) + oappend ("DWORD PTR "); + else + oappend ("QWORD PTR "); + break; + case x_mode: + oappend ("XWORD PTR "); + break; + default: + break; + } + } + *obufp++ = open_char; + if (intel_syntax && riprel) + oappend ("rip + "); + *obufp = '\0'; + USED_REX (REX_EXTZ); + if (!havesib && (rex & REX_EXTZ)) + base += 8; if (havebase) - oappend (names32[base]); + oappend (mode_64bit && (sizeflag & AFLAG) + ? names64[base] : names32[base]); if (havesib) { if (index != 4) { - sprintf (scratchbuf, ",%s", names32[index]); + if (intel_syntax) + { + if (havebase) + { + *obufp++ = separator_char; + *obufp = '\0'; + } + sprintf (scratchbuf, "%s", + mode_64bit && (sizeflag & AFLAG) + ? names64[index] : names32[index]); + } + else + sprintf (scratchbuf, ",%s", + mode_64bit && (sizeflag & AFLAG) + ? names64[index] : names32[index]); oappend (scratchbuf); } - sprintf (scratchbuf, ",%d", 1 << scale); - oappend (scratchbuf); + if (!intel_syntax + || (intel_syntax + && bytemode != b_mode + && bytemode != w_mode + && bytemode != v_mode)) + { + *obufp++ = scale_char; + *obufp = '\0'; + sprintf (scratchbuf, "%d", 1 << scale); + oappend (scratchbuf); + } } - oappend (")"); + if (intel_syntax) + if (mod != 0 || (base & 7) == 5) + { + /* Don't print zero displacements. */ + if (disp != 0) + { + if ((bfd_signed_vma) disp > 0) + { + *obufp++ = '+'; + *obufp = '\0'; + } + + print_operand_value (scratchbuf, 0, disp); + oappend (scratchbuf); + } + } + + *obufp++ = close_char; + *obufp = '\0'; } + else if (intel_syntax) + { + if (mod != 0 || (base & 7) == 5) + { + if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS + | PREFIX_ES | PREFIX_FS | PREFIX_GS)) + ; + else + { + oappend (names_seg[ds_reg - es_reg]); + oappend (":"); + } + print_operand_value (scratchbuf, 1, disp); + oappend (scratchbuf); + } + } } else { /* 16 bit address mode */ switch (mod) { case 0: - if (rm == 6) + if ((rm & 7) == 6) { disp = get16 (); if ((disp & 0x8000) != 0) @@ -1841,63 +3222,119 @@ OP_E (bytemode, aflag, dflag) break; } - if (mod != 0 || rm == 6) - { - sprintf (scratchbuf, "0x%x", disp); - oappend (scratchbuf); - } + if (!intel_syntax) + if (mod != 0 || (rm & 7) == 6) + { + print_operand_value (scratchbuf, 0, disp); + oappend (scratchbuf); + } - if (mod != 0 || rm != 6) + if (mod != 0 || (rm & 7) != 6) { - oappend ("("); - oappend (index16[rm]); - oappend (")"); + *obufp++ = open_char; + *obufp = '\0'; + oappend (index16[rm + add]); + *obufp++ = close_char; + *obufp = '\0'; } } - return 0; } -static int -OP_G (bytemode, aflag, dflag) +static void +OP_G (bytemode, sizeflag) int bytemode; - int aflag; - int dflag; + int sizeflag; { - switch (bytemode) + int add = 0; + USED_REX (REX_EXTX); + if (rex & REX_EXTX) + add += 8; + switch (bytemode) { case b_mode: - oappend (names8[reg]); + USED_REX (0); + if (rex) + oappend (names8rex[reg + add]); + else + oappend (names8[reg + add]); break; case w_mode: - oappend (names16[reg]); + oappend (names16[reg + add]); break; case d_mode: - oappend (names32[reg]); + oappend (names32[reg + add]); + break; + case q_mode: + oappend (names64[reg + add]); break; case v_mode: - if (dflag) - oappend (names32[reg]); + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + oappend (names64[reg + add]); + else if (sizeflag & DFLAG) + oappend (names32[reg + add]); else - oappend (names16[reg]); + oappend (names16[reg + add]); + used_prefixes |= (prefixes & PREFIX_DATA); break; default: - oappend (""); + oappend (INTERNAL_DISASSEMBLER_ERROR); break; } - return (0); } -static int +static bfd_vma +get64 () +{ + bfd_vma x; +#ifdef BFD64 + unsigned int a; + unsigned int b; + + FETCH_DATA (the_info, codep + 8); + a = *codep++ & 0xff; + a |= (*codep++ & 0xff) << 8; + a |= (*codep++ & 0xff) << 16; + a |= (*codep++ & 0xff) << 24; + b = *codep++ & 0xff; + b |= (*codep++ & 0xff) << 8; + b |= (*codep++ & 0xff) << 16; + b |= (*codep++ & 0xff) << 24; + x = a + ((bfd_vma) b << 32); +#else + abort (); + x = 0; +#endif + return x; +} + +static bfd_signed_vma get32 () { - int x = 0; + bfd_signed_vma 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); + x = *codep++ & (bfd_signed_vma) 0xff; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 8; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 16; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 24; + return x; +} + +static bfd_signed_vma +get32s () +{ + bfd_signed_vma x = 0; + + FETCH_DATA (the_info, codep + 4); + x = *codep++ & (bfd_signed_vma) 0xff; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 8; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 16; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 24; + + x = (x ^ ((bfd_signed_vma) 1 << 31)) - ((bfd_signed_vma) 1 << 31); + + return x; } static int @@ -1908,137 +3345,306 @@ get16 () FETCH_DATA (the_info, codep + 2); x = *codep++ & 0xff; x |= (*codep++ & 0xff) << 8; - return (x); + return x; } static void -set_op (op) - int op; +set_op (op, riprel) + bfd_vma op; + int riprel; { op_index[op_ad] = op_ad; - op_address[op_ad] = op; + if (mode_64bit) + { + op_address[op_ad] = op; + op_riprel[op_ad] = riprel; + } + else + { + /* Mask to get a 32-bit address. */ + op_address[op_ad] = op & 0xffffffff; + op_riprel[op_ad] = riprel & 0xffffffff; + } } -static int -OP_REG (code, aflag, dflag) +static void +OP_REG (code, sizeflag) int code; - int aflag; - int dflag; + int sizeflag; { - char *s; - - switch (code) + const char *s; + int add = 0; + USED_REX (REX_EXTZ); + if (rex & REX_EXTZ) + add = 8; + + 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]; + case indir_dx_reg: + if (intel_syntax) + s = "[dx]"; else - s = names16[code - eAX_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 + add]; + 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 + add]; + 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: + USED_REX (0); + if (rex) + s = names8rex[code - al_reg + add]; + else + s = names8[code - al_reg]; + break; + case rAX_reg: case rCX_reg: case rDX_reg: case rBX_reg: + case rSP_reg: case rBP_reg: case rSI_reg: case rDI_reg: + if (mode_64bit) + { + s = names64[code - rAX_reg + add]; + break; + } + code += eAX_reg - rAX_reg; + /* Fall through. */ + case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: + case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + s = names64[code - eAX_reg + add]; + else if (sizeflag & DFLAG) + s = names32[code - eAX_reg + add]; + else + s = names16[code - eAX_reg + add]; + used_prefixes |= (prefixes & PREFIX_DATA); break; default: - s = ""; + s = INTERNAL_DISASSEMBLER_ERROR; break; } oappend (s); - return (0); } -static int -OP_I (bytemode, aflag, dflag) - int bytemode; - int aflag; - int dflag; +static void +OP_IMREG (code, sizeflag) + int code; + int sizeflag; { - int op; - - switch (bytemode) + const char *s; + + switch (code) + { + case indir_dx_reg: + if (intel_syntax) + s = "[dx]"; + else + 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: + USED_REX (0); + if (rex) + s = names8rex[code - al_reg]; + else + 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: + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + s = names64[code - eAX_reg]; + else if (sizeflag & DFLAG) + s = names32[code - eAX_reg]; + else + s = names16[code - eAX_reg]; + used_prefixes |= (prefixes & PREFIX_DATA); + break; + default: + s = INTERNAL_DISASSEMBLER_ERROR; + break; + } + oappend (s); +} + +static void +OP_I (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + bfd_signed_vma op; + bfd_signed_vma mask = -1; + + switch (bytemode) { case b_mode: FETCH_DATA (the_info, codep + 1); - op = *codep++ & 0xff; + op = *codep++; + mask = 0xff; break; + case q_mode: + if (mode_64bit) + { + op = get32s (); + break; + } + /* Fall through. */ case v_mode: - if (dflag) - op = get32 (); + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + op = get32s (); + else if (sizeflag & DFLAG) + { + op = get32 (); + mask = 0xffffffff; + } else - op = get16 (); + { + op = get16 (); + mask = 0xfffff; + } + used_prefixes |= (prefixes & PREFIX_DATA); break; case w_mode: + mask = 0xfffff; op = get16 (); break; default: - oappend (""); - return (0); + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; } - sprintf (scratchbuf, "$0x%x", op); - oappend (scratchbuf); - return (0); + + op &= mask; + scratchbuf[0] = '$'; + print_operand_value (scratchbuf + 1, 1, op); + oappend (scratchbuf + intel_syntax); + scratchbuf[0] = '\0'; } -static int -OP_sI (bytemode, aflag, dflag) +static void +OP_I64 (bytemode, sizeflag) int bytemode; - int aflag; - int dflag; + int sizeflag; { - int op; - - switch (bytemode) + bfd_signed_vma op; + bfd_signed_vma mask = -1; + + if (!mode_64bit) + { + OP_I (bytemode, sizeflag); + return; + } + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *codep++; + mask = 0xff; + break; + case v_mode: + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + op = get64 (); + else if (sizeflag & DFLAG) + { + op = get32 (); + mask = 0xffffffff; + } + else + { + op = get16 (); + mask = 0xfffff; + } + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case w_mode: + mask = 0xfffff; + op = get16 (); + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; + } + + op &= mask; + scratchbuf[0] = '$'; + print_operand_value (scratchbuf + 1, 1, op); + oappend (scratchbuf + intel_syntax); + scratchbuf[0] = '\0'; +} + +static void +OP_sI (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + bfd_signed_vma op; + bfd_signed_vma mask = -1; + + switch (bytemode) { case b_mode: FETCH_DATA (the_info, codep + 1); op = *codep++; if ((op & 0x80) != 0) op -= 0x100; + mask = 0xffffffff; break; case v_mode: - if (dflag) - op = get32 (); + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + op = get32s (); + else if (sizeflag & DFLAG) + { + op = get32s (); + mask = 0xffffffff; + } else { - op = get16(); + mask = 0xffffffff; + op = get16 (); if ((op & 0x8000) != 0) op -= 0x10000; } + used_prefixes |= (prefixes & PREFIX_DATA); break; case w_mode: op = get16 (); + mask = 0xffffffff; if ((op & 0x8000) != 0) op -= 0x10000; break; default: - oappend (""); - return (0); + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; } - sprintf (scratchbuf, "$0x%x", op); - oappend (scratchbuf); - return (0); + + scratchbuf[0] = '$'; + print_operand_value (scratchbuf + 1, 1, op); + oappend (scratchbuf + intel_syntax); } -static int -OP_J (bytemode, aflag, dflag) +static void +OP_J (bytemode, sizeflag) int bytemode; - int aflag; - int dflag; + int sizeflag; { - int disp; - int mask = -1; - - switch (bytemode) + bfd_vma disp; + bfd_vma mask = -1; + + switch (bytemode) { case b_mode: FETCH_DATA (the_info, codep + 1); @@ -2047,131 +3653,160 @@ OP_J (bytemode, aflag, dflag) disp -= 0x100; break; case v_mode: - if (dflag) - disp = get32 (); + if (sizeflag & DFLAG) + disp = get32s (); else { disp = get16 (); - if ((disp & 0x8000) != 0) - disp -= 0x10000; - /* for some reason, a data16 prefix on a jump instruction + /* 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 (""); - return (0); + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; } disp = (start_pc + codep - start_codep + disp) & mask; - set_op (disp); - sprintf (scratchbuf, "0x%x", disp); + set_op (disp, 0); + print_operand_value (scratchbuf, 1, disp); oappend (scratchbuf); - return (0); } -/* ARGSUSED */ -static int -OP_SEG (dummy, aflag, dflag) +static void +OP_SEG (dummy, sizeflag) int dummy; - int aflag; - int dflag; + int sizeflag; { - static char *sreg[] = { - "%es","%cs","%ss","%ds","%fs","%gs","%?","%?", - }; - - oappend (sreg[reg]); - return (0); + oappend (names_seg[reg]); } -static int -OP_DIR (size, aflag, dflag) - int size; - int aflag; - int dflag; +static void +OP_DIR (dummy, sizeflag) + int dummy; + int sizeflag; { int seg, offset; - - switch (size) + + if (sizeflag & DFLAG) { - 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 (""); - break; + offset = get32 (); + seg = get16 (); } - return (0); + else + { + offset = get16 (); + seg = get16 (); + } + used_prefixes |= (prefixes & PREFIX_DATA); + if (intel_syntax) + sprintf (scratchbuf, "0x%x,0x%x", seg, offset); + else + sprintf (scratchbuf, "$0x%x,$0x%x", seg, offset); + oappend (scratchbuf); } -/* ARGSUSED */ -static int -OP_OFF (bytemode, aflag, dflag) +static void +OP_OFF (bytemode, sizeflag) int bytemode; - int aflag; - int dflag; + int sizeflag; { - int off; + bfd_vma off; - append_prefix (); + append_seg (); - if (aflag) + if ((sizeflag & AFLAG) || mode_64bit) off = get32 (); else off = get16 (); - - sprintf (scratchbuf, "0x%x", off); + + if (intel_syntax) + { + if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS + | PREFIX_ES | PREFIX_FS | PREFIX_GS))) + { + oappend (names_seg[ds_reg - es_reg]); + oappend (":"); + } + } + print_operand_value (scratchbuf, 1, off); oappend (scratchbuf); - return (0); } -/* ARGSUSED */ -static int -OP_ESDI (dummy, aflag, dflag) - int dummy; - int aflag; - int dflag; +static void +OP_OFF64 (bytemode, sizeflag) + int bytemode; + int sizeflag; { - oappend ("%es:("); - oappend (aflag ? "%edi" : "%di"); - oappend (")"); - return (0); + bfd_vma off; + + if (!mode_64bit) + { + OP_OFF (bytemode, sizeflag); + return; + } + + append_seg (); + + off = get64 (); + + if (intel_syntax) + { + if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS + | PREFIX_ES | PREFIX_FS | PREFIX_GS))) + { + oappend (names_seg[ds_reg - es_reg]); + oappend (":"); + } + } + print_operand_value (scratchbuf, 1, off); + oappend (scratchbuf); } -/* ARGSUSED */ -static int -OP_DSSI (dummy, aflag, dflag) - int dummy; - int aflag; - int dflag; +static void +ptr_reg (code, sizeflag) + int code; + int sizeflag; +{ + const char *s; + if (intel_syntax) + oappend ("["); + else + oappend ("("); + + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + { + if (!(sizeflag & AFLAG)) + s = names32[code - eAX_reg]; + else + s = names64[code - eAX_reg]; + } + else if (sizeflag & AFLAG) + s = names32[code - eAX_reg]; + else + s = names16[code - eAX_reg]; + oappend (s); + if (intel_syntax) + oappend ("]"); + else + oappend (")"); +} + +static void +OP_ESreg (code, sizeflag) + int code; + int sizeflag; +{ + oappend ("%es:" + intel_syntax); + ptr_reg (code, sizeflag); +} + +static void +OP_DSreg (code, sizeflag) + int code; + int sizeflag; { if ((prefixes & (PREFIX_CS @@ -2181,120 +3816,328 @@ OP_DSSI (dummy, aflag, dflag) | PREFIX_FS | PREFIX_GS)) == 0) prefixes |= PREFIX_DS; - append_prefix (); - oappend ("("); - oappend (aflag ? "%esi" : "%si"); - oappend (")"); - return (0); + append_seg (); + ptr_reg (code, sizeflag); } -#if 0 -/* Not used. */ - -/* ARGSUSED */ -static int -OP_ONE (dummy, aflag, dflag) +static void +OP_C (dummy, sizeflag) int dummy; - int aflag; - int dflag; + int sizeflag; { - oappend ("1"); - return (0); + int add = 0; + USED_REX (REX_EXTX); + if (rex & REX_EXTX) + add = 8; + sprintf (scratchbuf, "%%cr%d", reg + add); + oappend (scratchbuf + intel_syntax); } -#endif - -/* ARGSUSED */ -static int -OP_C (dummy, aflag, dflag) +static void +OP_D (dummy, sizeflag) int dummy; - int aflag; - int dflag; + int sizeflag; { - codep++; /* skip mod/rm */ - sprintf (scratchbuf, "%%cr%d", reg); + int add = 0; + USED_REX (REX_EXTX); + if (rex & REX_EXTX) + add = 8; + if (intel_syntax) + sprintf (scratchbuf, "db%d", reg + add); + else + sprintf (scratchbuf, "%%db%d", reg + add); oappend (scratchbuf); - return (0); } -/* ARGSUSED */ -static int -OP_D (dummy, aflag, dflag) +static void +OP_T (dummy, sizeflag) int dummy; - int aflag; - int dflag; + int sizeflag; { - 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); + oappend (scratchbuf + intel_syntax); } -static int -OP_rm (bytemode, aflag, dflag) +static void +OP_Rd (bytemode, sizeflag) int bytemode; - int aflag; - int dflag; + int sizeflag; { - switch (bytemode) - { - case d_mode: - oappend (names32[rm]); - break; - case w_mode: - oappend (names16[rm]); - break; - } - return (0); + if (mod == 3) + OP_E (bytemode, sizeflag); + else + BadOp (); } -static int -OP_MMX (bytemode, aflag, dflag) +static void +OP_MMX (bytemode, sizeflag) int bytemode; - int aflag; - int dflag; + int sizeflag; { - sprintf (scratchbuf, "%%mm%d", reg); - oappend (scratchbuf); - return 0; + int add = 0; + USED_REX (REX_EXTX); + if (rex & REX_EXTX) + add = 8; + used_prefixes |= (prefixes & PREFIX_DATA); + if (prefixes & PREFIX_DATA) + sprintf (scratchbuf, "%%xmm%d", reg + add); + else + sprintf (scratchbuf, "%%mm%d", reg + add); + oappend (scratchbuf + intel_syntax); } -static int -OP_EM (bytemode, aflag, dflag) +static void +OP_XMM (bytemode, sizeflag) int bytemode; - int aflag; - int dflag; + int sizeflag; { + int add = 0; + USED_REX (REX_EXTX); + if (rex & REX_EXTX) + add = 8; + sprintf (scratchbuf, "%%xmm%d", reg + add); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_EM (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + int add = 0; if (mod != 3) - return OP_E (bytemode, aflag, dflag); + { + OP_E (bytemode, sizeflag); + return; + } + USED_REX (REX_EXTZ); + if (rex & REX_EXTZ) + add = 8; + /* Skip mod/rm byte. */ + MODRM_CHECK; codep++; - sprintf (scratchbuf, "%%mm%d", rm); - oappend (scratchbuf); - return 0; + used_prefixes |= (prefixes & PREFIX_DATA); + if (prefixes & PREFIX_DATA) + sprintf (scratchbuf, "%%xmm%d", rm + add); + else + sprintf (scratchbuf, "%%mm%d", rm + add); + oappend (scratchbuf + intel_syntax); } -static int -OP_MS (bytemode, aflag, dflag) +static void +OP_EX (bytemode, sizeflag) int bytemode; - int aflag; - int dflag; + int sizeflag; { - ++codep; - sprintf (scratchbuf, "%%mm%d", rm); - oappend (scratchbuf); - return 0; + int add = 0; + if (mod != 3) + { + OP_E (bytemode, sizeflag); + return; + } + USED_REX (REX_EXTZ); + if (rex & REX_EXTZ) + add = 8; + + /* Skip mod/rm byte. */ + MODRM_CHECK; + codep++; + sprintf (scratchbuf, "%%xmm%d", rm + add); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_MS (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + if (mod == 3) + OP_EM (bytemode, sizeflag); + else + BadOp (); +} + +static void +OP_XS (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + if (mod == 3) + OP_EX (bytemode, sizeflag); + else + BadOp (); +} + +static const char *Suffix3DNow[] = { +/* 00 */ NULL, NULL, NULL, NULL, +/* 04 */ NULL, NULL, NULL, NULL, +/* 08 */ NULL, NULL, NULL, NULL, +/* 0C */ "pi2fw", "pi2fd", NULL, NULL, +/* 10 */ NULL, NULL, NULL, NULL, +/* 14 */ NULL, NULL, NULL, NULL, +/* 18 */ NULL, NULL, NULL, NULL, +/* 1C */ "pf2iw", "pf2id", NULL, NULL, +/* 20 */ NULL, NULL, NULL, NULL, +/* 24 */ NULL, NULL, NULL, NULL, +/* 28 */ NULL, NULL, NULL, NULL, +/* 2C */ NULL, NULL, NULL, NULL, +/* 30 */ NULL, NULL, NULL, NULL, +/* 34 */ NULL, NULL, NULL, NULL, +/* 38 */ NULL, NULL, NULL, NULL, +/* 3C */ NULL, NULL, NULL, NULL, +/* 40 */ NULL, NULL, NULL, NULL, +/* 44 */ NULL, NULL, NULL, NULL, +/* 48 */ NULL, NULL, NULL, NULL, +/* 4C */ NULL, NULL, NULL, NULL, +/* 50 */ NULL, NULL, NULL, NULL, +/* 54 */ NULL, NULL, NULL, NULL, +/* 58 */ NULL, NULL, NULL, NULL, +/* 5C */ NULL, NULL, NULL, NULL, +/* 60 */ NULL, NULL, NULL, NULL, +/* 64 */ NULL, NULL, NULL, NULL, +/* 68 */ NULL, NULL, NULL, NULL, +/* 6C */ NULL, NULL, NULL, NULL, +/* 70 */ NULL, NULL, NULL, NULL, +/* 74 */ NULL, NULL, NULL, NULL, +/* 78 */ NULL, NULL, NULL, NULL, +/* 7C */ NULL, NULL, NULL, NULL, +/* 80 */ NULL, NULL, NULL, NULL, +/* 84 */ NULL, NULL, NULL, NULL, +/* 88 */ NULL, NULL, "pfnacc", NULL, +/* 8C */ NULL, NULL, "pfpnacc", NULL, +/* 90 */ "pfcmpge", NULL, NULL, NULL, +/* 94 */ "pfmin", NULL, "pfrcp", "pfrsqrt", +/* 98 */ NULL, NULL, "pfsub", NULL, +/* 9C */ NULL, NULL, "pfadd", NULL, +/* A0 */ "pfcmpgt", NULL, NULL, NULL, +/* A4 */ "pfmax", NULL, "pfrcpit1", "pfrsqit1", +/* A8 */ NULL, NULL, "pfsubr", NULL, +/* AC */ NULL, NULL, "pfacc", NULL, +/* B0 */ "pfcmpeq", NULL, NULL, NULL, +/* B4 */ "pfmul", NULL, "pfrcpit2", "pfmulhrw", +/* B8 */ NULL, NULL, NULL, "pswapd", +/* BC */ NULL, NULL, NULL, "pavgusb", +/* C0 */ NULL, NULL, NULL, NULL, +/* C4 */ NULL, NULL, NULL, NULL, +/* C8 */ NULL, NULL, NULL, NULL, +/* CC */ NULL, NULL, NULL, NULL, +/* D0 */ NULL, NULL, NULL, NULL, +/* D4 */ NULL, NULL, NULL, NULL, +/* D8 */ NULL, NULL, NULL, NULL, +/* DC */ NULL, NULL, NULL, NULL, +/* E0 */ NULL, NULL, NULL, NULL, +/* E4 */ NULL, NULL, NULL, NULL, +/* E8 */ NULL, NULL, NULL, NULL, +/* EC */ NULL, NULL, NULL, NULL, +/* F0 */ NULL, NULL, NULL, NULL, +/* F4 */ NULL, NULL, NULL, NULL, +/* F8 */ NULL, NULL, NULL, NULL, +/* FC */ NULL, NULL, NULL, NULL, +}; + +static void +OP_3DNowSuffix (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + const char *mnemonic; + + FETCH_DATA (the_info, codep + 1); + /* AMD 3DNow! instructions are specified by an opcode suffix in the + place where an 8-bit immediate would normally go. ie. the last + byte of the instruction. */ + obufp = obuf + strlen (obuf); + mnemonic = Suffix3DNow[*codep++ & 0xff]; + if (mnemonic) + oappend (mnemonic); + else + { + /* Since a variable sized modrm/sib chunk is between the start + of the opcode (0x0f0f) and the opcode suffix, we need to do + all the modrm processing first, and don't know until now that + we have a bad opcode. This necessitates some cleaning up. */ + op1out[0] = '\0'; + op2out[0] = '\0'; + BadOp (); + } +} + +static const char *simd_cmp_op[] = { + "eq", + "lt", + "le", + "unord", + "neq", + "nlt", + "nle", + "ord" +}; + +static void +OP_SIMD_Suffix (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + unsigned int cmp_type; + + FETCH_DATA (the_info, codep + 1); + obufp = obuf + strlen (obuf); + cmp_type = *codep++ & 0xff; + if (cmp_type < 8) + { + char suffix1 = 'p', suffix2 = 's'; + used_prefixes |= (prefixes & PREFIX_REPZ); + if (prefixes & PREFIX_REPZ) + suffix1 = 's'; + else + { + used_prefixes |= (prefixes & PREFIX_DATA); + if (prefixes & PREFIX_DATA) + suffix2 = 'd'; + else + { + used_prefixes |= (prefixes & PREFIX_REPNZ); + if (prefixes & PREFIX_REPNZ) + suffix1 = 's', suffix2 = 'd'; + } + } + sprintf (scratchbuf, "cmp%s%c%c", + simd_cmp_op[cmp_type], suffix1, suffix2); + used_prefixes |= (prefixes & PREFIX_REPZ); + oappend (scratchbuf); + } + else + { + /* We have a bad extension byte. Clean up. */ + op1out[0] = '\0'; + op2out[0] = '\0'; + BadOp (); + } +} + +static void +SIMD_Fixup (extrachar, sizeflag) + int extrachar; + int sizeflag; +{ + /* Change movlps/movhps to movhlps/movlhps for 2 register operand + forms of these instructions. */ + if (mod == 3) + { + char *p = obuf + strlen (obuf); + *(p + 1) = '\0'; + *p = *(p - 1); + *(p - 1) = *(p - 2); + *(p - 2) = *(p - 3); + *(p - 3) = extrachar; + } +} + +static void +BadOp (void) +{ + /* Throw away prefixes and 1st. opcode byte. */ + codep = insn_codep + 1; + oappend ("(bad)"); } diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 0c2fe8dc1a..4f937443e7 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -188,7 +188,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot, host_start = start & host_page_mask; if (!(flags & MAP_FIXED)) { -#if defined(__alpha__) || defined(__sparc__) +#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) /* tell the kenel to search at the same place as i386 */ if (host_start == 0) host_start = 0x40000000; diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 0abe685030..f8b48d588a 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -207,7 +207,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ #define __NR_sys_getdents64 __NR_getdents64 #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo -#if defined(__alpha__) || defined (__ia64__) +#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) #define __NR__llseek __NR_lseek #endif diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 84b202659a..1cabbe42c7 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -252,7 +252,7 @@ enum { CC_OP_NB, }; -#ifdef __i386__ +#if defined(__i386__) || defined(__x86_64__) #define USE_X86LDOUBLE #endif diff --git a/target-i386/helper.c b/target-i386/helper.c index 0c320836c5..9bd1158b06 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1802,14 +1802,14 @@ void helper_invlpg(unsigned int addr) } /* rdtsc */ -#ifndef __i386__ +#if !defined(__i386__) && !defined(__x86_64__) uint64_t emu_time; #endif void helper_rdtsc(void) { uint64_t val; -#ifdef __i386__ +#if defined(__i386__) || defined(__x86_64__) asm("rdtsc" : "=A" (val)); #else /* better than nothing: the time increases */