aboutsummaryrefslogtreecommitdiff
path: root/opcodes/i386-dis.c
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2015-05-15 09:47:39 -0700
committerH.J. Lu <hjl.tools@gmail.com>2015-05-15 09:48:10 -0700
commit5db04b0965e3e7a9344a93de22caae3c111de2cc (patch)
tree40942f68d18dc161c6512acad6f408d1e55ce18b /opcodes/i386-dis.c
parent0e602686df5677fee06cbd1718b4a7aa5379cd2a (diff)
downloadgdb-5db04b0965e3e7a9344a93de22caae3c111de2cc.zip
gdb-5db04b0965e3e7a9344a93de22caae3c111de2cc.tar.gz
gdb-5db04b0965e3e7a9344a93de22caae3c111de2cc.tar.bz2
Support AMD64/Intel ISAs in assembler/disassembler
AMD64 spec and Intel64 spec differ in direct unconditional branches in 64-bit mode. AMD64 supports direct unconditional branches with 16-bit offset via the data size prefix, which truncates RIP to 16 bits, while the data size prefix is ignored by Intel64. This patch adds -mamd64/-mintel64 option to x86-64 assembler and -Mamd64/-Mintel64 option to x86-64 disassembler. The most permissive ISA, which is AMD64, is the default. GDB can add an option, similar to (gdb) help set disassembly-flavor Set the disassembly flavor. The valid values are "att" and "intel", and the default value is "att". to select which ISA to disassemble. binutils/ PR binutis/18386 * doc/binutils.texi: Document -Mamd64 and -Mintel64. gas/ PR binutis/18386 * config/tc-i386.c (OPTION_MAMD64): New. (OPTION_MINTEL64): Likewise. (md_longopts): Add -mamd64 and -mintel64. (md_parse_option): Handle OPTION_MAMD64 and OPTION_MINTEL64. (md_show_usage): Add -mamd64 and -mintel64. * doc/c-i386.texi: Document -mamd64 and -mintel64. gas/testsuite/ PR binutis/18386 * gas/i386/i386.exp: Run x86-64-branch-2 and x86-64-branch-3. * gas/i386/x86-64-branch.d: Also pass -Mintel64 to objdump. * gas/i386/ilp32/x86-64-branch.d: Likewise. * gas/i386/x86-64-branch-2.d: New file. * gas/i386/x86-64-branch-2.s: Likewise. * gas/i386/x86-64-branch-3.l: Likewise. * gas/i386/x86-64-branch-3.s: Likewise. ld/testsuite/ PR binutis/18386 * ld-x86-64/tlsgdesc.dd: Also pass -Mintel64 to objdump. * ld-x86-64/tlspic.dd: Likewise. * ld-x86-64/x86-64.exp (x86_64tests): Also pass -Mintel64 to objdump for tlspic.dd and tlsgdesc.dd. opcodes/ PR binutis/18386 * i386-dis.c: Add comments for '@'. (x86_64_table): Use '@' on call/jmp for X86_64_E8/X86_64_E9. (enum x86_64_isa): New. (isa64): Likewise. (print_i386_disassembler_options): Add amd64 and intel64. (print_insn): Handle amd64 and intel64. (putop): Handle '@'. (OP_J): Don't ignore the operand size prefix for AMD64 in 64-bit. * i386-gen.c (cpu_flags): Add CpuAMD64 and CpuIntel64. * i386-opc.h (AMD64): New. (CpuIntel64): Likewise. (i386_cpu_flags): Add cpuamd64 and cpuintel64. * i386-opc.tbl: Add direct call/jmp with Disp16|Disp32 for AMD64. Mark direct call/jmp without Disp16|Disp32 as Intel64. * i386-init.h: Regenerated. * i386-tbl.h: Likewise.
Diffstat (limited to 'opcodes/i386-dis.c')
-rw-r--r--opcodes/i386-dis.c45
1 files changed, 40 insertions, 5 deletions
diff --git a/opcodes/i386-dis.c b/opcodes/i386-dis.c
index 941f699..76f3ead 100644
--- a/opcodes/i386-dis.c
+++ b/opcodes/i386-dis.c
@@ -2418,6 +2418,8 @@ struct dis386 {
'%' => add 1 upper case letter to the macro.
'^' => print 'w' or 'l' depending on operand size prefix or
suffix_always is true (lcall/ljmp).
+ '@' => print 'q' for Intel64 ISA, 'w' or 'q' for AMD64 ISA depending
+ on operand size prefix.
2 upper case letter macros:
"XY" => print 'x' or 'y' if suffix_always is true or no register
@@ -6844,13 +6846,13 @@ static const struct dis386 x86_64_table[][2] = {
/* X86_64_E8 */
{
{ "callP", { Jv, BND }, 0 },
- { "callq", { Jv, BND }, 0 }
+ { "call@", { Jv, BND }, 0 }
},
/* X86_64_E9 */
{
{ "jmpP", { Jv, BND }, 0 },
- { "jmpq", { Jv, BND }, 0 }
+ { "jmp@", { Jv, BND }, 0 }
},
/* X86_64_EA */
@@ -12342,6 +12344,14 @@ static char close_char;
static char separator_char;
static char scale_char;
+enum x86_64_isa
+{
+ amd64 = 0,
+ intel64
+};
+
+static enum x86_64_isa isa64;
+
/* Here for backwards compatibility. When gdb stops using
print_insn_i386_att and print_insn_i386_intel these functions can
disappear, and print_insn_i386 be merged into print_insn. */
@@ -12391,6 +12401,8 @@ with the -M switch (multiple options should be separated by commas):\n"));
fprintf (stream, _(" data32 Assume 32bit data size\n"));
fprintf (stream, _(" data16 Assume 16bit data size\n"));
fprintf (stream, _(" suffix Always display instruction suffix in AT&T syntax\n"));
+ fprintf (stream, _(" amd64 Display instruction in AMD64 ISA\n"));
+ fprintf (stream, _(" intel64 Display instruction in Intel64 ISA\n"));
}
/* Bad opcode. */
@@ -12874,7 +12886,11 @@ print_insn (bfd_vma pc, disassemble_info *info)
for (p = info->disassembler_options; p != NULL; )
{
- if (CONST_STRNEQ (p, "x86-64"))
+ if (CONST_STRNEQ (p, "amd64"))
+ isa64 = amd64;
+ else if (CONST_STRNEQ (p, "intel64"))
+ isa64 = intel64;
+ else if (CONST_STRNEQ (p, "x86-64"))
{
address_mode = mode_64bit;
priv.orig_sizeflag = AFLAG | DFLAG;
@@ -14208,6 +14224,20 @@ case_S:
used_prefixes |= (prefixes & PREFIX_DATA);
}
break;
+ case '@':
+ if (intel_syntax)
+ break;
+ if (address_mode == mode_64bit
+ && (isa64 == intel64
+ || ((sizeflag & DFLAG) || (rex & REX_W))))
+ *obufp++ = 'q';
+ else if ((prefixes & PREFIX_DATA))
+ {
+ if (!(sizeflag & DFLAG))
+ *obufp++ = 'w';
+ used_prefixes |= (prefixes & PREFIX_DATA);
+ }
+ break;
}
alt = 0;
}
@@ -15724,7 +15754,11 @@ OP_J (int bytemode, int sizeflag)
disp -= 0x100;
break;
case v_mode:
- if (address_mode == mode_64bit || (sizeflag & DFLAG))
+ if (isa64 == amd64)
+ USED_REX (REX_W);
+ if ((sizeflag & DFLAG)
+ || (address_mode == mode_64bit
+ && (isa64 != amd64 || (rex & REX_W))))
disp = get32s ();
else
{
@@ -15740,7 +15774,8 @@ OP_J (int bytemode, int sizeflag)
segment = ((start_pc + codep - start_codep)
& ~((bfd_vma) 0xffff));
}
- if (address_mode != mode_64bit)
+ if (address_mode != mode_64bit
+ || (isa64 == amd64 && !(rex & REX_W)))
used_prefixes |= (prefixes & PREFIX_DATA);
break;
default: