X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-i386.c;h=3d935c1bd8d90a3db88e95897a409438d55dafb5;hb=76bc74dc40db159493206725ff7d65ad5cd4897d;hp=d4bba26daa560a008e39c254b2eeab4131e2c273;hpb=fc225355e8a67d38373dbced800eb2848723dc44;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index d4bba26daa..3d935c1bd8 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -1,13 +1,13 @@ -/* i386.c -- Assemble code for the Intel 80386 +/* tc-i386.c -- Assemble code for the Intel 80386 Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006 + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) + the Free Software Foundation; either version 3, or (at your option) any later version. GAS is distributed in the hope that it will be useful, @@ -32,7 +32,6 @@ #include "subsegs.h" #include "dwarf2dbg.h" #include "dw2gencfi.h" -#include "opcode/i386.h" #include "elf/x86-64.h" #ifndef REGISTER_WARNINGS @@ -63,55 +62,39 @@ #endif #endif -static INLINE unsigned int mode_from_disp_size PARAMS ((unsigned int)); -static INLINE int fits_in_signed_byte PARAMS ((offsetT)); -static INLINE int fits_in_unsigned_byte PARAMS ((offsetT)); -static INLINE int fits_in_unsigned_word PARAMS ((offsetT)); -static INLINE int fits_in_signed_word PARAMS ((offsetT)); -static INLINE int fits_in_unsigned_long PARAMS ((offsetT)); -static INLINE int fits_in_signed_long PARAMS ((offsetT)); -static int smallest_imm_type PARAMS ((offsetT)); -static offsetT offset_in_range PARAMS ((offsetT, int)); -static int add_prefix PARAMS ((unsigned int)); -static void set_code_flag PARAMS ((int)); -static void set_16bit_gcc_code_flag PARAMS ((int)); -static void set_intel_syntax PARAMS ((int)); -static void set_cpu_arch PARAMS ((int)); +static void set_code_flag (int); +static void set_16bit_gcc_code_flag (int); +static void set_intel_syntax (int); +static void set_cpu_arch (int); #ifdef TE_PE -static void pe_directive_secrel PARAMS ((int)); +static void pe_directive_secrel (int); #endif -static void signed_cons PARAMS ((int)); -static char *output_invalid PARAMS ((int c)); -static int i386_operand PARAMS ((char *operand_string)); -static int i386_intel_operand PARAMS ((char *operand_string, int got_a_float)); -static const reg_entry *parse_register PARAMS ((char *reg_string, - char **end_op)); -static char *parse_insn PARAMS ((char *, char *)); -static char *parse_operands PARAMS ((char *, const char *)); -static void swap_operands PARAMS ((void)); -static void swap_imm_operands PARAMS ((void)); -static void optimize_imm PARAMS ((void)); -static void optimize_disp PARAMS ((void)); -static int match_template PARAMS ((void)); -static int check_string PARAMS ((void)); -static int process_suffix PARAMS ((void)); -static int check_byte_reg PARAMS ((void)); -static int check_long_reg PARAMS ((void)); -static int check_qword_reg PARAMS ((void)); -static int check_word_reg PARAMS ((void)); -static int finalize_imm PARAMS ((void)); -static int process_operands PARAMS ((void)); -static const seg_entry *build_modrm_byte PARAMS ((void)); -static void output_insn PARAMS ((void)); -static void output_branch PARAMS ((void)); -static void output_jump PARAMS ((void)); -static void output_interseg_jump PARAMS ((void)); -static void output_imm PARAMS ((fragS *insn_start_frag, - offsetT insn_start_off)); -static void output_disp PARAMS ((fragS *insn_start_frag, - offsetT insn_start_off)); +static void signed_cons (int); +static char *output_invalid (int c); +static int i386_operand (char *); +static int i386_intel_operand (char *, int); +static const reg_entry *parse_register (char *, char **); +static char *parse_insn (char *, char *); +static char *parse_operands (char *, const char *); +static void swap_operands (void); +static void swap_2_operands (int, int); +static void optimize_imm (void); +static void optimize_disp (void); +static int match_template (void); +static int check_string (void); +static int process_suffix (void); +static int check_byte_reg (void); +static int check_long_reg (void); +static int check_qword_reg (void); +static int check_word_reg (void); +static int finalize_imm (void); +static int process_operands (void); +static const seg_entry *build_modrm_byte (void); +static void output_insn (void); +static void output_imm (fragS *, offsetT); +static void output_disp (fragS *, offsetT); #ifndef I386COFF -static void s_bss PARAMS ((int)); +static void s_bss (int); #endif #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) static void handle_large_common (int small ATTRIBUTE_UNUSED); @@ -272,8 +255,9 @@ static i386_insn i; /* Possible templates for current insn. */ static const templates *current_templates; -/* Per instruction expressionS buffers: 2 displacements & 2 immediate max. */ -static expressionS disp_expressions[2], im_expressions[2]; +/* Per instruction expressionS buffers: max displacements & immediates. */ +static expressionS disp_expressions[MAX_MEMORY_OPERANDS]; +static expressionS im_expressions[MAX_IMMEDIATE_OPERANDS]; /* Current operand we are working on. */ static int this_operand; @@ -306,6 +290,9 @@ static int intel_syntax = 0; /* 1 if register prefix % not required. */ static int allow_naked_reg = 0; +/* Register prefix used for error message. */ +static const char *register_prefix = "%"; + /* Used in 16 bit gcc mode to add an l suffix to call, ret, enter, leave, push, and pop instructions so that gcc has the same stack frame as in 32 bit mode. */ @@ -444,7 +431,7 @@ static const arch_entry cpu_arch[] = Cpu186}, {"i286", PROCESSOR_UNKNOWN, Cpu186|Cpu286}, - {"i386", PROCESSOR_GENERIC32, + {"i386", PROCESSOR_I386, Cpu186|Cpu286|Cpu386}, {"i486", PROCESSOR_I486, Cpu186|Cpu286|Cpu386|Cpu486}, @@ -511,6 +498,12 @@ static const arch_entry cpu_arch[] = CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3}, {".ssse3", PROCESSOR_UNKNOWN, CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3}, + {".sse4.1", PROCESSOR_UNKNOWN, + CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuSSE4_1}, + {".sse4.2", PROCESSOR_UNKNOWN, + CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuSSE4}, + {".sse4", PROCESSOR_UNKNOWN, + CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuSSE4}, {".3dnow", PROCESSOR_UNKNOWN, CpuMMX|Cpu3dnow}, {".3dnowa", PROCESSOR_UNKNOWN, @@ -554,7 +547,7 @@ const pseudo_typeS md_pseudo_table[] = #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) {"largecomm", handle_large_common, 0}, #else - {"file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0}, + {"file", (void (*) (int)) dwarf2_directive_file, 0}, {"loc", dwarf2_directive_loc, 0}, {"loc_mark_labels", dwarf2_directive_loc_mark_labels, 0}, #endif @@ -574,9 +567,7 @@ static struct hash_control *op_hash; static struct hash_control *reg_hash; void -i386_align_code (fragP, count) - fragS *fragP; - int count; +i386_align_code (fragS *fragP, int count) { /* Various efficient no-op patterns for aligning code labels. Note: Don't try to assemble the instructions in the comments. @@ -617,9 +608,6 @@ i386_align_code (fragP, count) static const char f32_14[] = {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00, /* leal 0L(%esi,1),%esi */ 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ - static const char f32_15[] = - {0xeb,0x0d,0x90,0x90,0x90,0x90,0x90, /* jmp .+15; lotsa nops */ - 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90}; static const char f16_3[] = {0x8d,0x74,0x00}; /* lea 0(%esi),%esi */ static const char f16_4[] = @@ -636,13 +624,17 @@ i386_align_code (fragP, count) static const char f16_8[] = {0x8d,0xb4,0x00,0x00, /* lea 0w(%si),%si */ 0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */ + static const char jump_31[] = + {0xeb,0x1d,0x90,0x90,0x90,0x90,0x90, /* jmp .+31; lotsa nops */ + 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, + 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, + 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90}; static const char *const f32_patt[] = { f32_1, f32_2, f32_3, f32_4, f32_5, f32_6, f32_7, f32_8, - f32_9, f32_10, f32_11, f32_12, f32_13, f32_14, f32_15 + f32_9, f32_10, f32_11, f32_12, f32_13, f32_14 }; static const char *const f16_patt[] = { - f32_1, f32_2, f16_3, f16_4, f16_5, f16_6, f16_7, f16_8, - f32_15, f32_15, f32_15, f32_15, f32_15, f32_15, f32_15 + f32_1, f32_2, f16_3, f16_4, f16_5, f16_6, f16_7, f16_8 }; /* nopl (%[re]ax) */ static const char alt_3[] = @@ -749,56 +741,40 @@ i386_align_code (fragP, count) alt_long_14, alt_long_15 }; - if (count <= 0 || count > 15) + /* Only align for at least a positive non-zero boundary. */ + if (count <= 0 || count > MAX_MEM_FOR_RS_ALIGN_CODE) return; /* We need to decide which NOP sequence to use for 32bit and 64bit. When -mtune= is used: - - 1. For PROCESSOR_I486, PROCESSOR_PENTIUM and PROCESSOR_GENERIC32, - f32_patt will be used. - 2. For PROCESSOR_K8 and PROCESSOR_AMDFAM10 in 64bit, NOPs with 0x66 prefix will be used. - 3. For PROCESSOR_CORE2, alt_long_patt will be used. - 4. For PROCESSOR_PENTIUMPRO, PROCESSOR_PENTIUM4, PROCESSOR_NOCONA, - PROCESSOR_CORE, PROCESSOR_CORE2, PROCESSOR_K6, PROCESSOR_ATHLON - and PROCESSOR_GENERIC64, alt_short_patt will be used. - - When -mtune= isn't used, alt_short_patt will be used if - cpu_arch_isa_flags has Cpu686. Otherwise, f32_patt will be used. + + 1. For PROCESSOR_I386, PROCESSOR_I486, PROCESSOR_PENTIUM and + PROCESSOR_GENERIC32, f32_patt will be used. + 2. For PROCESSOR_PENTIUMPRO, PROCESSOR_PENTIUM4, PROCESSOR_NOCONA, + PROCESSOR_CORE, PROCESSOR_CORE2, and PROCESSOR_GENERIC64, + alt_long_patt will be used. + 3. For PROCESSOR_ATHLON, PROCESSOR_K6, PROCESSOR_K8 and + PROCESSOR_AMDFAM10, alt_short_patt will be used. + + When -mtune= isn't used, alt_long_patt will be used if + cpu_arch_isa_flags has Cpu686. Otherwise, f32_patt will + be used. When -march= or .arch is used, we can't use anything beyond cpu_arch_isa_flags. */ if (flag_code == CODE_16BIT) { - memcpy (fragP->fr_literal + fragP->fr_fix, - f16_patt[count - 1], count); if (count > 8) - /* Adjust jump offset. */ - fragP->fr_literal[fragP->fr_fix + 1] = count - 2; - } - else if (flag_code == CODE_64BIT && cpu_arch_tune == PROCESSOR_K8) - { - int i; - int nnops = (count + 3) / 4; - int len = count / nnops; - int remains = count - nnops * len; - int pos = 0; - - /* The recommended way to pad 64bit code is to use NOPs preceded - by maximally four 0x66 prefixes. Balance the size of nops. */ - for (i = 0; i < remains; i++) - { - memset (fragP->fr_literal + fragP->fr_fix + pos, 0x66, len); - fragP->fr_literal[fragP->fr_fix + pos + len] = 0x90; - pos += len + 1; - } - for (; i < nnops; i++) { - memset (fragP->fr_literal + fragP->fr_fix + pos, 0x66, len - 1); - fragP->fr_literal[fragP->fr_fix + pos + len - 1] = 0x90; - pos += len; + memcpy (fragP->fr_literal + fragP->fr_fix, + jump_31, count); + /* Adjust jump offset. */ + fragP->fr_literal[fragP->fr_fix + 1] = count - 2; } + else + memcpy (fragP->fr_literal + fragP->fr_fix, + f16_patt[count - 1], count); } else { @@ -813,30 +789,31 @@ i386_align_code (fragP, count) /* We use cpu_arch_isa_flags to check if we SHOULD optimize for Cpu686. */ if ((cpu_arch_isa_flags & Cpu686) != 0) - patt = alt_short_patt; + patt = alt_long_patt; else patt = f32_patt; break; - case PROCESSOR_CORE2: - patt = alt_long_patt; - break; case PROCESSOR_PENTIUMPRO: case PROCESSOR_PENTIUM4: case PROCESSOR_NOCONA: case PROCESSOR_CORE: + case PROCESSOR_CORE2: + case PROCESSOR_GENERIC64: + patt = alt_long_patt; + break; case PROCESSOR_K6: case PROCESSOR_ATHLON: case PROCESSOR_K8: - case PROCESSOR_GENERIC64: - case PROCESSOR_AMDFAM10: + case PROCESSOR_AMDFAM10: patt = alt_short_patt; break; + case PROCESSOR_I386: case PROCESSOR_I486: case PROCESSOR_PENTIUM: case PROCESSOR_GENERIC32: patt = f32_patt; break; - } + } } else { @@ -848,16 +825,13 @@ i386_align_code (fragP, count) abort (); break; + case PROCESSOR_I386: case PROCESSOR_I486: case PROCESSOR_PENTIUM: - case PROCESSOR_PENTIUMPRO: - case PROCESSOR_PENTIUM4: - case PROCESSOR_NOCONA: - case PROCESSOR_CORE: case PROCESSOR_K6: case PROCESSOR_ATHLON: case PROCESSOR_K8: - case PROCESSOR_AMDFAM10: + case PROCESSOR_AMDFAM10: case PROCESSOR_GENERIC32: /* We use cpu_arch_isa_flags to check if we CAN optimize for Cpu686. */ @@ -866,6 +840,10 @@ i386_align_code (fragP, count) else patt = f32_patt; break; + case PROCESSOR_PENTIUMPRO: + case PROCESSOR_PENTIUM4: + case PROCESSOR_NOCONA: + case PROCESSOR_CORE: case PROCESSOR_CORE2: if ((cpu_arch_isa_flags & Cpu686) != 0) patt = alt_long_patt; @@ -873,54 +851,80 @@ i386_align_code (fragP, count) patt = f32_patt; break; case PROCESSOR_GENERIC64: - patt = alt_short_patt; + patt = alt_long_patt; break; - } + } } - memcpy (fragP->fr_literal + fragP->fr_fix, - patt[count - 1], count); + if (patt == f32_patt) + { + /* If the padding is less than 15 bytes, we use the normal + ones. Otherwise, we use a jump instruction and adjust + its offset. */ + if (count < 15) + memcpy (fragP->fr_literal + fragP->fr_fix, + patt[count - 1], count); + else + { + memcpy (fragP->fr_literal + fragP->fr_fix, + jump_31, count); + /* Adjust jump offset. */ + fragP->fr_literal[fragP->fr_fix + 1] = count - 2; + } + } + else + { + /* Maximum length of an instruction is 15 byte. If the + padding is greater than 15 bytes and we don't use jump, + we have to break it into smaller pieces. */ + int padding = count; + while (padding > 15) + { + padding -= 15; + memcpy (fragP->fr_literal + fragP->fr_fix + padding, + patt [14], 15); + } + + if (padding) + memcpy (fragP->fr_literal + fragP->fr_fix, + patt [padding - 1], padding); + } } fragP->fr_var = count; } static INLINE unsigned int -mode_from_disp_size (t) - unsigned int t; +mode_from_disp_size (unsigned int t) { return (t & Disp8) ? 1 : (t & (Disp16 | Disp32 | Disp32S)) ? 2 : 0; } static INLINE int -fits_in_signed_byte (num) - offsetT num; +fits_in_signed_byte (offsetT num) { return (num >= -128) && (num <= 127); } static INLINE int -fits_in_unsigned_byte (num) - offsetT num; +fits_in_unsigned_byte (offsetT num) { return (num & 0xff) == num; } static INLINE int -fits_in_unsigned_word (num) - offsetT num; +fits_in_unsigned_word (offsetT num) { return (num & 0xffff) == num; } static INLINE int -fits_in_signed_word (num) - offsetT num; +fits_in_signed_word (offsetT num) { return (-32768 <= num) && (num <= 32767); } + static INLINE int -fits_in_signed_long (num) - offsetT num ATTRIBUTE_UNUSED; +fits_in_signed_long (offsetT num ATTRIBUTE_UNUSED) { #ifndef BFD64 return 1; @@ -929,9 +933,9 @@ fits_in_signed_long (num) || (((offsetT) -1 << 31) & num) == ((offsetT) -1 << 31)); #endif } /* fits_in_signed_long() */ + static INLINE int -fits_in_unsigned_long (num) - offsetT num ATTRIBUTE_UNUSED; +fits_in_unsigned_long (offsetT num ATTRIBUTE_UNUSED) { #ifndef BFD64 return 1; @@ -940,9 +944,8 @@ fits_in_unsigned_long (num) #endif } /* fits_in_unsigned_long() */ -static int -smallest_imm_type (num) - offsetT num; +static unsigned int +smallest_imm_type (offsetT num) { if (cpu_arch_flags != (Cpu186 | Cpu286 | Cpu386 | Cpu486 | CpuNo64)) { @@ -968,9 +971,7 @@ smallest_imm_type (num) } static offsetT -offset_in_range (val, size) - offsetT val; - int size; +offset_in_range (offsetT val, int size) { addressT mask; @@ -1005,8 +1006,7 @@ offset_in_range (val, size) class already exists, 1 if non rep/repne added, 2 if rep/repne added. */ static int -add_prefix (prefix) - unsigned int prefix; +add_prefix (unsigned int prefix) { int ret = 1; unsigned int q; @@ -1014,9 +1014,9 @@ add_prefix (prefix) if (prefix >= REX_OPCODE && prefix < REX_OPCODE + 16 && flag_code == CODE_64BIT) { - if ((i.prefix[REX_PREFIX] & prefix & REX_MODE64) - || ((i.prefix[REX_PREFIX] & (REX_EXTX | REX_EXTY | REX_EXTZ)) - && (prefix & (REX_EXTX | REX_EXTY | REX_EXTZ)))) + if ((i.prefix[REX_PREFIX] & prefix & REX_W) + || ((i.prefix[REX_PREFIX] & (REX_R | REX_X | REX_B)) + && (prefix & (REX_R | REX_X | REX_B)))) ret = 0; q = REX_PREFIX; } @@ -1073,8 +1073,7 @@ add_prefix (prefix) } static void -set_code_flag (value) - int value; +set_code_flag (int value) { flag_code = value; cpu_arch_flags &= ~(Cpu64 | CpuNo64); @@ -1091,8 +1090,7 @@ set_code_flag (value) } static void -set_16bit_gcc_code_flag (new_code_flag) - int new_code_flag; +set_16bit_gcc_code_flag (int new_code_flag) { flag_code = new_code_flag; cpu_arch_flags &= ~(Cpu64 | CpuNo64); @@ -1101,8 +1099,7 @@ set_16bit_gcc_code_flag (new_code_flag) } static void -set_intel_syntax (syntax_flag) - int syntax_flag; +set_intel_syntax (int syntax_flag) { /* Find out if register prefixing is specified. */ int ask_naked_reg = 0; @@ -1133,11 +1130,11 @@ set_intel_syntax (syntax_flag) identifier_chars['%'] = intel_syntax && allow_naked_reg ? '%' : 0; identifier_chars['$'] = intel_syntax ? '$' : 0; + register_prefix = allow_naked_reg ? "" : "%"; } static void -set_cpu_arch (dummy) - int dummy ATTRIBUTE_UNUSED; +set_cpu_arch (int dummy ATTRIBUTE_UNUSED) { SKIP_WHITESPACE (); @@ -1156,7 +1153,8 @@ set_cpu_arch (dummy) cpu_arch_name = cpu_arch[i].name; cpu_sub_arch_name = NULL; cpu_arch_flags = (cpu_arch[i].flags - | (flag_code == CODE_64BIT ? Cpu64 : CpuNo64)); + | (flag_code == CODE_64BIT + ? Cpu64 : CpuNo64)); cpu_arch_isa = cpu_arch[i].type; cpu_arch_isa_flags = cpu_arch[i].flags; if (!cpu_arch_tune_set) @@ -1262,10 +1260,9 @@ md_begin () reg_hash = hash_new (); { const reg_entry *regtab; + unsigned int regtab_size = i386_regtab_size; - for (regtab = i386_regtab; - regtab < i386_regtab + sizeof (i386_regtab) / sizeof (i386_regtab[0]); - regtab++) + for (regtab = i386_regtab; regtab_size--; regtab++) { hash_err = hash_insert (reg_hash, regtab->reg_name, (PTR) regtab); if (hash_err) @@ -1320,6 +1317,7 @@ md_begin () #endif digit_chars['-'] = '-'; mnemonic_chars['-'] = '-'; + mnemonic_chars['.'] = '.'; identifier_chars['_'] = '_'; identifier_chars['.'] = '.'; @@ -1349,8 +1347,7 @@ md_begin () } void -i386_print_statistics (file) - FILE *file; +i386_print_statistics (FILE *file) { hash_print_statistics (file, "i386 opcode", op_hash); hash_print_statistics (file, "i386 register", reg_hash); @@ -1359,16 +1356,13 @@ i386_print_statistics (file) #ifdef DEBUG386 /* Debugging routines for md_assemble. */ -static void pi PARAMS ((char *, i386_insn *)); -static void pte PARAMS ((template *)); -static void pt PARAMS ((unsigned int)); -static void pe PARAMS ((expressionS *)); -static void ps PARAMS ((symbolS *)); +static void pte (template *); +static void pt (unsigned int); +static void pe (expressionS *); +static void ps (symbolS *); static void -pi (line, x) - char *line; - i386_insn *x; +pi (char *line, i386_insn *x) { unsigned int i; @@ -1383,10 +1377,10 @@ pi (line, x) fprintf (stdout, " sib: base %x index %x scale %x\n", x->sib.base, x->sib.index, x->sib.scale); fprintf (stdout, " rex: 64bit %x extX %x extY %x extZ %x\n", - (x->rex & REX_MODE64) != 0, - (x->rex & REX_EXTX) != 0, - (x->rex & REX_EXTY) != 0, - (x->rex & REX_EXTZ) != 0); + (x->rex & REX_W) != 0, + (x->rex & REX_R) != 0, + (x->rex & REX_X) != 0, + (x->rex & REX_B) != 0); for (i = 0; i < x->operands; i++) { fprintf (stdout, " #%d: ", i + 1); @@ -1403,8 +1397,7 @@ pi (line, x) } static void -pte (t) - template *t; +pte (template *t) { unsigned int i; fprintf (stdout, " %d operands ", t->operands); @@ -1425,8 +1418,7 @@ pte (t) } static void -pe (e) - expressionS *e; +pe (expressionS *e) { fprintf (stdout, " operation %d\n", e->X_op); fprintf (stdout, " add_number %ld (%lx)\n", @@ -1446,8 +1438,7 @@ pe (e) } static void -ps (s) - symbolS *s; +ps (symbolS *s) { fprintf (stdout, "%s type %s%s", S_GET_NAME (s), @@ -1610,8 +1601,7 @@ reloc (unsigned int size, some cases we force the original symbol to be used. */ int -tc_i386_fix_adjustable (fixP) - fixS *fixP ATTRIBUTE_UNUSED; +tc_i386_fix_adjustable (fixS *fixP ATTRIBUTE_UNUSED) { #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) if (!IS_ELF) @@ -1664,11 +1654,8 @@ tc_i386_fix_adjustable (fixP) return 1; } -static int intel_float_operand PARAMS ((const char *mnemonic)); - static int -intel_float_operand (mnemonic) - const char *mnemonic; +intel_float_operand (const char *mnemonic) { /* Note that the value returned is meaningful only for opcodes with (memory) operands, hence the code here is free to improperly handle opcodes that @@ -1751,14 +1738,14 @@ md_assemble (line) if (line == NULL) return; - /* The order of the immediates should be reversed + /* The order of the immediates should be reversed for 2 immediates extrq and insertq instructions */ - if ((i.imm_operands == 2) && - ((strcmp (mnemonic, "extrq") == 0) - || (strcmp (mnemonic, "insertq") == 0))) + if ((i.imm_operands == 2) + && ((strcmp (mnemonic, "extrq") == 0) + || (strcmp (mnemonic, "insertq") == 0))) { - swap_imm_operands (); - /* "extrq" and insertq" are the only two instructions whose operands + swap_2_operands (0, 1); + /* "extrq" and insertq" are the only two instructions whose operands have to be reversed even though they have two immediate operands. */ if (intel_syntax) @@ -1772,7 +1759,8 @@ md_assemble (line) "enter". We also don't reverse intersegment "jmp" and "call" instructions with 2 immediate operands so that the immediate segment precedes the offset, as it does when in AT&T mode. */ - if (intel_syntax && i.operands > 1 + if (intel_syntax + && i.operands > 1 && (strcmp (mnemonic, "bound") != 0) && (strcmp (mnemonic, "invlpga") != 0) && !((i.types[0] & Imm) && (i.types[1] & Imm))) @@ -1800,7 +1788,7 @@ md_assemble (line) /* Undo SYSV386_COMPAT brokenness when in Intel mode. See i386.h */ if (SYSV386_COMPAT && (i.tm.base_opcode & 0xfffffde0) == 0xdce0) - i.tm.base_opcode ^= FloatR; + i.tm.base_opcode ^= Opcode_FloatR; /* Zap movzx and movsx suffix. The suffix may have been set from "word ptr" or "byte ptr" on the source operand, but we'll use @@ -1864,8 +1852,11 @@ md_assemble (line) for (x = 0; x < i.operands; x++) if (i.op[x].regs->reg_num != x) - as_bad (_("can't use register '%%%s' as operand %d in '%s'."), - i.op[x].regs->reg_name, x + 1, i.tm.name); + as_bad (_("can't use register '%s%s' as operand %d in '%s'."), + register_prefix, + i.op[x].regs->reg_name, + x + 1, + i.tm.name); i.operands = 0; } @@ -1914,7 +1905,7 @@ md_assemble (line) } if ((i.tm.opcode_modifier & Rex64) != 0) - i.rex |= REX_MODE64; + i.rex |= REX_W; /* For 8 bit registers we need an empty rex prefix. Also if the instruction already has a prefix, we need to convert old @@ -1938,8 +1929,9 @@ md_assemble (line) { /* In case it is "hi" register, give up. */ if (i.op[x].regs->reg_num > 3) - as_bad (_("can't encode register '%%%s' in an instruction requiring REX prefix."), - i.op[x].regs->reg_name); + as_bad (_("can't encode register '%s%s' in an " + "instruction requiring REX prefix."), + register_prefix, i.op[x].regs->reg_name); /* Otherwise it is equivalent to the extended register. Since the encoding doesn't change this is merely @@ -1958,9 +1950,7 @@ md_assemble (line) } static char * -parse_insn (line, mnemonic) - char *line; - char *mnemonic; +parse_insn (char *line, char *mnemonic) { char *l = line; char *token_start = l; @@ -2179,9 +2169,7 @@ parse_insn (line, mnemonic) } static char * -parse_operands (l, mnemonic) - char *l; - const char *mnemonic; +parse_operands (char *l, const char *mnemonic) { char *token_start; @@ -2299,14 +2287,12 @@ parse_operands (l, mnemonic) } static void -swap_imm_operands () +swap_2_operands (int xchg1, int xchg2) { union i386_op temp_op; unsigned int temp_type; enum bfd_reloc_code_real temp_reloc; - int xchg1 = 0; - int xchg2 = 1; - + temp_type = i.types[xchg2]; i.types[xchg2] = i.types[xchg1]; i.types[xchg1] = temp_type; @@ -2318,55 +2304,20 @@ swap_imm_operands () i.reloc[xchg1] = temp_reloc; } - static void -swap_operands () +swap_operands (void) { - union i386_op temp_op; - unsigned int temp_type; - enum bfd_reloc_code_real temp_reloc; - int xchg1 = 0; - int xchg2 = 0; - - if (i.operands == 4) - /* There will be two exchanges in a 4 operand instruction. - First exchange is the done inside this block.(1st and 4rth operand) - The next exchange is done outside this block.(2nd and 3rd operand) */ - { - xchg1 = 0; - xchg2 = 3; - temp_type = i.types[xchg2]; - i.types[xchg2] = i.types[xchg1]; - i.types[xchg1] = temp_type; - temp_op = i.op[xchg2]; - i.op[xchg2] = i.op[xchg1]; - i.op[xchg1] = temp_op; - temp_reloc = i.reloc[xchg2]; - i.reloc[xchg2] = i.reloc[xchg1]; - i.reloc[xchg1] = temp_reloc; - xchg1 = 1; - xchg2 = 2; - } - - if (i.operands == 2) + switch (i.operands) { - xchg1 = 0; - xchg2 = 1; - } - else if (i.operands == 3) - { - xchg1 = 0; - xchg2 = 2; + case 4: + swap_2_operands (1, i.operands - 2); + case 3: + case 2: + swap_2_operands (0, i.operands - 1); + break; + default: + abort (); } - temp_type = i.types[xchg2]; - i.types[xchg2] = i.types[xchg1]; - i.types[xchg1] = temp_type; - temp_op = i.op[xchg2]; - i.op[xchg2] = i.op[xchg1]; - i.op[xchg1] = temp_op; - temp_reloc = i.reloc[xchg2]; - i.reloc[xchg2] = i.reloc[xchg1]; - i.reloc[xchg1] = temp_reloc; if (i.mem_operands == 2) { @@ -2380,7 +2331,7 @@ swap_operands () /* Try to ensure constant immediates are represented in the smallest opcode possible. */ static void -optimize_imm () +optimize_imm (void) { char guess_suffix = 0; int op; @@ -2470,8 +2421,10 @@ optimize_imm () unsigned int mask, allowed = 0; const template *t; - for (t = current_templates->start; t < current_templates->end; ++t) - allowed |= t->operand_types[op]; + for (t = current_templates->start; + t < current_templates->end; + ++t) + allowed |= t->operand_types[op]; switch (guess_suffix) { case QWORD_MNEM_SUFFIX: @@ -2500,7 +2453,7 @@ optimize_imm () /* Try to use the smallest displacement type too. */ static void -optimize_disp () +optimize_disp (void) { int op; @@ -2564,7 +2517,7 @@ optimize_disp () } static int -match_template () +match_template (void) { /* Points to template once we've found it. */ const template *t; @@ -2695,6 +2648,15 @@ match_template () continue; break; case 2: + /* xchg %eax, %eax is a special case. It is an aliase for nop + only in 32bit mode and we can use opcode 0x90. In 64bit + mode, we can't use 0x90 for xchg %eax, %eax since it should + zero-extend %eax to %rax. */ + if (flag_code == CODE_64BIT + && t->base_opcode == 0x90 + && i.types [0] == (Acc | Reg32) + && i.types [1] == (Acc | Reg32)) + continue; case 3: case 4: overlap1 = i.types[1] & operand_types[1]; @@ -2702,9 +2664,10 @@ match_template () || !MATCH (overlap1, i.types[1], operand_types[1]) /* monitor in SSE3 is a very special case. The first register and the second register may have different - sizes. */ + sizes. The same applies to crc32 in SSE4.2. */ || !((t->base_opcode == 0x0f01 && t->extension_opcode == 0xc8) + || t->base_opcode == 0xf20f38f1 || CONSISTENT_REGISTER_MATCH (overlap0, i.types[0], operand_types[0], overlap1, i.types[1], @@ -2729,7 +2692,14 @@ match_template () } /* found_reverse_match holds which of D or FloatDR we've found. */ - found_reverse_match = t->opcode_modifier & (D | FloatDR); + if ((t->opcode_modifier & D)) + found_reverse_match = Opcode_D; + else if ((t->opcode_modifier & FloatD)) + found_reverse_match = Opcode_FloatD; + else + found_reverse_match = 0; + if ((t->opcode_modifier & FloatR)) + found_reverse_match |= Opcode_FloatR; } else { @@ -2831,7 +2801,7 @@ match_template () } static int -check_string () +check_string (void) { int mem_op = (i.types[0] & AnyMem) ? 0 : 1; if ((i.tm.operand_types[mem_op] & EsSeg) != 0) @@ -2884,19 +2854,44 @@ process_suffix (void) { /* We take i.suffix from the last register operand specified, Destination register type is more significant than source - register type. */ - int op; - - for (op = i.operands; --op >= 0;) - if ((i.types[op] & Reg) - && !(i.tm.operand_types[op] & InOutPortReg)) - { - i.suffix = ((i.types[op] & Reg8) ? BYTE_MNEM_SUFFIX : - (i.types[op] & Reg16) ? WORD_MNEM_SUFFIX : - (i.types[op] & Reg64) ? QWORD_MNEM_SUFFIX : + register type. crc32 in SSE4.2 prefers source register + type. */ + if (i.tm.base_opcode == 0xf20f38f1) + { + if ((i.types[0] & Reg)) + i.suffix = ((i.types[0] & Reg16) ? WORD_MNEM_SUFFIX : LONG_MNEM_SUFFIX); - break; - } + } + else if (i.tm.base_opcode == 0xf20f38f0) + { + if ((i.types[0] & Reg8)) + i.suffix = BYTE_MNEM_SUFFIX; + } + + if (!i.suffix) + { + int op; + + if (i.tm.base_opcode == 0xf20f38f1 + || i.tm.base_opcode == 0xf20f38f0) + { + /* We have to know the operand size for crc32. */ + as_bad (_("ambiguous memory operand size for `%s`"), + i.tm.name); + return 0; + } + + for (op = i.operands; --op >= 0;) + if ((i.types[op] & Reg) + && !(i.tm.operand_types[op] & InOutPortReg)) + { + i.suffix = ((i.types[op] & Reg8) ? BYTE_MNEM_SUFFIX : + (i.types[op] & Reg16) ? WORD_MNEM_SUFFIX : + (i.types[op] & Reg64) ? QWORD_MNEM_SUFFIX : + LONG_MNEM_SUFFIX); + break; + } + } } else if (i.suffix == BYTE_MNEM_SUFFIX) { @@ -2963,7 +2958,8 @@ process_suffix (void) { if (i.tm.opcode_modifier & W) { - as_bad (_("no instruction mnemonic suffix given and no register operands; can't size instruction")); + as_bad (_("no instruction mnemonic suffix given and " + "no register operands; can't size instruction")); return 0; } } @@ -3040,8 +3036,8 @@ process_suffix (void) if (i.operands != 2 || i.types [0] != (Acc | Reg64) || i.types [1] != (Acc | Reg64) - || strcmp (i.tm.name, "xchg") != 0) - i.rex |= REX_MODE64; + || i.tm.base_opcode != 0x90) + i.rex |= REX_W; } /* Size floating point instruction. */ @@ -3075,6 +3071,10 @@ check_byte_reg (void) || i.tm.base_opcode == 0xfbf)) continue; + /* crc32 doesn't generate this warning. */ + if (i.tm.base_opcode == 0xf20f38f0) + continue; + if ((i.types[op] & WordReg) && i.op[op].regs->reg_num < 4) { /* Prohibit these changes in the 64bit mode, since the @@ -3082,18 +3082,20 @@ check_byte_reg (void) if (flag_code == CODE_64BIT && (i.tm.operand_types[op] & InOutPortReg) == 0) { - as_bad (_("Incorrect register `%%%s' used with `%c' suffix"), - i.op[op].regs->reg_name, + as_bad (_("Incorrect register `%s%s' used with `%c' suffix"), + register_prefix, i.op[op].regs->reg_name, i.suffix); return 0; } #if REGISTER_WARNINGS if (!quiet_warnings && (i.tm.operand_types[op] & InOutPortReg) == 0) - as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"), + as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"), + register_prefix, (i.op[op].regs + (i.types[op] & Reg16 ? REGNAM_AL - REGNAM_AX : REGNAM_AL - REGNAM_EAX))->reg_name, + register_prefix, i.op[op].regs->reg_name, i.suffix); #endif @@ -3105,7 +3107,8 @@ check_byte_reg (void) | Control | Debug | Test | FloatReg | FloatAcc)) { - as_bad (_("`%%%s' not allowed with `%s%c'"), + as_bad (_("`%s%s' not allowed with `%s%c'"), + register_prefix, i.op[op].regs->reg_name, i.tm.name, i.suffix); @@ -3116,7 +3119,7 @@ check_byte_reg (void) } static int -check_long_reg () +check_long_reg (void) { int op; @@ -3126,7 +3129,8 @@ check_long_reg () if ((i.types[op] & Reg8) != 0 && (i.tm.operand_types[op] & (Reg16 | Reg32 | Acc)) != 0) { - as_bad (_("`%%%s' not allowed with `%s%c'"), + as_bad (_("`%s%s' not allowed with `%s%c'"), + register_prefix, i.op[op].regs->reg_name, i.tm.name, i.suffix); @@ -3141,15 +3145,17 @@ check_long_reg () lowering is more complicated. */ if (flag_code == CODE_64BIT) { - as_bad (_("Incorrect register `%%%s' used with `%c' suffix"), - i.op[op].regs->reg_name, + as_bad (_("Incorrect register `%s%s' used with `%c' suffix"), + register_prefix, i.op[op].regs->reg_name, i.suffix); return 0; } #if REGISTER_WARNINGS else - as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"), + as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"), + register_prefix, (i.op[op].regs + REGNAM_EAX - REGNAM_AX)->reg_name, + register_prefix, i.op[op].regs->reg_name, i.suffix); #endif @@ -3158,8 +3164,8 @@ check_long_reg () else if ((i.types[op] & Reg64) != 0 && (i.tm.operand_types[op] & (Reg32 | Acc)) != 0) { - as_bad (_("Incorrect register `%%%s' used with `%c' suffix"), - i.op[op].regs->reg_name, + as_bad (_("Incorrect register `%s%s' used with `%c' suffix"), + register_prefix, i.op[op].regs->reg_name, i.suffix); return 0; } @@ -3167,7 +3173,7 @@ check_long_reg () } static int -check_qword_reg () +check_qword_reg (void) { int op; @@ -3177,7 +3183,8 @@ check_qword_reg () if ((i.types[op] & Reg8) != 0 && (i.tm.operand_types[op] & (Reg16 | Reg32 | Acc)) != 0) { - as_bad (_("`%%%s' not allowed with `%s%c'"), + as_bad (_("`%s%s' not allowed with `%s%c'"), + register_prefix, i.op[op].regs->reg_name, i.tm.name, i.suffix); @@ -3190,8 +3197,8 @@ check_qword_reg () { /* Prohibit these changes in the 64bit mode, since the lowering is more complicated. */ - as_bad (_("Incorrect register `%%%s' used with `%c' suffix"), - i.op[op].regs->reg_name, + as_bad (_("Incorrect register `%s%s' used with `%c' suffix"), + register_prefix, i.op[op].regs->reg_name, i.suffix); return 0; } @@ -3199,7 +3206,7 @@ check_qword_reg () } static int -check_word_reg () +check_word_reg (void) { int op; for (op = i.operands; --op >= 0;) @@ -3208,7 +3215,8 @@ check_word_reg () if ((i.types[op] & Reg8) != 0 && (i.tm.operand_types[op] & (Reg16 | Reg32 | Acc)) != 0) { - as_bad (_("`%%%s' not allowed with `%s%c'"), + as_bad (_("`%s%s' not allowed with `%s%c'"), + register_prefix, i.op[op].regs->reg_name, i.tm.name, i.suffix); @@ -3223,15 +3231,17 @@ check_word_reg () lowering is more complicated. */ if (flag_code == CODE_64BIT) { - as_bad (_("Incorrect register `%%%s' used with `%c' suffix"), - i.op[op].regs->reg_name, + as_bad (_("Incorrect register `%s%s' used with `%c' suffix"), + register_prefix, i.op[op].regs->reg_name, i.suffix); return 0; } else #if REGISTER_WARNINGS - as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"), + as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"), + register_prefix, (i.op[op].regs + REGNAM_AX - REGNAM_EAX)->reg_name, + register_prefix, i.op[op].regs->reg_name, i.suffix); #endif @@ -3240,7 +3250,7 @@ check_word_reg () } static int -finalize_imm () +finalize_imm (void) { unsigned int overlap0, overlap1, overlap2; @@ -3271,7 +3281,8 @@ finalize_imm () && overlap0 != Imm16 && overlap0 != Imm32S && overlap0 != Imm32 && overlap0 != Imm64) { - as_bad (_("no instruction mnemonic suffix given; can't determine immediate size")); + as_bad (_("no instruction mnemonic suffix given; " + "can't determine immediate size")); return 0; } } @@ -3304,7 +3315,9 @@ finalize_imm () && overlap1 != Imm16 && overlap1 != Imm32S && overlap1 != Imm32 && overlap1 != Imm64) { - as_bad (_("no instruction mnemonic suffix given; can't determine immediate size %x %c"),overlap1, i.suffix); + as_bad (_("no instruction mnemonic suffix given; " + "can't determine immediate size %x %c"), + overlap1, i.suffix); return 0; } } @@ -3318,7 +3331,7 @@ finalize_imm () } static int -process_operands () +process_operands (void) { /* Default segment register this instruction will use for memory accesses. 0 means unknown. This is only for optimizing out @@ -3328,40 +3341,90 @@ process_operands () /* The imul $imm, %reg instruction is converted into imul $imm, %reg, %reg, and the clr %reg instruction is converted into xor %reg, %reg. */ - if (i.tm.opcode_modifier & regKludge) - { - unsigned int first_reg_op = (i.types[0] & Reg) ? 0 : 1; - /* Pretend we saw the extra register operand. */ - assert (i.op[first_reg_op + 1].regs == 0); - i.op[first_reg_op + 1].regs = i.op[first_reg_op].regs; - i.types[first_reg_op + 1] = i.types[first_reg_op]; - i.reg_operands = 2; + if (i.tm.opcode_modifier & RegKludge) + { + if ((i.tm.cpu_flags & CpuSSE4_1)) + { + /* The first operand in instruction blendvpd, blendvps and + pblendvb in SSE4.1 is implicit and must be xmm0. */ + assert (i.operands == 3 + && i.reg_operands >= 2 + && i.types[0] == RegXMM); + if (i.op[0].regs->reg_num != 0) + { + if (intel_syntax) + as_bad (_("the last operand of `%s' must be `%sxmm0'"), + i.tm.name, register_prefix); + else + as_bad (_("the first operand of `%s' must be `%sxmm0'"), + i.tm.name, register_prefix); + return 0; + } + i.op[0] = i.op[1]; + i.op[1] = i.op[2]; + i.types[0] = i.types[1]; + i.types[1] = i.types[2]; + i.operands--; + i.reg_operands--; + + /* We need to adjust fields in i.tm since they are used by + build_modrm_byte. */ + i.tm.operand_types [0] = i.tm.operand_types [1]; + i.tm.operand_types [1] = i.tm.operand_types [2]; + i.tm.operands--; + } + else + { + unsigned int first_reg_op = (i.types[0] & Reg) ? 0 : 1; + /* Pretend we saw the extra register operand. */ + assert (i.reg_operands == 1 + && i.op[first_reg_op + 1].regs == 0); + i.op[first_reg_op + 1].regs = i.op[first_reg_op].regs; + i.types[first_reg_op + 1] = i.types[first_reg_op]; + i.operands++; + i.reg_operands++; + } } if (i.tm.opcode_modifier & ShortForm) { - /* The register or float register operand is in operand 0 or 1. */ - unsigned int op = (i.types[0] & (Reg | FloatReg)) ? 0 : 1; - /* Register goes in low 3 bits of opcode. */ - i.tm.base_opcode |= i.op[op].regs->reg_num; - if ((i.op[op].regs->reg_flags & RegRex) != 0) - i.rex |= REX_EXTZ; - if (!quiet_warnings && (i.tm.opcode_modifier & Ugh) != 0) + if (i.types[0] & (SReg2 | SReg3)) { - /* Warn about some common errors, but press on regardless. - The first case can be generated by gcc (<= 2.8.1). */ - if (i.operands == 2) + if (i.tm.base_opcode == POP_SEG_SHORT + && i.op[0].regs->reg_num == 1) { - /* Reversed arguments on faddp, fsubp, etc. */ - as_warn (_("translating to `%s %%%s,%%%s'"), i.tm.name, - i.op[1].regs->reg_name, - i.op[0].regs->reg_name); + as_bad (_("you can't `pop %%cs'")); + return 0; } - else + i.tm.base_opcode |= (i.op[0].regs->reg_num << 3); + if ((i.op[0].regs->reg_flags & RegRex) != 0) + i.rex |= REX_B; + } + else + { + /* The register or float register operand is in operand 0 or 1. */ + unsigned int op = (i.types[0] & (Reg | FloatReg)) ? 0 : 1; + /* Register goes in low 3 bits of opcode. */ + i.tm.base_opcode |= i.op[op].regs->reg_num; + if ((i.op[op].regs->reg_flags & RegRex) != 0) + i.rex |= REX_B; + if (!quiet_warnings && (i.tm.opcode_modifier & Ugh) != 0) { - /* Extraneous `l' suffix on fp insn. */ - as_warn (_("translating to `%s %%%s'"), i.tm.name, - i.op[0].regs->reg_name); + /* Warn about some common errors, but press on regardless. + The first case can be generated by gcc (<= 2.8.1). */ + if (i.operands == 2) + { + /* Reversed arguments on faddp, fsubp, etc. */ + as_warn (_("translating to `%s %s%s,%s%s'"), i.tm.name, + register_prefix, i.op[1].regs->reg_name, + register_prefix, i.op[0].regs->reg_name); + } + else + { + /* Extraneous `l' suffix on fp insn. */ + as_warn (_("translating to `%s %s%s'"), i.tm.name, + register_prefix, i.op[0].regs->reg_name); + } } } } @@ -3373,19 +3436,7 @@ process_operands () default_seg = build_modrm_byte (); } - else if (i.tm.opcode_modifier & (Seg2ShortForm | Seg3ShortForm)) - { - if (i.tm.base_opcode == POP_SEG_SHORT - && i.op[0].regs->reg_num == 1) - { - as_bad (_("you can't `pop %%cs'")); - return 0; - } - i.tm.base_opcode |= (i.op[0].regs->reg_num << 3); - if ((i.op[0].regs->reg_flags & RegRex) != 0) - i.rex |= REX_EXTZ; - } - else if ((i.tm.base_opcode & ~(D | W)) == MOV_AX_DISP32) + else if ((i.tm.base_opcode & ~0x3) == MOV_AX_DISP32) { default_seg = &ds; } @@ -3415,7 +3466,7 @@ process_operands () } static const seg_entry * -build_modrm_byte () +build_modrm_byte (void) { const seg_entry *default_seg = 0; @@ -3424,16 +3475,33 @@ build_modrm_byte () if (i.reg_operands == 2) { unsigned int source, dest; - source = ((i.types[0] - & (Reg | RegMMX | RegXMM - | SReg2 | SReg3 - | Control | Debug | Test)) - ? 0 : 1); - - /* In 4 operands instructions with 2 immediate operands, the first - two are immediate bytes and hence source operand will be in the - next byte after the immediates */ - if ((i.operands == 4)&&(i.imm_operands=2)) source++; + + switch (i.operands) + { + case 2: + source = 0; + break; + case 3: + /* When there are 3 operands, one of them may be immediate, + which may be the first or the last operand. Otherwise, + the first operand must be shift count register (cl). */ + assert (i.imm_operands == 1 + || (i.imm_operands == 0 + && (i.types[0] & ShiftCount))); + source = (i.types[0] & (Imm | ShiftCount)) ? 1 : 0; + break; + case 4: + /* When there are 4 operands, the first two must be immediate + operands. The source operand will be the 3rd one. */ + assert (i.imm_operands == 2 + && (i.types[0] & Imm) + && (i.types[1] & Imm)); + source = 2; + break; + default: + abort (); + } + dest = source + 1; i.rm.mode = 3; @@ -3443,29 +3511,29 @@ build_modrm_byte () destination operand, then we assume the source operand may sometimes be a memory operand and so we need to store the destination in the i.rm.reg field. */ - if ((i.tm.operand_types[dest] & AnyMem) == 0) + if ((i.tm.operand_types[dest] & (AnyMem | RegMem)) == 0) { i.rm.reg = i.op[dest].regs->reg_num; i.rm.regmem = i.op[source].regs->reg_num; if ((i.op[dest].regs->reg_flags & RegRex) != 0) - i.rex |= REX_EXTX; + i.rex |= REX_R; if ((i.op[source].regs->reg_flags & RegRex) != 0) - i.rex |= REX_EXTZ; + i.rex |= REX_B; } else { i.rm.reg = i.op[source].regs->reg_num; i.rm.regmem = i.op[dest].regs->reg_num; if ((i.op[dest].regs->reg_flags & RegRex) != 0) - i.rex |= REX_EXTZ; + i.rex |= REX_B; if ((i.op[source].regs->reg_flags & RegRex) != 0) - i.rex |= REX_EXTX; + i.rex |= REX_R; } - if (flag_code != CODE_64BIT && (i.rex & (REX_EXTX | REX_EXTZ))) + if (flag_code != CODE_64BIT && (i.rex & (REX_R | REX_B))) { if (!((i.types[0] | i.types[1]) & Control)) abort (); - i.rex &= ~(REX_EXTX | REX_EXTZ); + i.rex &= ~(REX_R | REX_B); add_prefix (LOCK_PREFIX_OPCODE); } } @@ -3474,9 +3542,12 @@ build_modrm_byte () if (i.mem_operands) { unsigned int fake_zero_displacement = 0; - unsigned int op = ((i.types[0] & AnyMem) - ? 0 - : (i.types[1] & AnyMem) ? 1 : 2); + unsigned int op; + + for (op = 0; op < i.operands; op++) + if ((i.types[op] & AnyMem)) + break; + assert (op < i.operands); default_seg = &ds; @@ -3524,7 +3595,7 @@ build_modrm_byte () else i.types[op] |= Disp32S; if ((i.index_reg->reg_flags & RegRex) != 0) - i.rex |= REX_EXTY; + i.rex |= REX_X; } } /* RIP addressing for 64bit mode. */ @@ -3577,7 +3648,7 @@ build_modrm_byte () i.rm.regmem = i.base_reg->reg_num; if ((i.base_reg->reg_flags & RegRex) != 0) - i.rex |= REX_EXTZ; + i.rex |= REX_B; i.sib.base = i.base_reg->reg_num; /* x86-64 ignores REX prefix bit here to avoid decoder complications. */ @@ -3614,7 +3685,7 @@ build_modrm_byte () i.sib.index = i.index_reg->reg_num; i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; if ((i.index_reg->reg_flags & RegRex) != 0) - i.rex |= REX_EXTY; + i.rex |= REX_X; } if (i.disp_operands @@ -3647,31 +3718,28 @@ build_modrm_byte () registers are coded into the i.rm.reg field. */ if (i.reg_operands) { - unsigned int op = - ((i.types[0] - & (Reg | RegMMX | RegXMM - | SReg2 | SReg3 - | Control | Debug | Test)) - ? 0 - : ((i.types[1] - & (Reg | RegMMX | RegXMM - | SReg2 | SReg3 - | Control | Debug | Test)) - ? 1 - : 2)); + unsigned int op; + + for (op = 0; op < i.operands; op++) + if ((i.types[op] & (Reg | RegMMX | RegXMM + | SReg2 | SReg3 + | Control | Debug | Test))) + break; + assert (op < i.operands); + /* If there is an extension opcode to put here, the register number must be put into the regmem field. */ if (i.tm.extension_opcode != None) { i.rm.regmem = i.op[op].regs->reg_num; if ((i.op[op].regs->reg_flags & RegRex) != 0) - i.rex |= REX_EXTZ; + i.rex |= REX_B; } else { i.rm.reg = i.op[op].regs->reg_num; if ((i.op[op].regs->reg_flags & RegRex) != 0) - i.rex |= REX_EXTX; + i.rex |= REX_R; } /* Now, if no memory operand has set i.rm.mode = 0, 1, 2 we @@ -3689,7 +3757,7 @@ build_modrm_byte () } static void -output_branch () +output_branch (void) { char *p; int code16; @@ -3767,7 +3835,7 @@ output_branch () } static void -output_jump () +output_jump (void) { char *p; int size; @@ -3833,7 +3901,7 @@ output_jump () } static void -output_interseg_jump () +output_interseg_jump (void) { char *p; int size; @@ -3897,7 +3965,7 @@ output_interseg_jump () } static void -output_insn () +output_insn (void) { fragS *insn_start_frag; offsetT insn_start_off; @@ -3924,11 +3992,12 @@ output_insn () unsigned char *q; unsigned int prefix; - /* All opcodes on i386 have either 1 or 2 bytes. Supplemental - Streaming SIMD extensions 3 Instructions have 3 bytes. We may - use one more higher byte to specify a prefix the instruction - requires. */ - if ((i.tm.cpu_flags & CpuSSSE3) != 0) + /* All opcodes on i386 have either 1 or 2 bytes. SSSE3 and + SSE4 instructions have 3 bytes. We may use one more higher + byte to specify a prefix the instruction requires. Exclude + instructions which are in both SSE4 and ABM. */ + if ((i.tm.cpu_flags & (CpuSSSE3 | CpuSSE4)) != 0 + && (i.tm.cpu_flags & CpuABM) == 0) { if (i.tm.base_opcode & 0xff000000) { @@ -3969,7 +4038,8 @@ output_insn () } else { - if ((i.tm.cpu_flags & CpuSSSE3) != 0) + if ((i.tm.cpu_flags & (CpuSSSE3 | CpuSSE4)) != 0 + && (i.tm.cpu_flags & CpuABM) == 0) { p = frag_more (3); *p++ = (i.tm.base_opcode >> 16) & 0xff; @@ -4023,6 +4093,40 @@ output_insn () #endif /* DEBUG386 */ } +/* Return the size of the displacement operand N. */ + +static int +disp_size (unsigned int n) +{ + int size = 4; + if (i.types[n] & (Disp8 | Disp16 | Disp64)) + { + size = 2; + if (i.types[n] & Disp8) + size = 1; + if (i.types[n] & Disp64) + size = 8; + } + return size; +} + +/* Return the size of the immediate operand N. */ + +static int +imm_size (unsigned int n) +{ + int size = 4; + if (i.types[n] & (Imm8 | Imm8S | Imm16 | Imm64)) + { + size = 2; + if (i.types[n] & (Imm8 | Imm8S)) + size = 1; + if (i.types[n] & Imm64) + size = 8; + } + return size; +} + static void output_disp (fragS *insn_start_frag, offsetT insn_start_off) { @@ -4035,18 +4139,9 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off) { if (i.op[n].disps->X_op == O_constant) { - int size; + int size = disp_size (n); offsetT val; - size = 4; - if (i.types[n] & (Disp8 | Disp16 | Disp64)) - { - size = 2; - if (i.types[n] & Disp8) - size = 1; - if (i.types[n] & Disp64) - size = 8; - } val = offset_in_range (i.op[n].disps->X_add_number, size); p = frag_more (size); @@ -4055,45 +4150,32 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off) else { enum bfd_reloc_code_real reloc_type; - int size = 4; - int sign = 0; + int size = disp_size (n); + int sign = (i.types[n] & Disp32S) != 0; int pcrel = (i.flags[n] & Operand_PCrel) != 0; + /* We can't have 8 bit displacement here. */ + assert ((i.types[n] & Disp8) == 0); + /* The PC relative address is computed relative to the instruction boundary, so in case immediate fields follows, we need to adjust the value. */ if (pcrel && i.imm_operands) { - int imm_size = 4; unsigned int n1; + int sz = 0; for (n1 = 0; n1 < i.operands; n1++) if (i.types[n1] & Imm) { - if (i.types[n1] & (Imm8 | Imm8S | Imm16 | Imm64)) - { - imm_size = 2; - if (i.types[n1] & (Imm8 | Imm8S)) - imm_size = 1; - if (i.types[n1] & Imm64) - imm_size = 8; - } - break; + /* Only one immediate is allowed for PC + relative address. */ + assert (sz == 0); + sz = imm_size (n1); + i.op[n].disps->X_add_number -= sz; } /* We should find the immediate. */ - if (n1 == i.operands) - abort (); - i.op[n].disps->X_add_number -= imm_size; - } - - if (i.types[n] & Disp32S) - sign = 1; - - if (i.types[n] & (Disp16 | Disp64)) - { - size = 2; - if (i.types[n] & Disp64) - size = 8; + assert (sz != 0); } p = frag_more (size); @@ -4158,18 +4240,9 @@ output_imm (fragS *insn_start_frag, offsetT insn_start_off) { if (i.op[n].imms->X_op == O_constant) { - int size; + int size = imm_size (n); offsetT val; - size = 4; - if (i.types[n] & (Imm8 | Imm8S | Imm16 | Imm64)) - { - size = 2; - if (i.types[n] & (Imm8 | Imm8S)) - size = 1; - else if (i.types[n] & Imm64) - size = 8; - } val = offset_in_range (i.op[n].imms->X_add_number, size); p = frag_more (size); @@ -4182,21 +4255,15 @@ output_imm (fragS *insn_start_frag, offsetT insn_start_off) non-absolute imms). Try to support other sizes ... */ enum bfd_reloc_code_real reloc_type; - int size = 4; - int sign = 0; + int size = imm_size (n); + int sign; if ((i.types[n] & (Imm32S)) && (i.suffix == QWORD_MNEM_SUFFIX || (!i.suffix && (i.tm.opcode_modifier & No_lSuf)))) sign = 1; - if (i.types[n] & (Imm8 | Imm8S | Imm16 | Imm64)) - { - size = 2; - if (i.types[n] & (Imm8 | Imm8S)) - size = 1; - if (i.types[n] & Imm64) - size = 8; - } + else + sign = 0; p = frag_more (size); reloc_type = reloc (size, 0, sign, i.reloc[n]); @@ -4290,9 +4357,7 @@ static enum bfd_reloc_code_real got_reloc = NO_RELOC; static int cons_sign = -1; void -x86_cons_fix_new (fragS *frag, - unsigned int off, - unsigned int len, +x86_cons_fix_new (fragS *frag, unsigned int off, unsigned int len, expressionS *exp) { enum bfd_reloc_code_real r = reloc (len, 0, cons_sign, got_reloc); @@ -4337,23 +4402,57 @@ lex_got (enum bfd_reloc_code_real *reloc, const enum bfd_reloc_code_real rel[2]; const unsigned int types64; } gotrel[] = { - { "PLTOFF", { 0, BFD_RELOC_X86_64_PLTOFF64 }, Imm64 }, - { "PLT", { BFD_RELOC_386_PLT32, BFD_RELOC_X86_64_PLT32 }, Imm32|Imm32S|Disp32 }, - { "GOTPLT", { 0, BFD_RELOC_X86_64_GOTPLT64 }, Imm64|Disp64 }, - { "GOTOFF", { BFD_RELOC_386_GOTOFF, BFD_RELOC_X86_64_GOTOFF64 }, Imm64|Disp64 }, - { "GOTPCREL", { 0, BFD_RELOC_X86_64_GOTPCREL }, Imm32|Imm32S|Disp32 }, - { "TLSGD", { BFD_RELOC_386_TLS_GD, BFD_RELOC_X86_64_TLSGD }, Imm32|Imm32S|Disp32 }, - { "TLSLDM", { BFD_RELOC_386_TLS_LDM, 0 }, 0 }, - { "TLSLD", { 0, BFD_RELOC_X86_64_TLSLD }, Imm32|Imm32S|Disp32 }, - { "GOTTPOFF", { BFD_RELOC_386_TLS_IE_32, BFD_RELOC_X86_64_GOTTPOFF }, Imm32|Imm32S|Disp32 }, - { "TPOFF", { BFD_RELOC_386_TLS_LE_32, BFD_RELOC_X86_64_TPOFF32 }, Imm32|Imm32S|Imm64|Disp32|Disp64 }, - { "NTPOFF", { BFD_RELOC_386_TLS_LE, 0 }, 0 }, - { "DTPOFF", { BFD_RELOC_386_TLS_LDO_32, BFD_RELOC_X86_64_DTPOFF32 }, Imm32|Imm32S|Imm64|Disp32|Disp64 }, - { "GOTNTPOFF",{ BFD_RELOC_386_TLS_GOTIE, 0 }, 0 }, - { "INDNTPOFF",{ BFD_RELOC_386_TLS_IE, 0 }, 0 }, - { "GOT", { BFD_RELOC_386_GOT32, BFD_RELOC_X86_64_GOT32 }, Imm32|Imm32S|Disp32|Imm64 }, - { "TLSDESC", { BFD_RELOC_386_TLS_GOTDESC, BFD_RELOC_X86_64_GOTPC32_TLSDESC }, Imm32|Imm32S|Disp32 }, - { "TLSCALL", { BFD_RELOC_386_TLS_DESC_CALL, BFD_RELOC_X86_64_TLSDESC_CALL }, Imm32|Imm32S|Disp32 } + { "PLTOFF", { 0, + BFD_RELOC_X86_64_PLTOFF64 }, + Imm64 }, + { "PLT", { BFD_RELOC_386_PLT32, + BFD_RELOC_X86_64_PLT32 }, + Imm32 | Imm32S | Disp32 }, + { "GOTPLT", { 0, + BFD_RELOC_X86_64_GOTPLT64 }, + Imm64 | Disp64 }, + { "GOTOFF", { BFD_RELOC_386_GOTOFF, + BFD_RELOC_X86_64_GOTOFF64 }, + Imm64 | Disp64 }, + { "GOTPCREL", { 0, + BFD_RELOC_X86_64_GOTPCREL }, + Imm32 | Imm32S | Disp32 }, + { "TLSGD", { BFD_RELOC_386_TLS_GD, + BFD_RELOC_X86_64_TLSGD }, + Imm32 | Imm32S | Disp32 }, + { "TLSLDM", { BFD_RELOC_386_TLS_LDM, + 0 }, + 0 }, + { "TLSLD", { 0, + BFD_RELOC_X86_64_TLSLD }, + Imm32 | Imm32S | Disp32 }, + { "GOTTPOFF", { BFD_RELOC_386_TLS_IE_32, + BFD_RELOC_X86_64_GOTTPOFF }, + Imm32 | Imm32S | Disp32 }, + { "TPOFF", { BFD_RELOC_386_TLS_LE_32, + BFD_RELOC_X86_64_TPOFF32 }, + Imm32 | Imm32S | Imm64 | Disp32 | Disp64 }, + { "NTPOFF", { BFD_RELOC_386_TLS_LE, + 0 }, + 0 }, + { "DTPOFF", { BFD_RELOC_386_TLS_LDO_32, + BFD_RELOC_X86_64_DTPOFF32 }, + Imm32 | Imm32S | Imm64 | Disp32 | Disp64 }, + { "GOTNTPOFF",{ BFD_RELOC_386_TLS_GOTIE, + 0 }, + 0 }, + { "INDNTPOFF",{ BFD_RELOC_386_TLS_IE, + 0 }, + 0 }, + { "GOT", { BFD_RELOC_386_GOT32, + BFD_RELOC_X86_64_GOT32 }, + Imm32 | Imm32S | Disp32 | Imm64 }, + { "TLSDESC", { BFD_RELOC_386_TLS_GOTDESC, + BFD_RELOC_X86_64_GOTPC32_TLSDESC }, + Imm32 | Imm32S | Disp32 }, + { "TLSCALL", { BFD_RELOC_386_TLS_DESC_CALL, + BFD_RELOC_X86_64_TLSDESC_CALL }, + Imm32 | Imm32S | Disp32 } }; char *cp; unsigned int j; @@ -4384,7 +4483,7 @@ lex_got (enum bfd_reloc_code_real *reloc, if (types) { if (flag_code != CODE_64BIT) - *types = Imm32|Disp32; + *types = Imm32 | Disp32; else *types = gotrel[j].types64; } @@ -4392,9 +4491,6 @@ lex_got (enum bfd_reloc_code_real *reloc, if (GOT_symbol == NULL) GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME); - /* Replace the relocation token with ' ', so that - errors like foo@GOTOFF1 will be detected. */ - /* The length of the first part of our input line. */ first = cp - input_line_pointer; @@ -4410,9 +4506,12 @@ lex_got (enum bfd_reloc_code_real *reloc, be necessary, but be safe. */ tmpbuf = xmalloc (first + second + 2); memcpy (tmpbuf, input_line_pointer, first); - tmpbuf[first] = ' '; - memcpy (tmpbuf + first + 1, past_reloc, second); - tmpbuf[first + second + 1] = '\0'; + if (second != 0 && *past_reloc != ' ') + /* Replace the relocation token with ' ', so that + errors like foo@GOTOFF1 will be detected. */ + tmpbuf[first++] = ' '; + memcpy (tmpbuf + first, past_reloc, second); + tmpbuf[first + second] = '\0'; return tmpbuf; } @@ -4427,9 +4526,7 @@ lex_got (enum bfd_reloc_code_real *reloc, } void -x86_cons (exp, size) - expressionS *exp; - int size; +x86_cons (expressionS *exp, int size) { if (size == 4 || (object_64bit && size == 8)) { @@ -4491,11 +4588,8 @@ pe_directive_secrel (dummy) } #endif -static int i386_immediate PARAMS ((char *)); - static int -i386_immediate (imm_start) - char *imm_start; +i386_immediate (char *imm_start) { char *save_input_line_pointer; char *gotfree_input_line; @@ -4505,7 +4599,8 @@ i386_immediate (imm_start) if (i.imm_operands == MAX_IMMEDIATE_OPERANDS) { - as_bad (_("only 1 or 2 immediate operands are allowed")); + as_bad (_("at most %d immediate operands are allowed"), + MAX_IMMEDIATE_OPERANDS); return 0; } @@ -4547,9 +4642,10 @@ i386_immediate (imm_start) /* Size it properly later. */ i.types[this_operand] |= Imm64; /* If BFD64, sign extend val. */ - if (!use_rela_relocations) - if ((exp->X_add_number & ~(((addressT) 2 << 31) - 1)) == 0) - exp->X_add_number = (exp->X_add_number ^ ((addressT) 1 << 31)) - ((addressT) 1 << 31); + if (!use_rela_relocations + && (exp->X_add_number & ~(((addressT) 2 << 31) - 1)) == 0) + exp->X_add_number + = (exp->X_add_number ^ ((addressT) 1 << 31)) - ((addressT) 1 << 31); } #if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT)) else if (OUTPUT_FLAVOR == bfd_target_aout_flavour @@ -4581,11 +4677,8 @@ i386_immediate (imm_start) return 1; } -static char *i386_scale PARAMS ((char *)); - static char * -i386_scale (scale) - char *scale; +i386_scale (char *scale) { offsetT val; char *save = input_line_pointer; @@ -4632,12 +4725,8 @@ i386_scale (scale) return scale; } -static int i386_displacement PARAMS ((char *, char *)); - static int -i386_displacement (disp_start, disp_end) - char *disp_start; - char *disp_end; +i386_displacement (char *disp_start, char *disp_end) { expressionS *exp; segT exp_seg = 0; @@ -4646,6 +4735,13 @@ i386_displacement (disp_start, disp_end) int bigdisp, override; unsigned int types = Disp; + if (i.disp_operands == MAX_MEMORY_OPERANDS) + { + as_bad (_("at most %d displacement operands are allowed"), + MAX_MEMORY_OPERANDS); + return 0; + } + if ((i.types[this_operand] & JumpAbsolute) || !(current_templates->start->opcode_modifier & (Jump | JumpDword))) { @@ -4812,14 +4908,11 @@ i386_displacement (disp_start, disp_end) return 1; } -static int i386_index_check PARAMS ((const char *)); - /* Make sure the memory operand we've been dealt is valid. Return 1 on success, 0 on a failure. */ static int -i386_index_check (operand_string) - const char *operand_string; +i386_index_check (const char *operand_string) { int ok; #if INFER_ADDR_PREFIX @@ -4904,7 +4997,8 @@ i386_index_check (operand_string) FIXME. There doesn't seem to be any real need for separate Disp16 and Disp32 flags. The same goes for Imm16 and Imm32. Removing them would probably clean up the code quite a lot. */ - if (flag_code != CODE_64BIT && (i.types[this_operand] & (Disp16 | Disp32))) + if (flag_code != CODE_64BIT + && (i.types[this_operand] & (Disp16 | Disp32))) i.types[this_operand] ^= (Disp16 | Disp32); fudged = 1; goto tryprefix; @@ -4925,8 +5019,7 @@ i386_index_check (operand_string) on error. */ static int -i386_operand (operand_string) - char *operand_string; +i386_operand (char *operand_string) { const reg_entry *r; char *end_op; @@ -5084,7 +5177,8 @@ i386_operand (operand_string) ++base_string; if (*base_string == ',' - || ((i.base_reg = parse_register (base_string, &end_op)) != NULL)) + || ((i.base_reg = parse_register (base_string, &end_op)) + != NULL)) { displacement_string_end = temp_string; @@ -5104,7 +5198,8 @@ i386_operand (operand_string) if (is_space_char (*base_string)) ++base_string; - if ((i.index_reg = parse_register (base_string, &end_op)) != NULL) + if ((i.index_reg = parse_register (base_string, &end_op)) + != NULL) { base_string = end_op; if (is_space_char (*base_string)) @@ -5117,7 +5212,8 @@ i386_operand (operand_string) } else if (*base_string != ')') { - as_bad (_("expecting `,' or `)' after index register in `%s'"), + as_bad (_("expecting `,' or `)' " + "after index register in `%s'"), operand_string); return 0; } @@ -5141,21 +5237,24 @@ i386_operand (operand_string) ++base_string; if (*base_string != ')') { - as_bad (_("expecting `)' after scale factor in `%s'"), + as_bad (_("expecting `)' " + "after scale factor in `%s'"), operand_string); return 0; } } else if (!i.index_reg) { - as_bad (_("expecting index register or scale factor after `,'; got '%c'"), + as_bad (_("expecting index register or scale factor " + "after `,'; got '%c'"), *base_string); return 0; } } else if (*base_string != ')') { - as_bad (_("expecting `,' or `)' after base register in `%s'"), + as_bad (_("expecting `,' or `)' " + "after base register in `%s'"), operand_string); return 0; } @@ -5371,7 +5470,8 @@ md_convert_frag (abfd, sec, fragP) { if (no_cond_jump_promotion && TYPE_FROM_RELAX_STATE (fragP->fr_subtype) != UNCOND_JUMP) - as_warn_where (fragP->fr_file, fragP->fr_line, _("long jump required")); + as_warn_where (fragP->fr_file, fragP->fr_line, + _("long jump required")); switch (fragP->fr_subtype) { @@ -5422,8 +5522,8 @@ md_convert_frag (abfd, sec, fragP) if (DISP_SIZE_FROM_RELAX_STATE (fragP->fr_subtype) == 4 && object_64bit && ((addressT) (displacement_from_opcode_start - extension - + ((addressT) 1 << 31)) - > (((addressT) 2 << 31) - 1))) + + ((addressT) 1 << 31)) + > (((addressT) 2 << 31) - 1))) { as_bad_where (fragP->fr_file, fragP->fr_line, _("jump target out of range")); @@ -5691,8 +5791,7 @@ md_atof (type, litP, sizeP) static char output_invalid_buf[sizeof (unsigned char) * 2 + 6]; static char * -output_invalid (c) - int c; +output_invalid (int c) { if (ISPRINT (c)) snprintf (output_invalid_buf, sizeof (output_invalid_buf), @@ -5750,14 +5849,16 @@ parse_real_register (char *reg_string, char **end_op) ++s; if (*s >= '0' && *s <= '7') { - r = &i386_float_regtab[*s - '0']; + int fpr = *s - '0'; ++s; if (is_space_char (*s)) ++s; if (*s == ')') { *end_op = s + 1; - return r; + r = hash_find (reg_hash, "st(0)"); + know (r); + return r + fpr; } } /* We have "%st(" then garbage. */ @@ -5799,7 +5900,8 @@ parse_register (char *reg_string, char **end_op) const expressionS *e = symbol_get_value_expression (symbolP); know (e->X_op == O_register); - know (e->X_add_number >= 0 && (valueT) e->X_add_number < ARRAY_SIZE (i386_regtab)); + know (e->X_add_number >= 0 + && (valueT) e->X_add_number < i386_regtab_size); r = i386_regtab + e->X_add_number; *end_op = input_line_pointer; } @@ -6012,6 +6114,10 @@ md_show_usage (stream) fprintf (stream, _("\ -s ignored\n")); #endif +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || defined(TE_PEP) + fprintf (stream, _("\ + --32/--64 generate 32bit/64bit code\n")); +#endif #ifdef SVR4_COMMENT_CHARS fprintf (stream, _("\ --divide do not treat `/' as a comment character\n")); @@ -6022,37 +6128,17 @@ md_show_usage (stream) fprintf (stream, _("\ -march=CPU/-mtune=CPU generate code/optimize for CPU, where CPU is one of:\n\ i386, i486, pentium, pentiumpro, pentium4, nocona,\n\ - core, core2, k6, athlon, k8, generic32, generic64\n")); - -} - -#if defined(TE_PEP) -const char * -x86_64_target_format (void) -{ - if (strcmp (default_arch, "x86_64") == 0) - { - set_code_flag (CODE_64BIT); - return COFF_TARGET_FORMAT; - } - else if (strcmp (default_arch, "i386") == 0) - { - set_code_flag (CODE_32BIT); - return "coff-i386"; - } + core, core2, k6, athlon, k8, generic32, generic64\n")); - as_fatal (_("Unknown architecture")); - return NULL; } -#endif #if ((defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT)) \ - || defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) + || defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || defined (TE_PEP)) /* Pick the target format to use. */ const char * -i386_target_format () +i386_target_format (void) { if (!strcmp (default_arch, "x86_64")) { @@ -6078,6 +6164,11 @@ i386_target_format () as_fatal (_("Unknown architecture")); switch (OUTPUT_FLAVOR) { +#ifdef TE_PEP + case bfd_target_coff_flavour: + return flag_code == CODE_64BIT ? COFF_TARGET_FORMAT : "coff-i386"; + break; +#endif #ifdef OBJ_MAYBE_AOUT case bfd_target_aout_flavour: return AOUT_TARGET_FORMAT; @@ -6106,7 +6197,8 @@ i386_target_format () #endif /* OBJ_MAYBE_ more than one */ #if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) -void i386_elf_emit_arch_note () +void +i386_elf_emit_arch_note (void) { if (IS_ELF && cpu_arch_name != NULL) { @@ -6197,8 +6289,7 @@ md_section_align (segment, size) size, since the offset is always the last part of the insn. */ long -md_pcrel_from (fixP) - fixS *fixP; +md_pcrel_from (fixS *fixP) { return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address; } @@ -6206,8 +6297,7 @@ md_pcrel_from (fixP) #ifndef I386COFF static void -s_bss (ignore) - int ignore ATTRIBUTE_UNUSED; +s_bss (int ignore ATTRIBUTE_UNUSED) { int temp; @@ -6223,8 +6313,7 @@ s_bss (ignore) #endif void -i386_validate_fix (fixp) - fixS *fixp; +i386_validate_fix (fixS *fixp) { if (fixp->fx_subsy && fixp->fx_subsy == GOT_symbol) { @@ -6573,8 +6662,8 @@ struct intel_parser_s int got_a_float; /* Whether the operand is a float. */ int op_modifier; /* Operand modifier. */ int is_mem; /* 1 if operand is memory reference. */ - int in_offset; /* >=1 if parsing operand of offset. */ - int in_bracket; /* >=1 if parsing operand in brackets. */ + int in_offset; /* >=1 if parsing operand of offset. */ + int in_bracket; /* >=1 if parsing operand in brackets. */ const reg_entry *reg; /* Last register reference found. */ char *disp; /* Displacement string being built. */ char *next_operand; /* Resume point when splitting operands. */ @@ -6613,22 +6702,19 @@ static struct intel_token cur_token, prev_token; #define T_SHR 15 /* Prototypes for intel parser functions. */ -static int intel_match_token PARAMS ((int code)); -static void intel_get_token PARAMS ((void)); -static void intel_putback_token PARAMS ((void)); -static int intel_expr PARAMS ((void)); -static int intel_e04 PARAMS ((void)); -static int intel_e05 PARAMS ((void)); -static int intel_e06 PARAMS ((void)); -static int intel_e09 PARAMS ((void)); -static int intel_bracket_expr PARAMS ((void)); -static int intel_e10 PARAMS ((void)); -static int intel_e11 PARAMS ((void)); +static int intel_match_token (int); +static void intel_putback_token (void); +static void intel_get_token (void); +static int intel_expr (void); +static int intel_e04 (void); +static int intel_e05 (void); +static int intel_e06 (void); +static int intel_e09 (void); +static int intel_e10 (void); +static int intel_e11 (void); static int -i386_intel_operand (operand_string, got_a_float) - char *operand_string; - int got_a_float; +i386_intel_operand (char *operand_string, int got_a_float) { int ret; char *p; @@ -6718,7 +6804,7 @@ i386_intel_operand (operand_string, got_a_float) ret = i386_immediate (intel_parser.disp); if (intel_parser.next_operand && this_operand >= MAX_OPERANDS - 1) - ret = 0; + ret = 0; if (!ret || !intel_parser.next_operand) break; intel_parser.op_string = intel_parser.next_operand; @@ -6738,7 +6824,7 @@ i386_intel_operand (operand_string, got_a_float) expr' cmpOp e04 expr' | Empty */ static int -intel_expr () +intel_expr (void) { /* XXX Implement the comparison operators. */ return intel_e04 (); @@ -6749,7 +6835,7 @@ intel_expr () e04' addOp e05 e04' | Empty */ static int -intel_e04 () +intel_e04 (void) { int nregs = -1; @@ -6778,7 +6864,7 @@ intel_e04 () e05' binOp e06 e05' | Empty */ static int -intel_e05 () +intel_e05 (void) { int nregs = ~NUM_ADDRESS_REGS; @@ -6787,7 +6873,9 @@ intel_e05 () if (!intel_e06()) return 0; - if (cur_token.code == '&' || cur_token.code == '|' || cur_token.code == '^') + if (cur_token.code == '&' + || cur_token.code == '|' + || cur_token.code == '^') { char str[2]; @@ -6813,7 +6901,7 @@ intel_e05 () e06' mulOp e09 e06' | Empty */ static int -intel_e06 () +intel_e06 (void) { int nregs = ~NUM_ADDRESS_REGS; @@ -6822,7 +6910,9 @@ intel_e06 () if (!intel_e09()) return 0; - if (cur_token.code == '*' || cur_token.code == '/' || cur_token.code == '%') + if (cur_token.code == '*' + || cur_token.code == '/' + || cur_token.code == '%') { char str[2]; @@ -6859,7 +6949,7 @@ intel_e06 () | : e10 e09' | Empty */ static int -intel_e09 () +intel_e09 (void) { int nregs = ~NUM_ADDRESS_REGS; int in_offset = 0; @@ -7073,7 +7163,7 @@ intel_e09 () } static int -intel_bracket_expr () +intel_bracket_expr (void) { int was_offset = intel_parser.op_modifier & (1 << T_OFFSET); const char *start = intel_parser.op_string; @@ -7134,7 +7224,8 @@ intel_bracket_expr () /* Defer the warning until all of the operand was parsed. */ intel_parser.is_mem = -1; else if (!quiet_warnings) - as_warn (_("`[%.*s]' taken to mean just `%.*s'"), len, start, len, start); + as_warn (_("`[%.*s]' taken to mean just `%.*s'"), + len, start, len, start); } } intel_parser.op_modifier |= was_offset; @@ -7149,7 +7240,7 @@ intel_bracket_expr () e10' [ expr ] e10' | Empty */ static int -intel_e10 () +intel_e10 (void) { if (!intel_e11 ()) return 0; @@ -7179,7 +7270,7 @@ intel_e10 () | id | constant */ static int -intel_e11 () +intel_e11 (void) { switch (cur_token.code) { @@ -7224,7 +7315,8 @@ intel_e11 () { if (!(reg->reg_type & (SReg2 | SReg3))) { - as_bad (_("`%s' is not a valid segment register"), reg->reg_name); + as_bad (_("`%s' is not a valid segment register"), + reg->reg_name); return 0; } else if (i.seg[i.mem_operands]) @@ -7414,7 +7506,8 @@ intel_e11 () /* Get the next token to check for register scaling. */ intel_match_token (cur_token.code); - /* Check if this constant is a scaling factor for an index register. */ + /* Check if this constant is a scaling factor for an + index register. */ if (cur_token.code == '*') { if (intel_match_token ('*') && cur_token.code == T_REG) @@ -7423,14 +7516,17 @@ intel_e11 () if (!intel_parser.in_bracket) { - as_bad (_("Register scaling only allowed in memory operands")); + as_bad (_("Register scaling only allowed " + "in memory operands")); return 0; } - if (reg->reg_type & Reg16) /* Disallow things like [1*si]. */ - reg = i386_regtab + REGNAM_AX + 4; /* sp is invalid as index */ + /* Disallow things like [1*si]. + sp and esp are invalid as index. */ + if (reg->reg_type & Reg16) + reg = i386_regtab + REGNAM_AX + 4; else if (i.index_reg) - reg = i386_regtab + REGNAM_EAX + 4; /* esp is invalid as index */ + reg = i386_regtab + REGNAM_EAX + 4; /* The constant is followed by `* reg', so it must be a valid scale. */ @@ -7480,8 +7576,7 @@ intel_e11 () /* Match the given token against cur_token. If they match, read the next token from the operand string. */ static int -intel_match_token (code) - int code; +intel_match_token (int code) { if (cur_token.code == code) { @@ -7497,7 +7592,7 @@ intel_match_token (code) /* Read a new token from intel_parser.op_string and store it in cur_token. */ static void -intel_get_token () +intel_get_token (void) { char *end_op; const reg_entry *reg; @@ -7682,7 +7777,7 @@ intel_get_token () /* Put cur_token back into the token stream and make cur_token point to prev_token. */ static void -intel_putback_token () +intel_putback_token (void) { if (cur_token.code != T_NIL) {