diff options
author | Jan Beulich <jbeulich@suse.com> | 2019-12-27 09:38:34 +0100 |
---|---|---|
committer | Jan Beulich <jbeulich@suse.com> | 2019-12-27 09:38:34 +0100 |
commit | 376cd056100dff2d6fc842aa013d0bbffdef363d (patch) | |
tree | 2fb3cf2b8cfcc1a3fe9cdda133e21fa0e4146377 /opcodes/i386-dis.c | |
parent | 48bcea9f48cce70005307befbc604de3618bbaf7 (diff) | |
download | gdb-376cd056100dff2d6fc842aa013d0bbffdef363d.zip gdb-376cd056100dff2d6fc842aa013d0bbffdef363d.tar.gz gdb-376cd056100dff2d6fc842aa013d0bbffdef363d.tar.bz2 |
x86-64: fix Intel64 handling of branch with data16 prefix
The expectation of x86-64-branch-3 for "call" / "jmp" with an obvious
direct destination to translate to an indirect _far_ branch is plain
wrong. The operand size prefix should have no effect at all on the
interpretation of the operand. The main underlying issue here is that
the Intel64 templates of the direct branches don't include Disp16, yet
various assumptions exist that it would always be there when there's
also Disp32/Disp32S, toggled by the operand size prefix (which is
being ignored by direct branches in Intel64 mode).
Along these lines it was also wrong to base the displacement width
decision solely on the operand size prefix: REX.W cancels this effect
and hence needs taking into consideration, too.
A disassembler change is needed here as well: XBEGIN was wrongly treated
the same as direct CALL/JMP, which isn't the case - the operand size
prefix does affect displacement size there, it's merely ignored when it
comes to updating [ER]IP.
Diffstat (limited to 'opcodes/i386-dis.c')
-rw-r--r-- | opcodes/i386-dis.c | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/opcodes/i386-dis.c b/opcodes/i386-dis.c index 2a0e765..6693b70 100644 --- a/opcodes/i386-dis.c +++ b/opcodes/i386-dis.c @@ -296,6 +296,7 @@ fetch_data (struct disassemble_info *info, bfd_byte *addr) #define I1 { OP_I, const_1_mode } #define Jb { OP_J, b_mode } #define Jv { OP_J, v_mode } +#define Jdqw { OP_J, dqw_mode } #define Cm { OP_C, m_mode } #define Dm { OP_D, m_mode } #define Td { OP_T, d_mode } @@ -558,7 +559,8 @@ enum v_bndmk_mode, /* operand size depends on REX prefixes. */ dq_mode, - /* registers like dq_mode, memory like w_mode. */ + /* registers like dq_mode, memory like w_mode, displacements like + v_mode without considering Intel64 ISA. */ dqw_mode, /* bounds operand */ bnd_mode, @@ -10969,7 +10971,7 @@ static const struct dis386 rm_table[][8] = { }, { /* RM_C7_REG_7 */ - { "xbeginT", { Skip_MODRM, Jv }, 0 }, + { "xbeginT", { Skip_MODRM, Jdqw }, 0 }, }, { /* RM_0F01_REG_0 */ @@ -14828,10 +14830,12 @@ OP_J (int bytemode, int sizeflag) break; case v_mode: if (isa64 == amd64) + case dqw_mode: USED_REX (REX_W); if ((sizeflag & DFLAG) || (address_mode == mode_64bit - && (isa64 != amd64 || (rex & REX_W)))) + && ((isa64 != amd64 && bytemode != dqw_mode) + || (rex & REX_W)))) disp = get32s (); else { |