diff options
-rw-r--r-- | binutils/ChangeLog | 4 | ||||
-rw-r--r-- | binutils/doc/binutils.texi | 13 | ||||
-rw-r--r-- | include/ChangeLog | 4 | ||||
-rw-r--r-- | include/dis-asm.h | 1 | ||||
-rw-r--r-- | opcodes/ChangeLog | 13 | ||||
-rw-r--r-- | opcodes/disassemble.c | 6 | ||||
-rw-r--r-- | opcodes/i386-dis.c | 199 |
7 files changed, 159 insertions, 81 deletions
diff --git a/binutils/ChangeLog b/binutils/ChangeLog index a35ea64..66cb990 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,7 @@ +2001-11-14 Alan Modra <amodra@bigpond.net.au> + + * doc/binutils.texi (objdump): Document x86 -M options. + 2001-11-13 Keith Walker <keith.walker@arm.com> * readelf.c (read_and_display_attr_value): New function to diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi index 45878cb..8a48607 100644 --- a/binutils/doc/binutils.texi +++ b/binutils/doc/binutils.texi @@ -1569,6 +1569,19 @@ using the switch @option{--disassembler-options=force-thumb}. This can be useful when attempting to disassemble thumb code produced by other compilers. +For the x86, some of the options duplicate functions of the @option{-m} +switch, but allow finer grained control. Multiple selections from the +following may be specified as a comma separated string. +@option{x86_64}, @option{i386} and @option{i8086} select disassembly for +the given architecture. @option{intel} and @option{att} select between +intel syntax mode and AT&T syntax mode. @option{addr32}, +@option{addr16}, @option{data32} and @option{data16} specify the default +address size and operand size. These four options will be overridden if +@option{x86_64}, @option{i386} or @option{i8086} appear later in the +option string. Lastly, @option{suffix}, when in AT&T mode, +instructs the dissassembler to print a mnemonic suffix even when the +suffix could be inferred by the operands. + @item -p @itemx --private-headers Print information that is specific to the object file format. The exact diff --git a/include/ChangeLog b/include/ChangeLog index 03663a4..4fea6f2 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,7 @@ +2001-11-14 Alan Modra <amodra@bigpond.net.au> + + * dis-asm.h (print_insn_i386): Declare. + 2001-11-11 Timothy Wall <twall@alum.mit.edu> * dis-asm.h: Fix comment to refer to octets rather than bytes. diff --git a/include/dis-asm.h b/include/dis-asm.h index 96f1dcf..1a4f287 100644 --- a/include/dis-asm.h +++ b/include/dis-asm.h @@ -177,6 +177,7 @@ typedef int (*disassembler_ftype) extern int print_insn_big_mips PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_little_mips PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i386 PARAMS ((bfd_vma, disassemble_info *)); extern int print_insn_i386_att PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_i386_intel PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_ia64 PARAMS ((bfd_vma, disassemble_info*)); diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index 84237c0..1805306 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,16 @@ +2001-11-14 Alan Modra <amodra@bigpond.net.au> + + * disassemble.c (disassembler): Call print_insn_i386. + * i386-dis.c (SUFFIX_ALWAYS): Define. + (struct dis_private): Add orig_sizeflag. + (print_insn_i386): Make it a wrapper, calling.. + (print_insn): ..The old body of print_insn_i386. Avoid longjmp + warning without using volatile by moving orig_sizeflag to priv, + and removing inbuf. Parse disassembler_options. + (print_insn_i386_att, print_insn_i386_intel): Move initialisation + code to print_insn. + (putop): Remove #ifdef SUFFIX_ALWAYS. + 2001-11-11 Timothy Wall <twall@alum.mit.edu> * tic54x-dis.c: Use revised opcode structure. Export opcode diff --git a/opcodes/disassemble.c b/opcodes/disassemble.c index ef2756d..3a978d4 100644 --- a/opcodes/disassemble.c +++ b/opcodes/disassemble.c @@ -150,11 +150,7 @@ disassembler (abfd) #endif #ifdef ARCH_i386 case bfd_arch_i386: - if (bfd_get_mach (abfd) == bfd_mach_i386_i386_intel_syntax - || bfd_get_mach (abfd) == bfd_mach_x86_64_intel_syntax) - disassemble = print_insn_i386_intel; - else - disassemble = print_insn_i386_att; + disassemble = print_insn_i386; break; #endif #ifdef ARCH_i860 diff --git a/opcodes/i386-dis.c b/opcodes/i386-dis.c index 9a16d52..6926dab 100644 --- a/opcodes/i386-dis.c +++ b/opcodes/i386-dis.c @@ -52,7 +52,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *)); static void ckprefix PARAMS ((void)); static const char *prefix_name PARAMS ((int, int)); -static int print_insn_i386 PARAMS ((bfd_vma, disassemble_info *)); +static int print_insn PARAMS ((bfd_vma, disassemble_info *)); static void dofloat PARAMS ((int)); static void OP_ST PARAMS ((int, int)); static void OP_STi PARAMS ((int, int)); @@ -101,6 +101,7 @@ struct dis_private { bfd_byte *max_fetched; bfd_byte the_buffer[MAXLEN]; bfd_vma insn_start; + int orig_sizeflag; jmp_buf bailout; }; @@ -298,9 +299,7 @@ fetch_data (info, addr) #define loop_jcxz_flag NULL, loop_jcxz_mode /* bits in sizeflag */ -#if 0 /* Leave undefined until someone adds the extra flag to objdump. */ #define SUFFIX_ALWAYS 4 -#endif #define AFLAG 2 #define DFLAG 1 @@ -442,9 +441,9 @@ struct dis386 { 'N' => print 'n' if instruction has no wait "prefix" 'O' => print 'd', or 'o' 'P' => print 'w', 'l' or 'q' if instruction has an operand size prefix, - or suffix_always is true - print 'q' if rex prefix is present. - 'Q' => print 'w', 'l' or 'q' if no register operands or suffix_always is true + . or suffix_always is true. print 'q' if rex prefix is present. + 'Q' => print 'w', 'l' or 'q' if no register operands or suffix_always + . is true 'R' => print 'w', 'l' or 'q' ("wd" or "dq" in intel mode) 'S' => print 'w', 'l' or 'q' if suffix_always is true 'T' => print 'q' in 64bit mode and behave as 'P' otherwise @@ -1837,25 +1836,17 @@ static char close_char; static char separator_char; static char scale_char; +/* Here for backwards compatibility. When gdb stops using + print_insn_i386_att and print_insn_i386_intel these functions can + disappear, and print_insn_i386 be merged into print_insn. */ int print_insn_i386_att (pc, info) bfd_vma pc; disassemble_info *info; { intel_syntax = 0; - names64 = att_names64; - names32 = att_names32; - names16 = att_names16; - names8 = att_names8; - names8rex = att_names8rex; - names_seg = att_names_seg; - index16 = att_index16; - open_char = '('; - close_char = ')'; - separator_char = ','; - scale_char = ','; - - return print_insn_i386 (pc, info); + + return print_insn (pc, info); } int @@ -1864,51 +1855,127 @@ print_insn_i386_intel (pc, info) disassemble_info *info; { intel_syntax = 1; - names64 = intel_names64; - names32 = intel_names32; - names16 = intel_names16; - names8 = intel_names8; - names8rex = intel_names8rex; - names_seg = intel_names_seg; - index16 = intel_index16; - open_char = '['; - close_char = ']'; - separator_char = '+'; - scale_char = '*'; - - return print_insn_i386 (pc, info); + + return print_insn (pc, info); } -static int +int print_insn_i386 (pc, info) bfd_vma pc; disassemble_info *info; { + intel_syntax = -1; + + return print_insn (pc, info); +} + +static int +print_insn (pc, info) + bfd_vma pc; + disassemble_info *info; +{ const struct dis386 *dp; int i; int two_source_ops; char *first, *second, *third; int needcomma; unsigned char uses_SSE_prefix; - VOLATILE int sizeflag; - VOLATILE int orig_sizeflag; - + int sizeflag; + const char *p; struct dis_private priv; - bfd_byte *inbuf = priv.the_buffer; mode_64bit = (info->mach == bfd_mach_x86_64_intel_syntax || info->mach == bfd_mach_x86_64); + if (intel_syntax == -1) + intel_syntax = (info->mach == bfd_mach_i386_i386_intel_syntax + || info->mach == bfd_mach_x86_64_intel_syntax); + if (info->mach == bfd_mach_i386_i386 || info->mach == bfd_mach_x86_64 || info->mach == bfd_mach_i386_i386_intel_syntax || info->mach == bfd_mach_x86_64_intel_syntax) - sizeflag = AFLAG | DFLAG; + priv.orig_sizeflag = AFLAG | DFLAG; else if (info->mach == bfd_mach_i386_i8086) - sizeflag = 0; + priv.orig_sizeflag = 0; else abort (); - orig_sizeflag = sizeflag; + + for (p = info->disassembler_options; p != NULL; ) + { + if (strncmp (p, "x86_64", 6) == 0) + { + mode_64bit = 1; + priv.orig_sizeflag = AFLAG | DFLAG; + } + else if (strncmp (p, "i386", 4) == 0) + { + mode_64bit = 0; + priv.orig_sizeflag = AFLAG | DFLAG; + } + else if (strncmp (p, "i8086", 5) == 0) + { + mode_64bit = 0; + priv.orig_sizeflag = 0; + } + else if (strncmp (p, "intel", 5) == 0) + { + intel_syntax = 1; + } + else if (strncmp (p, "att", 3) == 0) + { + intel_syntax = 0; + } + else if (strncmp (p, "addr", 4) == 0) + { + if (p[4] == '1' && p[5] == '6') + priv.orig_sizeflag &= ~AFLAG; + else if (p[4] == '3' && p[5] == '2') + priv.orig_sizeflag |= AFLAG; + } + else if (strncmp (p, "data", 4) == 0) + { + if (p[4] == '1' && p[5] == '6') + priv.orig_sizeflag &= ~DFLAG; + else if (p[4] == '3' && p[5] == '2') + priv.orig_sizeflag |= DFLAG; + } + else if (strncmp (p, "suffix", 6) == 0) + priv.orig_sizeflag |= SUFFIX_ALWAYS; + + p = strchr (p, ','); + if (p != NULL) + p++; + } + + if (intel_syntax) + { + names64 = intel_names64; + names32 = intel_names32; + names16 = intel_names16; + names8 = intel_names8; + names8rex = intel_names8rex; + names_seg = intel_names_seg; + index16 = intel_index16; + open_char = '['; + close_char = ']'; + separator_char = '+'; + scale_char = '*'; + } + else + { + names64 = att_names64; + names32 = att_names32; + names16 = att_names16; + names8 = att_names8; + names8rex = att_names8rex; + names_seg = att_names_seg; + index16 = att_index16; + open_char = '('; + close_char = ')'; + separator_char = ','; + scale_char = ','; + } /* The output looks better if we put 7 bytes on a line, since that puts most long word instructions on a single line. */ @@ -1927,26 +1994,26 @@ print_insn_i386 (pc, info) the_info = info; start_pc = pc; - start_codep = inbuf; - codep = inbuf; + start_codep = priv.the_buffer; + codep = priv.the_buffer; if (setjmp (priv.bailout) != 0) { const char *name; /* Getting here means we tried for data but didn't get it. That - means we have an incomplete instruction of some sort. Just - print the first byte as a prefix or a .byte pseudo-op. */ - if (codep > inbuf) + means we have an incomplete instruction of some sort. Just + print the first byte as a prefix or a .byte pseudo-op. */ + if (codep > priv.the_buffer) { - name = prefix_name (inbuf[0], orig_sizeflag); + name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); if (name != NULL) (*info->fprintf_func) (info->stream, "%s", name); else { /* Just print the first byte as a .byte instruction. */ (*info->fprintf_func) (info->stream, ".byte 0x%x", - (unsigned int) inbuf[0]); + (unsigned int) priv.the_buffer[0]); } return 1; @@ -1959,6 +2026,7 @@ print_insn_i386 (pc, info) ckprefix (); insn_codep = codep; + sizeflag = priv.orig_sizeflag; FETCH_DATA (info, codep + 1); two_source_ops = (*codep == 0x62) || (*codep == 0xc8); @@ -1970,7 +2038,7 @@ print_insn_i386 (pc, info) /* fwait not followed by floating point instruction. Print the first prefix, which is probably fwait itself. */ - name = prefix_name (inbuf[0], orig_sizeflag); + name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); if (name == NULL) name = INTERNAL_DISASSEMBLER_ERROR; (*info->fprintf_func) (info->stream, "%s", name); @@ -2116,7 +2184,7 @@ print_insn_i386 (pc, info) { const char *name; - name = prefix_name (inbuf[0], orig_sizeflag); + name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); if (name == NULL) name = INTERNAL_DISASSEMBLER_ERROR; (*info->fprintf_func) (info->stream, "%s", name); @@ -2125,7 +2193,7 @@ print_insn_i386 (pc, info) if (rex & ~rex_used) { const char *name; - name = prefix_name (rex | 0x40, orig_sizeflag); + name = prefix_name (rex | 0x40, priv.orig_sizeflag); if (name == NULL) name = INTERNAL_DISASSEMBLER_ERROR; (*info->fprintf_func) (info->stream, "%s ", name); @@ -2189,7 +2257,7 @@ print_insn_i386 (pc, info) (*info->print_address_func) ((bfd_vma) (start_pc + codep - start_codep + op_address[op_index[i]]), info); } - return codep - inbuf; + return codep - priv.the_buffer; } static const char *float_mem[] = { @@ -2548,20 +2616,14 @@ putop (template, sizeflag) case 'A': if (intel_syntax) break; - if (mod != 3 -#ifdef SUFFIX_ALWAYS - || (sizeflag & SUFFIX_ALWAYS) -#endif - ) + if (mod != 3 || (sizeflag & SUFFIX_ALWAYS)) *obufp++ = 'b'; break; case 'B': if (intel_syntax) break; -#ifdef SUFFIX_ALWAYS if (sizeflag & SUFFIX_ALWAYS) *obufp++ = 'b'; -#endif break; case 'E': /* For jcxz/jecxz */ if (sizeflag & AFLAG) @@ -2571,11 +2633,7 @@ putop (template, sizeflag) case 'F': if (intel_syntax) break; - if ((prefixes & PREFIX_ADDR) -#ifdef SUFFIX_ALWAYS - || (sizeflag & SUFFIX_ALWAYS) -#endif - ) + if ((prefixes & PREFIX_ADDR) || (sizeflag & SUFFIX_ALWAYS)) { if (sizeflag & AFLAG) *obufp++ = 'l'; @@ -2602,10 +2660,8 @@ putop (template, sizeflag) case 'L': if (intel_syntax) break; -#ifdef SUFFIX_ALWAYS if (sizeflag & SUFFIX_ALWAYS) *obufp++ = 'l'; -#endif break; case 'N': if ((prefixes & PREFIX_FWAIT) == 0) @@ -2634,10 +2690,7 @@ putop (template, sizeflag) break; if ((prefixes & PREFIX_DATA) || (rex & REX_MODE64) -#ifdef SUFFIX_ALWAYS - || (sizeflag & SUFFIX_ALWAYS) -#endif - ) + || (sizeflag & SUFFIX_ALWAYS)) { USED_REX (REX_MODE64); if (rex & REX_MODE64) @@ -2665,11 +2718,7 @@ putop (template, sizeflag) if (intel_syntax) break; USED_REX (REX_MODE64); - if (mod != 3 -#ifdef SUFFIX_ALWAYS - || (sizeflag & SUFFIX_ALWAYS) -#endif - ) + if (mod != 3 || (sizeflag & SUFFIX_ALWAYS)) { if (rex & REX_MODE64) *obufp++ = 'q'; @@ -2718,7 +2767,6 @@ putop (template, sizeflag) case 'S': if (intel_syntax) break; -#ifdef SUFFIX_ALWAYS if (sizeflag & SUFFIX_ALWAYS) { if (rex & REX_MODE64) @@ -2732,7 +2780,6 @@ putop (template, sizeflag) used_prefixes |= (prefixes & PREFIX_DATA); } } -#endif break; case 'X': if (prefixes & PREFIX_DATA) |