diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2020-01-27 04:38:10 -0800 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2020-01-27 04:38:29 -0800 |
commit | bc31405ebb2c4297ae815ab59f59165014347528 (patch) | |
tree | 4298be1f20f511497e961d2e672f38b0d2e75bf6 /opcodes/i386-dis.c | |
parent | e3696f67abfc46dcac6c9bbe47f8e25e34b17be5 (diff) | |
download | gdb-bc31405ebb2c4297ae815ab59f59165014347528.zip gdb-bc31405ebb2c4297ae815ab59f59165014347528.tar.gz gdb-bc31405ebb2c4297ae815ab59f59165014347528.tar.bz2 |
x86-64: Properly encode and decode movsxd
movsxd is a 64-bit only instruction. It supports both 16-bit and 32-bit
destination registers. Its AT&T mnemonic is movslq which only supports
64-bit destination register. There is also a discrepancy between AMD64
and Intel64 on movsxd with 16-bit destination register. AMD64 supports
32-bit source operand and Intel64 supports 16-bit source operand.
This patch updates movsxd encoding and decoding to alow 16-bit and 32-bit
destination registers. It also handles movsxd with 16-bit destination
register for AMD64 and Intel 64.
gas/
PR binutils/25445
* config/tc-i386.c (check_long_reg): Also convert to QWORD for
movsxd.
* doc/c-i386.texi: Add a node for AMD64 vs. Intel64 ISA
differences. Document movslq and movsxd.
* testsuite/gas/i386/i386.exp: Run PR binutils/25445 tests.
* testsuite/gas/i386/x86-64-movsxd-intel.d: New file.
* testsuite/gas/i386/x86-64-movsxd-intel64-intel.d: Likewise.
* testsuite/gas/i386/x86-64-movsxd-intel64-inval.l: Likewise.
* testsuite/gas/i386/x86-64-movsxd-intel64-inval.s: Likewise.
* testsuite/gas/i386/x86-64-movsxd-intel64.d: Likewise.
* testsuite/gas/i386/x86-64-movsxd-intel64.s: Likewise.
* testsuite/gas/i386/x86-64-movsxd-inval.l: Likewise.
* testsuite/gas/i386/x86-64-movsxd-inval.s: Likewise.
* testsuite/gas/i386/x86-64-movsxd.d: Likewise.
* testsuite/gas/i386/x86-64-movsxd.s: Likewise.
opcodes/
PR binutils/25445
* i386-dis.c (MOVSXD_Fixup): New function.
(movsxd_mode): New enum.
(x86_64_table): Use MOVSXD_Fixup and movsxd_mode on movsxd.
(intel_operand_size): Handle movsxd_mode.
(OP_E_register): Likewise.
(OP_G): Likewise.
* i386-opc.tbl: Remove Rex64 and allow 32-bit destination
register on movsxd. Add movsxd with 16-bit destination register
for AMD64 and Intel64 ISAs.
* i386-tbl.h: Regenerated.
Diffstat (limited to 'opcodes/i386-dis.c')
-rw-r--r-- | opcodes/i386-dis.c | 61 |
1 files changed, 59 insertions, 2 deletions
diff --git a/opcodes/i386-dis.c b/opcodes/i386-dis.c index c73e964..e6f73bf 100644 --- a/opcodes/i386-dis.c +++ b/opcodes/i386-dis.c @@ -124,6 +124,7 @@ static void OP_Vex_2src_1 (int, int); static void OP_Vex_2src_2 (int, int); static void MOVBE_Fixup (int, int); +static void MOVSXD_Fixup (int, int); static void OP_Mask (int, int); @@ -556,6 +557,7 @@ enum a_mode, cond_jump_mode, loop_jcxz_mode, + movsxd_mode, v_bnd_mode, /* like v_bnd_mode in 32bit, no RIP-rel in 64bit mode. */ v_bndmk_mode, @@ -6873,7 +6875,7 @@ static const struct dis386 x86_64_table[][2] = { /* X86_64_63 */ { { "arpl", { Ew, Gw }, 0 }, - { "movs{lq|xd}", { Gv, Ed }, 0 }, + { "movs", { { OP_G, movsxd_mode }, { MOVSXD_Fixup, movsxd_mode } }, 0 }, }, /* X86_64_6D */ @@ -13536,6 +13538,13 @@ intel_operand_size (int bytemode, int sizeflag) oappend ("DWORD PTR "); used_prefixes |= (prefixes & PREFIX_DATA); break; + case movsxd_mode: + if (!(sizeflag & DFLAG) && isa64 == intel64) + oappend ("WORD PTR "); + else + oappend ("DWORD PTR "); + used_prefixes |= (prefixes & PREFIX_DATA); + break; case d_mode: case d_scalar_mode: case d_scalar_swap_mode: @@ -13921,6 +13930,13 @@ OP_E_register (int bytemode, int sizeflag) used_prefixes |= (prefixes & PREFIX_DATA); } break; + case movsxd_mode: + if (!(sizeflag & DFLAG) && isa64 == intel64) + names = names16; + else + names = names32; + used_prefixes |= (prefixes & PREFIX_DATA); + break; case va_mode: names = (address_mode == mode_64bit ? names64 : names32); @@ -14492,12 +14508,14 @@ OP_G (int bytemode, int sizeflag) case dqb_mode: case dqd_mode: case dqw_mode: + case movsxd_mode: USED_REX (REX_W); if (rex & REX_W) oappend (names64[modrm.reg + add]); else { - if ((sizeflag & DFLAG) || bytemode != v_mode) + if ((sizeflag & DFLAG) + || (bytemode != v_mode && bytemode != movsxd_mode)) oappend (names32[modrm.reg + add]); else oappend (names16[modrm.reg + add]); @@ -16564,6 +16582,45 @@ skip: } static void +MOVSXD_Fixup (int bytemode, int sizeflag) +{ + /* Add proper suffix to "movsxd". */ + char *p = mnemonicendp; + + switch (bytemode) + { + case movsxd_mode: + if (intel_syntax) + { + *p++ = 'x'; + *p++ = 'd'; + goto skip; + } + + USED_REX (REX_W); + if (rex & REX_W) + { + *p++ = 'l'; + *p++ = 'q'; + } + else + { + *p++ = 'x'; + *p++ = 'd'; + } + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + break; + } + +skip: + mnemonicendp = p; + *p = '\0'; + OP_E (bytemode, sizeflag); +} + +static void OP_LWPCB_E (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) { int reg; |