nkeynes@362: /* Print i386 instructions for GDB, the GNU debugger. nkeynes@362: Copyright 1988, 1989, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, nkeynes@362: 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. nkeynes@362: nkeynes@362: This file is part of GDB. nkeynes@362: nkeynes@362: This program is free software; you can redistribute it and/or modify nkeynes@362: it under the terms of the GNU General Public License as published by nkeynes@362: the Free Software Foundation; either version 2 of the License, or nkeynes@362: (at your option) any later version. nkeynes@362: nkeynes@362: This program is distributed in the hope that it will be useful, nkeynes@362: but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@362: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@362: GNU General Public License for more details. nkeynes@362: nkeynes@362: You should have received a copy of the GNU General Public License nkeynes@362: along with this program; if not, write to the Free Software nkeynes@362: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ nkeynes@362: nkeynes@362: /* 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu) nkeynes@362: July 1988 nkeynes@362: modified by John Hassey (hassey@dg-rtp.dg.com) nkeynes@362: x86-64 support added by Jan Hubicka (jh@suse.cz) nkeynes@362: VIA PadLock support by Michal Ludvig (mludvig@suse.cz). */ nkeynes@362: nkeynes@362: /* The main tables describing the instructions is essentially a copy nkeynes@362: of the "Opcode Map" chapter (Appendix A) of the Intel 80386 nkeynes@362: Programmers Manual. Usually, there is a capital letter, followed nkeynes@362: by a small letter. The capital letter tell the addressing mode, nkeynes@362: and the small letter tells about the operand size. Refer to nkeynes@362: the Intel manual for details. */ nkeynes@362: nkeynes@1264: #include "xlat/disasm/dis-asm.h" nkeynes@1264: #include "xlat/disasm/sysdep.h" nkeynes@1263: #include "xlat/xlatdasm.h" nkeynes@755: #include "gettext.h" nkeynes@362: nkeynes@362: #define MAXLEN 20 nkeynes@362: nkeynes@362: #include nkeynes@362: nkeynes@362: #ifndef UNIXWARE_COMPAT nkeynes@362: /* Set non-zero for broken, compatible instructions. Set to zero for nkeynes@362: non-broken opcodes. */ nkeynes@362: #define UNIXWARE_COMPAT 1 nkeynes@362: #endif nkeynes@362: nkeynes@362: static int fetch_data (struct disassemble_info *, bfd_byte *); nkeynes@362: static void ckprefix (void); nkeynes@362: static const char *prefix_name (int, int); nkeynes@362: static int print_insn (bfd_vma, disassemble_info *); nkeynes@362: static void dofloat (int); nkeynes@362: static void OP_ST (int, int); nkeynes@362: static void OP_STi (int, int); nkeynes@362: static int putop (const char *, int); nkeynes@362: static void oappend (const char *); nkeynes@362: static void append_seg (void); nkeynes@362: static void OP_indirE (int, int); nkeynes@362: static void OP_E (int, int); nkeynes@362: static void OP_G (int, int); nkeynes@362: static bfd_vma get64 (void); nkeynes@362: static bfd_signed_vma get32 (void); nkeynes@362: static bfd_signed_vma get32s (void); nkeynes@362: static int get16 (void); nkeynes@362: static void set_op (bfd_vma, int); nkeynes@362: static void OP_REG (int, int); nkeynes@362: static void OP_IMREG (int, int); nkeynes@362: static void OP_I (int, int); nkeynes@362: static void OP_I64 (int, int); nkeynes@362: static void OP_sI (int, int); nkeynes@362: static void OP_J (int, int); nkeynes@362: static void OP_SEG (int, int); nkeynes@362: static void OP_DIR (int, int); nkeynes@362: static void OP_OFF (int, int); nkeynes@362: static void OP_OFF64 (int, int); nkeynes@362: static void ptr_reg (int, int); nkeynes@362: static void OP_ESreg (int, int); nkeynes@362: static void OP_DSreg (int, int); nkeynes@362: static void OP_C (int, int); nkeynes@362: static void OP_D (int, int); nkeynes@362: static void OP_T (int, int); nkeynes@362: static void OP_Rd (int, int); nkeynes@362: static void OP_MMX (int, int); nkeynes@362: static void OP_XMM (int, int); nkeynes@362: static void OP_EM (int, int); nkeynes@362: static void OP_EX (int, int); nkeynes@362: static void OP_MS (int, int); nkeynes@362: static void OP_XS (int, int); nkeynes@362: static void OP_M (int, int); nkeynes@362: static void OP_0fae (int, int); nkeynes@362: static void OP_0f07 (int, int); nkeynes@362: static void NOP_Fixup (int, int); nkeynes@362: static void OP_3DNowSuffix (int, int); nkeynes@362: static void OP_SIMD_Suffix (int, int); nkeynes@362: static void SIMD_Fixup (int, int); nkeynes@362: static void PNI_Fixup (int, int); nkeynes@362: static void INVLPG_Fixup (int, int); nkeynes@362: static void BadOp (void); nkeynes@362: nkeynes@362: struct dis_private { nkeynes@362: /* Points to first byte not fetched. */ nkeynes@362: bfd_byte *max_fetched; nkeynes@362: bfd_byte the_buffer[MAXLEN]; nkeynes@362: bfd_vma insn_start; nkeynes@362: int orig_sizeflag; nkeynes@362: jmp_buf bailout; nkeynes@362: }; nkeynes@362: nkeynes@362: /* The opcode for the fwait instruction, which we treat as a prefix nkeynes@362: when we can. */ nkeynes@362: #define FWAIT_OPCODE (0x9b) nkeynes@362: nkeynes@362: /* Set to 1 for 64bit mode disassembly. */ nkeynes@362: static int mode_64bit; nkeynes@362: nkeynes@362: /* Flags for the prefixes for the current instruction. See below. */ nkeynes@362: static int prefixes; nkeynes@362: nkeynes@362: /* REX prefix the current instruction. See below. */ nkeynes@362: static int rex; nkeynes@362: /* Bits of REX we've already used. */ nkeynes@362: static int rex_used; nkeynes@362: #define REX_MODE64 8 nkeynes@362: #define REX_EXTX 4 nkeynes@362: #define REX_EXTY 2 nkeynes@362: #define REX_EXTZ 1 nkeynes@362: /* Mark parts used in the REX prefix. When we are testing for nkeynes@362: empty prefix (for 8bit register REX extension), just mask it nkeynes@362: out. Otherwise test for REX bit is excuse for existence of REX nkeynes@362: only in case value is nonzero. */ nkeynes@362: #define USED_REX(value) \ nkeynes@362: { \ nkeynes@362: if (value) \ nkeynes@362: rex_used |= (rex & value) ? (value) | 0x40 : 0; \ nkeynes@362: else \ nkeynes@362: rex_used |= 0x40; \ nkeynes@362: } nkeynes@362: nkeynes@362: /* Flags for prefixes which we somehow handled when printing the nkeynes@362: current instruction. */ nkeynes@362: static int used_prefixes; nkeynes@362: nkeynes@362: /* Flags stored in PREFIXES. */ nkeynes@362: #define PREFIX_REPZ 1 nkeynes@362: #define PREFIX_REPNZ 2 nkeynes@362: #define PREFIX_LOCK 4 nkeynes@362: #define PREFIX_CS 8 nkeynes@362: #define PREFIX_SS 0x10 nkeynes@362: #define PREFIX_DS 0x20 nkeynes@362: #define PREFIX_ES 0x40 nkeynes@362: #define PREFIX_FS 0x80 nkeynes@362: #define PREFIX_GS 0x100 nkeynes@362: #define PREFIX_DATA 0x200 nkeynes@362: #define PREFIX_ADDR 0x400 nkeynes@362: #define PREFIX_FWAIT 0x800 nkeynes@362: nkeynes@362: /* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) nkeynes@362: to ADDR (exclusive) are valid. Returns 1 for success, longjmps nkeynes@362: on error. */ nkeynes@362: #define FETCH_DATA(info, addr) \ nkeynes@362: ((addr) <= ((struct dis_private *) (info->private_data))->max_fetched \ nkeynes@362: ? 1 : fetch_data ((info), (addr))) nkeynes@362: nkeynes@362: static int nkeynes@362: fetch_data (struct disassemble_info *info, bfd_byte *addr) nkeynes@362: { nkeynes@362: int status; nkeynes@362: struct dis_private *priv = (struct dis_private *) info->private_data; nkeynes@362: bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); nkeynes@362: nkeynes@362: status = (*info->read_memory_func) (start, nkeynes@362: priv->max_fetched, nkeynes@362: addr - priv->max_fetched, nkeynes@362: info); nkeynes@362: if (status != 0) nkeynes@362: { nkeynes@362: /* If we did manage to read at least one byte, then nkeynes@362: print_insn_i386 will do something sensible. Otherwise, print nkeynes@362: an error. We do that here because this is where we know nkeynes@362: STATUS. */ nkeynes@362: if (priv->max_fetched == priv->the_buffer) nkeynes@362: (*info->memory_error_func) (status, start, info); nkeynes@362: longjmp (priv->bailout, 1); nkeynes@362: } nkeynes@362: else nkeynes@362: priv->max_fetched = addr; nkeynes@362: return 1; nkeynes@362: } nkeynes@362: nkeynes@362: #define XX NULL, 0 nkeynes@362: nkeynes@362: #define Eb OP_E, b_mode nkeynes@362: #define Ev OP_E, v_mode nkeynes@362: #define Ed OP_E, d_mode nkeynes@362: #define Eq OP_E, q_mode nkeynes@362: #define Edq OP_E, dq_mode nkeynes@362: #define Edqw OP_E, dqw_mode nkeynes@362: #define indirEv OP_indirE, v_mode nkeynes@362: #define indirEp OP_indirE, f_mode nkeynes@362: #define Ew OP_E, w_mode nkeynes@362: #define Ma OP_E, v_mode nkeynes@362: #define M OP_M, 0 /* lea, lgdt, etc. */ nkeynes@362: #define Mp OP_M, f_mode /* 32 or 48 bit memory operand for LDS, LES etc */ nkeynes@362: #define Gb OP_G, b_mode nkeynes@362: #define Gv OP_G, v_mode nkeynes@362: #define Gd OP_G, d_mode nkeynes@362: #define Gdq OP_G, dq_mode nkeynes@362: #define Gw OP_G, w_mode nkeynes@362: #define Rd OP_Rd, d_mode nkeynes@362: #define Rm OP_Rd, m_mode nkeynes@362: #define Ib OP_I, b_mode nkeynes@362: #define sIb OP_sI, b_mode /* sign extened byte */ nkeynes@362: #define Iv OP_I, v_mode nkeynes@362: #define Iq OP_I, q_mode nkeynes@362: #define Iv64 OP_I64, v_mode nkeynes@362: #define Iw OP_I, w_mode nkeynes@362: #define I1 OP_I, const_1_mode nkeynes@362: #define Jb OP_J, b_mode nkeynes@362: #define Jv OP_J, v_mode nkeynes@362: #define Cm OP_C, m_mode nkeynes@362: #define Dm OP_D, m_mode nkeynes@362: #define Td OP_T, d_mode nkeynes@362: nkeynes@362: #define RMeAX OP_REG, eAX_reg nkeynes@362: #define RMeBX OP_REG, eBX_reg nkeynes@362: #define RMeCX OP_REG, eCX_reg nkeynes@362: #define RMeDX OP_REG, eDX_reg nkeynes@362: #define RMeSP OP_REG, eSP_reg nkeynes@362: #define RMeBP OP_REG, eBP_reg nkeynes@362: #define RMeSI OP_REG, eSI_reg nkeynes@362: #define RMeDI OP_REG, eDI_reg nkeynes@362: #define RMrAX OP_REG, rAX_reg nkeynes@362: #define RMrBX OP_REG, rBX_reg nkeynes@362: #define RMrCX OP_REG, rCX_reg nkeynes@362: #define RMrDX OP_REG, rDX_reg nkeynes@362: #define RMrSP OP_REG, rSP_reg nkeynes@362: #define RMrBP OP_REG, rBP_reg nkeynes@362: #define RMrSI OP_REG, rSI_reg nkeynes@362: #define RMrDI OP_REG, rDI_reg nkeynes@362: #define RMAL OP_REG, al_reg nkeynes@362: #define RMAL OP_REG, al_reg nkeynes@362: #define RMCL OP_REG, cl_reg nkeynes@362: #define RMDL OP_REG, dl_reg nkeynes@362: #define RMBL OP_REG, bl_reg nkeynes@362: #define RMAH OP_REG, ah_reg nkeynes@362: #define RMCH OP_REG, ch_reg nkeynes@362: #define RMDH OP_REG, dh_reg nkeynes@362: #define RMBH OP_REG, bh_reg nkeynes@362: #define RMAX OP_REG, ax_reg nkeynes@362: #define RMDX OP_REG, dx_reg nkeynes@362: nkeynes@362: #define eAX OP_IMREG, eAX_reg nkeynes@362: #define eBX OP_IMREG, eBX_reg nkeynes@362: #define eCX OP_IMREG, eCX_reg nkeynes@362: #define eDX OP_IMREG, eDX_reg nkeynes@362: #define eSP OP_IMREG, eSP_reg nkeynes@362: #define eBP OP_IMREG, eBP_reg nkeynes@362: #define eSI OP_IMREG, eSI_reg nkeynes@362: #define eDI OP_IMREG, eDI_reg nkeynes@362: #define AL OP_IMREG, al_reg nkeynes@362: #define AL OP_IMREG, al_reg nkeynes@362: #define CL OP_IMREG, cl_reg nkeynes@362: #define DL OP_IMREG, dl_reg nkeynes@362: #define BL OP_IMREG, bl_reg nkeynes@362: #define AH OP_IMREG, ah_reg nkeynes@362: #define CH OP_IMREG, ch_reg nkeynes@362: #define DH OP_IMREG, dh_reg nkeynes@362: #define BH OP_IMREG, bh_reg nkeynes@362: #define AX OP_IMREG, ax_reg nkeynes@362: #define DX OP_IMREG, dx_reg nkeynes@362: #define indirDX OP_IMREG, indir_dx_reg nkeynes@362: nkeynes@362: #define Sw OP_SEG, w_mode nkeynes@362: #define Ap OP_DIR, 0 nkeynes@362: #define Ob OP_OFF, b_mode nkeynes@362: #define Ob64 OP_OFF64, b_mode nkeynes@362: #define Ov OP_OFF, v_mode nkeynes@362: #define Ov64 OP_OFF64, v_mode nkeynes@362: #define Xb OP_DSreg, eSI_reg nkeynes@362: #define Xv OP_DSreg, eSI_reg nkeynes@362: #define Yb OP_ESreg, eDI_reg nkeynes@362: #define Yv OP_ESreg, eDI_reg nkeynes@362: #define DSBX OP_DSreg, eBX_reg nkeynes@362: nkeynes@362: #define es OP_REG, es_reg nkeynes@362: #define ss OP_REG, ss_reg nkeynes@362: #define cs OP_REG, cs_reg nkeynes@362: #define ds OP_REG, ds_reg nkeynes@362: #define fs OP_REG, fs_reg nkeynes@362: #define gs OP_REG, gs_reg nkeynes@362: nkeynes@362: #define MX OP_MMX, 0 nkeynes@362: #define XM OP_XMM, 0 nkeynes@362: #define EM OP_EM, v_mode nkeynes@362: #define EX OP_EX, v_mode nkeynes@362: #define MS OP_MS, v_mode nkeynes@362: #define XS OP_XS, v_mode nkeynes@362: #define OPSUF OP_3DNowSuffix, 0 nkeynes@362: #define OPSIMD OP_SIMD_Suffix, 0 nkeynes@362: nkeynes@362: #define cond_jump_flag NULL, cond_jump_mode nkeynes@362: #define loop_jcxz_flag NULL, loop_jcxz_mode nkeynes@362: nkeynes@362: /* bits in sizeflag */ nkeynes@362: #define SUFFIX_ALWAYS 4 nkeynes@362: #define AFLAG 2 nkeynes@362: #define DFLAG 1 nkeynes@362: nkeynes@362: #define b_mode 1 /* byte operand */ nkeynes@362: #define v_mode 2 /* operand size depends on prefixes */ nkeynes@362: #define w_mode 3 /* word operand */ nkeynes@362: #define d_mode 4 /* double word operand */ nkeynes@362: #define q_mode 5 /* quad word operand */ nkeynes@362: #define t_mode 6 /* ten-byte operand */ nkeynes@362: #define x_mode 7 /* 16-byte XMM operand */ nkeynes@362: #define m_mode 8 /* d_mode in 32bit, q_mode in 64bit mode. */ nkeynes@362: #define cond_jump_mode 9 nkeynes@362: #define loop_jcxz_mode 10 nkeynes@362: #define dq_mode 11 /* operand size depends on REX prefixes. */ nkeynes@362: #define dqw_mode 12 /* registers like dq_mode, memory like w_mode. */ nkeynes@362: #define f_mode 13 /* 4- or 6-byte pointer operand */ nkeynes@362: #define const_1_mode 14 nkeynes@362: nkeynes@362: #define es_reg 100 nkeynes@362: #define cs_reg 101 nkeynes@362: #define ss_reg 102 nkeynes@362: #define ds_reg 103 nkeynes@362: #define fs_reg 104 nkeynes@362: #define gs_reg 105 nkeynes@362: nkeynes@362: #define eAX_reg 108 nkeynes@362: #define eCX_reg 109 nkeynes@362: #define eDX_reg 110 nkeynes@362: #define eBX_reg 111 nkeynes@362: #define eSP_reg 112 nkeynes@362: #define eBP_reg 113 nkeynes@362: #define eSI_reg 114 nkeynes@362: #define eDI_reg 115 nkeynes@362: nkeynes@362: #define al_reg 116 nkeynes@362: #define cl_reg 117 nkeynes@362: #define dl_reg 118 nkeynes@362: #define bl_reg 119 nkeynes@362: #define ah_reg 120 nkeynes@362: #define ch_reg 121 nkeynes@362: #define dh_reg 122 nkeynes@362: #define bh_reg 123 nkeynes@362: nkeynes@362: #define ax_reg 124 nkeynes@362: #define cx_reg 125 nkeynes@362: #define dx_reg 126 nkeynes@362: #define bx_reg 127 nkeynes@362: #define sp_reg 128 nkeynes@362: #define bp_reg 129 nkeynes@362: #define si_reg 130 nkeynes@362: #define di_reg 131 nkeynes@362: nkeynes@362: #define rAX_reg 132 nkeynes@362: #define rCX_reg 133 nkeynes@362: #define rDX_reg 134 nkeynes@362: #define rBX_reg 135 nkeynes@362: #define rSP_reg 136 nkeynes@362: #define rBP_reg 137 nkeynes@362: #define rSI_reg 138 nkeynes@362: #define rDI_reg 139 nkeynes@362: nkeynes@362: #define indir_dx_reg 150 nkeynes@362: nkeynes@362: #define FLOATCODE 1 nkeynes@362: #define USE_GROUPS 2 nkeynes@362: #define USE_PREFIX_USER_TABLE 3 nkeynes@362: #define X86_64_SPECIAL 4 nkeynes@362: nkeynes@362: #define FLOAT NULL, NULL, FLOATCODE, NULL, 0, NULL, 0 nkeynes@362: nkeynes@362: #define GRP1b NULL, NULL, USE_GROUPS, NULL, 0, NULL, 0 nkeynes@362: #define GRP1S NULL, NULL, USE_GROUPS, NULL, 1, NULL, 0 nkeynes@362: #define GRP1Ss NULL, NULL, USE_GROUPS, NULL, 2, NULL, 0 nkeynes@362: #define GRP2b NULL, NULL, USE_GROUPS, NULL, 3, NULL, 0 nkeynes@362: #define GRP2S NULL, NULL, USE_GROUPS, NULL, 4, NULL, 0 nkeynes@362: #define GRP2b_one NULL, NULL, USE_GROUPS, NULL, 5, NULL, 0 nkeynes@362: #define GRP2S_one NULL, NULL, USE_GROUPS, NULL, 6, NULL, 0 nkeynes@362: #define GRP2b_cl NULL, NULL, USE_GROUPS, NULL, 7, NULL, 0 nkeynes@362: #define GRP2S_cl NULL, NULL, USE_GROUPS, NULL, 8, NULL, 0 nkeynes@362: #define GRP3b NULL, NULL, USE_GROUPS, NULL, 9, NULL, 0 nkeynes@362: #define GRP3S NULL, NULL, USE_GROUPS, NULL, 10, NULL, 0 nkeynes@362: #define GRP4 NULL, NULL, USE_GROUPS, NULL, 11, NULL, 0 nkeynes@362: #define GRP5 NULL, NULL, USE_GROUPS, NULL, 12, NULL, 0 nkeynes@362: #define GRP6 NULL, NULL, USE_GROUPS, NULL, 13, NULL, 0 nkeynes@362: #define GRP7 NULL, NULL, USE_GROUPS, NULL, 14, NULL, 0 nkeynes@362: #define GRP8 NULL, NULL, USE_GROUPS, NULL, 15, NULL, 0 nkeynes@362: #define GRP9 NULL, NULL, USE_GROUPS, NULL, 16, NULL, 0 nkeynes@362: #define GRP10 NULL, NULL, USE_GROUPS, NULL, 17, NULL, 0 nkeynes@362: #define GRP11 NULL, NULL, USE_GROUPS, NULL, 18, NULL, 0 nkeynes@362: #define GRP12 NULL, NULL, USE_GROUPS, NULL, 19, NULL, 0 nkeynes@362: #define GRP13 NULL, NULL, USE_GROUPS, NULL, 20, NULL, 0 nkeynes@362: #define GRP14 NULL, NULL, USE_GROUPS, NULL, 21, NULL, 0 nkeynes@362: #define GRPAMD NULL, NULL, USE_GROUPS, NULL, 22, NULL, 0 nkeynes@362: #define GRPPADLCK1 NULL, NULL, USE_GROUPS, NULL, 23, NULL, 0 nkeynes@362: #define GRPPADLCK2 NULL, NULL, USE_GROUPS, NULL, 24, NULL, 0 nkeynes@362: nkeynes@362: #define PREGRP0 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 0, NULL, 0 nkeynes@362: #define PREGRP1 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 1, NULL, 0 nkeynes@362: #define PREGRP2 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 2, NULL, 0 nkeynes@362: #define PREGRP3 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 3, NULL, 0 nkeynes@362: #define PREGRP4 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 4, NULL, 0 nkeynes@362: #define PREGRP5 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 5, NULL, 0 nkeynes@362: #define PREGRP6 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 6, NULL, 0 nkeynes@362: #define PREGRP7 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 7, NULL, 0 nkeynes@362: #define PREGRP8 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 8, NULL, 0 nkeynes@362: #define PREGRP9 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 9, NULL, 0 nkeynes@362: #define PREGRP10 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 10, NULL, 0 nkeynes@362: #define PREGRP11 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 11, NULL, 0 nkeynes@362: #define PREGRP12 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 12, NULL, 0 nkeynes@362: #define PREGRP13 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 13, NULL, 0 nkeynes@362: #define PREGRP14 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 14, NULL, 0 nkeynes@362: #define PREGRP15 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 15, NULL, 0 nkeynes@362: #define PREGRP16 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 16, NULL, 0 nkeynes@362: #define PREGRP17 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 17, NULL, 0 nkeynes@362: #define PREGRP18 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 18, NULL, 0 nkeynes@362: #define PREGRP19 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 19, NULL, 0 nkeynes@362: #define PREGRP20 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 20, NULL, 0 nkeynes@362: #define PREGRP21 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 21, NULL, 0 nkeynes@362: #define PREGRP22 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 22, NULL, 0 nkeynes@362: #define PREGRP23 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 23, NULL, 0 nkeynes@362: #define PREGRP24 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 24, NULL, 0 nkeynes@362: #define PREGRP25 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 25, NULL, 0 nkeynes@362: #define PREGRP26 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 26, NULL, 0 nkeynes@362: #define PREGRP27 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 27, NULL, 0 nkeynes@362: #define PREGRP28 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 28, NULL, 0 nkeynes@362: #define PREGRP29 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 29, NULL, 0 nkeynes@362: #define PREGRP30 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 30, NULL, 0 nkeynes@362: #define PREGRP31 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 31, NULL, 0 nkeynes@362: #define PREGRP32 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 32, NULL, 0 nkeynes@362: nkeynes@362: #define X86_64_0 NULL, NULL, X86_64_SPECIAL, NULL, 0, NULL, 0 nkeynes@362: nkeynes@362: typedef void (*op_rtn) (int bytemode, int sizeflag); nkeynes@362: nkeynes@362: struct dis386 { nkeynes@362: const char *name; nkeynes@362: op_rtn op1; nkeynes@362: int bytemode1; nkeynes@362: op_rtn op2; nkeynes@362: int bytemode2; nkeynes@362: op_rtn op3; nkeynes@362: int bytemode3; nkeynes@362: }; nkeynes@362: nkeynes@362: /* Upper case letters in the instruction names here are macros. nkeynes@362: 'A' => print 'b' if no register operands or suffix_always is true nkeynes@362: 'B' => print 'b' if suffix_always is true nkeynes@362: 'C' => print 's' or 'l' ('w' or 'd' in Intel mode) depending on operand nkeynes@362: . size prefix nkeynes@362: 'E' => print 'e' if 32-bit form of jcxz nkeynes@362: 'F' => print 'w' or 'l' depending on address size prefix (loop insns) nkeynes@362: 'H' => print ",pt" or ",pn" branch hint nkeynes@362: 'I' => honor following macro letter even in Intel mode (implemented only nkeynes@362: . for some of the macro letters) nkeynes@362: 'J' => print 'l' nkeynes@362: 'L' => print 'l' if suffix_always is true nkeynes@362: 'N' => print 'n' if instruction has no wait "prefix" nkeynes@362: 'O' => print 'd', or 'o' nkeynes@362: 'P' => print 'w', 'l' or 'q' if instruction has an operand size prefix, nkeynes@362: . or suffix_always is true. print 'q' if rex prefix is present. nkeynes@362: 'Q' => print 'w', 'l' or 'q' if no register operands or suffix_always nkeynes@362: . is true nkeynes@362: 'R' => print 'w', 'l' or 'q' ("wd" or "dq" in intel mode) nkeynes@362: 'S' => print 'w', 'l' or 'q' if suffix_always is true nkeynes@362: 'T' => print 'q' in 64bit mode and behave as 'P' otherwise nkeynes@362: 'U' => print 'q' in 64bit mode and behave as 'Q' otherwise nkeynes@362: 'W' => print 'b' or 'w' ("w" or "de" in intel mode) nkeynes@362: 'X' => print 's', 'd' depending on data16 prefix (for XMM) nkeynes@362: 'Y' => 'q' if instruction has an REX 64bit overwrite prefix nkeynes@362: nkeynes@362: Many of the above letters print nothing in Intel mode. See "putop" nkeynes@362: for the details. nkeynes@362: nkeynes@362: Braces '{' and '}', and vertical bars '|', indicate alternative nkeynes@362: mnemonic strings for AT&T, Intel, X86_64 AT&T, and X86_64 Intel nkeynes@362: modes. In cases where there are only two alternatives, the X86_64 nkeynes@362: instruction is reserved, and "(bad)" is printed. nkeynes@362: */ nkeynes@362: nkeynes@362: static const struct dis386 dis386[] = { nkeynes@362: /* 00 */ nkeynes@362: { "addB", Eb, Gb, XX }, nkeynes@362: { "addS", Ev, Gv, XX }, nkeynes@362: { "addB", Gb, Eb, XX }, nkeynes@362: { "addS", Gv, Ev, XX }, nkeynes@362: { "addB", AL, Ib, XX }, nkeynes@362: { "addS", eAX, Iv, XX }, nkeynes@362: { "push{T|}", es, XX, XX }, nkeynes@362: { "pop{T|}", es, XX, XX }, nkeynes@362: /* 08 */ nkeynes@362: { "orB", Eb, Gb, XX }, nkeynes@362: { "orS", Ev, Gv, XX }, nkeynes@362: { "orB", Gb, Eb, XX }, nkeynes@362: { "orS", Gv, Ev, XX }, nkeynes@362: { "orB", AL, Ib, XX }, nkeynes@362: { "orS", eAX, Iv, XX }, nkeynes@362: { "push{T|}", cs, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, /* 0x0f extended opcode escape */ nkeynes@362: /* 10 */ nkeynes@362: { "adcB", Eb, Gb, XX }, nkeynes@362: { "adcS", Ev, Gv, XX }, nkeynes@362: { "adcB", Gb, Eb, XX }, nkeynes@362: { "adcS", Gv, Ev, XX }, nkeynes@362: { "adcB", AL, Ib, XX }, nkeynes@362: { "adcS", eAX, Iv, XX }, nkeynes@362: { "push{T|}", ss, XX, XX }, nkeynes@362: { "popT|}", ss, XX, XX }, nkeynes@362: /* 18 */ nkeynes@362: { "sbbB", Eb, Gb, XX }, nkeynes@362: { "sbbS", Ev, Gv, XX }, nkeynes@362: { "sbbB", Gb, Eb, XX }, nkeynes@362: { "sbbS", Gv, Ev, XX }, nkeynes@362: { "sbbB", AL, Ib, XX }, nkeynes@362: { "sbbS", eAX, Iv, XX }, nkeynes@362: { "push{T|}", ds, XX, XX }, nkeynes@362: { "pop{T|}", ds, XX, XX }, nkeynes@362: /* 20 */ nkeynes@362: { "andB", Eb, Gb, XX }, nkeynes@362: { "andS", Ev, Gv, XX }, nkeynes@362: { "andB", Gb, Eb, XX }, nkeynes@362: { "andS", Gv, Ev, XX }, nkeynes@362: { "andB", AL, Ib, XX }, nkeynes@362: { "andS", eAX, Iv, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, /* SEG ES prefix */ nkeynes@362: { "daa{|}", XX, XX, XX }, nkeynes@362: /* 28 */ nkeynes@362: { "subB", Eb, Gb, XX }, nkeynes@362: { "subS", Ev, Gv, XX }, nkeynes@362: { "subB", Gb, Eb, XX }, nkeynes@362: { "subS", Gv, Ev, XX }, nkeynes@362: { "subB", AL, Ib, XX }, nkeynes@362: { "subS", eAX, Iv, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, /* SEG CS prefix */ nkeynes@362: { "das{|}", XX, XX, XX }, nkeynes@362: /* 30 */ nkeynes@362: { "xorB", Eb, Gb, XX }, nkeynes@362: { "xorS", Ev, Gv, XX }, nkeynes@362: { "xorB", Gb, Eb, XX }, nkeynes@362: { "xorS", Gv, Ev, XX }, nkeynes@362: { "xorB", AL, Ib, XX }, nkeynes@362: { "xorS", eAX, Iv, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, /* SEG SS prefix */ nkeynes@362: { "aaa{|}", XX, XX, XX }, nkeynes@362: /* 38 */ nkeynes@362: { "cmpB", Eb, Gb, XX }, nkeynes@362: { "cmpS", Ev, Gv, XX }, nkeynes@362: { "cmpB", Gb, Eb, XX }, nkeynes@362: { "cmpS", Gv, Ev, XX }, nkeynes@362: { "cmpB", AL, Ib, XX }, nkeynes@362: { "cmpS", eAX, Iv, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, /* SEG DS prefix */ nkeynes@362: { "aas{|}", XX, XX, XX }, nkeynes@362: /* 40 */ nkeynes@362: { "inc{S|}", RMeAX, XX, XX }, nkeynes@362: { "inc{S|}", RMeCX, XX, XX }, nkeynes@362: { "inc{S|}", RMeDX, XX, XX }, nkeynes@362: { "inc{S|}", RMeBX, XX, XX }, nkeynes@362: { "inc{S|}", RMeSP, XX, XX }, nkeynes@362: { "inc{S|}", RMeBP, XX, XX }, nkeynes@362: { "inc{S|}", RMeSI, XX, XX }, nkeynes@362: { "inc{S|}", RMeDI, XX, XX }, nkeynes@362: /* 48 */ nkeynes@362: { "dec{S|}", RMeAX, XX, XX }, nkeynes@362: { "dec{S|}", RMeCX, XX, XX }, nkeynes@362: { "dec{S|}", RMeDX, XX, XX }, nkeynes@362: { "dec{S|}", RMeBX, XX, XX }, nkeynes@362: { "dec{S|}", RMeSP, XX, XX }, nkeynes@362: { "dec{S|}", RMeBP, XX, XX }, nkeynes@362: { "dec{S|}", RMeSI, XX, XX }, nkeynes@362: { "dec{S|}", RMeDI, XX, XX }, nkeynes@362: /* 50 */ nkeynes@362: { "pushS", RMrAX, XX, XX }, nkeynes@362: { "pushS", RMrCX, XX, XX }, nkeynes@362: { "pushS", RMrDX, XX, XX }, nkeynes@362: { "pushS", RMrBX, XX, XX }, nkeynes@362: { "pushS", RMrSP, XX, XX }, nkeynes@362: { "pushS", RMrBP, XX, XX }, nkeynes@362: { "pushS", RMrSI, XX, XX }, nkeynes@362: { "pushS", RMrDI, XX, XX }, nkeynes@362: /* 58 */ nkeynes@362: { "popS", RMrAX, XX, XX }, nkeynes@362: { "popS", RMrCX, XX, XX }, nkeynes@362: { "popS", RMrDX, XX, XX }, nkeynes@362: { "popS", RMrBX, XX, XX }, nkeynes@362: { "popS", RMrSP, XX, XX }, nkeynes@362: { "popS", RMrBP, XX, XX }, nkeynes@362: { "popS", RMrSI, XX, XX }, nkeynes@362: { "popS", RMrDI, XX, XX }, nkeynes@362: /* 60 */ nkeynes@362: { "pusha{P|}", XX, XX, XX }, nkeynes@362: { "popa{P|}", XX, XX, XX }, nkeynes@362: { "bound{S|}", Gv, Ma, XX }, nkeynes@362: { X86_64_0 }, nkeynes@362: { "(bad)", XX, XX, XX }, /* seg fs */ nkeynes@362: { "(bad)", XX, XX, XX }, /* seg gs */ nkeynes@362: { "(bad)", XX, XX, XX }, /* op size prefix */ nkeynes@362: { "(bad)", XX, XX, XX }, /* adr size prefix */ nkeynes@362: /* 68 */ nkeynes@362: { "pushT", Iq, XX, XX }, nkeynes@362: { "imulS", Gv, Ev, Iv }, nkeynes@362: { "pushT", sIb, XX, XX }, nkeynes@362: { "imulS", Gv, Ev, sIb }, nkeynes@362: { "ins{b||b|}", Yb, indirDX, XX }, nkeynes@362: { "ins{R||R|}", Yv, indirDX, XX }, nkeynes@362: { "outs{b||b|}", indirDX, Xb, XX }, nkeynes@362: { "outs{R||R|}", indirDX, Xv, XX }, nkeynes@362: /* 70 */ nkeynes@362: { "joH", Jb, XX, cond_jump_flag }, nkeynes@362: { "jnoH", Jb, XX, cond_jump_flag }, nkeynes@362: { "jbH", Jb, XX, cond_jump_flag }, nkeynes@362: { "jaeH", Jb, XX, cond_jump_flag }, nkeynes@362: { "jeH", Jb, XX, cond_jump_flag }, nkeynes@362: { "jneH", Jb, XX, cond_jump_flag }, nkeynes@362: { "jbeH", Jb, XX, cond_jump_flag }, nkeynes@362: { "jaH", Jb, XX, cond_jump_flag }, nkeynes@362: /* 78 */ nkeynes@362: { "jsH", Jb, XX, cond_jump_flag }, nkeynes@362: { "jnsH", Jb, XX, cond_jump_flag }, nkeynes@362: { "jpH", Jb, XX, cond_jump_flag }, nkeynes@362: { "jnpH", Jb, XX, cond_jump_flag }, nkeynes@362: { "jlH", Jb, XX, cond_jump_flag }, nkeynes@362: { "jgeH", Jb, XX, cond_jump_flag }, nkeynes@362: { "jleH", Jb, XX, cond_jump_flag }, nkeynes@362: { "jgH", Jb, XX, cond_jump_flag }, nkeynes@362: /* 80 */ nkeynes@362: { GRP1b }, nkeynes@362: { GRP1S }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { GRP1Ss }, nkeynes@362: { "testB", Eb, Gb, XX }, nkeynes@362: { "testS", Ev, Gv, XX }, nkeynes@362: { "xchgB", Eb, Gb, XX }, nkeynes@362: { "xchgS", Ev, Gv, XX }, nkeynes@362: /* 88 */ nkeynes@362: { "movB", Eb, Gb, XX }, nkeynes@362: { "movS", Ev, Gv, XX }, nkeynes@362: { "movB", Gb, Eb, XX }, nkeynes@362: { "movS", Gv, Ev, XX }, nkeynes@362: { "movQ", Ev, Sw, XX }, nkeynes@362: { "leaS", Gv, M, XX }, nkeynes@362: { "movQ", Sw, Ev, XX }, nkeynes@362: { "popU", Ev, XX, XX }, nkeynes@362: /* 90 */ nkeynes@362: { "nop", NOP_Fixup, 0, XX, XX }, nkeynes@362: { "xchgS", RMeCX, eAX, XX }, nkeynes@362: { "xchgS", RMeDX, eAX, XX }, nkeynes@362: { "xchgS", RMeBX, eAX, XX }, nkeynes@362: { "xchgS", RMeSP, eAX, XX }, nkeynes@362: { "xchgS", RMeBP, eAX, XX }, nkeynes@362: { "xchgS", RMeSI, eAX, XX }, nkeynes@362: { "xchgS", RMeDI, eAX, XX }, nkeynes@362: /* 98 */ nkeynes@362: { "cW{tR||tR|}", XX, XX, XX }, nkeynes@362: { "cR{tO||tO|}", XX, XX, XX }, nkeynes@362: { "Jcall{T|}", Ap, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, /* fwait */ nkeynes@362: { "pushfT", XX, XX, XX }, nkeynes@362: { "popfT", XX, XX, XX }, nkeynes@362: { "sahf{|}", XX, XX, XX }, nkeynes@362: { "lahf{|}", XX, XX, XX }, nkeynes@362: /* a0 */ nkeynes@362: { "movB", AL, Ob64, XX }, nkeynes@362: { "movS", eAX, Ov64, XX }, nkeynes@362: { "movB", Ob64, AL, XX }, nkeynes@362: { "movS", Ov64, eAX, XX }, nkeynes@362: { "movs{b||b|}", Yb, Xb, XX }, nkeynes@362: { "movs{R||R|}", Yv, Xv, XX }, nkeynes@362: { "cmps{b||b|}", Xb, Yb, XX }, nkeynes@362: { "cmps{R||R|}", Xv, Yv, XX }, nkeynes@362: /* a8 */ nkeynes@362: { "testB", AL, Ib, XX }, nkeynes@362: { "testS", eAX, Iv, XX }, nkeynes@362: { "stosB", Yb, AL, XX }, nkeynes@362: { "stosS", Yv, eAX, XX }, nkeynes@362: { "lodsB", AL, Xb, XX }, nkeynes@362: { "lodsS", eAX, Xv, XX }, nkeynes@362: { "scasB", AL, Yb, XX }, nkeynes@362: { "scasS", eAX, Yv, XX }, nkeynes@362: /* b0 */ nkeynes@362: { "movB", RMAL, Ib, XX }, nkeynes@362: { "movB", RMCL, Ib, XX }, nkeynes@362: { "movB", RMDL, Ib, XX }, nkeynes@362: { "movB", RMBL, Ib, XX }, nkeynes@362: { "movB", RMAH, Ib, XX }, nkeynes@362: { "movB", RMCH, Ib, XX }, nkeynes@362: { "movB", RMDH, Ib, XX }, nkeynes@362: { "movB", RMBH, Ib, XX }, nkeynes@362: /* b8 */ nkeynes@362: { "movS", RMeAX, Iv64, XX }, nkeynes@362: { "movS", RMeCX, Iv64, XX }, nkeynes@362: { "movS", RMeDX, Iv64, XX }, nkeynes@362: { "movS", RMeBX, Iv64, XX }, nkeynes@362: { "movS", RMeSP, Iv64, XX }, nkeynes@362: { "movS", RMeBP, Iv64, XX }, nkeynes@362: { "movS", RMeSI, Iv64, XX }, nkeynes@362: { "movS", RMeDI, Iv64, XX }, nkeynes@362: /* c0 */ nkeynes@362: { GRP2b }, nkeynes@362: { GRP2S }, nkeynes@362: { "retT", Iw, XX, XX }, nkeynes@362: { "retT", XX, XX, XX }, nkeynes@362: { "les{S|}", Gv, Mp, XX }, nkeynes@362: { "ldsS", Gv, Mp, XX }, nkeynes@362: { "movA", Eb, Ib, XX }, nkeynes@362: { "movQ", Ev, Iv, XX }, nkeynes@362: /* c8 */ nkeynes@362: { "enterT", Iw, Ib, XX }, nkeynes@362: { "leaveT", XX, XX, XX }, nkeynes@362: { "lretP", Iw, XX, XX }, nkeynes@362: { "lretP", XX, XX, XX }, nkeynes@362: { "int3", XX, XX, XX }, nkeynes@362: { "int", Ib, XX, XX }, nkeynes@362: { "into{|}", XX, XX, XX }, nkeynes@362: { "iretP", XX, XX, XX }, nkeynes@362: /* d0 */ nkeynes@362: { GRP2b_one }, nkeynes@362: { GRP2S_one }, nkeynes@362: { GRP2b_cl }, nkeynes@362: { GRP2S_cl }, nkeynes@362: { "aam{|}", sIb, XX, XX }, nkeynes@362: { "aad{|}", sIb, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "xlat", DSBX, XX, XX }, nkeynes@362: /* d8 */ nkeynes@362: { FLOAT }, nkeynes@362: { FLOAT }, nkeynes@362: { FLOAT }, nkeynes@362: { FLOAT }, nkeynes@362: { FLOAT }, nkeynes@362: { FLOAT }, nkeynes@362: { FLOAT }, nkeynes@362: { FLOAT }, nkeynes@362: /* e0 */ nkeynes@362: { "loopneFH", Jb, XX, loop_jcxz_flag }, nkeynes@362: { "loopeFH", Jb, XX, loop_jcxz_flag }, nkeynes@362: { "loopFH", Jb, XX, loop_jcxz_flag }, nkeynes@362: { "jEcxzH", Jb, XX, loop_jcxz_flag }, nkeynes@362: { "inB", AL, Ib, XX }, nkeynes@362: { "inS", eAX, Ib, XX }, nkeynes@362: { "outB", Ib, AL, XX }, nkeynes@362: { "outS", Ib, eAX, XX }, nkeynes@362: /* e8 */ nkeynes@362: { "callT", Jv, XX, XX }, nkeynes@362: { "jmpT", Jv, XX, XX }, nkeynes@362: { "Jjmp{T|}", Ap, XX, XX }, nkeynes@362: { "jmp", Jb, XX, XX }, nkeynes@362: { "inB", AL, indirDX, XX }, nkeynes@362: { "inS", eAX, indirDX, XX }, nkeynes@362: { "outB", indirDX, AL, XX }, nkeynes@362: { "outS", indirDX, eAX, XX }, nkeynes@362: /* f0 */ nkeynes@362: { "(bad)", XX, XX, XX }, /* lock prefix */ nkeynes@362: { "icebp", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, /* repne */ nkeynes@362: { "(bad)", XX, XX, XX }, /* repz */ nkeynes@362: { "hlt", XX, XX, XX }, nkeynes@362: { "cmc", XX, XX, XX }, nkeynes@362: { GRP3b }, nkeynes@362: { GRP3S }, nkeynes@362: /* f8 */ nkeynes@362: { "clc", XX, XX, XX }, nkeynes@362: { "stc", XX, XX, XX }, nkeynes@362: { "cli", XX, XX, XX }, nkeynes@362: { "sti", XX, XX, XX }, nkeynes@362: { "cld", XX, XX, XX }, nkeynes@362: { "std", XX, XX, XX }, nkeynes@362: { GRP4 }, nkeynes@362: { GRP5 }, nkeynes@362: }; nkeynes@362: nkeynes@362: static const struct dis386 dis386_twobyte[] = { nkeynes@362: /* 00 */ nkeynes@362: { GRP6 }, nkeynes@362: { GRP7 }, nkeynes@362: { "larS", Gv, Ew, XX }, nkeynes@362: { "lslS", Gv, Ew, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "syscall", XX, XX, XX }, nkeynes@362: { "clts", XX, XX, XX }, nkeynes@362: { "sysretP", XX, XX, XX }, nkeynes@362: /* 08 */ nkeynes@362: { "invd", XX, XX, XX }, nkeynes@362: { "wbinvd", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "ud2a", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { GRPAMD }, nkeynes@362: { "femms", XX, XX, XX }, nkeynes@362: { "", MX, EM, OPSUF }, /* See OP_3DNowSuffix. */ nkeynes@362: /* 10 */ nkeynes@362: { PREGRP8 }, nkeynes@362: { PREGRP9 }, nkeynes@362: { PREGRP30 }, nkeynes@362: { "movlpX", EX, XM, SIMD_Fixup, 'h' }, nkeynes@362: { "unpcklpX", XM, EX, XX }, nkeynes@362: { "unpckhpX", XM, EX, XX }, nkeynes@362: { PREGRP31 }, nkeynes@362: { "movhpX", EX, XM, SIMD_Fixup, 'l' }, nkeynes@362: /* 18 */ nkeynes@362: { GRP14 }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: /* 20 */ nkeynes@362: { "movL", Rm, Cm, XX }, nkeynes@362: { "movL", Rm, Dm, XX }, nkeynes@362: { "movL", Cm, Rm, XX }, nkeynes@362: { "movL", Dm, Rm, XX }, nkeynes@362: { "movL", Rd, Td, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "movL", Td, Rd, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: /* 28 */ nkeynes@362: { "movapX", XM, EX, XX }, nkeynes@362: { "movapX", EX, XM, XX }, nkeynes@362: { PREGRP2 }, nkeynes@362: { "movntpX", Ev, XM, XX }, nkeynes@362: { PREGRP4 }, nkeynes@362: { PREGRP3 }, nkeynes@362: { "ucomisX", XM,EX, XX }, nkeynes@362: { "comisX", XM,EX, XX }, nkeynes@362: /* 30 */ nkeynes@362: { "wrmsr", XX, XX, XX }, nkeynes@362: { "rdtsc", XX, XX, XX }, nkeynes@362: { "rdmsr", XX, XX, XX }, nkeynes@362: { "rdpmc", XX, XX, XX }, nkeynes@362: { "sysenter", XX, XX, XX }, nkeynes@362: { "sysexit", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: /* 38 */ nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: /* 40 */ nkeynes@362: { "cmovo", Gv, Ev, XX }, nkeynes@362: { "cmovno", Gv, Ev, XX }, nkeynes@362: { "cmovb", Gv, Ev, XX }, nkeynes@362: { "cmovae", Gv, Ev, XX }, nkeynes@362: { "cmove", Gv, Ev, XX }, nkeynes@362: { "cmovne", Gv, Ev, XX }, nkeynes@362: { "cmovbe", Gv, Ev, XX }, nkeynes@362: { "cmova", Gv, Ev, XX }, nkeynes@362: /* 48 */ nkeynes@362: { "cmovs", Gv, Ev, XX }, nkeynes@362: { "cmovns", Gv, Ev, XX }, nkeynes@362: { "cmovp", Gv, Ev, XX }, nkeynes@362: { "cmovnp", Gv, Ev, XX }, nkeynes@362: { "cmovl", Gv, Ev, XX }, nkeynes@362: { "cmovge", Gv, Ev, XX }, nkeynes@362: { "cmovle", Gv, Ev, XX }, nkeynes@362: { "cmovg", Gv, Ev, XX }, nkeynes@362: /* 50 */ nkeynes@362: { "movmskpX", Gdq, XS, XX }, nkeynes@362: { PREGRP13 }, nkeynes@362: { PREGRP12 }, nkeynes@362: { PREGRP11 }, nkeynes@362: { "andpX", XM, EX, XX }, nkeynes@362: { "andnpX", XM, EX, XX }, nkeynes@362: { "orpX", XM, EX, XX }, nkeynes@362: { "xorpX", XM, EX, XX }, nkeynes@362: /* 58 */ nkeynes@362: { PREGRP0 }, nkeynes@362: { PREGRP10 }, nkeynes@362: { PREGRP17 }, nkeynes@362: { PREGRP16 }, nkeynes@362: { PREGRP14 }, nkeynes@362: { PREGRP7 }, nkeynes@362: { PREGRP5 }, nkeynes@362: { PREGRP6 }, nkeynes@362: /* 60 */ nkeynes@362: { "punpcklbw", MX, EM, XX }, nkeynes@362: { "punpcklwd", MX, EM, XX }, nkeynes@362: { "punpckldq", MX, EM, XX }, nkeynes@362: { "packsswb", MX, EM, XX }, nkeynes@362: { "pcmpgtb", MX, EM, XX }, nkeynes@362: { "pcmpgtw", MX, EM, XX }, nkeynes@362: { "pcmpgtd", MX, EM, XX }, nkeynes@362: { "packuswb", MX, EM, XX }, nkeynes@362: /* 68 */ nkeynes@362: { "punpckhbw", MX, EM, XX }, nkeynes@362: { "punpckhwd", MX, EM, XX }, nkeynes@362: { "punpckhdq", MX, EM, XX }, nkeynes@362: { "packssdw", MX, EM, XX }, nkeynes@362: { PREGRP26 }, nkeynes@362: { PREGRP24 }, nkeynes@362: { "movd", MX, Edq, XX }, nkeynes@362: { PREGRP19 }, nkeynes@362: /* 70 */ nkeynes@362: { PREGRP22 }, nkeynes@362: { GRP10 }, nkeynes@362: { GRP11 }, nkeynes@362: { GRP12 }, nkeynes@362: { "pcmpeqb", MX, EM, XX }, nkeynes@362: { "pcmpeqw", MX, EM, XX }, nkeynes@362: { "pcmpeqd", MX, EM, XX }, nkeynes@362: { "emms", XX, XX, XX }, nkeynes@362: /* 78 */ nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { PREGRP28 }, nkeynes@362: { PREGRP29 }, nkeynes@362: { PREGRP23 }, nkeynes@362: { PREGRP20 }, nkeynes@362: /* 80 */ nkeynes@362: { "joH", Jv, XX, cond_jump_flag }, nkeynes@362: { "jnoH", Jv, XX, cond_jump_flag }, nkeynes@362: { "jbH", Jv, XX, cond_jump_flag }, nkeynes@362: { "jaeH", Jv, XX, cond_jump_flag }, nkeynes@362: { "jeH", Jv, XX, cond_jump_flag }, nkeynes@362: { "jneH", Jv, XX, cond_jump_flag }, nkeynes@362: { "jbeH", Jv, XX, cond_jump_flag }, nkeynes@362: { "jaH", Jv, XX, cond_jump_flag }, nkeynes@362: /* 88 */ nkeynes@362: { "jsH", Jv, XX, cond_jump_flag }, nkeynes@362: { "jnsH", Jv, XX, cond_jump_flag }, nkeynes@362: { "jpH", Jv, XX, cond_jump_flag }, nkeynes@362: { "jnpH", Jv, XX, cond_jump_flag }, nkeynes@362: { "jlH", Jv, XX, cond_jump_flag }, nkeynes@362: { "jgeH", Jv, XX, cond_jump_flag }, nkeynes@362: { "jleH", Jv, XX, cond_jump_flag }, nkeynes@362: { "jgH", Jv, XX, cond_jump_flag }, nkeynes@362: /* 90 */ nkeynes@362: { "seto", Eb, XX, XX }, nkeynes@362: { "setno", Eb, XX, XX }, nkeynes@362: { "setb", Eb, XX, XX }, nkeynes@362: { "setae", Eb, XX, XX }, nkeynes@362: { "sete", Eb, XX, XX }, nkeynes@362: { "setne", Eb, XX, XX }, nkeynes@362: { "setbe", Eb, XX, XX }, nkeynes@362: { "seta", Eb, XX, XX }, nkeynes@362: /* 98 */ nkeynes@362: { "sets", Eb, XX, XX }, nkeynes@362: { "setns", Eb, XX, XX }, nkeynes@362: { "setp", Eb, XX, XX }, nkeynes@362: { "setnp", Eb, XX, XX }, nkeynes@362: { "setl", Eb, XX, XX }, nkeynes@362: { "setge", Eb, XX, XX }, nkeynes@362: { "setle", Eb, XX, XX }, nkeynes@362: { "setg", Eb, XX, XX }, nkeynes@362: /* a0 */ nkeynes@362: { "pushT", fs, XX, XX }, nkeynes@362: { "popT", fs, XX, XX }, nkeynes@362: { "cpuid", XX, XX, XX }, nkeynes@362: { "btS", Ev, Gv, XX }, nkeynes@362: { "shldS", Ev, Gv, Ib }, nkeynes@362: { "shldS", Ev, Gv, CL }, nkeynes@362: { GRPPADLCK2 }, nkeynes@362: { GRPPADLCK1 }, nkeynes@362: /* a8 */ nkeynes@362: { "pushT", gs, XX, XX }, nkeynes@362: { "popT", gs, XX, XX }, nkeynes@362: { "rsm", XX, XX, XX }, nkeynes@362: { "btsS", Ev, Gv, XX }, nkeynes@362: { "shrdS", Ev, Gv, Ib }, nkeynes@362: { "shrdS", Ev, Gv, CL }, nkeynes@362: { GRP13 }, nkeynes@362: { "imulS", Gv, Ev, XX }, nkeynes@362: /* b0 */ nkeynes@362: { "cmpxchgB", Eb, Gb, XX }, nkeynes@362: { "cmpxchgS", Ev, Gv, XX }, nkeynes@362: { "lssS", Gv, Mp, XX }, nkeynes@362: { "btrS", Ev, Gv, XX }, nkeynes@362: { "lfsS", Gv, Mp, XX }, nkeynes@362: { "lgsS", Gv, Mp, XX }, nkeynes@362: { "movz{bR|x|bR|x}", Gv, Eb, XX }, nkeynes@362: { "movz{wR|x|wR|x}", Gv, Ew, XX }, /* yes, there really is movzww ! */ nkeynes@362: /* b8 */ nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "ud2b", XX, XX, XX }, nkeynes@362: { GRP8 }, nkeynes@362: { "btcS", Ev, Gv, XX }, nkeynes@362: { "bsfS", Gv, Ev, XX }, nkeynes@362: { "bsrS", Gv, Ev, XX }, nkeynes@362: { "movs{bR|x|bR|x}", Gv, Eb, XX }, nkeynes@362: { "movs{wR|x|wR|x}", Gv, Ew, XX }, /* yes, there really is movsww ! */ nkeynes@362: /* c0 */ nkeynes@362: { "xaddB", Eb, Gb, XX }, nkeynes@362: { "xaddS", Ev, Gv, XX }, nkeynes@362: { PREGRP1 }, nkeynes@362: { "movntiS", Ev, Gv, XX }, nkeynes@362: { "pinsrw", MX, Edqw, Ib }, nkeynes@362: { "pextrw", Gdq, MS, Ib }, nkeynes@362: { "shufpX", XM, EX, Ib }, nkeynes@362: { GRP9 }, nkeynes@362: /* c8 */ nkeynes@362: { "bswap", RMeAX, XX, XX }, nkeynes@362: { "bswap", RMeCX, XX, XX }, nkeynes@362: { "bswap", RMeDX, XX, XX }, nkeynes@362: { "bswap", RMeBX, XX, XX }, nkeynes@362: { "bswap", RMeSP, XX, XX }, nkeynes@362: { "bswap", RMeBP, XX, XX }, nkeynes@362: { "bswap", RMeSI, XX, XX }, nkeynes@362: { "bswap", RMeDI, XX, XX }, nkeynes@362: /* d0 */ nkeynes@362: { PREGRP27 }, nkeynes@362: { "psrlw", MX, EM, XX }, nkeynes@362: { "psrld", MX, EM, XX }, nkeynes@362: { "psrlq", MX, EM, XX }, nkeynes@362: { "paddq", MX, EM, XX }, nkeynes@362: { "pmullw", MX, EM, XX }, nkeynes@362: { PREGRP21 }, nkeynes@362: { "pmovmskb", Gdq, MS, XX }, nkeynes@362: /* d8 */ nkeynes@362: { "psubusb", MX, EM, XX }, nkeynes@362: { "psubusw", MX, EM, XX }, nkeynes@362: { "pminub", MX, EM, XX }, nkeynes@362: { "pand", MX, EM, XX }, nkeynes@362: { "paddusb", MX, EM, XX }, nkeynes@362: { "paddusw", MX, EM, XX }, nkeynes@362: { "pmaxub", MX, EM, XX }, nkeynes@362: { "pandn", MX, EM, XX }, nkeynes@362: /* e0 */ nkeynes@362: { "pavgb", MX, EM, XX }, nkeynes@362: { "psraw", MX, EM, XX }, nkeynes@362: { "psrad", MX, EM, XX }, nkeynes@362: { "pavgw", MX, EM, XX }, nkeynes@362: { "pmulhuw", MX, EM, XX }, nkeynes@362: { "pmulhw", MX, EM, XX }, nkeynes@362: { PREGRP15 }, nkeynes@362: { PREGRP25 }, nkeynes@362: /* e8 */ nkeynes@362: { "psubsb", MX, EM, XX }, nkeynes@362: { "psubsw", MX, EM, XX }, nkeynes@362: { "pminsw", MX, EM, XX }, nkeynes@362: { "por", MX, EM, XX }, nkeynes@362: { "paddsb", MX, EM, XX }, nkeynes@362: { "paddsw", MX, EM, XX }, nkeynes@362: { "pmaxsw", MX, EM, XX }, nkeynes@362: { "pxor", MX, EM, XX }, nkeynes@362: /* f0 */ nkeynes@362: { PREGRP32 }, nkeynes@362: { "psllw", MX, EM, XX }, nkeynes@362: { "pslld", MX, EM, XX }, nkeynes@362: { "psllq", MX, EM, XX }, nkeynes@362: { "pmuludq", MX, EM, XX }, nkeynes@362: { "pmaddwd", MX, EM, XX }, nkeynes@362: { "psadbw", MX, EM, XX }, nkeynes@362: { PREGRP18 }, nkeynes@362: /* f8 */ nkeynes@362: { "psubb", MX, EM, XX }, nkeynes@362: { "psubw", MX, EM, XX }, nkeynes@362: { "psubd", MX, EM, XX }, nkeynes@362: { "psubq", MX, EM, XX }, nkeynes@362: { "paddb", MX, EM, XX }, nkeynes@362: { "paddw", MX, EM, XX }, nkeynes@362: { "paddd", MX, EM, XX }, nkeynes@362: { "(bad)", XX, XX, XX } nkeynes@362: }; nkeynes@362: nkeynes@362: static const unsigned char onebyte_has_modrm[256] = { nkeynes@362: /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ nkeynes@362: /* ------------------------------- */ nkeynes@362: /* 00 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 00 */ nkeynes@362: /* 10 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 10 */ nkeynes@362: /* 20 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 20 */ nkeynes@362: /* 30 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 30 */ nkeynes@362: /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40 */ nkeynes@362: /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */ nkeynes@362: /* 60 */ 0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0, /* 60 */ nkeynes@362: /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */ nkeynes@362: /* 80 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 80 */ nkeynes@362: /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 90 */ nkeynes@362: /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* a0 */ nkeynes@362: /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* b0 */ nkeynes@362: /* c0 */ 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* c0 */ nkeynes@362: /* d0 */ 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* d0 */ nkeynes@362: /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* e0 */ nkeynes@362: /* f0 */ 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1 /* f0 */ nkeynes@362: /* ------------------------------- */ nkeynes@362: /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ nkeynes@362: }; nkeynes@362: nkeynes@362: static const unsigned char twobyte_has_modrm[256] = { nkeynes@362: /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ nkeynes@362: /* ------------------------------- */ nkeynes@362: /* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,1, /* 0f */ nkeynes@362: /* 10 */ 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, /* 1f */ nkeynes@362: /* 20 */ 1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1, /* 2f */ nkeynes@362: /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ nkeynes@362: /* 40 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4f */ nkeynes@362: /* 50 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 5f */ nkeynes@362: /* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6f */ nkeynes@362: /* 70 */ 1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1, /* 7f */ nkeynes@362: /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ nkeynes@362: /* 90 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 9f */ nkeynes@362: /* a0 */ 0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1, /* af */ nkeynes@362: /* b0 */ 1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1, /* bf */ nkeynes@362: /* c0 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* cf */ nkeynes@362: /* d0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* df */ nkeynes@362: /* e0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* ef */ nkeynes@362: /* f0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 /* ff */ nkeynes@362: /* ------------------------------- */ nkeynes@362: /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ nkeynes@362: }; nkeynes@362: nkeynes@362: static const unsigned char twobyte_uses_SSE_prefix[256] = { nkeynes@362: /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ nkeynes@362: /* ------------------------------- */ nkeynes@362: /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ nkeynes@362: /* 10 */ 1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0, /* 1f */ nkeynes@362: /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0, /* 2f */ nkeynes@362: /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ nkeynes@362: /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ nkeynes@362: /* 50 */ 0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* 5f */ nkeynes@362: /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1, /* 6f */ nkeynes@362: /* 70 */ 1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1, /* 7f */ nkeynes@362: /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ nkeynes@362: /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ nkeynes@362: /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ nkeynes@362: /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ nkeynes@362: /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ nkeynes@362: /* d0 */ 1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */ nkeynes@362: /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */ nkeynes@362: /* f0 */ 1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 /* ff */ nkeynes@362: /* ------------------------------- */ nkeynes@362: /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ nkeynes@362: }; nkeynes@362: nkeynes@362: static char obuf[100]; nkeynes@362: static char *obufp; nkeynes@362: static char scratchbuf[100]; nkeynes@362: static unsigned char *start_codep; nkeynes@362: static unsigned char *insn_codep; nkeynes@362: static unsigned char *codep; nkeynes@362: static disassemble_info *the_info; nkeynes@362: static int mod; nkeynes@362: static int rm; nkeynes@362: static int reg; nkeynes@362: static unsigned char need_modrm; nkeynes@362: nkeynes@362: /* If we are accessing mod/rm/reg without need_modrm set, then the nkeynes@362: values are stale. Hitting this abort likely indicates that you nkeynes@362: need to update onebyte_has_modrm or twobyte_has_modrm. */ nkeynes@362: #define MODRM_CHECK if (!need_modrm) abort () nkeynes@362: nkeynes@362: static const char **names64; nkeynes@362: static const char **names32; nkeynes@362: static const char **names16; nkeynes@362: static const char **names8; nkeynes@362: static const char **names8rex; nkeynes@362: static const char **names_seg; nkeynes@362: static const char **index16; nkeynes@362: nkeynes@362: static const char *intel_names64[] = { nkeynes@362: "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", nkeynes@362: "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" nkeynes@362: }; nkeynes@362: static const char *intel_names32[] = { nkeynes@362: "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", nkeynes@362: "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" nkeynes@362: }; nkeynes@362: static const char *intel_names16[] = { nkeynes@362: "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", nkeynes@362: "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" nkeynes@362: }; nkeynes@362: static const char *intel_names8[] = { nkeynes@362: "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", nkeynes@362: }; nkeynes@362: static const char *intel_names8rex[] = { nkeynes@362: "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", nkeynes@362: "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" nkeynes@362: }; nkeynes@362: static const char *intel_names_seg[] = { nkeynes@362: "es", "cs", "ss", "ds", "fs", "gs", "?", "?", nkeynes@362: }; nkeynes@362: static const char *intel_index16[] = { nkeynes@362: "bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx" nkeynes@362: }; nkeynes@362: nkeynes@362: static const char *att_names64[] = { nkeynes@362: "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi", nkeynes@362: "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" nkeynes@362: }; nkeynes@362: static const char *att_names32[] = { nkeynes@362: "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi", nkeynes@362: "%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d" nkeynes@362: }; nkeynes@362: static const char *att_names16[] = { nkeynes@362: "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di", nkeynes@362: "%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w" nkeynes@362: }; nkeynes@362: static const char *att_names8[] = { nkeynes@362: "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh", nkeynes@362: }; nkeynes@362: static const char *att_names8rex[] = { nkeynes@362: "%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil", nkeynes@362: "%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b" nkeynes@362: }; nkeynes@362: static const char *att_names_seg[] = { nkeynes@362: "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "%?", "%?", nkeynes@362: }; nkeynes@362: static const char *att_index16[] = { nkeynes@362: "%bx,%si", "%bx,%di", "%bp,%si", "%bp,%di", "%si", "%di", "%bp", "%bx" nkeynes@362: }; nkeynes@362: nkeynes@362: static const struct dis386 grps[][8] = { nkeynes@362: /* GRP1b */ nkeynes@362: { nkeynes@362: { "addA", Eb, Ib, XX }, nkeynes@362: { "orA", Eb, Ib, XX }, nkeynes@362: { "adcA", Eb, Ib, XX }, nkeynes@362: { "sbbA", Eb, Ib, XX }, nkeynes@362: { "andA", Eb, Ib, XX }, nkeynes@362: { "subA", Eb, Ib, XX }, nkeynes@362: { "xorA", Eb, Ib, XX }, nkeynes@362: { "cmpA", Eb, Ib, XX } nkeynes@362: }, nkeynes@362: /* GRP1S */ nkeynes@362: { nkeynes@362: { "addQ", Ev, Iv, XX }, nkeynes@362: { "orQ", Ev, Iv, XX }, nkeynes@362: { "adcQ", Ev, Iv, XX }, nkeynes@362: { "sbbQ", Ev, Iv, XX }, nkeynes@362: { "andQ", Ev, Iv, XX }, nkeynes@362: { "subQ", Ev, Iv, XX }, nkeynes@362: { "xorQ", Ev, Iv, XX }, nkeynes@362: { "cmpQ", Ev, Iv, XX } nkeynes@362: }, nkeynes@362: /* GRP1Ss */ nkeynes@362: { nkeynes@362: { "addQ", Ev, sIb, XX }, nkeynes@362: { "orQ", Ev, sIb, XX }, nkeynes@362: { "adcQ", Ev, sIb, XX }, nkeynes@362: { "sbbQ", Ev, sIb, XX }, nkeynes@362: { "andQ", Ev, sIb, XX }, nkeynes@362: { "subQ", Ev, sIb, XX }, nkeynes@362: { "xorQ", Ev, sIb, XX }, nkeynes@362: { "cmpQ", Ev, sIb, XX } nkeynes@362: }, nkeynes@362: /* GRP2b */ nkeynes@362: { nkeynes@362: { "rolA", Eb, Ib, XX }, nkeynes@362: { "rorA", Eb, Ib, XX }, nkeynes@362: { "rclA", Eb, Ib, XX }, nkeynes@362: { "rcrA", Eb, Ib, XX }, nkeynes@362: { "shlA", Eb, Ib, XX }, nkeynes@362: { "shrA", Eb, Ib, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "sarA", Eb, Ib, XX }, nkeynes@362: }, nkeynes@362: /* GRP2S */ nkeynes@362: { nkeynes@362: { "rolQ", Ev, Ib, XX }, nkeynes@362: { "rorQ", Ev, Ib, XX }, nkeynes@362: { "rclQ", Ev, Ib, XX }, nkeynes@362: { "rcrQ", Ev, Ib, XX }, nkeynes@362: { "shlQ", Ev, Ib, XX }, nkeynes@362: { "shrQ", Ev, Ib, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "sarQ", Ev, Ib, XX }, nkeynes@362: }, nkeynes@362: /* GRP2b_one */ nkeynes@362: { nkeynes@362: { "rolA", Eb, I1, XX }, nkeynes@362: { "rorA", Eb, I1, XX }, nkeynes@362: { "rclA", Eb, I1, XX }, nkeynes@362: { "rcrA", Eb, I1, XX }, nkeynes@362: { "shlA", Eb, I1, XX }, nkeynes@362: { "shrA", Eb, I1, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "sarA", Eb, I1, XX }, nkeynes@362: }, nkeynes@362: /* GRP2S_one */ nkeynes@362: { nkeynes@362: { "rolQ", Ev, I1, XX }, nkeynes@362: { "rorQ", Ev, I1, XX }, nkeynes@362: { "rclQ", Ev, I1, XX }, nkeynes@362: { "rcrQ", Ev, I1, XX }, nkeynes@362: { "shlQ", Ev, I1, XX }, nkeynes@362: { "shrQ", Ev, I1, XX }, nkeynes@362: { "(bad)", XX, XX, XX}, nkeynes@362: { "sarQ", Ev, I1, XX }, nkeynes@362: }, nkeynes@362: /* GRP2b_cl */ nkeynes@362: { nkeynes@362: { "rolA", Eb, CL, XX }, nkeynes@362: { "rorA", Eb, CL, XX }, nkeynes@362: { "rclA", Eb, CL, XX }, nkeynes@362: { "rcrA", Eb, CL, XX }, nkeynes@362: { "shlA", Eb, CL, XX }, nkeynes@362: { "shrA", Eb, CL, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "sarA", Eb, CL, XX }, nkeynes@362: }, nkeynes@362: /* GRP2S_cl */ nkeynes@362: { nkeynes@362: { "rolQ", Ev, CL, XX }, nkeynes@362: { "rorQ", Ev, CL, XX }, nkeynes@362: { "rclQ", Ev, CL, XX }, nkeynes@362: { "rcrQ", Ev, CL, XX }, nkeynes@362: { "shlQ", Ev, CL, XX }, nkeynes@362: { "shrQ", Ev, CL, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "sarQ", Ev, CL, XX } nkeynes@362: }, nkeynes@362: /* GRP3b */ nkeynes@362: { nkeynes@362: { "testA", Eb, Ib, XX }, nkeynes@362: { "(bad)", Eb, XX, XX }, nkeynes@362: { "notA", Eb, XX, XX }, nkeynes@362: { "negA", Eb, XX, XX }, nkeynes@362: { "mulA", Eb, XX, XX }, /* Don't print the implicit %al register, */ nkeynes@362: { "imulA", Eb, XX, XX }, /* to distinguish these opcodes from other */ nkeynes@362: { "divA", Eb, XX, XX }, /* mul/imul opcodes. Do the same for div */ nkeynes@362: { "idivA", Eb, XX, XX } /* and idiv for consistency. */ nkeynes@362: }, nkeynes@362: /* GRP3S */ nkeynes@362: { nkeynes@362: { "testQ", Ev, Iv, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "notQ", Ev, XX, XX }, nkeynes@362: { "negQ", Ev, XX, XX }, nkeynes@362: { "mulQ", Ev, XX, XX }, /* Don't print the implicit register. */ nkeynes@362: { "imulQ", Ev, XX, XX }, nkeynes@362: { "divQ", Ev, XX, XX }, nkeynes@362: { "idivQ", Ev, XX, XX }, nkeynes@362: }, nkeynes@362: /* GRP4 */ nkeynes@362: { nkeynes@362: { "incA", Eb, XX, XX }, nkeynes@362: { "decA", Eb, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: }, nkeynes@362: /* GRP5 */ nkeynes@362: { nkeynes@362: { "incQ", Ev, XX, XX }, nkeynes@362: { "decQ", Ev, XX, XX }, nkeynes@362: { "callT", indirEv, XX, XX }, nkeynes@362: { "JcallT", indirEp, XX, XX }, nkeynes@362: { "jmpT", indirEv, XX, XX }, nkeynes@362: { "JjmpT", indirEp, XX, XX }, nkeynes@362: { "pushU", Ev, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: }, nkeynes@362: /* GRP6 */ nkeynes@362: { nkeynes@362: { "sldtQ", Ev, XX, XX }, nkeynes@362: { "strQ", Ev, XX, XX }, nkeynes@362: { "lldt", Ew, XX, XX }, nkeynes@362: { "ltr", Ew, XX, XX }, nkeynes@362: { "verr", Ew, XX, XX }, nkeynes@362: { "verw", Ew, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX } nkeynes@362: }, nkeynes@362: /* GRP7 */ nkeynes@362: { nkeynes@362: { "sgdtIQ", M, XX, XX }, nkeynes@362: { "sidtIQ", PNI_Fixup, 0, XX, XX }, nkeynes@362: { "lgdt{Q|Q||}", M, XX, XX }, nkeynes@362: { "lidt{Q|Q||}", M, XX, XX }, nkeynes@362: { "smswQ", Ev, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "lmsw", Ew, XX, XX }, nkeynes@362: { "invlpg", INVLPG_Fixup, w_mode, XX, XX }, nkeynes@362: }, nkeynes@362: /* GRP8 */ nkeynes@362: { nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "btQ", Ev, Ib, XX }, nkeynes@362: { "btsQ", Ev, Ib, XX }, nkeynes@362: { "btrQ", Ev, Ib, XX }, nkeynes@362: { "btcQ", Ev, Ib, XX }, nkeynes@362: }, nkeynes@362: /* GRP9 */ nkeynes@362: { nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "cmpxchg8b", Eq, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: }, nkeynes@362: /* GRP10 */ nkeynes@362: { nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "psrlw", MS, Ib, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "psraw", MS, Ib, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "psllw", MS, Ib, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: }, nkeynes@362: /* GRP11 */ nkeynes@362: { nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "psrld", MS, Ib, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "psrad", MS, Ib, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "pslld", MS, Ib, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: }, nkeynes@362: /* GRP12 */ nkeynes@362: { nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "psrlq", MS, Ib, XX }, nkeynes@362: { "psrldq", MS, Ib, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "psllq", MS, Ib, XX }, nkeynes@362: { "pslldq", MS, Ib, XX }, nkeynes@362: }, nkeynes@362: /* GRP13 */ nkeynes@362: { nkeynes@362: { "fxsave", Ev, XX, XX }, nkeynes@362: { "fxrstor", Ev, XX, XX }, nkeynes@362: { "ldmxcsr", Ev, XX, XX }, nkeynes@362: { "stmxcsr", Ev, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "lfence", OP_0fae, 0, XX, XX }, nkeynes@362: { "mfence", OP_0fae, 0, XX, XX }, nkeynes@362: { "clflush", OP_0fae, 0, XX, XX }, nkeynes@362: }, nkeynes@362: /* GRP14 */ nkeynes@362: { nkeynes@362: { "prefetchnta", Ev, XX, XX }, nkeynes@362: { "prefetcht0", Ev, XX, XX }, nkeynes@362: { "prefetcht1", Ev, XX, XX }, nkeynes@362: { "prefetcht2", Ev, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: }, nkeynes@362: /* GRPAMD */ nkeynes@362: { nkeynes@362: { "prefetch", Eb, XX, XX }, nkeynes@362: { "prefetchw", Eb, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: }, nkeynes@362: /* GRPPADLCK1 */ nkeynes@362: { nkeynes@362: { "xstorerng", OP_0f07, 0, XX, XX }, nkeynes@362: { "xcryptecb", OP_0f07, 0, XX, XX }, nkeynes@362: { "xcryptcbc", OP_0f07, 0, XX, XX }, nkeynes@362: { "(bad)", OP_0f07, 0, XX, XX }, nkeynes@362: { "xcryptcfb", OP_0f07, 0, XX, XX }, nkeynes@362: { "xcryptofb", OP_0f07, 0, XX, XX }, nkeynes@362: { "(bad)", OP_0f07, 0, XX, XX }, nkeynes@362: { "(bad)", OP_0f07, 0, XX, XX }, nkeynes@362: }, nkeynes@362: /* GRPPADLCK2 */ nkeynes@362: { nkeynes@362: { "montmul", OP_0f07, 0, XX, XX }, nkeynes@362: { "xsha1", OP_0f07, 0, XX, XX }, nkeynes@362: { "xsha256", OP_0f07, 0, XX, XX }, nkeynes@362: { "(bad)", OP_0f07, 0, XX, XX }, nkeynes@362: { "(bad)", OP_0f07, 0, XX, XX }, nkeynes@362: { "(bad)", OP_0f07, 0, XX, XX }, nkeynes@362: { "(bad)", OP_0f07, 0, XX, XX }, nkeynes@362: { "(bad)", OP_0f07, 0, XX, XX }, nkeynes@362: } nkeynes@362: }; nkeynes@362: nkeynes@362: static const struct dis386 prefix_user_table[][4] = { nkeynes@362: /* PREGRP0 */ nkeynes@362: { nkeynes@362: { "addps", XM, EX, XX }, nkeynes@362: { "addss", XM, EX, XX }, nkeynes@362: { "addpd", XM, EX, XX }, nkeynes@362: { "addsd", XM, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP1 */ nkeynes@362: { nkeynes@362: { "", XM, EX, OPSIMD }, /* See OP_SIMD_SUFFIX. */ nkeynes@362: { "", XM, EX, OPSIMD }, nkeynes@362: { "", XM, EX, OPSIMD }, nkeynes@362: { "", XM, EX, OPSIMD }, nkeynes@362: }, nkeynes@362: /* PREGRP2 */ nkeynes@362: { nkeynes@362: { "cvtpi2ps", XM, EM, XX }, nkeynes@362: { "cvtsi2ssY", XM, Ev, XX }, nkeynes@362: { "cvtpi2pd", XM, EM, XX }, nkeynes@362: { "cvtsi2sdY", XM, Ev, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP3 */ nkeynes@362: { nkeynes@362: { "cvtps2pi", MX, EX, XX }, nkeynes@362: { "cvtss2siY", Gv, EX, XX }, nkeynes@362: { "cvtpd2pi", MX, EX, XX }, nkeynes@362: { "cvtsd2siY", Gv, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP4 */ nkeynes@362: { nkeynes@362: { "cvttps2pi", MX, EX, XX }, nkeynes@362: { "cvttss2siY", Gv, EX, XX }, nkeynes@362: { "cvttpd2pi", MX, EX, XX }, nkeynes@362: { "cvttsd2siY", Gv, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP5 */ nkeynes@362: { nkeynes@362: { "divps", XM, EX, XX }, nkeynes@362: { "divss", XM, EX, XX }, nkeynes@362: { "divpd", XM, EX, XX }, nkeynes@362: { "divsd", XM, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP6 */ nkeynes@362: { nkeynes@362: { "maxps", XM, EX, XX }, nkeynes@362: { "maxss", XM, EX, XX }, nkeynes@362: { "maxpd", XM, EX, XX }, nkeynes@362: { "maxsd", XM, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP7 */ nkeynes@362: { nkeynes@362: { "minps", XM, EX, XX }, nkeynes@362: { "minss", XM, EX, XX }, nkeynes@362: { "minpd", XM, EX, XX }, nkeynes@362: { "minsd", XM, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP8 */ nkeynes@362: { nkeynes@362: { "movups", XM, EX, XX }, nkeynes@362: { "movss", XM, EX, XX }, nkeynes@362: { "movupd", XM, EX, XX }, nkeynes@362: { "movsd", XM, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP9 */ nkeynes@362: { nkeynes@362: { "movups", EX, XM, XX }, nkeynes@362: { "movss", EX, XM, XX }, nkeynes@362: { "movupd", EX, XM, XX }, nkeynes@362: { "movsd", EX, XM, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP10 */ nkeynes@362: { nkeynes@362: { "mulps", XM, EX, XX }, nkeynes@362: { "mulss", XM, EX, XX }, nkeynes@362: { "mulpd", XM, EX, XX }, nkeynes@362: { "mulsd", XM, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP11 */ nkeynes@362: { nkeynes@362: { "rcpps", XM, EX, XX }, nkeynes@362: { "rcpss", XM, EX, XX }, nkeynes@362: { "(bad)", XM, EX, XX }, nkeynes@362: { "(bad)", XM, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP12 */ nkeynes@362: { nkeynes@362: { "rsqrtps", XM, EX, XX }, nkeynes@362: { "rsqrtss", XM, EX, XX }, nkeynes@362: { "(bad)", XM, EX, XX }, nkeynes@362: { "(bad)", XM, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP13 */ nkeynes@362: { nkeynes@362: { "sqrtps", XM, EX, XX }, nkeynes@362: { "sqrtss", XM, EX, XX }, nkeynes@362: { "sqrtpd", XM, EX, XX }, nkeynes@362: { "sqrtsd", XM, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP14 */ nkeynes@362: { nkeynes@362: { "subps", XM, EX, XX }, nkeynes@362: { "subss", XM, EX, XX }, nkeynes@362: { "subpd", XM, EX, XX }, nkeynes@362: { "subsd", XM, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP15 */ nkeynes@362: { nkeynes@362: { "(bad)", XM, EX, XX }, nkeynes@362: { "cvtdq2pd", XM, EX, XX }, nkeynes@362: { "cvttpd2dq", XM, EX, XX }, nkeynes@362: { "cvtpd2dq", XM, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP16 */ nkeynes@362: { nkeynes@362: { "cvtdq2ps", XM, EX, XX }, nkeynes@362: { "cvttps2dq",XM, EX, XX }, nkeynes@362: { "cvtps2dq",XM, EX, XX }, nkeynes@362: { "(bad)", XM, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP17 */ nkeynes@362: { nkeynes@362: { "cvtps2pd", XM, EX, XX }, nkeynes@362: { "cvtss2sd", XM, EX, XX }, nkeynes@362: { "cvtpd2ps", XM, EX, XX }, nkeynes@362: { "cvtsd2ss", XM, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP18 */ nkeynes@362: { nkeynes@362: { "maskmovq", MX, MS, XX }, nkeynes@362: { "(bad)", XM, EX, XX }, nkeynes@362: { "maskmovdqu", XM, EX, XX }, nkeynes@362: { "(bad)", XM, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP19 */ nkeynes@362: { nkeynes@362: { "movq", MX, EM, XX }, nkeynes@362: { "movdqu", XM, EX, XX }, nkeynes@362: { "movdqa", XM, EX, XX }, nkeynes@362: { "(bad)", XM, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP20 */ nkeynes@362: { nkeynes@362: { "movq", EM, MX, XX }, nkeynes@362: { "movdqu", EX, XM, XX }, nkeynes@362: { "movdqa", EX, XM, XX }, nkeynes@362: { "(bad)", EX, XM, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP21 */ nkeynes@362: { nkeynes@362: { "(bad)", EX, XM, XX }, nkeynes@362: { "movq2dq", XM, MS, XX }, nkeynes@362: { "movq", EX, XM, XX }, nkeynes@362: { "movdq2q", MX, XS, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP22 */ nkeynes@362: { nkeynes@362: { "pshufw", MX, EM, Ib }, nkeynes@362: { "pshufhw", XM, EX, Ib }, nkeynes@362: { "pshufd", XM, EX, Ib }, nkeynes@362: { "pshuflw", XM, EX, Ib }, nkeynes@362: }, nkeynes@362: /* PREGRP23 */ nkeynes@362: { nkeynes@362: { "movd", Edq, MX, XX }, nkeynes@362: { "movq", XM, EX, XX }, nkeynes@362: { "movd", Edq, XM, XX }, nkeynes@362: { "(bad)", Ed, XM, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP24 */ nkeynes@362: { nkeynes@362: { "(bad)", MX, EX, XX }, nkeynes@362: { "(bad)", XM, EX, XX }, nkeynes@362: { "punpckhqdq", XM, EX, XX }, nkeynes@362: { "(bad)", XM, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP25 */ nkeynes@362: { nkeynes@362: { "movntq", EM, MX, XX }, nkeynes@362: { "(bad)", EM, XM, XX }, nkeynes@362: { "movntdq", EM, XM, XX }, nkeynes@362: { "(bad)", EM, XM, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP26 */ nkeynes@362: { nkeynes@362: { "(bad)", MX, EX, XX }, nkeynes@362: { "(bad)", XM, EX, XX }, nkeynes@362: { "punpcklqdq", XM, EX, XX }, nkeynes@362: { "(bad)", XM, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP27 */ nkeynes@362: { nkeynes@362: { "(bad)", MX, EX, XX }, nkeynes@362: { "(bad)", XM, EX, XX }, nkeynes@362: { "addsubpd", XM, EX, XX }, nkeynes@362: { "addsubps", XM, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP28 */ nkeynes@362: { nkeynes@362: { "(bad)", MX, EX, XX }, nkeynes@362: { "(bad)", XM, EX, XX }, nkeynes@362: { "haddpd", XM, EX, XX }, nkeynes@362: { "haddps", XM, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP29 */ nkeynes@362: { nkeynes@362: { "(bad)", MX, EX, XX }, nkeynes@362: { "(bad)", XM, EX, XX }, nkeynes@362: { "hsubpd", XM, EX, XX }, nkeynes@362: { "hsubps", XM, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP30 */ nkeynes@362: { nkeynes@362: { "movlpX", XM, EX, SIMD_Fixup, 'h' }, /* really only 2 operands */ nkeynes@362: { "movsldup", XM, EX, XX }, nkeynes@362: { "movlpd", XM, EX, XX }, nkeynes@362: { "movddup", XM, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP31 */ nkeynes@362: { nkeynes@362: { "movhpX", XM, EX, SIMD_Fixup, 'l' }, nkeynes@362: { "movshdup", XM, EX, XX }, nkeynes@362: { "movhpd", XM, EX, XX }, nkeynes@362: { "(bad)", XM, EX, XX }, nkeynes@362: }, nkeynes@362: /* PREGRP32 */ nkeynes@362: { nkeynes@362: { "(bad)", XM, EX, XX }, nkeynes@362: { "(bad)", XM, EX, XX }, nkeynes@362: { "(bad)", XM, EX, XX }, nkeynes@362: { "lddqu", XM, M, XX }, nkeynes@362: }, nkeynes@362: }; nkeynes@362: nkeynes@362: static const struct dis386 x86_64_table[][2] = { nkeynes@362: { nkeynes@362: { "arpl", Ew, Gw, XX }, nkeynes@362: { "movs{||lq|xd}", Gv, Ed, XX }, nkeynes@362: }, nkeynes@362: }; nkeynes@362: nkeynes@362: #define INTERNAL_DISASSEMBLER_ERROR _("") nkeynes@362: nkeynes@362: static void nkeynes@362: ckprefix (void) nkeynes@362: { nkeynes@362: int newrex; nkeynes@362: rex = 0; nkeynes@362: prefixes = 0; nkeynes@362: used_prefixes = 0; nkeynes@362: rex_used = 0; nkeynes@362: while (1) nkeynes@362: { nkeynes@362: FETCH_DATA (the_info, codep + 1); nkeynes@362: newrex = 0; nkeynes@362: switch (*codep) nkeynes@362: { nkeynes@362: /* REX prefixes family. */ nkeynes@362: case 0x40: nkeynes@362: case 0x41: nkeynes@362: case 0x42: nkeynes@362: case 0x43: nkeynes@362: case 0x44: nkeynes@362: case 0x45: nkeynes@362: case 0x46: nkeynes@362: case 0x47: nkeynes@362: case 0x48: nkeynes@362: case 0x49: nkeynes@362: case 0x4a: nkeynes@362: case 0x4b: nkeynes@362: case 0x4c: nkeynes@362: case 0x4d: nkeynes@362: case 0x4e: nkeynes@362: case 0x4f: nkeynes@362: if (mode_64bit) nkeynes@362: newrex = *codep; nkeynes@362: else nkeynes@362: return; nkeynes@362: break; nkeynes@362: case 0xf3: nkeynes@362: prefixes |= PREFIX_REPZ; nkeynes@362: break; nkeynes@362: case 0xf2: nkeynes@362: prefixes |= PREFIX_REPNZ; nkeynes@362: break; nkeynes@362: case 0xf0: nkeynes@362: prefixes |= PREFIX_LOCK; nkeynes@362: break; nkeynes@362: case 0x2e: nkeynes@362: prefixes |= PREFIX_CS; nkeynes@362: break; nkeynes@362: case 0x36: nkeynes@362: prefixes |= PREFIX_SS; nkeynes@362: break; nkeynes@362: case 0x3e: nkeynes@362: prefixes |= PREFIX_DS; nkeynes@362: break; nkeynes@362: case 0x26: nkeynes@362: prefixes |= PREFIX_ES; nkeynes@362: break; nkeynes@362: case 0x64: nkeynes@362: prefixes |= PREFIX_FS; nkeynes@362: break; nkeynes@362: case 0x65: nkeynes@362: prefixes |= PREFIX_GS; nkeynes@362: break; nkeynes@362: case 0x66: nkeynes@362: prefixes |= PREFIX_DATA; nkeynes@362: break; nkeynes@362: case 0x67: nkeynes@362: prefixes |= PREFIX_ADDR; nkeynes@362: break; nkeynes@362: case FWAIT_OPCODE: nkeynes@362: /* fwait is really an instruction. If there are prefixes nkeynes@362: before the fwait, they belong to the fwait, *not* to the nkeynes@362: following instruction. */ nkeynes@362: if (prefixes) nkeynes@362: { nkeynes@362: prefixes |= PREFIX_FWAIT; nkeynes@362: codep++; nkeynes@362: return; nkeynes@362: } nkeynes@362: prefixes = PREFIX_FWAIT; nkeynes@362: break; nkeynes@362: default: nkeynes@362: return; nkeynes@362: } nkeynes@362: /* Rex is ignored when followed by another prefix. */ nkeynes@362: if (rex) nkeynes@362: { nkeynes@362: oappend (prefix_name (rex, 0)); nkeynes@362: oappend (" "); nkeynes@362: } nkeynes@362: rex = newrex; nkeynes@362: codep++; nkeynes@362: } nkeynes@362: } nkeynes@362: nkeynes@362: /* Return the name of the prefix byte PREF, or NULL if PREF is not a nkeynes@362: prefix byte. */ nkeynes@362: nkeynes@362: static const char * nkeynes@362: prefix_name (int pref, int sizeflag) nkeynes@362: { nkeynes@362: switch (pref) nkeynes@362: { nkeynes@362: /* REX prefixes family. */ nkeynes@362: case 0x40: nkeynes@362: return "rex"; nkeynes@362: case 0x41: nkeynes@362: return "rexZ"; nkeynes@362: case 0x42: nkeynes@362: return "rexY"; nkeynes@362: case 0x43: nkeynes@362: return "rexYZ"; nkeynes@362: case 0x44: nkeynes@362: return "rexX"; nkeynes@362: case 0x45: nkeynes@362: return "rexXZ"; nkeynes@362: case 0x46: nkeynes@362: return "rexXY"; nkeynes@362: case 0x47: nkeynes@362: return "rexXYZ"; nkeynes@362: case 0x48: nkeynes@362: return "rex64"; nkeynes@362: case 0x49: nkeynes@362: return "rex64Z"; nkeynes@362: case 0x4a: nkeynes@362: return "rex64Y"; nkeynes@362: case 0x4b: nkeynes@362: return "rex64YZ"; nkeynes@362: case 0x4c: nkeynes@362: return "rex64X"; nkeynes@362: case 0x4d: nkeynes@362: return "rex64XZ"; nkeynes@362: case 0x4e: nkeynes@362: return "rex64XY"; nkeynes@362: case 0x4f: nkeynes@362: return "rex64XYZ"; nkeynes@362: case 0xf3: nkeynes@362: return "repz"; nkeynes@362: case 0xf2: nkeynes@362: return "repnz"; nkeynes@362: case 0xf0: nkeynes@362: return "lock"; nkeynes@362: case 0x2e: nkeynes@362: return "cs"; nkeynes@362: case 0x36: nkeynes@362: return "ss"; nkeynes@362: case 0x3e: nkeynes@362: return "ds"; nkeynes@362: case 0x26: nkeynes@362: return "es"; nkeynes@362: case 0x64: nkeynes@362: return "fs"; nkeynes@362: case 0x65: nkeynes@362: return "gs"; nkeynes@362: case 0x66: nkeynes@362: return (sizeflag & DFLAG) ? "data16" : "data32"; nkeynes@362: case 0x67: nkeynes@362: if (mode_64bit) nkeynes@362: return (sizeflag & AFLAG) ? "addr32" : "addr64"; nkeynes@362: else nkeynes@362: return ((sizeflag & AFLAG) && !mode_64bit) ? "addr16" : "addr32"; nkeynes@362: case FWAIT_OPCODE: nkeynes@362: return "fwait"; nkeynes@362: default: nkeynes@362: return NULL; nkeynes@362: } nkeynes@362: } nkeynes@362: nkeynes@362: static char op1out[100], op2out[100], op3out[100]; nkeynes@362: static int op_ad, op_index[3]; nkeynes@362: static int two_source_ops; nkeynes@362: static bfd_vma op_address[3]; nkeynes@362: static bfd_vma op_riprel[3]; nkeynes@362: static bfd_vma start_pc; nkeynes@362: nkeynes@362: /* nkeynes@362: * On the 386's of 1988, the maximum length of an instruction is 15 bytes. nkeynes@362: * (see topic "Redundant prefixes" in the "Differences from 8086" nkeynes@362: * section of the "Virtual 8086 Mode" chapter.) nkeynes@362: * 'pc' should be the address of this instruction, it will nkeynes@362: * be used to print the target address if this is a relative jump or call nkeynes@362: * The function returns the length of this instruction in bytes. nkeynes@362: */ nkeynes@362: nkeynes@362: static char intel_syntax; nkeynes@362: static char open_char; nkeynes@362: static char close_char; nkeynes@362: static char separator_char; nkeynes@362: static char scale_char; nkeynes@362: nkeynes@362: /* Here for backwards compatibility. When gdb stops using nkeynes@362: print_insn_i386_att and print_insn_i386_intel these functions can nkeynes@362: disappear, and print_insn_i386 be merged into print_insn. */ nkeynes@362: int nkeynes@362: print_insn_i386_att (bfd_vma pc, disassemble_info *info) nkeynes@362: { nkeynes@362: intel_syntax = 0; nkeynes@362: nkeynes@362: return print_insn (pc, info); nkeynes@362: } nkeynes@362: nkeynes@362: int nkeynes@362: print_insn_i386_intel (bfd_vma pc, disassemble_info *info) nkeynes@362: { nkeynes@362: intel_syntax = 1; nkeynes@362: nkeynes@362: return print_insn (pc, info); nkeynes@362: } nkeynes@362: nkeynes@362: int nkeynes@362: print_insn_i386 (bfd_vma pc, disassemble_info *info) nkeynes@362: { nkeynes@362: intel_syntax = -1; nkeynes@362: nkeynes@362: return print_insn (pc, info); nkeynes@362: } nkeynes@362: nkeynes@362: static int nkeynes@362: print_insn (bfd_vma pc, disassemble_info *info) nkeynes@362: { nkeynes@362: const struct dis386 *dp; nkeynes@362: int i; nkeynes@362: char *first, *second, *third; nkeynes@362: int needcomma; nkeynes@362: unsigned char uses_SSE_prefix, uses_LOCK_prefix; nkeynes@362: int sizeflag; nkeynes@362: const char *p; nkeynes@362: struct dis_private priv; nkeynes@362: nkeynes@362: mode_64bit = (info->mach == bfd_mach_x86_64_intel_syntax nkeynes@362: || info->mach == bfd_mach_x86_64); nkeynes@362: nkeynes@362: if (intel_syntax == (char) -1) nkeynes@362: intel_syntax = (info->mach == bfd_mach_i386_i386_intel_syntax nkeynes@362: || info->mach == bfd_mach_x86_64_intel_syntax); nkeynes@362: nkeynes@362: if (info->mach == bfd_mach_i386_i386 nkeynes@362: || info->mach == bfd_mach_x86_64 nkeynes@362: || info->mach == bfd_mach_i386_i386_intel_syntax nkeynes@362: || info->mach == bfd_mach_x86_64_intel_syntax) nkeynes@362: priv.orig_sizeflag = AFLAG | DFLAG; nkeynes@362: else if (info->mach == bfd_mach_i386_i8086) nkeynes@362: priv.orig_sizeflag = 0; nkeynes@362: else nkeynes@362: abort (); nkeynes@362: nkeynes@362: for (p = info->disassembler_options; p != NULL; ) nkeynes@362: { nkeynes@362: if (strncmp (p, "x86-64", 6) == 0) nkeynes@362: { nkeynes@362: mode_64bit = 1; nkeynes@362: priv.orig_sizeflag = AFLAG | DFLAG; nkeynes@362: } nkeynes@362: else if (strncmp (p, "i386", 4) == 0) nkeynes@362: { nkeynes@362: mode_64bit = 0; nkeynes@362: priv.orig_sizeflag = AFLAG | DFLAG; nkeynes@362: } nkeynes@362: else if (strncmp (p, "i8086", 5) == 0) nkeynes@362: { nkeynes@362: mode_64bit = 0; nkeynes@362: priv.orig_sizeflag = 0; nkeynes@362: } nkeynes@362: else if (strncmp (p, "intel", 5) == 0) nkeynes@362: { nkeynes@362: intel_syntax = 1; nkeynes@362: } nkeynes@362: else if (strncmp (p, "att", 3) == 0) nkeynes@362: { nkeynes@362: intel_syntax = 0; nkeynes@362: } nkeynes@362: else if (strncmp (p, "addr", 4) == 0) nkeynes@362: { nkeynes@362: if (p[4] == '1' && p[5] == '6') nkeynes@362: priv.orig_sizeflag &= ~AFLAG; nkeynes@362: else if (p[4] == '3' && p[5] == '2') nkeynes@362: priv.orig_sizeflag |= AFLAG; nkeynes@362: } nkeynes@362: else if (strncmp (p, "data", 4) == 0) nkeynes@362: { nkeynes@362: if (p[4] == '1' && p[5] == '6') nkeynes@362: priv.orig_sizeflag &= ~DFLAG; nkeynes@362: else if (p[4] == '3' && p[5] == '2') nkeynes@362: priv.orig_sizeflag |= DFLAG; nkeynes@362: } nkeynes@362: else if (strncmp (p, "suffix", 6) == 0) nkeynes@362: priv.orig_sizeflag |= SUFFIX_ALWAYS; nkeynes@362: nkeynes@362: p = strchr (p, ','); nkeynes@362: if (p != NULL) nkeynes@362: p++; nkeynes@362: } nkeynes@362: nkeynes@362: if (intel_syntax) nkeynes@362: { nkeynes@362: names64 = intel_names64; nkeynes@362: names32 = intel_names32; nkeynes@362: names16 = intel_names16; nkeynes@362: names8 = intel_names8; nkeynes@362: names8rex = intel_names8rex; nkeynes@362: names_seg = intel_names_seg; nkeynes@362: index16 = intel_index16; nkeynes@362: open_char = '['; nkeynes@362: close_char = ']'; nkeynes@362: separator_char = '+'; nkeynes@362: scale_char = '*'; nkeynes@362: } nkeynes@362: else nkeynes@362: { nkeynes@362: names64 = att_names64; nkeynes@362: names32 = att_names32; nkeynes@362: names16 = att_names16; nkeynes@362: names8 = att_names8; nkeynes@362: names8rex = att_names8rex; nkeynes@362: names_seg = att_names_seg; nkeynes@362: index16 = att_index16; nkeynes@362: open_char = '('; nkeynes@362: close_char = ')'; nkeynes@362: separator_char = ','; nkeynes@362: scale_char = ','; nkeynes@362: } nkeynes@362: nkeynes@362: /* The output looks better if we put 7 bytes on a line, since that nkeynes@362: puts most long word instructions on a single line. */ nkeynes@362: info->bytes_per_line = 7; nkeynes@362: nkeynes@362: info->private_data = &priv; nkeynes@362: priv.max_fetched = priv.the_buffer; nkeynes@362: priv.insn_start = pc; nkeynes@362: nkeynes@362: obuf[0] = 0; nkeynes@362: op1out[0] = 0; nkeynes@362: op2out[0] = 0; nkeynes@362: op3out[0] = 0; nkeynes@362: nkeynes@362: op_index[0] = op_index[1] = op_index[2] = -1; nkeynes@362: nkeynes@362: the_info = info; nkeynes@362: start_pc = pc; nkeynes@362: start_codep = priv.the_buffer; nkeynes@362: codep = priv.the_buffer; nkeynes@362: nkeynes@362: if (setjmp (priv.bailout) != 0) nkeynes@362: { nkeynes@362: const char *name; nkeynes@362: nkeynes@362: /* Getting here means we tried for data but didn't get it. That nkeynes@362: means we have an incomplete instruction of some sort. Just nkeynes@362: print the first byte as a prefix or a .byte pseudo-op. */ nkeynes@362: if (codep > priv.the_buffer) nkeynes@362: { nkeynes@362: name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); nkeynes@362: if (name != NULL) nkeynes@362: (*info->fprintf_func) (info->stream, "%s", name); nkeynes@362: else nkeynes@362: { nkeynes@362: /* Just print the first byte as a .byte instruction. */ nkeynes@362: (*info->fprintf_func) (info->stream, ".byte 0x%x", nkeynes@362: (unsigned int) priv.the_buffer[0]); nkeynes@362: } nkeynes@362: nkeynes@362: return 1; nkeynes@362: } nkeynes@362: nkeynes@362: return -1; nkeynes@362: } nkeynes@362: nkeynes@362: obufp = obuf; nkeynes@362: ckprefix (); nkeynes@362: nkeynes@362: insn_codep = codep; nkeynes@362: sizeflag = priv.orig_sizeflag; nkeynes@362: nkeynes@362: FETCH_DATA (info, codep + 1); nkeynes@362: two_source_ops = (*codep == 0x62) || (*codep == 0xc8); nkeynes@362: nkeynes@362: if ((prefixes & PREFIX_FWAIT) nkeynes@362: && ((*codep < 0xd8) || (*codep > 0xdf))) nkeynes@362: { nkeynes@362: const char *name; nkeynes@362: nkeynes@362: /* fwait not followed by floating point instruction. Print the nkeynes@362: first prefix, which is probably fwait itself. */ nkeynes@362: name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); nkeynes@362: if (name == NULL) nkeynes@362: name = INTERNAL_DISASSEMBLER_ERROR; nkeynes@362: (*info->fprintf_func) (info->stream, "%s", name); nkeynes@362: return 1; nkeynes@362: } nkeynes@362: nkeynes@362: if (*codep == 0x0f) nkeynes@362: { nkeynes@362: FETCH_DATA (info, codep + 2); nkeynes@362: dp = &dis386_twobyte[*++codep]; nkeynes@362: need_modrm = twobyte_has_modrm[*codep]; nkeynes@362: uses_SSE_prefix = twobyte_uses_SSE_prefix[*codep]; nkeynes@362: uses_LOCK_prefix = (*codep & ~0x02) == 0x20; nkeynes@362: } nkeynes@362: else nkeynes@362: { nkeynes@362: dp = &dis386[*codep]; nkeynes@362: need_modrm = onebyte_has_modrm[*codep]; nkeynes@362: uses_SSE_prefix = 0; nkeynes@362: uses_LOCK_prefix = 0; nkeynes@362: } nkeynes@362: codep++; nkeynes@362: nkeynes@362: if (!uses_SSE_prefix && (prefixes & PREFIX_REPZ)) nkeynes@362: { nkeynes@362: oappend ("repz "); nkeynes@362: used_prefixes |= PREFIX_REPZ; nkeynes@362: } nkeynes@362: if (!uses_SSE_prefix && (prefixes & PREFIX_REPNZ)) nkeynes@362: { nkeynes@362: oappend ("repnz "); nkeynes@362: used_prefixes |= PREFIX_REPNZ; nkeynes@362: } nkeynes@362: if (!uses_LOCK_prefix && (prefixes & PREFIX_LOCK)) nkeynes@362: { nkeynes@362: oappend ("lock "); nkeynes@362: used_prefixes |= PREFIX_LOCK; nkeynes@362: } nkeynes@362: nkeynes@362: if (prefixes & PREFIX_ADDR) nkeynes@362: { nkeynes@362: sizeflag ^= AFLAG; nkeynes@362: if (dp->bytemode3 != loop_jcxz_mode || intel_syntax) nkeynes@362: { nkeynes@362: if ((sizeflag & AFLAG) || mode_64bit) nkeynes@362: oappend ("addr32 "); nkeynes@362: else nkeynes@362: oappend ("addr16 "); nkeynes@362: used_prefixes |= PREFIX_ADDR; nkeynes@362: } nkeynes@362: } nkeynes@362: nkeynes@362: if (!uses_SSE_prefix && (prefixes & PREFIX_DATA)) nkeynes@362: { nkeynes@362: sizeflag ^= DFLAG; nkeynes@362: if (dp->bytemode3 == cond_jump_mode nkeynes@362: && dp->bytemode1 == v_mode nkeynes@362: && !intel_syntax) nkeynes@362: { nkeynes@362: if (sizeflag & DFLAG) nkeynes@362: oappend ("data32 "); nkeynes@362: else nkeynes@362: oappend ("data16 "); nkeynes@362: used_prefixes |= PREFIX_DATA; nkeynes@362: } nkeynes@362: } nkeynes@362: nkeynes@362: if (need_modrm) nkeynes@362: { nkeynes@362: FETCH_DATA (info, codep + 1); nkeynes@362: mod = (*codep >> 6) & 3; nkeynes@362: reg = (*codep >> 3) & 7; nkeynes@362: rm = *codep & 7; nkeynes@362: } nkeynes@362: nkeynes@362: if (dp->name == NULL && dp->bytemode1 == FLOATCODE) nkeynes@362: { nkeynes@362: dofloat (sizeflag); nkeynes@362: } nkeynes@362: else nkeynes@362: { nkeynes@362: int index; nkeynes@362: if (dp->name == NULL) nkeynes@362: { nkeynes@362: switch (dp->bytemode1) nkeynes@362: { nkeynes@362: case USE_GROUPS: nkeynes@362: dp = &grps[dp->bytemode2][reg]; nkeynes@362: break; nkeynes@362: nkeynes@362: case USE_PREFIX_USER_TABLE: nkeynes@362: index = 0; nkeynes@362: used_prefixes |= (prefixes & PREFIX_REPZ); nkeynes@362: if (prefixes & PREFIX_REPZ) nkeynes@362: index = 1; nkeynes@362: else nkeynes@362: { nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: if (prefixes & PREFIX_DATA) nkeynes@362: index = 2; nkeynes@362: else nkeynes@362: { nkeynes@362: used_prefixes |= (prefixes & PREFIX_REPNZ); nkeynes@362: if (prefixes & PREFIX_REPNZ) nkeynes@362: index = 3; nkeynes@362: } nkeynes@362: } nkeynes@362: dp = &prefix_user_table[dp->bytemode2][index]; nkeynes@362: break; nkeynes@362: nkeynes@362: case X86_64_SPECIAL: nkeynes@362: dp = &x86_64_table[dp->bytemode2][mode_64bit]; nkeynes@362: break; nkeynes@362: nkeynes@362: default: nkeynes@362: oappend (INTERNAL_DISASSEMBLER_ERROR); nkeynes@362: break; nkeynes@362: } nkeynes@362: } nkeynes@362: nkeynes@362: if (putop (dp->name, sizeflag) == 0) nkeynes@362: { nkeynes@362: obufp = op1out; nkeynes@362: op_ad = 2; nkeynes@362: if (dp->op1) nkeynes@362: (*dp->op1) (dp->bytemode1, sizeflag); nkeynes@362: nkeynes@362: obufp = op2out; nkeynes@362: op_ad = 1; nkeynes@362: if (dp->op2) nkeynes@362: (*dp->op2) (dp->bytemode2, sizeflag); nkeynes@362: nkeynes@362: obufp = op3out; nkeynes@362: op_ad = 0; nkeynes@362: if (dp->op3) nkeynes@362: (*dp->op3) (dp->bytemode3, sizeflag); nkeynes@362: } nkeynes@362: } nkeynes@362: nkeynes@362: /* See if any prefixes were not used. If so, print the first one nkeynes@362: separately. If we don't do this, we'll wind up printing an nkeynes@362: instruction stream which does not precisely correspond to the nkeynes@362: bytes we are disassembling. */ nkeynes@362: if ((prefixes & ~used_prefixes) != 0) nkeynes@362: { nkeynes@362: const char *name; nkeynes@362: nkeynes@362: name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); nkeynes@362: if (name == NULL) nkeynes@362: name = INTERNAL_DISASSEMBLER_ERROR; nkeynes@362: (*info->fprintf_func) (info->stream, "%s", name); nkeynes@362: return 1; nkeynes@362: } nkeynes@362: if (rex & ~rex_used) nkeynes@362: { nkeynes@362: const char *name; nkeynes@362: name = prefix_name (rex | 0x40, priv.orig_sizeflag); nkeynes@362: if (name == NULL) nkeynes@362: name = INTERNAL_DISASSEMBLER_ERROR; nkeynes@362: (*info->fprintf_func) (info->stream, "%s ", name); nkeynes@362: } nkeynes@362: nkeynes@362: obufp = obuf + strlen (obuf); nkeynes@362: for (i = strlen (obuf); i < 6; i++) nkeynes@362: oappend (" "); nkeynes@362: oappend (" "); nkeynes@362: (*info->fprintf_func) (info->stream, "%s", obuf); nkeynes@362: nkeynes@362: /* The enter and bound instructions are printed with operands in the same nkeynes@362: order as the intel book; everything else is printed in reverse order. */ nkeynes@362: if (intel_syntax || two_source_ops) nkeynes@362: { nkeynes@362: first = op1out; nkeynes@362: second = op2out; nkeynes@362: third = op3out; nkeynes@362: op_ad = op_index[0]; nkeynes@362: op_index[0] = op_index[2]; nkeynes@362: op_index[2] = op_ad; nkeynes@362: } nkeynes@362: else nkeynes@362: { nkeynes@362: first = op3out; nkeynes@362: second = op2out; nkeynes@362: third = op1out; nkeynes@362: } nkeynes@362: needcomma = 0; nkeynes@362: if (*first) nkeynes@362: { nkeynes@362: if (op_index[0] != -1 && !op_riprel[0]) nkeynes@362: (*info->print_address_func) ((bfd_vma) op_address[op_index[0]], info); nkeynes@362: else nkeynes@362: (*info->fprintf_func) (info->stream, "%s", first); nkeynes@362: needcomma = 1; nkeynes@362: } nkeynes@362: if (*second) nkeynes@362: { nkeynes@362: if (needcomma) nkeynes@362: (*info->fprintf_func) (info->stream, ","); nkeynes@362: if (op_index[1] != -1 && !op_riprel[1]) nkeynes@362: (*info->print_address_func) ((bfd_vma) op_address[op_index[1]], info); nkeynes@362: else nkeynes@362: (*info->fprintf_func) (info->stream, "%s", second); nkeynes@362: needcomma = 1; nkeynes@362: } nkeynes@362: if (*third) nkeynes@362: { nkeynes@362: if (needcomma) nkeynes@362: (*info->fprintf_func) (info->stream, ","); nkeynes@362: if (op_index[2] != -1 && !op_riprel[2]) nkeynes@362: (*info->print_address_func) ((bfd_vma) op_address[op_index[2]], info); nkeynes@362: else nkeynes@362: (*info->fprintf_func) (info->stream, "%s", third); nkeynes@362: } nkeynes@362: for (i = 0; i < 3; i++) nkeynes@362: if (op_index[i] != -1 && op_riprel[i]) nkeynes@362: { nkeynes@362: (*info->fprintf_func) (info->stream, " # "); nkeynes@362: (*info->print_address_func) ((bfd_vma) (start_pc + codep - start_codep nkeynes@362: + op_address[op_index[i]]), info); nkeynes@362: } nkeynes@362: return codep - priv.the_buffer; nkeynes@362: } nkeynes@362: nkeynes@362: static const char *float_mem[] = { nkeynes@362: /* d8 */ nkeynes@362: "fadd{s||s|}", nkeynes@362: "fmul{s||s|}", nkeynes@362: "fcom{s||s|}", nkeynes@362: "fcomp{s||s|}", nkeynes@362: "fsub{s||s|}", nkeynes@362: "fsubr{s||s|}", nkeynes@362: "fdiv{s||s|}", nkeynes@362: "fdivr{s||s|}", nkeynes@362: /* d9 */ nkeynes@362: "fld{s||s|}", nkeynes@362: "(bad)", nkeynes@362: "fst{s||s|}", nkeynes@362: "fstp{s||s|}", nkeynes@362: "fldenvIC", nkeynes@362: "fldcw", nkeynes@362: "fNstenvIC", nkeynes@362: "fNstcw", nkeynes@362: /* da */ nkeynes@362: "fiadd{l||l|}", nkeynes@362: "fimul{l||l|}", nkeynes@362: "ficom{l||l|}", nkeynes@362: "ficomp{l||l|}", nkeynes@362: "fisub{l||l|}", nkeynes@362: "fisubr{l||l|}", nkeynes@362: "fidiv{l||l|}", nkeynes@362: "fidivr{l||l|}", nkeynes@362: /* db */ nkeynes@362: "fild{l||l|}", nkeynes@362: "fisttp{l||l|}", nkeynes@362: "fist{l||l|}", nkeynes@362: "fistp{l||l|}", nkeynes@362: "(bad)", nkeynes@362: "fld{t||t|}", nkeynes@362: "(bad)", nkeynes@362: "fstp{t||t|}", nkeynes@362: /* dc */ nkeynes@362: "fadd{l||l|}", nkeynes@362: "fmul{l||l|}", nkeynes@362: "fcom{l||l|}", nkeynes@362: "fcomp{l||l|}", nkeynes@362: "fsub{l||l|}", nkeynes@362: "fsubr{l||l|}", nkeynes@362: "fdiv{l||l|}", nkeynes@362: "fdivr{l||l|}", nkeynes@362: /* dd */ nkeynes@362: "fld{l||l|}", nkeynes@362: "fisttp{ll||ll|}", nkeynes@362: "fst{l||l|}", nkeynes@362: "fstp{l||l|}", nkeynes@362: "frstorIC", nkeynes@362: "(bad)", nkeynes@362: "fNsaveIC", nkeynes@362: "fNstsw", nkeynes@362: /* de */ nkeynes@362: "fiadd", nkeynes@362: "fimul", nkeynes@362: "ficom", nkeynes@362: "ficomp", nkeynes@362: "fisub", nkeynes@362: "fisubr", nkeynes@362: "fidiv", nkeynes@362: "fidivr", nkeynes@362: /* df */ nkeynes@362: "fild", nkeynes@362: "fisttp", nkeynes@362: "fist", nkeynes@362: "fistp", nkeynes@362: "fbld", nkeynes@362: "fild{ll||ll|}", nkeynes@362: "fbstp", nkeynes@362: "fistp{ll||ll|}", nkeynes@362: }; nkeynes@362: nkeynes@362: static const unsigned char float_mem_mode[] = { nkeynes@362: /* d8 */ nkeynes@362: d_mode, nkeynes@362: d_mode, nkeynes@362: d_mode, nkeynes@362: d_mode, nkeynes@362: d_mode, nkeynes@362: d_mode, nkeynes@362: d_mode, nkeynes@362: d_mode, nkeynes@362: /* d9 */ nkeynes@362: d_mode, nkeynes@362: 0, nkeynes@362: d_mode, nkeynes@362: d_mode, nkeynes@362: 0, nkeynes@362: w_mode, nkeynes@362: 0, nkeynes@362: w_mode, nkeynes@362: /* da */ nkeynes@362: d_mode, nkeynes@362: d_mode, nkeynes@362: d_mode, nkeynes@362: d_mode, nkeynes@362: d_mode, nkeynes@362: d_mode, nkeynes@362: d_mode, nkeynes@362: d_mode, nkeynes@362: /* db */ nkeynes@362: d_mode, nkeynes@362: d_mode, nkeynes@362: d_mode, nkeynes@362: d_mode, nkeynes@362: 0, nkeynes@362: t_mode, nkeynes@362: 0, nkeynes@362: t_mode, nkeynes@362: /* dc */ nkeynes@362: q_mode, nkeynes@362: q_mode, nkeynes@362: q_mode, nkeynes@362: q_mode, nkeynes@362: q_mode, nkeynes@362: q_mode, nkeynes@362: q_mode, nkeynes@362: q_mode, nkeynes@362: /* dd */ nkeynes@362: q_mode, nkeynes@362: q_mode, nkeynes@362: q_mode, nkeynes@362: q_mode, nkeynes@362: 0, nkeynes@362: 0, nkeynes@362: 0, nkeynes@362: w_mode, nkeynes@362: /* de */ nkeynes@362: w_mode, nkeynes@362: w_mode, nkeynes@362: w_mode, nkeynes@362: w_mode, nkeynes@362: w_mode, nkeynes@362: w_mode, nkeynes@362: w_mode, nkeynes@362: w_mode, nkeynes@362: /* df */ nkeynes@362: w_mode, nkeynes@362: w_mode, nkeynes@362: w_mode, nkeynes@362: w_mode, nkeynes@362: t_mode, nkeynes@362: q_mode, nkeynes@362: t_mode, nkeynes@362: q_mode nkeynes@362: }; nkeynes@362: nkeynes@362: #define ST OP_ST, 0 nkeynes@362: #define STi OP_STi, 0 nkeynes@362: nkeynes@362: #define FGRPd9_2 NULL, NULL, 0, NULL, 0, NULL, 0 nkeynes@362: #define FGRPd9_4 NULL, NULL, 1, NULL, 0, NULL, 0 nkeynes@362: #define FGRPd9_5 NULL, NULL, 2, NULL, 0, NULL, 0 nkeynes@362: #define FGRPd9_6 NULL, NULL, 3, NULL, 0, NULL, 0 nkeynes@362: #define FGRPd9_7 NULL, NULL, 4, NULL, 0, NULL, 0 nkeynes@362: #define FGRPda_5 NULL, NULL, 5, NULL, 0, NULL, 0 nkeynes@362: #define FGRPdb_4 NULL, NULL, 6, NULL, 0, NULL, 0 nkeynes@362: #define FGRPde_3 NULL, NULL, 7, NULL, 0, NULL, 0 nkeynes@362: #define FGRPdf_4 NULL, NULL, 8, NULL, 0, NULL, 0 nkeynes@362: nkeynes@362: static const struct dis386 float_reg[][8] = { nkeynes@362: /* d8 */ nkeynes@362: { nkeynes@362: { "fadd", ST, STi, XX }, nkeynes@362: { "fmul", ST, STi, XX }, nkeynes@362: { "fcom", STi, XX, XX }, nkeynes@362: { "fcomp", STi, XX, XX }, nkeynes@362: { "fsub", ST, STi, XX }, nkeynes@362: { "fsubr", ST, STi, XX }, nkeynes@362: { "fdiv", ST, STi, XX }, nkeynes@362: { "fdivr", ST, STi, XX }, nkeynes@362: }, nkeynes@362: /* d9 */ nkeynes@362: { nkeynes@362: { "fld", STi, XX, XX }, nkeynes@362: { "fxch", STi, XX, XX }, nkeynes@362: { FGRPd9_2 }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { FGRPd9_4 }, nkeynes@362: { FGRPd9_5 }, nkeynes@362: { FGRPd9_6 }, nkeynes@362: { FGRPd9_7 }, nkeynes@362: }, nkeynes@362: /* da */ nkeynes@362: { nkeynes@362: { "fcmovb", ST, STi, XX }, nkeynes@362: { "fcmove", ST, STi, XX }, nkeynes@362: { "fcmovbe",ST, STi, XX }, nkeynes@362: { "fcmovu", ST, STi, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { FGRPda_5 }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: }, nkeynes@362: /* db */ nkeynes@362: { nkeynes@362: { "fcmovnb",ST, STi, XX }, nkeynes@362: { "fcmovne",ST, STi, XX }, nkeynes@362: { "fcmovnbe",ST, STi, XX }, nkeynes@362: { "fcmovnu",ST, STi, XX }, nkeynes@362: { FGRPdb_4 }, nkeynes@362: { "fucomi", ST, STi, XX }, nkeynes@362: { "fcomi", ST, STi, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: }, nkeynes@362: /* dc */ nkeynes@362: { nkeynes@362: { "fadd", STi, ST, XX }, nkeynes@362: { "fmul", STi, ST, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: #if UNIXWARE_COMPAT nkeynes@362: { "fsub", STi, ST, XX }, nkeynes@362: { "fsubr", STi, ST, XX }, nkeynes@362: { "fdiv", STi, ST, XX }, nkeynes@362: { "fdivr", STi, ST, XX }, nkeynes@362: #else nkeynes@362: { "fsubr", STi, ST, XX }, nkeynes@362: { "fsub", STi, ST, XX }, nkeynes@362: { "fdivr", STi, ST, XX }, nkeynes@362: { "fdiv", STi, ST, XX }, nkeynes@362: #endif nkeynes@362: }, nkeynes@362: /* dd */ nkeynes@362: { nkeynes@362: { "ffree", STi, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "fst", STi, XX, XX }, nkeynes@362: { "fstp", STi, XX, XX }, nkeynes@362: { "fucom", STi, XX, XX }, nkeynes@362: { "fucomp", STi, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: }, nkeynes@362: /* de */ nkeynes@362: { nkeynes@362: { "faddp", STi, ST, XX }, nkeynes@362: { "fmulp", STi, ST, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { FGRPde_3 }, nkeynes@362: #if UNIXWARE_COMPAT nkeynes@362: { "fsubp", STi, ST, XX }, nkeynes@362: { "fsubrp", STi, ST, XX }, nkeynes@362: { "fdivp", STi, ST, XX }, nkeynes@362: { "fdivrp", STi, ST, XX }, nkeynes@362: #else nkeynes@362: { "fsubrp", STi, ST, XX }, nkeynes@362: { "fsubp", STi, ST, XX }, nkeynes@362: { "fdivrp", STi, ST, XX }, nkeynes@362: { "fdivp", STi, ST, XX }, nkeynes@362: #endif nkeynes@362: }, nkeynes@362: /* df */ nkeynes@362: { nkeynes@362: { "ffreep", STi, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: { FGRPdf_4 }, nkeynes@362: { "fucomip",ST, STi, XX }, nkeynes@362: { "fcomip", ST, STi, XX }, nkeynes@362: { "(bad)", XX, XX, XX }, nkeynes@362: }, nkeynes@362: }; nkeynes@362: nkeynes@362: static char *fgrps[][8] = { nkeynes@362: /* d9_2 0 */ nkeynes@362: { nkeynes@362: "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", nkeynes@362: }, nkeynes@362: nkeynes@362: /* d9_4 1 */ nkeynes@362: { nkeynes@362: "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)", nkeynes@362: }, nkeynes@362: nkeynes@362: /* d9_5 2 */ nkeynes@362: { nkeynes@362: "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)", nkeynes@362: }, nkeynes@362: nkeynes@362: /* d9_6 3 */ nkeynes@362: { nkeynes@362: "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp", nkeynes@362: }, nkeynes@362: nkeynes@362: /* d9_7 4 */ nkeynes@362: { nkeynes@362: "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos", nkeynes@362: }, nkeynes@362: nkeynes@362: /* da_5 5 */ nkeynes@362: { nkeynes@362: "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", nkeynes@362: }, nkeynes@362: nkeynes@362: /* db_4 6 */ nkeynes@362: { nkeynes@362: "feni(287 only)","fdisi(287 only)","fNclex","fNinit", nkeynes@362: "fNsetpm(287 only)","(bad)","(bad)","(bad)", nkeynes@362: }, nkeynes@362: nkeynes@362: /* de_3 7 */ nkeynes@362: { nkeynes@362: "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", nkeynes@362: }, nkeynes@362: nkeynes@362: /* df_4 8 */ nkeynes@362: { nkeynes@362: "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", nkeynes@362: }, nkeynes@362: }; nkeynes@362: nkeynes@362: static void nkeynes@362: dofloat (int sizeflag) nkeynes@362: { nkeynes@362: const struct dis386 *dp; nkeynes@362: unsigned char floatop; nkeynes@362: nkeynes@362: floatop = codep[-1]; nkeynes@362: nkeynes@362: if (mod != 3) nkeynes@362: { nkeynes@362: int fp_indx = (floatop - 0xd8) * 8 + reg; nkeynes@362: nkeynes@362: putop (float_mem[fp_indx], sizeflag); nkeynes@362: obufp = op1out; nkeynes@362: OP_E (float_mem_mode[fp_indx], sizeflag); nkeynes@362: return; nkeynes@362: } nkeynes@362: /* Skip mod/rm byte. */ nkeynes@362: MODRM_CHECK; nkeynes@362: codep++; nkeynes@362: nkeynes@362: dp = &float_reg[floatop - 0xd8][reg]; nkeynes@362: if (dp->name == NULL) nkeynes@362: { nkeynes@362: putop (fgrps[dp->bytemode1][rm], sizeflag); nkeynes@362: nkeynes@362: /* Instruction fnstsw is only one with strange arg. */ nkeynes@362: if (floatop == 0xdf && codep[-1] == 0xe0) nkeynes@362: strcpy (op1out, names16[0]); nkeynes@362: } nkeynes@362: else nkeynes@362: { nkeynes@362: putop (dp->name, sizeflag); nkeynes@362: nkeynes@362: obufp = op1out; nkeynes@362: if (dp->op1) nkeynes@362: (*dp->op1) (dp->bytemode1, sizeflag); nkeynes@362: obufp = op2out; nkeynes@362: if (dp->op2) nkeynes@362: (*dp->op2) (dp->bytemode2, sizeflag); nkeynes@362: } nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_ST (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) nkeynes@362: { nkeynes@362: oappend ("%st"); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_STi (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) nkeynes@362: { nkeynes@362: sprintf (scratchbuf, "%%st(%d)", rm); nkeynes@362: oappend (scratchbuf + intel_syntax); nkeynes@362: } nkeynes@362: nkeynes@362: /* Capital letters in template are macros. */ nkeynes@362: static int nkeynes@362: putop (const char *template, int sizeflag) nkeynes@362: { nkeynes@362: const char *p; nkeynes@362: int alt = 0; nkeynes@362: nkeynes@362: for (p = template; *p; p++) nkeynes@362: { nkeynes@362: switch (*p) nkeynes@362: { nkeynes@362: default: nkeynes@362: *obufp++ = *p; nkeynes@362: break; nkeynes@362: case '{': nkeynes@362: alt = 0; nkeynes@362: if (intel_syntax) nkeynes@362: alt += 1; nkeynes@362: if (mode_64bit) nkeynes@362: alt += 2; nkeynes@362: while (alt != 0) nkeynes@362: { nkeynes@362: while (*++p != '|') nkeynes@362: { nkeynes@362: if (*p == '}') nkeynes@362: { nkeynes@362: /* Alternative not valid. */ nkeynes@362: strcpy (obuf, "(bad)"); nkeynes@362: obufp = obuf + 5; nkeynes@362: return 1; nkeynes@362: } nkeynes@362: else if (*p == '\0') nkeynes@362: abort (); nkeynes@362: } nkeynes@362: alt--; nkeynes@362: } nkeynes@362: /* Fall through. */ nkeynes@362: case 'I': nkeynes@362: alt = 1; nkeynes@362: continue; nkeynes@362: case '|': nkeynes@362: while (*++p != '}') nkeynes@362: { nkeynes@362: if (*p == '\0') nkeynes@362: abort (); nkeynes@362: } nkeynes@362: break; nkeynes@362: case '}': nkeynes@362: break; nkeynes@362: case 'A': nkeynes@362: if (intel_syntax) nkeynes@362: break; nkeynes@362: if (mod != 3 || (sizeflag & SUFFIX_ALWAYS)) nkeynes@362: *obufp++ = 'b'; nkeynes@362: break; nkeynes@362: case 'B': nkeynes@362: if (intel_syntax) nkeynes@362: break; nkeynes@362: if (sizeflag & SUFFIX_ALWAYS) nkeynes@362: *obufp++ = 'b'; nkeynes@362: break; nkeynes@362: case 'C': nkeynes@362: if (intel_syntax && !alt) nkeynes@362: break; nkeynes@362: if ((prefixes & PREFIX_DATA) || (sizeflag & SUFFIX_ALWAYS)) nkeynes@362: { nkeynes@362: if (sizeflag & DFLAG) nkeynes@362: *obufp++ = intel_syntax ? 'd' : 'l'; nkeynes@362: else nkeynes@362: *obufp++ = intel_syntax ? 'w' : 's'; nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: } nkeynes@362: break; nkeynes@362: case 'E': /* For jcxz/jecxz */ nkeynes@362: if (mode_64bit) nkeynes@362: { nkeynes@362: if (sizeflag & AFLAG) nkeynes@362: *obufp++ = 'r'; nkeynes@362: else nkeynes@362: *obufp++ = 'e'; nkeynes@362: } nkeynes@362: else nkeynes@362: if (sizeflag & AFLAG) nkeynes@362: *obufp++ = 'e'; nkeynes@362: used_prefixes |= (prefixes & PREFIX_ADDR); nkeynes@362: break; nkeynes@362: case 'F': nkeynes@362: if (intel_syntax) nkeynes@362: break; nkeynes@362: if ((prefixes & PREFIX_ADDR) || (sizeflag & SUFFIX_ALWAYS)) nkeynes@362: { nkeynes@362: if (sizeflag & AFLAG) nkeynes@362: *obufp++ = mode_64bit ? 'q' : 'l'; nkeynes@362: else nkeynes@362: *obufp++ = mode_64bit ? 'l' : 'w'; nkeynes@362: used_prefixes |= (prefixes & PREFIX_ADDR); nkeynes@362: } nkeynes@362: break; nkeynes@362: case 'H': nkeynes@362: if (intel_syntax) nkeynes@362: break; nkeynes@362: if ((prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_CS nkeynes@362: || (prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_DS) nkeynes@362: { nkeynes@362: used_prefixes |= prefixes & (PREFIX_CS | PREFIX_DS); nkeynes@362: *obufp++ = ','; nkeynes@362: *obufp++ = 'p'; nkeynes@362: if (prefixes & PREFIX_DS) nkeynes@362: *obufp++ = 't'; nkeynes@362: else nkeynes@362: *obufp++ = 'n'; nkeynes@362: } nkeynes@362: break; nkeynes@362: case 'J': nkeynes@362: if (intel_syntax) nkeynes@362: break; nkeynes@362: *obufp++ = 'l'; nkeynes@362: break; nkeynes@362: case 'L': nkeynes@362: if (intel_syntax) nkeynes@362: break; nkeynes@362: if (sizeflag & SUFFIX_ALWAYS) nkeynes@362: *obufp++ = 'l'; nkeynes@362: break; nkeynes@362: case 'N': nkeynes@362: if ((prefixes & PREFIX_FWAIT) == 0) nkeynes@362: *obufp++ = 'n'; nkeynes@362: else nkeynes@362: used_prefixes |= PREFIX_FWAIT; nkeynes@362: break; nkeynes@362: case 'O': nkeynes@362: USED_REX (REX_MODE64); nkeynes@362: if (rex & REX_MODE64) nkeynes@362: *obufp++ = 'o'; nkeynes@362: else nkeynes@362: *obufp++ = 'd'; nkeynes@362: break; nkeynes@362: case 'T': nkeynes@362: if (intel_syntax) nkeynes@362: break; nkeynes@362: if (mode_64bit) nkeynes@362: { nkeynes@362: *obufp++ = 'q'; nkeynes@362: break; nkeynes@362: } nkeynes@362: /* Fall through. */ nkeynes@362: case 'P': nkeynes@362: if (intel_syntax) nkeynes@362: break; nkeynes@362: if ((prefixes & PREFIX_DATA) nkeynes@362: || (rex & REX_MODE64) nkeynes@362: || (sizeflag & SUFFIX_ALWAYS)) nkeynes@362: { nkeynes@362: USED_REX (REX_MODE64); nkeynes@362: if (rex & REX_MODE64) nkeynes@362: *obufp++ = 'q'; nkeynes@362: else nkeynes@362: { nkeynes@362: if (sizeflag & DFLAG) nkeynes@362: *obufp++ = 'l'; nkeynes@362: else nkeynes@362: *obufp++ = 'w'; nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: } nkeynes@362: } nkeynes@362: break; nkeynes@362: case 'U': nkeynes@362: if (intel_syntax) nkeynes@362: break; nkeynes@362: if (mode_64bit) nkeynes@362: { nkeynes@362: *obufp++ = 'q'; nkeynes@362: break; nkeynes@362: } nkeynes@362: /* Fall through. */ nkeynes@362: case 'Q': nkeynes@362: if (intel_syntax && !alt) nkeynes@362: break; nkeynes@362: USED_REX (REX_MODE64); nkeynes@362: if (mod != 3 || (sizeflag & SUFFIX_ALWAYS)) nkeynes@362: { nkeynes@362: if (rex & REX_MODE64) nkeynes@362: *obufp++ = 'q'; nkeynes@362: else nkeynes@362: { nkeynes@362: if (sizeflag & DFLAG) nkeynes@362: *obufp++ = intel_syntax ? 'd' : 'l'; nkeynes@362: else nkeynes@362: *obufp++ = 'w'; nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: } nkeynes@362: } nkeynes@362: break; nkeynes@362: case 'R': nkeynes@362: USED_REX (REX_MODE64); nkeynes@362: if (intel_syntax) nkeynes@362: { nkeynes@362: if (rex & REX_MODE64) nkeynes@362: { nkeynes@362: *obufp++ = 'q'; nkeynes@362: *obufp++ = 't'; nkeynes@362: } nkeynes@362: else if (sizeflag & DFLAG) nkeynes@362: { nkeynes@362: *obufp++ = 'd'; nkeynes@362: *obufp++ = 'q'; nkeynes@362: } nkeynes@362: else nkeynes@362: { nkeynes@362: *obufp++ = 'w'; nkeynes@362: *obufp++ = 'd'; nkeynes@362: } nkeynes@362: } nkeynes@362: else nkeynes@362: { nkeynes@362: if (rex & REX_MODE64) nkeynes@362: *obufp++ = 'q'; nkeynes@362: else if (sizeflag & DFLAG) nkeynes@362: *obufp++ = 'l'; nkeynes@362: else nkeynes@362: *obufp++ = 'w'; nkeynes@362: } nkeynes@362: if (!(rex & REX_MODE64)) nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: break; nkeynes@362: case 'S': nkeynes@362: if (intel_syntax) nkeynes@362: break; nkeynes@362: if (sizeflag & SUFFIX_ALWAYS) nkeynes@362: { nkeynes@362: if (rex & REX_MODE64) nkeynes@362: *obufp++ = 'q'; nkeynes@362: else nkeynes@362: { nkeynes@362: if (sizeflag & DFLAG) nkeynes@362: *obufp++ = 'l'; nkeynes@362: else nkeynes@362: *obufp++ = 'w'; nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: } nkeynes@362: } nkeynes@362: break; nkeynes@362: case 'X': nkeynes@362: if (prefixes & PREFIX_DATA) nkeynes@362: *obufp++ = 'd'; nkeynes@362: else nkeynes@362: *obufp++ = 's'; nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: break; nkeynes@362: case 'Y': nkeynes@362: if (intel_syntax) nkeynes@362: break; nkeynes@362: if (rex & REX_MODE64) nkeynes@362: { nkeynes@362: USED_REX (REX_MODE64); nkeynes@362: *obufp++ = 'q'; nkeynes@362: } nkeynes@362: break; nkeynes@362: /* implicit operand size 'l' for i386 or 'q' for x86-64 */ nkeynes@362: case 'W': nkeynes@362: /* operand size flag for cwtl, cbtw */ nkeynes@362: USED_REX (0); nkeynes@362: if (rex) nkeynes@362: *obufp++ = 'l'; nkeynes@362: else if (sizeflag & DFLAG) nkeynes@362: *obufp++ = 'w'; nkeynes@362: else nkeynes@362: *obufp++ = 'b'; nkeynes@362: if (intel_syntax) nkeynes@362: { nkeynes@362: if (rex) nkeynes@362: { nkeynes@362: *obufp++ = 'q'; nkeynes@362: *obufp++ = 'e'; nkeynes@362: } nkeynes@362: if (sizeflag & DFLAG) nkeynes@362: { nkeynes@362: *obufp++ = 'd'; nkeynes@362: *obufp++ = 'e'; nkeynes@362: } nkeynes@362: else nkeynes@362: { nkeynes@362: *obufp++ = 'w'; nkeynes@362: } nkeynes@362: } nkeynes@362: if (!rex) nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: break; nkeynes@362: } nkeynes@362: alt = 0; nkeynes@362: } nkeynes@362: *obufp = 0; nkeynes@362: return 0; nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: oappend (const char *s) nkeynes@362: { nkeynes@362: strcpy (obufp, s); nkeynes@362: obufp += strlen (s); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: append_seg (void) nkeynes@362: { nkeynes@362: if (prefixes & PREFIX_CS) nkeynes@362: { nkeynes@362: used_prefixes |= PREFIX_CS; nkeynes@1298: oappend ( &"%cs:"[(int)intel_syntax]); nkeynes@362: } nkeynes@362: if (prefixes & PREFIX_DS) nkeynes@362: { nkeynes@362: used_prefixes |= PREFIX_DS; nkeynes@1298: oappend (&"%ds:"[(int)intel_syntax]); nkeynes@362: } nkeynes@362: if (prefixes & PREFIX_SS) nkeynes@362: { nkeynes@362: used_prefixes |= PREFIX_SS; nkeynes@1298: oappend (&"%ss:"[(int)intel_syntax]); nkeynes@362: } nkeynes@362: if (prefixes & PREFIX_ES) nkeynes@362: { nkeynes@362: used_prefixes |= PREFIX_ES; nkeynes@1298: oappend (&"%es:"[(int)intel_syntax]); nkeynes@362: } nkeynes@362: if (prefixes & PREFIX_FS) nkeynes@362: { nkeynes@362: used_prefixes |= PREFIX_FS; nkeynes@1298: oappend (&"%fs:"[(int)intel_syntax]); nkeynes@362: } nkeynes@362: if (prefixes & PREFIX_GS) nkeynes@362: { nkeynes@362: used_prefixes |= PREFIX_GS; nkeynes@1298: oappend (&"%gs:"[(int)intel_syntax]); nkeynes@362: } nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_indirE (int bytemode, int sizeflag) nkeynes@362: { nkeynes@362: if (!intel_syntax) nkeynes@362: oappend ("*"); nkeynes@362: OP_E (bytemode, sizeflag); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_E (int bytemode, int sizeflag) nkeynes@362: { nkeynes@362: bfd_vma disp; nkeynes@362: int add = 0; nkeynes@362: int riprel = 0; nkeynes@362: USED_REX (REX_EXTZ); nkeynes@362: if (rex & REX_EXTZ) nkeynes@362: add += 8; nkeynes@362: nkeynes@362: /* Skip mod/rm byte. */ nkeynes@362: MODRM_CHECK; nkeynes@362: codep++; nkeynes@362: nkeynes@362: if (mod == 3) nkeynes@362: { nkeynes@362: switch (bytemode) nkeynes@362: { nkeynes@362: case b_mode: nkeynes@362: USED_REX (0); nkeynes@362: if (rex) nkeynes@362: oappend (names8rex[rm + add]); nkeynes@362: else nkeynes@362: oappend (names8[rm + add]); nkeynes@362: break; nkeynes@362: case w_mode: nkeynes@362: oappend (names16[rm + add]); nkeynes@362: break; nkeynes@362: case d_mode: nkeynes@362: oappend (names32[rm + add]); nkeynes@362: break; nkeynes@362: case q_mode: nkeynes@362: oappend (names64[rm + add]); nkeynes@362: break; nkeynes@362: case m_mode: nkeynes@362: if (mode_64bit) nkeynes@362: oappend (names64[rm + add]); nkeynes@362: else nkeynes@362: oappend (names32[rm + add]); nkeynes@362: break; nkeynes@362: case v_mode: nkeynes@362: case dq_mode: nkeynes@362: case dqw_mode: nkeynes@362: USED_REX (REX_MODE64); nkeynes@362: if (rex & REX_MODE64) nkeynes@362: oappend (names64[rm + add]); nkeynes@362: else if ((sizeflag & DFLAG) || bytemode != v_mode) nkeynes@362: oappend (names32[rm + add]); nkeynes@362: else nkeynes@362: oappend (names16[rm + add]); nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: break; nkeynes@362: case 0: nkeynes@362: break; nkeynes@362: default: nkeynes@362: oappend (INTERNAL_DISASSEMBLER_ERROR); nkeynes@362: break; nkeynes@362: } nkeynes@362: return; nkeynes@362: } nkeynes@362: nkeynes@362: disp = 0; nkeynes@362: append_seg (); nkeynes@362: nkeynes@362: if ((sizeflag & AFLAG) || mode_64bit) /* 32 bit address mode */ nkeynes@362: { nkeynes@362: int havesib; nkeynes@362: int havebase; nkeynes@362: int base; nkeynes@362: int index = 0; nkeynes@362: int scale = 0; nkeynes@362: nkeynes@362: havesib = 0; nkeynes@362: havebase = 1; nkeynes@362: base = rm; nkeynes@362: nkeynes@362: if (base == 4) nkeynes@362: { nkeynes@362: havesib = 1; nkeynes@362: FETCH_DATA (the_info, codep + 1); nkeynes@362: index = (*codep >> 3) & 7; nkeynes@362: if (mode_64bit || index != 0x4) nkeynes@362: /* When INDEX == 0x4 in 32 bit mode, SCALE is ignored. */ nkeynes@362: scale = (*codep >> 6) & 3; nkeynes@362: base = *codep & 7; nkeynes@362: USED_REX (REX_EXTY); nkeynes@362: USED_REX (REX_EXTZ); nkeynes@362: if (rex & REX_EXTY) nkeynes@362: index += 8; nkeynes@362: if (rex & REX_EXTZ) nkeynes@362: base += 8; nkeynes@362: codep++; nkeynes@362: } nkeynes@362: nkeynes@362: switch (mod) nkeynes@362: { nkeynes@362: case 0: nkeynes@362: if ((base & 7) == 5) nkeynes@362: { nkeynes@362: havebase = 0; nkeynes@362: if (mode_64bit && !havesib) nkeynes@362: riprel = 1; nkeynes@362: disp = get32s (); nkeynes@362: } nkeynes@362: break; nkeynes@362: case 1: nkeynes@362: FETCH_DATA (the_info, codep + 1); nkeynes@362: disp = *codep++; nkeynes@362: if ((disp & 0x80) != 0) nkeynes@362: disp -= 0x100; nkeynes@362: break; nkeynes@362: case 2: nkeynes@362: disp = get32s (); nkeynes@362: break; nkeynes@362: } nkeynes@362: nkeynes@362: if (!intel_syntax) nkeynes@362: if (mod != 0 || (base & 7) == 5) nkeynes@362: { nkeynes@1263: xlat_print_symbolic_operand (scratchbuf, !riprel, disp); nkeynes@362: oappend (scratchbuf); nkeynes@362: if (riprel) nkeynes@362: { nkeynes@362: set_op (disp, 1); nkeynes@362: oappend ("(%rip)"); nkeynes@362: } nkeynes@362: } nkeynes@362: nkeynes@362: if (havebase || (havesib && (index != 4 || scale != 0))) nkeynes@362: { nkeynes@362: if (intel_syntax) nkeynes@362: { nkeynes@362: switch (bytemode) nkeynes@362: { nkeynes@362: case b_mode: nkeynes@362: oappend ("BYTE PTR "); nkeynes@362: break; nkeynes@362: case w_mode: nkeynes@362: case dqw_mode: nkeynes@362: oappend ("WORD PTR "); nkeynes@362: break; nkeynes@362: case v_mode: nkeynes@362: case dq_mode: nkeynes@362: USED_REX (REX_MODE64); nkeynes@362: if (rex & REX_MODE64) nkeynes@362: oappend ("QWORD PTR "); nkeynes@362: else if ((sizeflag & DFLAG) || bytemode == dq_mode) nkeynes@362: oappend ("DWORD PTR "); nkeynes@362: else nkeynes@362: oappend ("WORD PTR "); nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: break; nkeynes@362: case d_mode: nkeynes@362: oappend ("DWORD PTR "); nkeynes@362: break; nkeynes@362: case q_mode: nkeynes@362: oappend ("QWORD PTR "); nkeynes@362: break; nkeynes@362: case m_mode: nkeynes@362: if (mode_64bit) nkeynes@362: oappend ("QWORD PTR "); nkeynes@362: else nkeynes@362: oappend ("DWORD PTR "); nkeynes@362: break; nkeynes@362: case f_mode: nkeynes@362: if (sizeflag & DFLAG) nkeynes@362: { nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: oappend ("FWORD PTR "); nkeynes@362: } nkeynes@362: else nkeynes@362: oappend ("DWORD PTR "); nkeynes@362: break; nkeynes@362: case t_mode: nkeynes@362: oappend ("TBYTE PTR "); nkeynes@362: break; nkeynes@362: case x_mode: nkeynes@362: oappend ("XMMWORD PTR "); nkeynes@362: break; nkeynes@362: default: nkeynes@362: break; nkeynes@362: } nkeynes@362: } nkeynes@362: *obufp++ = open_char; nkeynes@362: if (intel_syntax && riprel) nkeynes@362: oappend ("rip + "); nkeynes@362: *obufp = '\0'; nkeynes@362: USED_REX (REX_EXTZ); nkeynes@362: if (!havesib && (rex & REX_EXTZ)) nkeynes@362: base += 8; nkeynes@362: if (havebase) nkeynes@362: oappend (mode_64bit && (sizeflag & AFLAG) nkeynes@362: ? names64[base] : names32[base]); nkeynes@362: if (havesib) nkeynes@362: { nkeynes@362: if (index != 4) nkeynes@362: { nkeynes@362: if (!intel_syntax || havebase) nkeynes@362: { nkeynes@362: *obufp++ = separator_char; nkeynes@362: *obufp = '\0'; nkeynes@362: } nkeynes@362: oappend (mode_64bit && (sizeflag & AFLAG) nkeynes@362: ? names64[index] : names32[index]); nkeynes@362: } nkeynes@362: if (scale != 0 || (!intel_syntax && index != 4)) nkeynes@362: { nkeynes@362: *obufp++ = scale_char; nkeynes@362: *obufp = '\0'; nkeynes@362: sprintf (scratchbuf, "%d", 1 << scale); nkeynes@362: oappend (scratchbuf); nkeynes@362: } nkeynes@362: } nkeynes@362: if (intel_syntax) nkeynes@362: if (mod != 0 || (base & 7) == 5) nkeynes@362: { nkeynes@362: /* Don't print zero displacements. */ nkeynes@362: if (disp != 0) nkeynes@362: { nkeynes@362: if ((bfd_signed_vma) disp > 0) nkeynes@362: { nkeynes@362: *obufp++ = '+'; nkeynes@362: *obufp = '\0'; nkeynes@362: } nkeynes@362: nkeynes@1263: xlat_print_symbolic_operand (scratchbuf, 0, disp); nkeynes@362: oappend (scratchbuf); nkeynes@362: } nkeynes@362: } nkeynes@362: nkeynes@362: *obufp++ = close_char; nkeynes@362: *obufp = '\0'; nkeynes@362: } nkeynes@362: else if (intel_syntax) nkeynes@362: { nkeynes@362: if (mod != 0 || (base & 7) == 5) nkeynes@362: { nkeynes@362: if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS nkeynes@362: | PREFIX_ES | PREFIX_FS | PREFIX_GS)) nkeynes@362: ; nkeynes@362: else nkeynes@362: { nkeynes@362: oappend (names_seg[ds_reg - es_reg]); nkeynes@362: oappend (":"); nkeynes@362: } nkeynes@1263: xlat_print_symbolic_operand (scratchbuf, 1, disp); nkeynes@362: oappend (scratchbuf); nkeynes@362: } nkeynes@362: } nkeynes@362: } nkeynes@362: else nkeynes@362: { /* 16 bit address mode */ nkeynes@362: switch (mod) nkeynes@362: { nkeynes@362: case 0: nkeynes@362: if ((rm & 7) == 6) nkeynes@362: { nkeynes@362: disp = get16 (); nkeynes@362: if ((disp & 0x8000) != 0) nkeynes@362: disp -= 0x10000; nkeynes@362: } nkeynes@362: break; nkeynes@362: case 1: nkeynes@362: FETCH_DATA (the_info, codep + 1); nkeynes@362: disp = *codep++; nkeynes@362: if ((disp & 0x80) != 0) nkeynes@362: disp -= 0x100; nkeynes@362: break; nkeynes@362: case 2: nkeynes@362: disp = get16 (); nkeynes@362: if ((disp & 0x8000) != 0) nkeynes@362: disp -= 0x10000; nkeynes@362: break; nkeynes@362: } nkeynes@362: nkeynes@362: if (!intel_syntax) nkeynes@362: if (mod != 0 || (rm & 7) == 6) nkeynes@362: { nkeynes@1263: xlat_print_symbolic_operand (scratchbuf, 0, disp); nkeynes@362: oappend (scratchbuf); nkeynes@362: } nkeynes@362: nkeynes@362: if (mod != 0 || (rm & 7) != 6) nkeynes@362: { nkeynes@362: *obufp++ = open_char; nkeynes@362: *obufp = '\0'; nkeynes@362: oappend (index16[rm + add]); nkeynes@362: *obufp++ = close_char; nkeynes@362: *obufp = '\0'; nkeynes@362: } nkeynes@362: } nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_G (int bytemode, int sizeflag) nkeynes@362: { nkeynes@362: int add = 0; nkeynes@362: USED_REX (REX_EXTX); nkeynes@362: if (rex & REX_EXTX) nkeynes@362: add += 8; nkeynes@362: switch (bytemode) nkeynes@362: { nkeynes@362: case b_mode: nkeynes@362: USED_REX (0); nkeynes@362: if (rex) nkeynes@362: oappend (names8rex[reg + add]); nkeynes@362: else nkeynes@362: oappend (names8[reg + add]); nkeynes@362: break; nkeynes@362: case w_mode: nkeynes@362: oappend (names16[reg + add]); nkeynes@362: break; nkeynes@362: case d_mode: nkeynes@362: oappend (names32[reg + add]); nkeynes@362: break; nkeynes@362: case q_mode: nkeynes@362: oappend (names64[reg + add]); nkeynes@362: break; nkeynes@362: case v_mode: nkeynes@362: case dq_mode: nkeynes@362: case dqw_mode: nkeynes@362: USED_REX (REX_MODE64); nkeynes@362: if (rex & REX_MODE64) nkeynes@362: oappend (names64[reg + add]); nkeynes@362: else if ((sizeflag & DFLAG) || bytemode != v_mode) nkeynes@362: oappend (names32[reg + add]); nkeynes@362: else nkeynes@362: oappend (names16[reg + add]); nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: break; nkeynes@362: default: nkeynes@362: oappend (INTERNAL_DISASSEMBLER_ERROR); nkeynes@362: break; nkeynes@362: } nkeynes@362: } nkeynes@362: nkeynes@362: static bfd_vma nkeynes@362: get64 (void) nkeynes@362: { nkeynes@362: bfd_vma x; nkeynes@362: #ifdef BFD64 nkeynes@362: unsigned int a; nkeynes@362: unsigned int b; nkeynes@362: nkeynes@362: FETCH_DATA (the_info, codep + 8); nkeynes@362: a = *codep++ & 0xff; nkeynes@362: a |= (*codep++ & 0xff) << 8; nkeynes@362: a |= (*codep++ & 0xff) << 16; nkeynes@362: a |= (*codep++ & 0xff) << 24; nkeynes@362: b = *codep++ & 0xff; nkeynes@362: b |= (*codep++ & 0xff) << 8; nkeynes@362: b |= (*codep++ & 0xff) << 16; nkeynes@362: b |= (*codep++ & 0xff) << 24; nkeynes@362: x = a + ((bfd_vma) b << 32); nkeynes@362: #else nkeynes@362: abort (); nkeynes@362: x = 0; nkeynes@362: #endif nkeynes@362: return x; nkeynes@362: } nkeynes@362: nkeynes@362: static bfd_signed_vma nkeynes@362: get32 (void) nkeynes@362: { nkeynes@362: bfd_signed_vma x = 0; nkeynes@362: nkeynes@362: FETCH_DATA (the_info, codep + 4); nkeynes@362: x = *codep++ & (bfd_signed_vma) 0xff; nkeynes@362: x |= (*codep++ & (bfd_signed_vma) 0xff) << 8; nkeynes@362: x |= (*codep++ & (bfd_signed_vma) 0xff) << 16; nkeynes@362: x |= (*codep++ & (bfd_signed_vma) 0xff) << 24; nkeynes@362: return x; nkeynes@362: } nkeynes@362: nkeynes@362: static bfd_signed_vma nkeynes@362: get32s (void) nkeynes@362: { nkeynes@362: bfd_signed_vma x = 0; nkeynes@362: nkeynes@362: FETCH_DATA (the_info, codep + 4); nkeynes@362: x = *codep++ & (bfd_signed_vma) 0xff; nkeynes@362: x |= (*codep++ & (bfd_signed_vma) 0xff) << 8; nkeynes@362: x |= (*codep++ & (bfd_signed_vma) 0xff) << 16; nkeynes@362: x |= (*codep++ & (bfd_signed_vma) 0xff) << 24; nkeynes@362: nkeynes@362: x = (x ^ ((bfd_signed_vma) 1 << 31)) - ((bfd_signed_vma) 1 << 31); nkeynes@362: nkeynes@362: return x; nkeynes@362: } nkeynes@362: nkeynes@362: static int nkeynes@362: get16 (void) nkeynes@362: { nkeynes@362: int x = 0; nkeynes@362: nkeynes@362: FETCH_DATA (the_info, codep + 2); nkeynes@362: x = *codep++ & 0xff; nkeynes@362: x |= (*codep++ & 0xff) << 8; nkeynes@362: return x; nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: set_op (bfd_vma op, int riprel) nkeynes@362: { nkeynes@362: op_index[op_ad] = op_ad; nkeynes@362: if (mode_64bit) nkeynes@362: { nkeynes@362: op_address[op_ad] = op; nkeynes@362: op_riprel[op_ad] = riprel; nkeynes@362: } nkeynes@362: else nkeynes@362: { nkeynes@362: /* Mask to get a 32-bit address. */ nkeynes@362: op_address[op_ad] = op & 0xffffffff; nkeynes@362: op_riprel[op_ad] = riprel & 0xffffffff; nkeynes@362: } nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_REG (int code, int sizeflag) nkeynes@362: { nkeynes@362: const char *s; nkeynes@362: int add = 0; nkeynes@362: USED_REX (REX_EXTZ); nkeynes@362: if (rex & REX_EXTZ) nkeynes@362: add = 8; nkeynes@362: nkeynes@362: switch (code) nkeynes@362: { nkeynes@362: case indir_dx_reg: nkeynes@362: if (intel_syntax) nkeynes@362: s = "[dx]"; nkeynes@362: else nkeynes@362: s = "(%dx)"; nkeynes@362: break; nkeynes@362: case ax_reg: case cx_reg: case dx_reg: case bx_reg: nkeynes@362: case sp_reg: case bp_reg: case si_reg: case di_reg: nkeynes@362: s = names16[code - ax_reg + add]; nkeynes@362: break; nkeynes@362: case es_reg: case ss_reg: case cs_reg: nkeynes@362: case ds_reg: case fs_reg: case gs_reg: nkeynes@362: s = names_seg[code - es_reg + add]; nkeynes@362: break; nkeynes@362: case al_reg: case ah_reg: case cl_reg: case ch_reg: nkeynes@362: case dl_reg: case dh_reg: case bl_reg: case bh_reg: nkeynes@362: USED_REX (0); nkeynes@362: if (rex) nkeynes@362: s = names8rex[code - al_reg + add]; nkeynes@362: else nkeynes@362: s = names8[code - al_reg]; nkeynes@362: break; nkeynes@362: case rAX_reg: case rCX_reg: case rDX_reg: case rBX_reg: nkeynes@362: case rSP_reg: case rBP_reg: case rSI_reg: case rDI_reg: nkeynes@362: if (mode_64bit) nkeynes@362: { nkeynes@362: s = names64[code - rAX_reg + add]; nkeynes@362: break; nkeynes@362: } nkeynes@362: code += eAX_reg - rAX_reg; nkeynes@362: /* Fall through. */ nkeynes@362: case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: nkeynes@362: case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: nkeynes@362: USED_REX (REX_MODE64); nkeynes@362: if (rex & REX_MODE64) nkeynes@362: s = names64[code - eAX_reg + add]; nkeynes@362: else if (sizeflag & DFLAG) nkeynes@362: s = names32[code - eAX_reg + add]; nkeynes@362: else nkeynes@362: s = names16[code - eAX_reg + add]; nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: break; nkeynes@362: default: nkeynes@362: s = INTERNAL_DISASSEMBLER_ERROR; nkeynes@362: break; nkeynes@362: } nkeynes@362: oappend (s); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_IMREG (int code, int sizeflag) nkeynes@362: { nkeynes@362: const char *s; nkeynes@362: nkeynes@362: switch (code) nkeynes@362: { nkeynes@362: case indir_dx_reg: nkeynes@362: if (intel_syntax) nkeynes@362: s = "[dx]"; nkeynes@362: else nkeynes@362: s = "(%dx)"; nkeynes@362: break; nkeynes@362: case ax_reg: case cx_reg: case dx_reg: case bx_reg: nkeynes@362: case sp_reg: case bp_reg: case si_reg: case di_reg: nkeynes@362: s = names16[code - ax_reg]; nkeynes@362: break; nkeynes@362: case es_reg: case ss_reg: case cs_reg: nkeynes@362: case ds_reg: case fs_reg: case gs_reg: nkeynes@362: s = names_seg[code - es_reg]; nkeynes@362: break; nkeynes@362: case al_reg: case ah_reg: case cl_reg: case ch_reg: nkeynes@362: case dl_reg: case dh_reg: case bl_reg: case bh_reg: nkeynes@362: USED_REX (0); nkeynes@362: if (rex) nkeynes@362: s = names8rex[code - al_reg]; nkeynes@362: else nkeynes@362: s = names8[code - al_reg]; nkeynes@362: break; nkeynes@362: case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: nkeynes@362: case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: nkeynes@362: USED_REX (REX_MODE64); nkeynes@362: if (rex & REX_MODE64) nkeynes@362: s = names64[code - eAX_reg]; nkeynes@362: else if (sizeflag & DFLAG) nkeynes@362: s = names32[code - eAX_reg]; nkeynes@362: else nkeynes@362: s = names16[code - eAX_reg]; nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: break; nkeynes@362: default: nkeynes@362: s = INTERNAL_DISASSEMBLER_ERROR; nkeynes@362: break; nkeynes@362: } nkeynes@362: oappend (s); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_I (int bytemode, int sizeflag) nkeynes@362: { nkeynes@362: bfd_signed_vma op; nkeynes@362: bfd_signed_vma mask = -1; nkeynes@362: nkeynes@362: switch (bytemode) nkeynes@362: { nkeynes@362: case b_mode: nkeynes@362: FETCH_DATA (the_info, codep + 1); nkeynes@362: op = *codep++; nkeynes@362: mask = 0xff; nkeynes@362: break; nkeynes@362: case q_mode: nkeynes@362: if (mode_64bit) nkeynes@362: { nkeynes@362: op = get32s (); nkeynes@362: break; nkeynes@362: } nkeynes@362: /* Fall through. */ nkeynes@362: case v_mode: nkeynes@362: USED_REX (REX_MODE64); nkeynes@362: if (rex & REX_MODE64) nkeynes@362: op = get32s (); nkeynes@362: else if (sizeflag & DFLAG) nkeynes@362: { nkeynes@362: op = get32 (); nkeynes@362: mask = 0xffffffff; nkeynes@362: } nkeynes@362: else nkeynes@362: { nkeynes@362: op = get16 (); nkeynes@362: mask = 0xfffff; nkeynes@362: } nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: break; nkeynes@362: case w_mode: nkeynes@362: mask = 0xfffff; nkeynes@362: op = get16 (); nkeynes@362: break; nkeynes@362: case const_1_mode: nkeynes@362: if (intel_syntax) nkeynes@362: oappend ("1"); nkeynes@362: return; nkeynes@362: default: nkeynes@362: oappend (INTERNAL_DISASSEMBLER_ERROR); nkeynes@362: return; nkeynes@362: } nkeynes@362: nkeynes@362: op &= mask; nkeynes@362: scratchbuf[0] = '$'; nkeynes@1263: xlat_print_symbolic_operand (scratchbuf + 1, 1, op); nkeynes@362: oappend (scratchbuf + intel_syntax); nkeynes@362: scratchbuf[0] = '\0'; nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_I64 (int bytemode, int sizeflag) nkeynes@362: { nkeynes@362: bfd_signed_vma op; nkeynes@362: bfd_signed_vma mask = -1; nkeynes@362: nkeynes@362: if (!mode_64bit) nkeynes@362: { nkeynes@362: OP_I (bytemode, sizeflag); nkeynes@362: return; nkeynes@362: } nkeynes@362: nkeynes@362: switch (bytemode) nkeynes@362: { nkeynes@362: case b_mode: nkeynes@362: FETCH_DATA (the_info, codep + 1); nkeynes@362: op = *codep++; nkeynes@362: mask = 0xff; nkeynes@362: break; nkeynes@362: case v_mode: nkeynes@362: USED_REX (REX_MODE64); nkeynes@362: if (rex & REX_MODE64) nkeynes@362: op = get64 (); nkeynes@362: else if (sizeflag & DFLAG) nkeynes@362: { nkeynes@362: op = get32 (); nkeynes@362: mask = 0xffffffff; nkeynes@362: } nkeynes@362: else nkeynes@362: { nkeynes@362: op = get16 (); nkeynes@362: mask = 0xfffff; nkeynes@362: } nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: break; nkeynes@362: case w_mode: nkeynes@362: mask = 0xfffff; nkeynes@362: op = get16 (); nkeynes@362: break; nkeynes@362: default: nkeynes@362: oappend (INTERNAL_DISASSEMBLER_ERROR); nkeynes@362: return; nkeynes@362: } nkeynes@362: nkeynes@362: op &= mask; nkeynes@362: scratchbuf[0] = '$'; nkeynes@1263: xlat_print_symbolic_operand (scratchbuf + 1, 1, op); nkeynes@362: oappend (scratchbuf + intel_syntax); nkeynes@362: scratchbuf[0] = '\0'; nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_sI (int bytemode, int sizeflag) nkeynes@362: { nkeynes@362: bfd_signed_vma op; nkeynes@362: bfd_signed_vma mask = -1; nkeynes@362: nkeynes@362: switch (bytemode) nkeynes@362: { nkeynes@362: case b_mode: nkeynes@362: FETCH_DATA (the_info, codep + 1); nkeynes@362: op = *codep++; nkeynes@362: if ((op & 0x80) != 0) nkeynes@362: op -= 0x100; nkeynes@362: mask = 0xffffffff; nkeynes@362: break; nkeynes@362: case v_mode: nkeynes@362: USED_REX (REX_MODE64); nkeynes@362: if (rex & REX_MODE64) nkeynes@362: op = get32s (); nkeynes@362: else if (sizeflag & DFLAG) nkeynes@362: { nkeynes@362: op = get32s (); nkeynes@362: mask = 0xffffffff; nkeynes@362: } nkeynes@362: else nkeynes@362: { nkeynes@362: mask = 0xffffffff; nkeynes@362: op = get16 (); nkeynes@362: if ((op & 0x8000) != 0) nkeynes@362: op -= 0x10000; nkeynes@362: } nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: break; nkeynes@362: case w_mode: nkeynes@362: op = get16 (); nkeynes@362: mask = 0xffffffff; nkeynes@362: if ((op & 0x8000) != 0) nkeynes@362: op -= 0x10000; nkeynes@362: break; nkeynes@362: default: nkeynes@362: oappend (INTERNAL_DISASSEMBLER_ERROR); nkeynes@362: return; nkeynes@362: } nkeynes@362: nkeynes@362: scratchbuf[0] = '$'; nkeynes@1263: xlat_print_symbolic_operand (scratchbuf + 1, 1, op); nkeynes@362: oappend (scratchbuf + intel_syntax); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_J (int bytemode, int sizeflag) nkeynes@362: { nkeynes@362: bfd_vma disp; nkeynes@362: bfd_vma mask = -1; nkeynes@362: nkeynes@362: switch (bytemode) nkeynes@362: { nkeynes@362: case b_mode: nkeynes@362: FETCH_DATA (the_info, codep + 1); nkeynes@362: disp = *codep++; nkeynes@362: if ((disp & 0x80) != 0) nkeynes@362: disp -= 0x100; nkeynes@362: break; nkeynes@362: case v_mode: nkeynes@362: if (sizeflag & DFLAG) nkeynes@362: disp = get32s (); nkeynes@362: else nkeynes@362: { nkeynes@362: disp = get16 (); nkeynes@362: /* For some reason, a data16 prefix on a jump instruction nkeynes@362: means that the pc is masked to 16 bits after the nkeynes@362: displacement is added! */ nkeynes@362: mask = 0xffff; nkeynes@362: } nkeynes@362: break; nkeynes@362: default: nkeynes@362: oappend (INTERNAL_DISASSEMBLER_ERROR); nkeynes@362: return; nkeynes@362: } nkeynes@362: disp = (start_pc + codep - start_codep + disp) & mask; nkeynes@362: set_op (disp, 0); nkeynes@1263: xlat_print_symbolic_operand (scratchbuf, 1, disp); nkeynes@362: oappend (scratchbuf); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_SEG (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) nkeynes@362: { nkeynes@362: oappend (names_seg[reg]); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_DIR (int dummy ATTRIBUTE_UNUSED, int sizeflag) nkeynes@362: { nkeynes@362: int seg, offset; nkeynes@362: nkeynes@362: if (sizeflag & DFLAG) nkeynes@362: { nkeynes@362: offset = get32 (); nkeynes@362: seg = get16 (); nkeynes@362: } nkeynes@362: else nkeynes@362: { nkeynes@362: offset = get16 (); nkeynes@362: seg = get16 (); nkeynes@362: } nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: if (intel_syntax) nkeynes@362: sprintf (scratchbuf, "0x%x,0x%x", seg, offset); nkeynes@362: else nkeynes@362: sprintf (scratchbuf, "$0x%x,$0x%x", seg, offset); nkeynes@362: oappend (scratchbuf); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_OFF (int bytemode ATTRIBUTE_UNUSED, int sizeflag) nkeynes@362: { nkeynes@362: bfd_vma off; nkeynes@362: nkeynes@362: append_seg (); nkeynes@362: nkeynes@362: if ((sizeflag & AFLAG) || mode_64bit) nkeynes@362: off = get32 (); nkeynes@362: else nkeynes@362: off = get16 (); nkeynes@362: nkeynes@362: if (intel_syntax) nkeynes@362: { nkeynes@362: if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS nkeynes@362: | PREFIX_ES | PREFIX_FS | PREFIX_GS))) nkeynes@362: { nkeynes@362: oappend (names_seg[ds_reg - es_reg]); nkeynes@362: oappend (":"); nkeynes@362: } nkeynes@362: } nkeynes@1263: xlat_print_symbolic_operand (scratchbuf, 1, off); nkeynes@362: oappend (scratchbuf); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_OFF64 (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) nkeynes@362: { nkeynes@362: bfd_vma off; nkeynes@362: nkeynes@362: if (!mode_64bit) nkeynes@362: { nkeynes@362: OP_OFF (bytemode, sizeflag); nkeynes@362: return; nkeynes@362: } nkeynes@362: nkeynes@362: append_seg (); nkeynes@362: nkeynes@362: off = get64 (); nkeynes@362: nkeynes@362: if (intel_syntax) nkeynes@362: { nkeynes@362: if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS nkeynes@362: | PREFIX_ES | PREFIX_FS | PREFIX_GS))) nkeynes@362: { nkeynes@362: oappend (names_seg[ds_reg - es_reg]); nkeynes@362: oappend (":"); nkeynes@362: } nkeynes@362: } nkeynes@1263: xlat_print_symbolic_operand (scratchbuf, 1, off); nkeynes@362: oappend (scratchbuf); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: ptr_reg (int code, int sizeflag) nkeynes@362: { nkeynes@362: const char *s; nkeynes@362: nkeynes@362: *obufp++ = open_char; nkeynes@362: used_prefixes |= (prefixes & PREFIX_ADDR); nkeynes@362: if (mode_64bit) nkeynes@362: { nkeynes@362: if (!(sizeflag & AFLAG)) nkeynes@362: s = names32[code - eAX_reg]; nkeynes@362: else nkeynes@362: s = names64[code - eAX_reg]; nkeynes@362: } nkeynes@362: else if (sizeflag & AFLAG) nkeynes@362: s = names32[code - eAX_reg]; nkeynes@362: else nkeynes@362: s = names16[code - eAX_reg]; nkeynes@362: oappend (s); nkeynes@362: *obufp++ = close_char; nkeynes@362: *obufp = 0; nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_ESreg (int code, int sizeflag) nkeynes@362: { nkeynes@362: if (intel_syntax) nkeynes@362: { nkeynes@362: if (codep[-1] & 1) nkeynes@362: { nkeynes@362: USED_REX (REX_MODE64); nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: if (rex & REX_MODE64) nkeynes@362: oappend ("QWORD PTR "); nkeynes@362: else if ((sizeflag & DFLAG)) nkeynes@362: oappend ("DWORD PTR "); nkeynes@362: else nkeynes@362: oappend ("WORD PTR "); nkeynes@362: } nkeynes@362: else nkeynes@362: oappend ("BYTE PTR "); nkeynes@362: } nkeynes@362: nkeynes@1298: oappend (&"%es:"[(int)intel_syntax]); nkeynes@362: ptr_reg (code, sizeflag); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_DSreg (int code, int sizeflag) nkeynes@362: { nkeynes@362: if (intel_syntax) nkeynes@362: { nkeynes@362: if (codep[-1] != 0xd7 && (codep[-1] & 1)) nkeynes@362: { nkeynes@362: USED_REX (REX_MODE64); nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: if (rex & REX_MODE64) nkeynes@362: oappend ("QWORD PTR "); nkeynes@362: else if ((sizeflag & DFLAG)) nkeynes@362: oappend ("DWORD PTR "); nkeynes@362: else nkeynes@362: oappend ("WORD PTR "); nkeynes@362: } nkeynes@362: else nkeynes@362: oappend ("BYTE PTR "); nkeynes@362: } nkeynes@362: nkeynes@362: if ((prefixes nkeynes@362: & (PREFIX_CS nkeynes@362: | PREFIX_DS nkeynes@362: | PREFIX_SS nkeynes@362: | PREFIX_ES nkeynes@362: | PREFIX_FS nkeynes@362: | PREFIX_GS)) == 0) nkeynes@362: prefixes |= PREFIX_DS; nkeynes@362: append_seg (); nkeynes@362: ptr_reg (code, sizeflag); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_C (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) nkeynes@362: { nkeynes@362: int add = 0; nkeynes@362: if (rex & REX_EXTX) nkeynes@362: { nkeynes@362: USED_REX (REX_EXTX); nkeynes@362: add = 8; nkeynes@362: } nkeynes@362: else if (!mode_64bit && (prefixes & PREFIX_LOCK)) nkeynes@362: { nkeynes@362: used_prefixes |= PREFIX_LOCK; nkeynes@362: add = 8; nkeynes@362: } nkeynes@362: sprintf (scratchbuf, "%%cr%d", reg + add); nkeynes@362: oappend (scratchbuf + intel_syntax); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_D (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) nkeynes@362: { nkeynes@362: int add = 0; nkeynes@362: USED_REX (REX_EXTX); nkeynes@362: if (rex & REX_EXTX) nkeynes@362: add = 8; nkeynes@362: if (intel_syntax) nkeynes@362: sprintf (scratchbuf, "db%d", reg + add); nkeynes@362: else nkeynes@362: sprintf (scratchbuf, "%%db%d", reg + add); nkeynes@362: oappend (scratchbuf); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_T (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) nkeynes@362: { nkeynes@362: sprintf (scratchbuf, "%%tr%d", reg); nkeynes@362: oappend (scratchbuf + intel_syntax); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_Rd (int bytemode, int sizeflag) nkeynes@362: { nkeynes@362: if (mod == 3) nkeynes@362: OP_E (bytemode, sizeflag); nkeynes@362: else nkeynes@362: BadOp (); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_MMX (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) nkeynes@362: { nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: if (prefixes & PREFIX_DATA) nkeynes@362: { nkeynes@362: int add = 0; nkeynes@362: USED_REX (REX_EXTX); nkeynes@362: if (rex & REX_EXTX) nkeynes@362: add = 8; nkeynes@362: sprintf (scratchbuf, "%%xmm%d", reg + add); nkeynes@362: } nkeynes@362: else nkeynes@362: sprintf (scratchbuf, "%%mm%d", reg); nkeynes@362: oappend (scratchbuf + intel_syntax); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_XMM (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) nkeynes@362: { nkeynes@362: int add = 0; nkeynes@362: USED_REX (REX_EXTX); nkeynes@362: if (rex & REX_EXTX) nkeynes@362: add = 8; nkeynes@362: sprintf (scratchbuf, "%%xmm%d", reg + add); nkeynes@362: oappend (scratchbuf + intel_syntax); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_EM (int bytemode, int sizeflag) nkeynes@362: { nkeynes@362: if (mod != 3) nkeynes@362: { nkeynes@362: if (intel_syntax && bytemode == v_mode) nkeynes@362: { nkeynes@362: bytemode = (prefixes & PREFIX_DATA) ? x_mode : q_mode; nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: } nkeynes@362: OP_E (bytemode, sizeflag); nkeynes@362: return; nkeynes@362: } nkeynes@362: nkeynes@362: /* Skip mod/rm byte. */ nkeynes@362: MODRM_CHECK; nkeynes@362: codep++; nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: if (prefixes & PREFIX_DATA) nkeynes@362: { nkeynes@362: int add = 0; nkeynes@362: nkeynes@362: USED_REX (REX_EXTZ); nkeynes@362: if (rex & REX_EXTZ) nkeynes@362: add = 8; nkeynes@362: sprintf (scratchbuf, "%%xmm%d", rm + add); nkeynes@362: } nkeynes@362: else nkeynes@362: sprintf (scratchbuf, "%%mm%d", rm); nkeynes@362: oappend (scratchbuf + intel_syntax); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_EX (int bytemode, int sizeflag) nkeynes@362: { nkeynes@362: int add = 0; nkeynes@362: if (mod != 3) nkeynes@362: { nkeynes@362: if (intel_syntax && bytemode == v_mode) nkeynes@362: { nkeynes@362: switch (prefixes & (PREFIX_DATA|PREFIX_REPZ|PREFIX_REPNZ)) nkeynes@362: { nkeynes@362: case 0: bytemode = x_mode; break; nkeynes@362: case PREFIX_REPZ: bytemode = d_mode; used_prefixes |= PREFIX_REPZ; break; nkeynes@362: case PREFIX_DATA: bytemode = x_mode; used_prefixes |= PREFIX_DATA; break; nkeynes@362: case PREFIX_REPNZ: bytemode = q_mode; used_prefixes |= PREFIX_REPNZ; break; nkeynes@362: default: bytemode = 0; break; nkeynes@362: } nkeynes@362: } nkeynes@362: OP_E (bytemode, sizeflag); nkeynes@362: return; nkeynes@362: } nkeynes@362: USED_REX (REX_EXTZ); nkeynes@362: if (rex & REX_EXTZ) nkeynes@362: add = 8; nkeynes@362: nkeynes@362: /* Skip mod/rm byte. */ nkeynes@362: MODRM_CHECK; nkeynes@362: codep++; nkeynes@362: sprintf (scratchbuf, "%%xmm%d", rm + add); nkeynes@362: oappend (scratchbuf + intel_syntax); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_MS (int bytemode, int sizeflag) nkeynes@362: { nkeynes@362: if (mod == 3) nkeynes@362: OP_EM (bytemode, sizeflag); nkeynes@362: else nkeynes@362: BadOp (); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_XS (int bytemode, int sizeflag) nkeynes@362: { nkeynes@362: if (mod == 3) nkeynes@362: OP_EX (bytemode, sizeflag); nkeynes@362: else nkeynes@362: BadOp (); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_M (int bytemode, int sizeflag) nkeynes@362: { nkeynes@362: if (mod == 3) nkeynes@362: BadOp (); /* bad lea,lds,les,lfs,lgs,lss modrm */ nkeynes@362: else nkeynes@362: OP_E (bytemode, sizeflag); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_0f07 (int bytemode, int sizeflag) nkeynes@362: { nkeynes@362: if (mod != 3 || rm != 0) nkeynes@362: BadOp (); nkeynes@362: else nkeynes@362: OP_E (bytemode, sizeflag); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: OP_0fae (int bytemode, int sizeflag) nkeynes@362: { nkeynes@362: if (mod == 3) nkeynes@362: { nkeynes@362: if (reg == 7) nkeynes@362: strcpy (obuf + strlen (obuf) - sizeof ("clflush") + 1, "sfence"); nkeynes@362: nkeynes@362: if (reg < 5 || rm != 0) nkeynes@362: { nkeynes@362: BadOp (); /* bad sfence, mfence, or lfence */ nkeynes@362: return; nkeynes@362: } nkeynes@362: } nkeynes@362: else if (reg != 7) nkeynes@362: { nkeynes@362: BadOp (); /* bad clflush */ nkeynes@362: return; nkeynes@362: } nkeynes@362: nkeynes@362: OP_E (bytemode, sizeflag); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: NOP_Fixup (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) nkeynes@362: { nkeynes@362: /* NOP with REPZ prefix is called PAUSE. */ nkeynes@362: if (prefixes == PREFIX_REPZ) nkeynes@362: strcpy (obuf, "pause"); nkeynes@362: } nkeynes@362: nkeynes@362: static const char *const Suffix3DNow[] = { nkeynes@362: /* 00 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 04 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 08 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 0C */ "pi2fw", "pi2fd", NULL, NULL, nkeynes@362: /* 10 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 14 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 18 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 1C */ "pf2iw", "pf2id", NULL, NULL, nkeynes@362: /* 20 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 24 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 28 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 2C */ NULL, NULL, NULL, NULL, nkeynes@362: /* 30 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 34 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 38 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 3C */ NULL, NULL, NULL, NULL, nkeynes@362: /* 40 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 44 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 48 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 4C */ NULL, NULL, NULL, NULL, nkeynes@362: /* 50 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 54 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 58 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 5C */ NULL, NULL, NULL, NULL, nkeynes@362: /* 60 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 64 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 68 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 6C */ NULL, NULL, NULL, NULL, nkeynes@362: /* 70 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 74 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 78 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 7C */ NULL, NULL, NULL, NULL, nkeynes@362: /* 80 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 84 */ NULL, NULL, NULL, NULL, nkeynes@362: /* 88 */ NULL, NULL, "pfnacc", NULL, nkeynes@362: /* 8C */ NULL, NULL, "pfpnacc", NULL, nkeynes@362: /* 90 */ "pfcmpge", NULL, NULL, NULL, nkeynes@362: /* 94 */ "pfmin", NULL, "pfrcp", "pfrsqrt", nkeynes@362: /* 98 */ NULL, NULL, "pfsub", NULL, nkeynes@362: /* 9C */ NULL, NULL, "pfadd", NULL, nkeynes@362: /* A0 */ "pfcmpgt", NULL, NULL, NULL, nkeynes@362: /* A4 */ "pfmax", NULL, "pfrcpit1", "pfrsqit1", nkeynes@362: /* A8 */ NULL, NULL, "pfsubr", NULL, nkeynes@362: /* AC */ NULL, NULL, "pfacc", NULL, nkeynes@362: /* B0 */ "pfcmpeq", NULL, NULL, NULL, nkeynes@362: /* B4 */ "pfmul", NULL, "pfrcpit2", "pfmulhrw", nkeynes@362: /* B8 */ NULL, NULL, NULL, "pswapd", nkeynes@362: /* BC */ NULL, NULL, NULL, "pavgusb", nkeynes@362: /* C0 */ NULL, NULL, NULL, NULL, nkeynes@362: /* C4 */ NULL, NULL, NULL, NULL, nkeynes@362: /* C8 */ NULL, NULL, NULL, NULL, nkeynes@362: /* CC */ NULL, NULL, NULL, NULL, nkeynes@362: /* D0 */ NULL, NULL, NULL, NULL, nkeynes@362: /* D4 */ NULL, NULL, NULL, NULL, nkeynes@362: /* D8 */ NULL, NULL, NULL, NULL, nkeynes@362: /* DC */ NULL, NULL, NULL, NULL, nkeynes@362: /* E0 */ NULL, NULL, NULL, NULL, nkeynes@362: /* E4 */ NULL, NULL, NULL, NULL, nkeynes@362: /* E8 */ NULL, NULL, NULL, NULL, nkeynes@362: /* EC */ NULL, NULL, NULL, NULL, nkeynes@362: /* F0 */ NULL, NULL, NULL, NULL, nkeynes@362: /* F4 */ NULL, NULL, NULL, NULL, nkeynes@362: /* F8 */ NULL, NULL, NULL, NULL, nkeynes@362: /* FC */ NULL, NULL, NULL, NULL, nkeynes@362: }; nkeynes@362: nkeynes@362: static void nkeynes@362: OP_3DNowSuffix (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) nkeynes@362: { nkeynes@362: const char *mnemonic; nkeynes@362: nkeynes@362: FETCH_DATA (the_info, codep + 1); nkeynes@362: /* AMD 3DNow! instructions are specified by an opcode suffix in the nkeynes@362: place where an 8-bit immediate would normally go. ie. the last nkeynes@362: byte of the instruction. */ nkeynes@362: obufp = obuf + strlen (obuf); nkeynes@362: mnemonic = Suffix3DNow[*codep++ & 0xff]; nkeynes@362: if (mnemonic) nkeynes@362: oappend (mnemonic); nkeynes@362: else nkeynes@362: { nkeynes@362: /* Since a variable sized modrm/sib chunk is between the start nkeynes@362: of the opcode (0x0f0f) and the opcode suffix, we need to do nkeynes@362: all the modrm processing first, and don't know until now that nkeynes@362: we have a bad opcode. This necessitates some cleaning up. */ nkeynes@362: op1out[0] = '\0'; nkeynes@362: op2out[0] = '\0'; nkeynes@362: BadOp (); nkeynes@362: } nkeynes@362: } nkeynes@362: nkeynes@362: static const char *simd_cmp_op[] = { nkeynes@362: "eq", nkeynes@362: "lt", nkeynes@362: "le", nkeynes@362: "unord", nkeynes@362: "neq", nkeynes@362: "nlt", nkeynes@362: "nle", nkeynes@362: "ord" nkeynes@362: }; nkeynes@362: nkeynes@362: static void nkeynes@362: OP_SIMD_Suffix (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) nkeynes@362: { nkeynes@362: unsigned int cmp_type; nkeynes@362: nkeynes@362: FETCH_DATA (the_info, codep + 1); nkeynes@362: obufp = obuf + strlen (obuf); nkeynes@362: cmp_type = *codep++ & 0xff; nkeynes@362: if (cmp_type < 8) nkeynes@362: { nkeynes@362: char suffix1 = 'p', suffix2 = 's'; nkeynes@362: used_prefixes |= (prefixes & PREFIX_REPZ); nkeynes@362: if (prefixes & PREFIX_REPZ) nkeynes@362: suffix1 = 's'; nkeynes@362: else nkeynes@362: { nkeynes@362: used_prefixes |= (prefixes & PREFIX_DATA); nkeynes@362: if (prefixes & PREFIX_DATA) nkeynes@362: suffix2 = 'd'; nkeynes@362: else nkeynes@362: { nkeynes@362: used_prefixes |= (prefixes & PREFIX_REPNZ); nkeynes@362: if (prefixes & PREFIX_REPNZ) nkeynes@362: suffix1 = 's', suffix2 = 'd'; nkeynes@362: } nkeynes@362: } nkeynes@362: sprintf (scratchbuf, "cmp%s%c%c", nkeynes@362: simd_cmp_op[cmp_type], suffix1, suffix2); nkeynes@362: used_prefixes |= (prefixes & PREFIX_REPZ); nkeynes@362: oappend (scratchbuf); nkeynes@362: } nkeynes@362: else nkeynes@362: { nkeynes@362: /* We have a bad extension byte. Clean up. */ nkeynes@362: op1out[0] = '\0'; nkeynes@362: op2out[0] = '\0'; nkeynes@362: BadOp (); nkeynes@362: } nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: SIMD_Fixup (int extrachar, int sizeflag ATTRIBUTE_UNUSED) nkeynes@362: { nkeynes@362: /* Change movlps/movhps to movhlps/movlhps for 2 register operand nkeynes@362: forms of these instructions. */ nkeynes@362: if (mod == 3) nkeynes@362: { nkeynes@362: char *p = obuf + strlen (obuf); nkeynes@362: *(p + 1) = '\0'; nkeynes@362: *p = *(p - 1); nkeynes@362: *(p - 1) = *(p - 2); nkeynes@362: *(p - 2) = *(p - 3); nkeynes@362: *(p - 3) = extrachar; nkeynes@362: } nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: PNI_Fixup (int extrachar ATTRIBUTE_UNUSED, int sizeflag) nkeynes@362: { nkeynes@362: if (mod == 3 && reg == 1 && rm <= 1) nkeynes@362: { nkeynes@362: /* Override "sidt". */ nkeynes@362: char *p = obuf + strlen (obuf) - 4; nkeynes@362: nkeynes@362: /* We might have a suffix. */ nkeynes@362: if (*p == 'i') nkeynes@362: --p; nkeynes@362: nkeynes@362: if (rm) nkeynes@362: { nkeynes@362: /* mwait %eax,%ecx */ nkeynes@362: strcpy (p, "mwait"); nkeynes@362: if (!intel_syntax) nkeynes@362: strcpy (op1out, names32[0]); nkeynes@362: } nkeynes@362: else nkeynes@362: { nkeynes@362: /* monitor %eax,%ecx,%edx" */ nkeynes@362: strcpy (p, "monitor"); nkeynes@362: if (!intel_syntax) nkeynes@362: { nkeynes@362: if (!mode_64bit) nkeynes@362: strcpy (op1out, names32[0]); nkeynes@362: else if (!(prefixes & PREFIX_ADDR)) nkeynes@362: strcpy (op1out, names64[0]); nkeynes@362: else nkeynes@362: { nkeynes@362: strcpy (op1out, names32[0]); nkeynes@362: used_prefixes |= PREFIX_ADDR; nkeynes@362: } nkeynes@362: strcpy (op3out, names32[2]); nkeynes@362: } nkeynes@362: } nkeynes@362: if (!intel_syntax) nkeynes@362: { nkeynes@362: strcpy (op2out, names32[1]); nkeynes@362: two_source_ops = 1; nkeynes@362: } nkeynes@362: nkeynes@362: codep++; nkeynes@362: } nkeynes@362: else nkeynes@362: OP_E (0, sizeflag); nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: INVLPG_Fixup (int bytemode, int sizeflag) nkeynes@362: { nkeynes@362: const char *alt; nkeynes@362: nkeynes@362: switch (*codep) nkeynes@362: { nkeynes@362: case 0xf8: nkeynes@362: alt = "swapgs"; nkeynes@362: break; nkeynes@362: case 0xf9: nkeynes@362: alt = "rdtscp"; nkeynes@362: break; nkeynes@362: default: nkeynes@362: OP_E (bytemode, sizeflag); nkeynes@362: return; nkeynes@362: } nkeynes@362: /* Override "invlpg". */ nkeynes@362: strcpy (obuf + strlen (obuf) - 6, alt); nkeynes@362: codep++; nkeynes@362: } nkeynes@362: nkeynes@362: static void nkeynes@362: BadOp (void) nkeynes@362: { nkeynes@362: /* Throw away prefixes and 1st. opcode byte. */ nkeynes@362: codep = insn_codep + 1; nkeynes@362: oappend ("(bad)"); nkeynes@362: }