X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-i386.c;h=3d935c1bd8d90a3db88e95897a409438d55dafb5;hb=76bc74dc40db159493206725ff7d65ad5cd4897d;hp=15db848037a4af960e0168264418b2f6f2fdb14e;hpb=4b4da1607aeed19ac399963a3aa12b0417e477ae;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 15db848037..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 + 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,53 +62,42 @@ #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 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 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); #endif static const char *default_arch = DEFAULT_ARCH; @@ -194,15 +182,23 @@ const char extra_symbol_chars[] = "*%-([" #if (defined (TE_I386AIX) \ || ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) \ + && !defined (TE_GNU) \ && !defined (TE_LINUX) \ && !defined (TE_NETWARE) \ && !defined (TE_FreeBSD) \ && !defined (TE_NetBSD))) /* This array holds the chars that always start a comment. If the - pre-processor is disabled, these aren't very useful. */ -const char comment_chars[] = "#/"; + pre-processor is disabled, these aren't very useful. The option + --divide will remove '/' from this list. */ +const char *i386_comment_chars = "#/"; +#define SVR4_COMMENT_CHARS 1 #define PREFIX_SEPARATOR '\\' +#else +const char *i386_comment_chars = "#"; +#define PREFIX_SEPARATOR '/' +#endif + /* This array holds the chars that only start a comment at the beginning of a line. If the line seems to have the form '# 123 filename' .line and .file directives will appear in the pre-processed output. @@ -211,16 +207,7 @@ const char comment_chars[] = "#/"; #NO_APP at the beginning of its output. Also note that comments started like this one will always work if '/' isn't otherwise defined. */ -const char line_comment_chars[] = "#"; - -#else -/* Putting '/' here makes it impossible to use the divide operator. - However, we need it for compatibility with SVR4 systems. */ -const char comment_chars[] = "#"; -#define PREFIX_SEPARATOR '/' - -const char line_comment_chars[] = "/#"; -#endif +const char line_comment_chars[] = "#/"; const char line_separator_chars[] = ";"; @@ -268,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; @@ -284,6 +272,7 @@ enum flag_code { #define NUM_FLAG_CODE ((int) CODE_64BIT + 1) static enum flag_code flag_code; +static unsigned int object_64bit; static int use_rela_relocations = 0; /* The names used to print error messages. */ @@ -301,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. */ @@ -319,6 +311,21 @@ static const char *cpu_sub_arch_name = NULL; /* CPU feature flags. */ static unsigned int cpu_arch_flags = CpuUnknownFlags | CpuNo64; +/* If we have selected a cpu we are generating instructions for. */ +static int cpu_arch_tune_set = 0; + +/* Cpu we are generating instructions for. */ +static enum processor_type cpu_arch_tune = PROCESSOR_UNKNOWN; + +/* CPU feature flags of cpu we are generating instructions for. */ +static unsigned int cpu_arch_tune_flags = 0; + +/* CPU instruction set architecture used. */ +static enum processor_type cpu_arch_isa = PROCESSOR_UNKNOWN; + +/* CPU feature flags of instruction set architecture used. */ +static unsigned int cpu_arch_isa_flags = 0; + /* If set, conditional jumps are not automatically promoted to handle larger than a byte offset. */ static unsigned int no_cond_jump_promotion = 0; @@ -411,31 +418,106 @@ const relax_typeS md_relax_table[] = {0, 0, 4, 0} }; -static const arch_entry cpu_arch[] = { - {"i8086", Cpu086 }, - {"i186", Cpu086|Cpu186 }, - {"i286", Cpu086|Cpu186|Cpu286 }, - {"i386", Cpu086|Cpu186|Cpu286|Cpu386 }, - {"i486", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486 }, - {"i586", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586 }, - {"i686", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686 }, - {"pentium", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586 }, - {"pentiumpro",Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686 }, - {"pentiumii", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX }, - {"pentiumiii",Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX|CpuMMX2|CpuSSE }, - {"pentium4", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX|CpuMMX2|CpuSSE|CpuSSE2 }, - {"prescott", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuPNI }, - {"k6", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuK6|CpuMMX }, - {"k6_2", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuK6|CpuMMX|Cpu3dnow }, - {"athlon", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuAthlon|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA }, - {"sledgehammer",Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuAthlon|CpuSledgehammer|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2 }, - {".mmx", CpuMMX }, - {".sse", CpuMMX|CpuMMX2|CpuSSE }, - {".sse2", CpuMMX|CpuMMX2|CpuSSE|CpuSSE2 }, - {".3dnow", CpuMMX|Cpu3dnow }, - {".3dnowa", CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA }, - {".padlock", CpuPadLock }, - {NULL, 0 } +static const arch_entry cpu_arch[] = +{ + {"generic32", PROCESSOR_GENERIC32, + Cpu186|Cpu286|Cpu386}, + {"generic64", PROCESSOR_GENERIC64, + Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX + |CpuMMX2|CpuSSE|CpuSSE2}, + {"i8086", PROCESSOR_UNKNOWN, + 0}, + {"i186", PROCESSOR_UNKNOWN, + Cpu186}, + {"i286", PROCESSOR_UNKNOWN, + Cpu186|Cpu286}, + {"i386", PROCESSOR_I386, + Cpu186|Cpu286|Cpu386}, + {"i486", PROCESSOR_I486, + Cpu186|Cpu286|Cpu386|Cpu486}, + {"i586", PROCESSOR_PENTIUM, + Cpu186|Cpu286|Cpu386|Cpu486|Cpu586}, + {"i686", PROCESSOR_PENTIUMPRO, + Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686}, + {"pentium", PROCESSOR_PENTIUM, + Cpu186|Cpu286|Cpu386|Cpu486|Cpu586}, + {"pentiumpro",PROCESSOR_PENTIUMPRO, + Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686}, + {"pentiumii", PROCESSOR_PENTIUMPRO, + Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX}, + {"pentiumiii",PROCESSOR_PENTIUMPRO, + Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX|CpuMMX2|CpuSSE}, + {"pentium4", PROCESSOR_PENTIUM4, + Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX + |CpuMMX2|CpuSSE|CpuSSE2}, + {"prescott", PROCESSOR_NOCONA, + Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX + |CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3}, + {"nocona", PROCESSOR_NOCONA, + Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX + |CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3}, + {"yonah", PROCESSOR_CORE, + Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX + |CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3}, + {"core", PROCESSOR_CORE, + Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX + |CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3}, + {"merom", PROCESSOR_CORE2, + Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX + |CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3}, + {"core2", PROCESSOR_CORE2, + Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX + |CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3}, + {"k6", PROCESSOR_K6, + Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuK6|CpuMMX}, + {"k6_2", PROCESSOR_K6, + Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuK6|CpuMMX|Cpu3dnow}, + {"athlon", PROCESSOR_ATHLON, + Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6 + |CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA}, + {"sledgehammer", PROCESSOR_K8, + Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6 + |CpuSledgehammer|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2}, + {"opteron", PROCESSOR_K8, + Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6 + |CpuSledgehammer|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2}, + {"k8", PROCESSOR_K8, + Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6 + |CpuSledgehammer|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2}, + {"amdfam10", PROCESSOR_AMDFAM10, + Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuSledgehammer + |CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2|CpuSSE3|CpuSSE4a + |CpuABM}, + {".mmx", PROCESSOR_UNKNOWN, + CpuMMX}, + {".sse", PROCESSOR_UNKNOWN, + CpuMMX|CpuMMX2|CpuSSE}, + {".sse2", PROCESSOR_UNKNOWN, + CpuMMX|CpuMMX2|CpuSSE|CpuSSE2}, + {".sse3", PROCESSOR_UNKNOWN, + 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, + CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA}, + {".padlock", PROCESSOR_UNKNOWN, + CpuPadLock}, + {".pacifica", PROCESSOR_UNKNOWN, + CpuSVME}, + {".svme", PROCESSOR_UNKNOWN, + CpuSVME}, + {".sse4a", PROCESSOR_UNKNOWN, + CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSE4a}, + {".abm", PROCESSOR_UNKNOWN, + CpuABM} }; const pseudo_typeS md_pseudo_table[] = @@ -453,6 +535,7 @@ const pseudo_typeS md_pseudo_table[] = {"dfloat", float_cons, 'd'}, {"tfloat", float_cons, 'x'}, {"value", cons, 2}, + {"slong", signed_cons, 4}, {"noopt", s_ignore, 0}, {"optim", s_ignore, 0}, {"code16gcc", set_16bit_gcc_code_flag, CODE_16BIT}, @@ -461,8 +544,13 @@ const pseudo_typeS md_pseudo_table[] = {"code64", set_code_flag, CODE_64BIT}, {"intel_syntax", set_intel_syntax, 1}, {"att_syntax", set_intel_syntax, 0}, - {"file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0}, +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + {"largecomm", handle_large_common, 0}, +#else + {"file", (void (*) (int)) dwarf2_directive_file, 0}, {"loc", dwarf2_directive_loc, 0}, + {"loc_mark_labels", dwarf2_directive_loc_mark_labels, 0}, +#endif #ifdef TE_PE {"secrel32", pe_directive_secrel, 0}, #endif @@ -479,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. @@ -489,7 +575,7 @@ i386_align_code (fragP, count) static const char f32_1[] = {0x90}; /* nop */ static const char f32_2[] = - {0x89,0xf6}; /* movl %esi,%esi */ + {0x66,0x90}; /* xchg %ax,%ax */ static const char f32_3[] = {0x8d,0x76,0x00}; /* leal 0(%esi),%esi */ static const char f32_4[] = @@ -522,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[] = @@ -541,93 +624,307 @@ 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[] = + {0x0f,0x1f,0x00}; + /* nopl 0(%[re]ax) */ + static const char alt_4[] = + {0x0f,0x1f,0x40,0x00}; + /* nopl 0(%[re]ax,%[re]ax,1) */ + static const char alt_5[] = + {0x0f,0x1f,0x44,0x00,0x00}; + /* nopw 0(%[re]ax,%[re]ax,1) */ + static const char alt_6[] = + {0x66,0x0f,0x1f,0x44,0x00,0x00}; + /* nopl 0L(%[re]ax) */ + static const char alt_7[] = + {0x0f,0x1f,0x80,0x00,0x00,0x00,0x00}; + /* nopl 0L(%[re]ax,%[re]ax,1) */ + static const char alt_8[] = + {0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; + /* nopw 0L(%[re]ax,%[re]ax,1) */ + static const char alt_9[] = + {0x66,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; + /* nopw %cs:0L(%[re]ax,%[re]ax,1) */ + static const char alt_10[] = + {0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; + /* data16 + nopw %cs:0L(%[re]ax,%[re]ax,1) */ + static const char alt_long_11[] = + {0x66, + 0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; + /* data16 + data16 + nopw %cs:0L(%[re]ax,%[re]ax,1) */ + static const char alt_long_12[] = + {0x66, + 0x66, + 0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; + /* data16 + data16 + data16 + nopw %cs:0L(%[re]ax,%[re]ax,1) */ + static const char alt_long_13[] = + {0x66, + 0x66, + 0x66, + 0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; + /* data16 + data16 + data16 + data16 + nopw %cs:0L(%[re]ax,%[re]ax,1) */ + static const char alt_long_14[] = + {0x66, + 0x66, + 0x66, + 0x66, + 0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; + /* data16 + data16 + data16 + data16 + data16 + nopw %cs:0L(%[re]ax,%[re]ax,1) */ + static const char alt_long_15[] = + {0x66, + 0x66, + 0x66, + 0x66, + 0x66, + 0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; + /* nopl 0(%[re]ax,%[re]ax,1) + nopw 0(%[re]ax,%[re]ax,1) */ + static const char alt_short_11[] = + {0x0f,0x1f,0x44,0x00,0x00, + 0x66,0x0f,0x1f,0x44,0x00,0x00}; + /* nopw 0(%[re]ax,%[re]ax,1) + nopw 0(%[re]ax,%[re]ax,1) */ + static const char alt_short_12[] = + {0x66,0x0f,0x1f,0x44,0x00,0x00, + 0x66,0x0f,0x1f,0x44,0x00,0x00}; + /* nopw 0(%[re]ax,%[re]ax,1) + nopl 0L(%[re]ax) */ + static const char alt_short_13[] = + {0x66,0x0f,0x1f,0x44,0x00,0x00, + 0x0f,0x1f,0x80,0x00,0x00,0x00,0x00}; + /* nopl 0L(%[re]ax) + nopl 0L(%[re]ax) */ + static const char alt_short_14[] = + {0x0f,0x1f,0x80,0x00,0x00,0x00,0x00, + 0x0f,0x1f,0x80,0x00,0x00,0x00,0x00}; + /* nopl 0L(%[re]ax) + nopl 0L(%[re]ax,%[re]ax,1) */ + static const char alt_short_15[] = + {0x0f,0x1f,0x80,0x00,0x00,0x00,0x00, + 0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; + static const char *const alt_short_patt[] = { + f32_1, f32_2, alt_3, alt_4, alt_5, alt_6, alt_7, alt_8, + alt_9, alt_10, alt_short_11, alt_short_12, alt_short_13, + alt_short_14, alt_short_15 + }; + static const char *const alt_long_patt[] = { + f32_1, f32_2, alt_3, alt_4, alt_5, alt_6, alt_7, alt_8, + alt_9, alt_10, alt_long_11, alt_long_12, alt_long_13, + 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; - /* The recommended way to pad 64bit code is to use NOPs preceded by - maximally four 0x66 prefixes. Balance the size of nops. */ - if (flag_code == CODE_64BIT) + /* We need to decide which NOP sequence to use for 32bit and + 64bit. When -mtune= is 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) { - int i; - int nnops = (count + 3) / 4; - int len = count / nnops; - int remains = count - nnops * len; - int pos = 0; + if (count > 8) + { + 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 + { + const char *const *patt = NULL; - for (i = 0; i < remains; i++) + if (cpu_arch_isa == PROCESSOR_UNKNOWN) { - memset (fragP->fr_literal + fragP->fr_fix + pos, 0x66, len); - fragP->fr_literal[fragP->fr_fix + pos + len] = 0x90; - pos += len + 1; + /* PROCESSOR_UNKNOWN means that all ISAs may be used. */ + switch (cpu_arch_tune) + { + case PROCESSOR_UNKNOWN: + /* We use cpu_arch_isa_flags to check if we SHOULD + optimize for Cpu686. */ + if ((cpu_arch_isa_flags & Cpu686) != 0) + patt = alt_long_patt; + else + patt = f32_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_AMDFAM10: + patt = alt_short_patt; + break; + case PROCESSOR_I386: + case PROCESSOR_I486: + case PROCESSOR_PENTIUM: + case PROCESSOR_GENERIC32: + patt = f32_patt; + break; + } + } + else + { + switch (cpu_arch_tune) + { + case PROCESSOR_UNKNOWN: + /* When cpu_arch_isa is net, cpu_arch_tune shouldn't be + PROCESSOR_UNKNOWN. */ + abort (); + break; + + case PROCESSOR_I386: + case PROCESSOR_I486: + case PROCESSOR_PENTIUM: + case PROCESSOR_K6: + case PROCESSOR_ATHLON: + case PROCESSOR_K8: + case PROCESSOR_AMDFAM10: + case PROCESSOR_GENERIC32: + /* We use cpu_arch_isa_flags to check if we CAN optimize + for Cpu686. */ + if ((cpu_arch_isa_flags & Cpu686) != 0) + patt = alt_short_patt; + 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; + else + patt = f32_patt; + break; + case PROCESSOR_GENERIC64: + patt = alt_long_patt; + break; + } + } + + 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; + } } - for (; i < nnops; i++) + else { - memset (fragP->fr_literal + fragP->fr_fix + pos, 0x66, len - 1); - fragP->fr_literal[fragP->fr_fix + pos + len - 1] = 0x90; - pos += len; + /* 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); } } - else - 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 - memcpy (fragP->fr_literal + fragP->fr_fix, - f32_patt[count - 1], count); 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; @@ -636,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; @@ -647,11 +944,10 @@ 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 != (Cpu086 | Cpu186 | Cpu286 | Cpu386 | Cpu486 | CpuNo64)) + if (cpu_arch_flags != (Cpu186 | Cpu286 | Cpu386 | Cpu486 | CpuNo64)) { /* This code is disabled on the 486 because all the Imm1 forms in the opcode table are slower on the i486. They're the @@ -675,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; @@ -712,65 +1006,74 @@ 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; - int q; + unsigned int q; if (prefix >= REX_OPCODE && prefix < REX_OPCODE + 16 && flag_code == CODE_64BIT) - q = REX_PREFIX; + { + 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; + } else - switch (prefix) - { - default: - abort (); - - case CS_PREFIX_OPCODE: - case DS_PREFIX_OPCODE: - case ES_PREFIX_OPCODE: - case FS_PREFIX_OPCODE: - case GS_PREFIX_OPCODE: - case SS_PREFIX_OPCODE: - q = SEG_PREFIX; - break; + { + switch (prefix) + { + default: + abort (); + + case CS_PREFIX_OPCODE: + case DS_PREFIX_OPCODE: + case ES_PREFIX_OPCODE: + case FS_PREFIX_OPCODE: + case GS_PREFIX_OPCODE: + case SS_PREFIX_OPCODE: + q = SEG_PREFIX; + break; - case REPNE_PREFIX_OPCODE: - case REPE_PREFIX_OPCODE: - ret = 2; - /* fall thru */ - case LOCK_PREFIX_OPCODE: - q = LOCKREP_PREFIX; - break; + case REPNE_PREFIX_OPCODE: + case REPE_PREFIX_OPCODE: + ret = 2; + /* fall thru */ + case LOCK_PREFIX_OPCODE: + q = LOCKREP_PREFIX; + break; - case FWAIT_OPCODE: - q = WAIT_PREFIX; - break; + case FWAIT_OPCODE: + q = WAIT_PREFIX; + break; - case ADDR_PREFIX_OPCODE: - q = ADDR_PREFIX; - break; + case ADDR_PREFIX_OPCODE: + q = ADDR_PREFIX; + break; - case DATA_PREFIX_OPCODE: - q = DATA_PREFIX; - break; - } + case DATA_PREFIX_OPCODE: + q = DATA_PREFIX; + break; + } + if (i.prefix[q] != 0) + ret = 0; + } - if (i.prefix[q] != 0) + if (ret) { - as_bad (_("same type of prefix used twice")); - return 0; + if (!i.prefix[q]) + ++i.prefixes; + i.prefix[q] |= prefix; } + else + as_bad (_("same type of prefix used twice")); - i.prefixes += 1; - i.prefix[q] = prefix; return ret; } static void -set_code_flag (value) - int value; +set_code_flag (int value) { flag_code = value; cpu_arch_flags &= ~(Cpu64 | CpuNo64); @@ -787,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); @@ -797,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; @@ -829,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 (); @@ -841,9 +1142,9 @@ set_cpu_arch (dummy) { char *string = input_line_pointer; int e = get_symbol_end (); - int i; + unsigned int i; - for (i = 0; cpu_arch[i].name; i++) + for (i = 0; i < ARRAY_SIZE (cpu_arch); i++) { if (strcmp (string, cpu_arch[i].name) == 0) { @@ -852,7 +1153,15 @@ 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) + { + cpu_arch_tune = cpu_arch_isa; + cpu_arch_tune_flags = cpu_arch_isa_flags; + } break; } if ((cpu_arch_flags | cpu_arch[i].flags) != cpu_arch_flags) @@ -865,7 +1174,7 @@ set_cpu_arch (dummy) return; } } - if (!cpu_arch[i].name) + if (i >= ARRAY_SIZE (cpu_arch)) as_bad (_("no such architecture: `%s'"), string); *input_line_pointer = e; @@ -951,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) @@ -1009,6 +1317,7 @@ md_begin () #endif digit_chars['-'] = '-'; mnemonic_chars['-'] = '-'; + mnemonic_chars['.'] = '.'; identifier_chars['_'] = '_'; identifier_chars['.'] = '.'; @@ -1017,7 +1326,7 @@ md_begin () } #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) - if (OUTPUT_FLAVOR == bfd_target_elf_flavour) + if (IS_ELF) { record_alignment (text_section, 2); record_alignment (data_section, 2); @@ -1038,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); @@ -1048,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; @@ -1072,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); @@ -1092,8 +1397,7 @@ pi (line, x) } static void -pte (t) - template *t; +pte (template *t) { unsigned int i; fprintf (stdout, " %d operands ", t->operands); @@ -1114,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", @@ -1135,8 +1438,7 @@ pe (e) } static void -ps (s) - symbolS *s; +ps (symbolS *s) { fprintf (stdout, "%s type %s%s", S_GET_NAME (s), @@ -1144,13 +1446,12 @@ ps (s) segment_name (S_GET_SEGMENT (s))); } -struct type_name +static struct type_name { unsigned int mask; char *tname; } - -static const type_names[] = +const type_names[] = { { Reg8, "r8" }, { Reg16, "r16" }, @@ -1200,34 +1501,80 @@ pt (t) #endif /* DEBUG386 */ -static bfd_reloc_code_real_type reloc - PARAMS ((int, int, int, bfd_reloc_code_real_type)); - static bfd_reloc_code_real_type -reloc (size, pcrel, sign, other) - int size; - int pcrel; - int sign; - bfd_reloc_code_real_type other; +reloc (unsigned int size, + int pcrel, + int sign, + bfd_reloc_code_real_type other) { if (other != NO_RELOC) - return other; + { + reloc_howto_type *reloc; + + if (size == 8) + switch (other) + { + case BFD_RELOC_X86_64_GOT32: + return BFD_RELOC_X86_64_GOT64; + break; + case BFD_RELOC_X86_64_PLTOFF64: + return BFD_RELOC_X86_64_PLTOFF64; + break; + case BFD_RELOC_X86_64_GOTPC32: + other = BFD_RELOC_X86_64_GOTPC64; + break; + case BFD_RELOC_X86_64_GOTPCREL: + other = BFD_RELOC_X86_64_GOTPCREL64; + break; + case BFD_RELOC_X86_64_TPOFF32: + other = BFD_RELOC_X86_64_TPOFF64; + break; + case BFD_RELOC_X86_64_DTPOFF32: + other = BFD_RELOC_X86_64_DTPOFF64; + break; + default: + break; + } + + /* Sign-checking 4-byte relocations in 16-/32-bit code is pointless. */ + if (size == 4 && flag_code != CODE_64BIT) + sign = -1; + + reloc = bfd_reloc_type_lookup (stdoutput, other); + if (!reloc) + as_bad (_("unknown relocation (%u)"), other); + else if (size != bfd_get_reloc_size (reloc)) + as_bad (_("%u-byte relocation cannot be applied to %u-byte field"), + bfd_get_reloc_size (reloc), + size); + else if (pcrel && !reloc->pc_relative) + as_bad (_("non-pc-relative relocation for pc-relative field")); + else if ((reloc->complain_on_overflow == complain_overflow_signed + && !sign) + || (reloc->complain_on_overflow == complain_overflow_unsigned + && sign > 0)) + as_bad (_("relocated field and relocation type differ in signedness")); + else + return other; + return NO_RELOC; + } if (pcrel) { if (!sign) - as_bad (_("There are no unsigned pc-relative relocations")); + as_bad (_("there are no unsigned pc-relative relocations")); switch (size) { case 1: return BFD_RELOC_8_PCREL; case 2: return BFD_RELOC_16_PCREL; case 4: return BFD_RELOC_32_PCREL; + case 8: return BFD_RELOC_64_PCREL; } - as_bad (_("can not do %d byte pc-relative relocation"), size); + as_bad (_("cannot do %u byte pc-relative relocation"), size); } else { - if (sign) + if (sign > 0) switch (size) { case 4: return BFD_RELOC_X86_64_32S; @@ -1240,8 +1587,8 @@ reloc (size, pcrel, sign, other) case 4: return BFD_RELOC_32; case 8: return BFD_RELOC_64; } - as_bad (_("can not do %s %d byte relocation"), - sign ? "signed" : "unsigned", size); + as_bad (_("cannot do %s %u byte relocation"), + sign > 0 ? "signed" : "unsigned", size); } abort (); @@ -1254,11 +1601,10 @@ reloc (size, pcrel, sign, other) 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 (OUTPUT_FLAVOR != bfd_target_elf_flavour) + if (!IS_ELF) return 1; /* Don't adjust pc-relative references to merge sections in 64-bit @@ -1286,14 +1632,21 @@ tc_i386_fix_adjustable (fixP) || fixP->fx_r_type == BFD_RELOC_386_TLS_GOTIE || fixP->fx_r_type == BFD_RELOC_386_TLS_LE_32 || fixP->fx_r_type == BFD_RELOC_386_TLS_LE + || fixP->fx_r_type == BFD_RELOC_386_TLS_GOTDESC + || fixP->fx_r_type == BFD_RELOC_386_TLS_DESC_CALL || fixP->fx_r_type == BFD_RELOC_X86_64_PLT32 || fixP->fx_r_type == BFD_RELOC_X86_64_GOT32 || fixP->fx_r_type == BFD_RELOC_X86_64_GOTPCREL || fixP->fx_r_type == BFD_RELOC_X86_64_TLSGD || fixP->fx_r_type == BFD_RELOC_X86_64_TLSLD || fixP->fx_r_type == BFD_RELOC_X86_64_DTPOFF32 + || fixP->fx_r_type == BFD_RELOC_X86_64_DTPOFF64 || fixP->fx_r_type == BFD_RELOC_X86_64_GOTTPOFF || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF32 + || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF64 + || fixP->fx_r_type == BFD_RELOC_X86_64_GOTOFF64 + || fixP->fx_r_type == BFD_RELOC_X86_64_GOTPC32_TLSDESC + || fixP->fx_r_type == BFD_RELOC_X86_64_TLSDESC_CALL || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) return 0; @@ -1301,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 @@ -1388,24 +1738,42 @@ md_assemble (line) if (line == NULL) return; + /* 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))) + { + 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) + swap_operands (); + } + /* Now we've parsed the mnemonic into a set of templates, and have the operands at hand. */ /* All intel opcodes have reversed operands except for "bound" and "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. "enter" and the - intersegment "jmp" and "call" instructions are the only ones that - have two immediate operands. */ - if (intel_syntax && i.operands > 1 + precedes the offset, as it does when in AT&T mode. */ + if (intel_syntax + && i.operands > 1 && (strcmp (mnemonic, "bound") != 0) + && (strcmp (mnemonic, "invlpga") != 0) && !((i.types[0] & Imm) && (i.types[1] & Imm))) swap_operands (); if (i.imm_operands) optimize_imm (); - if (i.disp_operands) + /* Don't optimize displacement for movabs since it only takes 64bit + displacement. */ + if (i.disp_operands + && (flag_code != CODE_64BIT + || strcmp (mnemonic, "movabs") != 0)) optimize_disp (); /* Next, we find a template that matches the given insn, @@ -1420,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 @@ -1474,9 +1842,9 @@ md_assemble (line) { expressionS *exp; - if ((i.tm.cpu_flags & CpuPNI) && i.operands > 0) + if ((i.tm.cpu_flags & CpuSSE3) && i.operands > 0) { - /* These Intel Prescott New Instructions have the fixed + /* Streaming SIMD extensions 3 Instructions have the fixed operands with an opcode suffix which is coded in the same place as an 8-bit immediate field would be. Here we check those operands and remove them afterwards. */ @@ -1484,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; } @@ -1534,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 @@ -1558,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 @@ -1578,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; @@ -1606,8 +1976,9 @@ parse_insn (line, mnemonic) } if (!is_space_char (*l) && *l != END_OF_INSN - && *l != PREFIX_SEPARATOR - && *l != ',') + && (intel_syntax + || (*l != PREFIX_SEPARATOR + && *l != ','))) { as_bad (_("invalid character %s in mnemonic"), output_invalid (*l)); @@ -1615,7 +1986,7 @@ parse_insn (line, mnemonic) } if (token_start == l) { - if (*l == PREFIX_SEPARATOR) + if (!intel_syntax && *l == PREFIX_SEPARATOR) as_bad (_("expecting prefix; got nothing")); else as_bad (_("expecting mnemonic; got nothing")); @@ -1630,6 +2001,15 @@ parse_insn (line, mnemonic) && current_templates && (current_templates->start->opcode_modifier & IsPrefix)) { + if (current_templates->start->cpu_flags + & (flag_code != CODE_64BIT ? Cpu64 : CpuNo64)) + { + as_bad ((flag_code != CODE_64BIT + ? _("`%s' is only supported in 64-bit mode") + : _("`%s' is not supported in 64-bit mode")), + current_templates->start->name); + return NULL; + } /* If we are in 16-bit mode, do not allow addr16 or data16. Similarly, in 32-bit mode, do not allow addr32 or data32. */ if ((current_templates->start->opcode_modifier & (Size16 | Size32)) @@ -1740,9 +2120,9 @@ parse_insn (line, mnemonic) { if (!((t->cpu_flags & ~(Cpu64 | CpuNo64)) & ~(cpu_arch_flags & ~(Cpu64 | CpuNo64)))) - supported |= 1; + supported |= 1; if (!(t->cpu_flags & (flag_code == CODE_64BIT ? CpuNo64 : Cpu64))) - supported |= 2; + supported |= 2; } if (!(supported & 2)) { @@ -1765,21 +2145,31 @@ parse_insn (line, mnemonic) } /* Check for rep/repne without a string instruction. */ - if (expecting_string_instruction - && !(current_templates->start->opcode_modifier & IsString)) + if (expecting_string_instruction) { - as_bad (_("expecting string instruction after `%s'"), - expecting_string_instruction); - return NULL; + static templates override; + + for (t = current_templates->start; t < current_templates->end; ++t) + if (t->opcode_modifier & IsString) + break; + if (t >= current_templates->end) + { + as_bad (_("expecting string instruction after `%s'"), + expecting_string_instruction); + return NULL; + } + for (override.start = t; t < current_templates->end; ++t) + if (!(t->opcode_modifier & IsString)) + break; + override.end = t; + current_templates = &override; } return l; } static char * -parse_operands (l, mnemonic) - char *l; - const char *mnemonic; +parse_operands (char *l, const char *mnemonic) { char *token_start; @@ -1897,24 +2287,12 @@ parse_operands (l, mnemonic) } static void -swap_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 = 0; - if (i.operands == 2) - { - xchg1 = 0; - xchg2 = 1; - } - else if (i.operands == 3) - { - xchg1 = 0; - xchg2 = 2; - } temp_type = i.types[xchg2]; i.types[xchg2] = i.types[xchg1]; i.types[xchg1] = temp_type; @@ -1924,6 +2302,22 @@ swap_operands () temp_reloc = i.reloc[xchg2]; i.reloc[xchg2] = i.reloc[xchg1]; i.reloc[xchg1] = temp_reloc; +} + +static void +swap_operands (void) +{ + switch (i.operands) + { + case 4: + swap_2_operands (1, i.operands - 2); + case 3: + case 2: + swap_2_operands (0, i.operands - 1); + break; + default: + abort (); + } if (i.mem_operands == 2) { @@ -1937,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; @@ -2020,22 +2414,38 @@ optimize_imm () /* Symbols and expressions. */ default: - /* Convert symbolic operand to proper sizes for matching. */ - switch (guess_suffix) - { - case QWORD_MNEM_SUFFIX: - i.types[op] = Imm64 | Imm32S; - break; - case LONG_MNEM_SUFFIX: - i.types[op] = Imm32; - break; - case WORD_MNEM_SUFFIX: - i.types[op] = Imm16; - break; - case BYTE_MNEM_SUFFIX: - i.types[op] = Imm8 | Imm8S; - break; - } + /* Convert symbolic operand to proper sizes for matching, but don't + prevent matching a set of insns that only supports sizes other + than those matching the insn suffix. */ + { + unsigned int mask, allowed = 0; + const template *t; + + for (t = current_templates->start; + t < current_templates->end; + ++t) + allowed |= t->operand_types[op]; + switch (guess_suffix) + { + case QWORD_MNEM_SUFFIX: + mask = Imm64 | Imm32S; + break; + case LONG_MNEM_SUFFIX: + mask = Imm32; + break; + case WORD_MNEM_SUFFIX: + mask = Imm16; + break; + case BYTE_MNEM_SUFFIX: + mask = Imm8; + break; + default: + mask = 0; + break; + } + if (mask & allowed) + i.types[op] &= mask; + } break; } } @@ -2043,53 +2453,84 @@ optimize_imm () /* Try to use the smallest displacement type too. */ static void -optimize_disp () +optimize_disp (void) { int op; for (op = i.operands; --op >= 0;) - if ((i.types[op] & Disp) && i.op[op].disps->X_op == O_constant) + if (i.types[op] & Disp) { - offsetT disp = i.op[op].disps->X_add_number; - - if (i.types[op] & Disp16) + if (i.op[op].disps->X_op == O_constant) { - /* We know this operand is at most 16 bits, so - convert to a signed 16 bit number before trying - to see whether it will fit in an even smaller - size. */ + offsetT disp = i.op[op].disps->X_add_number; - disp = (((disp & 0xffff) ^ 0x8000) - 0x8000); - } - else if (i.types[op] & Disp32) - { - /* We know this operand is at most 32 bits, so convert to a - signed 32 bit number before trying to see whether it will - fit in an even smaller size. */ - disp &= (((offsetT) 2 << 31) - 1); - disp = (disp ^ ((offsetT) 1 << 31)) - ((addressT) 1 << 31); + if ((i.types[op] & Disp16) + && (disp & ~(offsetT) 0xffff) == 0) + { + /* If this operand is at most 16 bits, convert + to a signed 16 bit number and don't use 64bit + displacement. */ + disp = (((disp & 0xffff) ^ 0x8000) - 0x8000); + i.types[op] &= ~Disp64; + } + if ((i.types[op] & Disp32) + && (disp & ~(((offsetT) 2 << 31) - 1)) == 0) + { + /* If this operand is at most 32 bits, convert + to a signed 32 bit number and don't use 64bit + displacement. */ + disp &= (((offsetT) 2 << 31) - 1); + disp = (disp ^ ((offsetT) 1 << 31)) - ((addressT) 1 << 31); + i.types[op] &= ~Disp64; + } + if (!disp && (i.types[op] & BaseIndex)) + { + i.types[op] &= ~Disp; + i.op[op].disps = 0; + i.disp_operands--; + } + else if (flag_code == CODE_64BIT) + { + if (fits_in_signed_long (disp)) + { + i.types[op] &= ~Disp64; + i.types[op] |= Disp32S; + } + if (fits_in_unsigned_long (disp)) + i.types[op] |= Disp32; + } + if ((i.types[op] & (Disp32 | Disp32S | Disp16)) + && fits_in_signed_byte (disp)) + i.types[op] |= Disp8; } - if (flag_code == CODE_64BIT) + else if (i.reloc[op] == BFD_RELOC_386_TLS_DESC_CALL + || i.reloc[op] == BFD_RELOC_X86_64_TLSDESC_CALL) { - if (fits_in_signed_long (disp)) - i.types[op] |= Disp32S; - if (fits_in_unsigned_long (disp)) - i.types[op] |= Disp32; + fix_new_exp (frag_now, frag_more (0) - frag_now->fr_literal, 0, + i.op[op].disps, 0, i.reloc[op]); + i.types[op] &= ~Disp; } - if ((i.types[op] & (Disp32 | Disp32S | Disp16)) - && fits_in_signed_byte (disp)) - i.types[op] |= Disp8; + else + /* We only support 64bit displacement on constants. */ + i.types[op] &= ~Disp64; } } static int -match_template () +match_template (void) { /* Points to template once we've found it. */ const template *t; - unsigned int overlap0, overlap1, overlap2; + unsigned int overlap0, overlap1, overlap2, overlap3; unsigned int found_reverse_match; int suffix_check; + unsigned int operand_types [MAX_OPERANDS]; + int addr_prefix_disp; + unsigned int j; + +#if MAX_OPERANDS != 4 +# error "MAX_OPERANDS must be 4." +#endif #define MATCH(overlap, given, template) \ ((overlap & ~JumpAbsolute) \ @@ -2107,7 +2548,11 @@ match_template () overlap0 = 0; overlap1 = 0; overlap2 = 0; + overlap3 = 0; found_reverse_match = 0; + for (j = 0; j < MAX_OPERANDS; j++) + operand_types [j] = 0; + addr_prefix_disp = -1; suffix_check = (i.suffix == BYTE_MNEM_SUFFIX ? No_bSuf : (i.suffix == WORD_MNEM_SUFFIX @@ -2121,20 +2566,10 @@ match_template () : (i.suffix == LONG_DOUBLE_MNEM_SUFFIX ? No_xSuf : 0)))))); - t = current_templates->start; - if (i.suffix == QWORD_MNEM_SUFFIX - && flag_code != CODE_64BIT - && (intel_syntax - ? !(t->opcode_modifier & IgnoreSize) - && !intel_float_operand (t->name) - : intel_float_operand (t->name) != 2) - && (!(t->operand_types[0] & (RegMMX | RegXMM)) - || !(t->operand_types[t->operands > 1] & (RegMMX | RegXMM))) - && (t->base_opcode != 0x0fc7 - || t->extension_opcode != 1 /* cmpxchg8b */)) - t = current_templates->end; - for (; t < current_templates->end; t++) + for (t = current_templates->start; t < current_templates->end; t++) { + addr_prefix_disp = -1; + /* Must have right number of operands. */ if (i.operands != t->operands) continue; @@ -2145,6 +2580,22 @@ match_template () && (t->opcode_modifier & IgnoreSize))) continue; + for (j = 0; j < MAX_OPERANDS; j++) + operand_types [j] = t->operand_types [j]; + + /* In general, don't allow 64-bit operands in 32-bit mode. */ + if (i.suffix == QWORD_MNEM_SUFFIX + && flag_code != CODE_64BIT + && (intel_syntax + ? (!(t->opcode_modifier & IgnoreSize) + && !intel_float_operand (t->name)) + : intel_float_operand (t->name) != 2) + && (!(operand_types[0] & (RegMMX | RegXMM)) + || !(operand_types[t->operands > 1] & (RegMMX | RegXMM))) + && (t->base_opcode != 0x0fc7 + || t->extension_opcode != 1 /* cmpxchg8b */)) + continue; + /* Do not verify operands when there are none. */ else if (!t->operands) { @@ -2154,61 +2605,142 @@ match_template () break; } - overlap0 = i.types[0] & t->operand_types[0]; + /* Address size prefix will turn Disp64/Disp32/Disp16 operand + into Disp32/Disp16/Disp32 operand. */ + if (i.prefix[ADDR_PREFIX] != 0) + { + unsigned int DispOn = 0, DispOff = 0; + + switch (flag_code) + { + case CODE_16BIT: + DispOn = Disp32; + DispOff = Disp16; + break; + case CODE_32BIT: + DispOn = Disp16; + DispOff = Disp32; + break; + case CODE_64BIT: + DispOn = Disp32; + DispOff = Disp64; + break; + } + + for (j = 0; j < MAX_OPERANDS; j++) + { + /* There should be only one Disp operand. */ + if ((operand_types[j] & DispOff)) + { + addr_prefix_disp = j; + operand_types[j] |= DispOn; + operand_types[j] &= ~DispOff; + break; + } + } + } + + overlap0 = i.types[0] & operand_types[0]; switch (t->operands) { case 1: - if (!MATCH (overlap0, i.types[0], t->operand_types[0])) + if (!MATCH (overlap0, i.types[0], operand_types[0])) 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: - overlap1 = i.types[1] & t->operand_types[1]; - if (!MATCH (overlap0, i.types[0], t->operand_types[0]) - || !MATCH (overlap1, i.types[1], t->operand_types[1]) - || !CONSISTENT_REGISTER_MATCH (overlap0, i.types[0], - t->operand_types[0], - overlap1, i.types[1], - t->operand_types[1])) + case 4: + overlap1 = i.types[1] & operand_types[1]; + if (!MATCH (overlap0, i.types[0], operand_types[0]) + || !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. 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], + operand_types[1]))) { /* Check if other direction is valid ... */ if ((t->opcode_modifier & (D | FloatD)) == 0) continue; /* Try reversing direction of operands. */ - overlap0 = i.types[0] & t->operand_types[1]; - overlap1 = i.types[1] & t->operand_types[0]; - if (!MATCH (overlap0, i.types[0], t->operand_types[1]) - || !MATCH (overlap1, i.types[1], t->operand_types[0]) + overlap0 = i.types[0] & operand_types[1]; + overlap1 = i.types[1] & operand_types[0]; + if (!MATCH (overlap0, i.types[0], operand_types[1]) + || !MATCH (overlap1, i.types[1], operand_types[0]) || !CONSISTENT_REGISTER_MATCH (overlap0, i.types[0], - t->operand_types[1], + operand_types[1], overlap1, i.types[1], - t->operand_types[0])) + operand_types[0])) { /* Does not match either direction. */ continue; } /* 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; } - /* Found a forward 2 operand match here. */ - else if (t->operands == 3) + else { - /* Here we make use of the fact that there are no - reverse match 3 operand instructions, and all 3 - operand instructions only need to be checked for - register consistency between operands 2 and 3. */ - overlap2 = i.types[2] & t->operand_types[2]; - if (!MATCH (overlap2, i.types[2], t->operand_types[2]) - || !CONSISTENT_REGISTER_MATCH (overlap1, i.types[1], - t->operand_types[1], - overlap2, i.types[2], - t->operand_types[2])) + /* Found a forward 2 operand match here. */ + switch (t->operands) + { + case 4: + overlap3 = i.types[3] & operand_types[3]; + case 3: + overlap2 = i.types[2] & operand_types[2]; + break; + } - continue; + switch (t->operands) + { + case 4: + if (!MATCH (overlap3, i.types[3], operand_types[3]) + || !CONSISTENT_REGISTER_MATCH (overlap2, + i.types[2], + operand_types[2], + overlap3, + i.types[3], + operand_types[3])) + continue; + case 3: + /* Here we make use of the fact that there are no + reverse match 3 operand instructions, and all 3 + operand instructions only need to be checked for + register consistency between operands 2 and 3. */ + if (!MATCH (overlap2, i.types[2], operand_types[2]) + || !CONSISTENT_REGISTER_MATCH (overlap1, + i.types[1], + operand_types[1], + overlap2, + i.types[2], + operand_types[2])) + continue; + break; + } } - /* Found either forward/reverse 2 or 3 operand match here: + /* Found either forward/reverse 2, 3 or 4 operand match here: slip through to break. */ } if (t->cpu_flags & ~cpu_arch_flags) @@ -2232,7 +2764,7 @@ match_template () { if (!intel_syntax && ((i.types[0] & JumpAbsolute) - != (t->operand_types[0] & JumpAbsolute))) + != (operand_types[0] & JumpAbsolute))) { as_warn (_("indirect %s without `*'"), t->name); } @@ -2248,6 +2780,11 @@ match_template () /* Copy the template we found. */ i.tm = *t; + + if (addr_prefix_disp != -1) + i.tm.operand_types[addr_prefix_disp] + = operand_types[addr_prefix_disp]; + if (found_reverse_match) { /* If we found a reverse match we must alter the opcode @@ -2256,15 +2793,15 @@ match_template () i.tm.base_opcode ^= found_reverse_match; - i.tm.operand_types[0] = t->operand_types[1]; - i.tm.operand_types[1] = t->operand_types[0]; + i.tm.operand_types[0] = operand_types[1]; + i.tm.operand_types[1] = operand_types[0]; } return 1; } 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) @@ -2317,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) { @@ -2367,9 +2929,9 @@ process_suffix (void) else if (intel_syntax && !i.suffix && ((i.tm.operand_types[0] & JumpAbsolute) - || (i.tm.opcode_modifier & (JumpByte|JumpInterSegment)) - || (i.tm.base_opcode == 0x0f01 /* [ls][gi]dt */ - && i.tm.extension_opcode <= 3))) + || (i.tm.opcode_modifier & (JumpByte|JumpInterSegment)) + || (i.tm.base_opcode == 0x0f01 /* [ls][gi]dt */ + && i.tm.extension_opcode <= 3))) { switch (flag_code) { @@ -2396,19 +2958,20 @@ 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; } } else { - unsigned int suffixes = ~i.tm.opcode_modifier - & (No_bSuf - | No_wSuf - | No_lSuf - | No_sSuf - | No_xSuf - | No_qSuf); + unsigned int suffixes = (~i.tm.opcode_modifier + & (No_bSuf + | No_wSuf + | No_lSuf + | No_sSuf + | No_xSuf + | No_qSuf)); if ((i.tm.opcode_modifier & W) || ((suffixes & (suffixes - 1)) @@ -2437,12 +3000,22 @@ process_suffix (void) /* Now select between word & dword operations via the operand size prefix, except for instructions that will ignore this prefix anyway. */ - if (i.suffix != QWORD_MNEM_SUFFIX - && i.suffix != LONG_DOUBLE_MNEM_SUFFIX - && !(i.tm.opcode_modifier & (IgnoreSize | FloatMF)) - && ((i.suffix == LONG_MNEM_SUFFIX) == (flag_code == CODE_16BIT) - || (flag_code == CODE_64BIT - && (i.tm.opcode_modifier & JumpByte)))) + if (i.tm.base_opcode == 0x0f01 && i.tm.extension_opcode == 0xc8) + { + /* monitor in SSE3 is a very special case. The default size + of AX is the size of mode. The address size override + prefix will change the size of AX. */ + if (i.op->regs[0].reg_type & + (flag_code == CODE_32BIT ? Reg16 : Reg32)) + if (!add_prefix (ADDR_PREFIX_OPCODE)) + return 0; + } + else if (i.suffix != QWORD_MNEM_SUFFIX + && i.suffix != LONG_DOUBLE_MNEM_SUFFIX + && !(i.tm.opcode_modifier & (IgnoreSize | FloatMF)) + && ((i.suffix == LONG_MNEM_SUFFIX) == (flag_code == CODE_16BIT) + || (flag_code == CODE_64BIT + && (i.tm.opcode_modifier & JumpByte)))) { unsigned int prefix = DATA_PREFIX_OPCODE; @@ -2457,7 +3030,15 @@ process_suffix (void) if (i.suffix == QWORD_MNEM_SUFFIX && flag_code == CODE_64BIT && (i.tm.opcode_modifier & NoRex64) == 0) - i.rex |= REX_MODE64; + { + /* Special case for xchg %rax,%rax. It is NOP and doesn't + need rex64. */ + if (i.operands != 2 + || i.types [0] != (Acc | Reg64) + || i.types [1] != (Acc | Reg64) + || i.tm.base_opcode != 0x90) + i.rex |= REX_W; + } /* Size floating point instruction. */ if (i.suffix == LONG_MNEM_SUFFIX) @@ -2490,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 @@ -2497,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 @@ -2520,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); @@ -2531,7 +3119,7 @@ check_byte_reg (void) } static int -check_long_reg () +check_long_reg (void) { int op; @@ -2541,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); @@ -2556,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 @@ -2573,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; } @@ -2582,7 +3173,7 @@ check_long_reg () } static int -check_qword_reg () +check_qword_reg (void) { int op; @@ -2592,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); @@ -2605,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; } @@ -2614,7 +3206,7 @@ check_qword_reg () } static int -check_word_reg () +check_word_reg (void) { int op; for (op = i.operands; --op >= 0;) @@ -2623,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); @@ -2638,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 @@ -2655,7 +3250,7 @@ check_word_reg () } static int -finalize_imm () +finalize_imm (void) { unsigned int overlap0, overlap1, overlap2; @@ -2686,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; } } @@ -2719,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; } } @@ -2733,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 @@ -2743,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); + } } } } @@ -2788,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; } @@ -2811,8 +3447,10 @@ process_operands () default_seg = &ds; } - if (i.tm.base_opcode == 0x8d /* lea */ && i.seg[0] && !quiet_warnings) - as_warn (_("segment override on `lea' is ineffectual")); + if ((i.tm.base_opcode == 0x8d /* lea */ + || (i.tm.cpu_flags & CpuSVME)) + && i.seg[0] && !quiet_warnings) + as_warn (_("segment override on `%s' is ineffectual"), i.tm.name); /* If a segment was explicitly specified, and the specified segment is not the default, use an opcode prefix to select it. If we @@ -2828,7 +3466,7 @@ process_operands () } static const seg_entry * -build_modrm_byte () +build_modrm_byte (void) { const seg_entry *default_seg = 0; @@ -2837,11 +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); + + 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; @@ -2851,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); } } @@ -2882,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; @@ -2905,9 +3568,11 @@ build_modrm_byte () i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; i.sib.base = NO_BASE_REGISTER; i.sib.index = NO_INDEX_REGISTER; - i.types[op] = ((i.prefix[ADDR_PREFIX] == 0) ? Disp32S : Disp32); + i.types[op] = ((i.prefix[ADDR_PREFIX] == 0) + ? Disp32S : Disp32); } - else if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0)) + else if ((flag_code == CODE_16BIT) + ^ (i.prefix[ADDR_PREFIX] != 0)) { i.rm.regmem = NO_BASE_REGISTER_16; i.types[op] = Disp16; @@ -2930,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. */ @@ -2939,7 +3604,7 @@ build_modrm_byte () i.rm.regmem = NO_BASE_REGISTER; i.types[op] &= ~ Disp; i.types[op] |= Disp32S; - i.flags[op] = Operand_PCrel; + i.flags[op] |= Operand_PCrel; if (! i.disp_operands) fake_zero_displacement = 1; } @@ -2977,11 +3642,13 @@ build_modrm_byte () { if (flag_code == CODE_64BIT && (i.types[op] & Disp)) - i.types[op] = (i.types[op] & Disp8) | (i.prefix[ADDR_PREFIX] == 0 ? Disp32S : Disp32); + i.types[op] = ((i.types[op] & Disp8) + | (i.prefix[ADDR_PREFIX] == 0 + ? Disp32S : Disp32)); 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. */ @@ -3018,9 +3685,15 @@ 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; } - i.rm.mode = mode_from_disp_size (i.types[op]); + + if (i.disp_operands + && (i.reloc[op] == BFD_RELOC_386_TLS_DESC_CALL + || i.reloc[op] == BFD_RELOC_X86_64_TLSDESC_CALL)) + i.rm.mode = 0; + else + i.rm.mode = mode_from_disp_size (i.types[op]); } if (fake_zero_displacement) @@ -3045,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 @@ -3087,7 +3757,7 @@ build_modrm_byte () } static void -output_branch () +output_branch (void) { char *p; int code16; @@ -3165,7 +3835,7 @@ output_branch () } static void -output_jump () +output_jump (void) { char *p; int size; @@ -3231,7 +3901,7 @@ output_jump () } static void -output_interseg_jump () +output_interseg_jump (void) { char *p; int size; @@ -3295,7 +3965,7 @@ output_interseg_jump () } static void -output_insn () +output_insn (void) { fragS *insn_start_frag; offsetT insn_start_off; @@ -3320,23 +3990,33 @@ output_insn () /* Output normal instructions here. */ char *p; unsigned char *q; - - /* All opcodes on i386 have either 1 or 2 bytes. We may use one - more higher byte to specify a prefix the instruction - requires. */ - if ((i.tm.base_opcode & 0xff0000) != 0) + unsigned int prefix; + + /* 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) + { + prefix = (i.tm.base_opcode >> 24) & 0xff; + goto check_prefix; + } + } + else if ((i.tm.base_opcode & 0xff0000) != 0) + { + prefix = (i.tm.base_opcode >> 16) & 0xff; if ((i.tm.cpu_flags & CpuPadLock) != 0) { - unsigned int prefix; - prefix = (i.tm.base_opcode >> 16) & 0xff; - + check_prefix: if (prefix != REPE_PREFIX_OPCODE || i.prefix[LOCKREP_PREFIX] != REPE_PREFIX_OPCODE) add_prefix (prefix); } else - add_prefix ((i.tm.base_opcode >> 16) & 0xff); + add_prefix (prefix); } /* The prefix bytes. */ @@ -3358,7 +4038,14 @@ output_insn () } else { - p = frag_more (2); + 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; + } + else + p = frag_more (2); /* Put out high byte first: can't use md_number_to_chars! */ *p++ = (i.tm.base_opcode >> 8) & 0xff; @@ -3401,15 +4088,47 @@ output_insn () #ifdef DEBUG386 if (flag_debug) { - pi (line, &i); + pi ("" /*line*/, &i); } #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 (insn_start_frag, insn_start_off) - fragS *insn_start_frag; - offsetT insn_start_off; +output_disp (fragS *insn_start_frag, offsetT insn_start_off) { char *p; unsigned int n; @@ -3420,18 +4139,9 @@ output_disp (insn_start_frag, 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); @@ -3440,57 +4150,48 @@ output_disp (insn_start_frag, 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); reloc_type = reloc (size, pcrel, sign, i.reloc[n]); - if (reloc_type == BFD_RELOC_32 - && GOT_symbol + if (GOT_symbol && GOT_symbol == i.op[n].disps->X_add_symbol - && (i.op[n].disps->X_op == O_symbol - || (i.op[n].disps->X_op == O_add - && ((symbol_get_value_expression - (i.op[n].disps->X_op_symbol)->X_op) - == O_subtract)))) + && (((reloc_type == BFD_RELOC_32 + || reloc_type == BFD_RELOC_X86_64_32S + || (reloc_type == BFD_RELOC_64 + && object_64bit)) + && (i.op[n].disps->X_op == O_symbol + || (i.op[n].disps->X_op == O_add + && ((symbol_get_value_expression + (i.op[n].disps->X_op_symbol)->X_op) + == O_subtract)))) + || reloc_type == BFD_RELOC_32_PCREL)) { offsetT add; @@ -3506,12 +4207,19 @@ output_disp (insn_start_frag, insn_start_off) add += fr->fr_fix; add += p - frag_now->fr_literal; } - - /* We don't support dynamic linking on x86-64 yet. */ - if (flag_code == CODE_64BIT) - abort (); - reloc_type = BFD_RELOC_386_GOTPC; - i.op[n].disps->X_add_number += add; + + if (!object_64bit) + { + reloc_type = BFD_RELOC_386_GOTPC; + i.op[n].imms->X_add_number += add; + } + else if (reloc_type == BFD_RELOC_64) + reloc_type = BFD_RELOC_X86_64_GOTPC64; + else + /* Don't do the adjustment for x86-64, as there + the pcrel addressing is relative to the _next_ + insn, and that is taken care of in other code. */ + reloc_type = BFD_RELOC_X86_64_GOTPC32; } fix_new_exp (frag_now, p - frag_now->fr_literal, size, i.op[n].disps, pcrel, reloc_type); @@ -3521,9 +4229,7 @@ output_disp (insn_start_frag, insn_start_off) } static void -output_imm (insn_start_frag, insn_start_off) - fragS *insn_start_frag; - offsetT insn_start_off; +output_imm (fragS *insn_start_frag, offsetT insn_start_off) { char *p; unsigned int n; @@ -3534,18 +4240,9 @@ output_imm (insn_start_frag, 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); @@ -3558,21 +4255,15 @@ output_imm (insn_start_frag, 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]); @@ -3619,7 +4310,9 @@ output_imm (insn_start_frag, insn_start_off) * since the expression is not pcrel, I felt it would be * confusing to do it this way. */ - if (reloc_type == BFD_RELOC_32 + if ((reloc_type == BFD_RELOC_32 + || reloc_type == BFD_RELOC_X86_64_32S + || reloc_type == BFD_RELOC_64) && GOT_symbol && GOT_symbol == i.op[n].imms->X_add_symbol && (i.op[n].imms->X_op == O_symbol @@ -3643,10 +4336,12 @@ output_imm (insn_start_frag, insn_start_off) add += p - frag_now->fr_literal; } - /* We don't support dynamic linking on x86-64 yet. */ - if (flag_code == CODE_64BIT) - abort (); - reloc_type = BFD_RELOC_386_GOTPC; + if (!object_64bit) + reloc_type = BFD_RELOC_386_GOTPC; + else if (size == 4) + reloc_type = BFD_RELOC_X86_64_GOTPC32; + else if (size == 8) + reloc_type = BFD_RELOC_X86_64_GOTPC64; i.op[n].imms->X_add_number += add; } fix_new_exp (frag_now, p - frag_now->fr_literal, size, @@ -3656,9 +4351,33 @@ output_imm (insn_start_frag, insn_start_off) } } -#ifndef LEX_AT -static char *lex_got PARAMS ((enum bfd_reloc_code_real *, int *)); +/* x86_cons_fix_new is called via the expression parsing code when a + reloc is needed. We use this hook to get the correct .got reloc. */ +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, + expressionS *exp) +{ + enum bfd_reloc_code_real r = reloc (len, 0, cons_sign, got_reloc); + + got_reloc = NO_RELOC; + +#ifdef TE_PE + if (exp->X_op == O_secrel) + { + exp->X_op = O_symbol; + r = BFD_RELOC_32_SECREL; + } +#endif + + fix_new_exp (frag, off, len, exp, 0, r); +} +#if (!defined (OBJ_ELF) && !defined (OBJ_MAYBE_ELF)) || defined (LEX_AT) +# define lex_got(reloc, adjust, types) NULL +#else /* Parse operands of the form @GOTOFF+ and similar .plt or .got references. @@ -3669,32 +4388,78 @@ static char *lex_got PARAMS ((enum bfd_reloc_code_real *, int *)); is non-null set it to the length of the string we removed from the input line. Otherwise return NULL. */ static char * -lex_got (reloc, adjust) - enum bfd_reloc_code_real *reloc; - int *adjust; +lex_got (enum bfd_reloc_code_real *reloc, + int *adjust, + unsigned int *types) { - static const char * const mode_name[NUM_FLAG_CODE] = { "32", "16", "64" }; + /* Some of the relocations depend on the size of what field is to + be relocated. But in our callers i386_immediate and i386_displacement + we don't yet know the operand size (this will be set by insn + matching). Hence we record the word32 relocation here, + and adjust the reloc according to the real size in reloc(). */ static const struct { const char *str; - const enum bfd_reloc_code_real rel[NUM_FLAG_CODE]; + const enum bfd_reloc_code_real rel[2]; + const unsigned int types64; } gotrel[] = { - { "PLT", { BFD_RELOC_386_PLT32, 0, BFD_RELOC_X86_64_PLT32 } }, - { "GOTOFF", { BFD_RELOC_386_GOTOFF, 0, 0 } }, - { "GOTPCREL", { 0, 0, BFD_RELOC_X86_64_GOTPCREL } }, - { "TLSGD", { BFD_RELOC_386_TLS_GD, 0, BFD_RELOC_X86_64_TLSGD } }, - { "TLSLDM", { BFD_RELOC_386_TLS_LDM, 0, 0 } }, - { "TLSLD", { 0, 0, BFD_RELOC_X86_64_TLSLD } }, - { "GOTTPOFF", { BFD_RELOC_386_TLS_IE_32, 0, BFD_RELOC_X86_64_GOTTPOFF } }, - { "TPOFF", { BFD_RELOC_386_TLS_LE_32, 0, BFD_RELOC_X86_64_TPOFF32 } }, - { "NTPOFF", { BFD_RELOC_386_TLS_LE, 0, 0 } }, - { "DTPOFF", { BFD_RELOC_386_TLS_LDO_32, 0, BFD_RELOC_X86_64_DTPOFF32 } }, - { "GOTNTPOFF",{ BFD_RELOC_386_TLS_GOTIE, 0, 0 } }, - { "INDNTPOFF",{ BFD_RELOC_386_TLS_IE, 0, 0 } }, - { "GOT", { BFD_RELOC_386_GOT32, 0, BFD_RELOC_X86_64_GOT32 } } + { "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; + if (!IS_ELF) + return NULL; + for (cp = input_line_pointer; *cp != '@'; cp++) if (is_end_of_line[(unsigned char) *cp]) return NULL; @@ -3706,21 +4471,26 @@ lex_got (reloc, adjust) len = strlen (gotrel[j].str); if (strncasecmp (cp + 1, gotrel[j].str, len) == 0) { - if (gotrel[j].rel[(unsigned int) flag_code] != 0) + if (gotrel[j].rel[object_64bit] != 0) { int first, second; char *tmpbuf, *past_reloc; - *reloc = gotrel[j].rel[(unsigned int) flag_code]; + *reloc = gotrel[j].rel[object_64bit]; if (adjust) *adjust = len; + if (types) + { + if (flag_code != CODE_64BIT) + *types = Imm32 | Disp32; + else + *types = gotrel[j].types64; + } + 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; @@ -3736,14 +4506,17 @@ lex_got (reloc, adjust) 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; } - as_bad (_("@%s reloc is not supported in %s bit mode"), - gotrel[j].str, mode_name[(unsigned int) flag_code]); + as_bad (_("@%s reloc is not supported with %d-bit output format"), + gotrel[j].str, 1 << (5 + object_64bit)); return NULL; } } @@ -3752,28 +4525,10 @@ lex_got (reloc, adjust) return NULL; } -/* x86_cons_fix_new is called via the expression parsing code when a - reloc is needed. We use this hook to get the correct .got reloc. */ -static enum bfd_reloc_code_real got_reloc = NO_RELOC; - -void -x86_cons_fix_new (frag, off, len, exp) - fragS *frag; - unsigned int off; - unsigned int len; - expressionS *exp; -{ - enum bfd_reloc_code_real r = reloc (len, 0, 0, got_reloc); - got_reloc = NO_RELOC; - fix_new_exp (frag, off, len, exp, 0, r); -} - void -x86_cons (exp, size) - expressionS *exp; - int size; +x86_cons (expressionS *exp, int size) { - if (size == 4) + if (size == 4 || (object_64bit && size == 8)) { /* Handle @GOTOFF and the like in an expression. */ char *save; @@ -3781,7 +4536,7 @@ x86_cons (exp, size) int adjust; save = input_line_pointer; - gotfree_input_line = lex_got (&got_reloc, &adjust); + gotfree_input_line = lex_got (&got_reloc, &adjust, NULL); if (gotfree_input_line) input_line_pointer = gotfree_input_line; @@ -3803,26 +4558,15 @@ x86_cons (exp, size) } #endif -#ifdef TE_PE - -void -x86_pe_cons_fix_new (frag, off, len, exp) - fragS *frag; - unsigned int off; - unsigned int len; - expressionS *exp; +static void signed_cons (int size) { - enum bfd_reloc_code_real r = reloc (len, 0, 0, NO_RELOC); - - if (exp->X_op == O_secrel) - { - exp->X_op = O_symbol; - r = BFD_RELOC_32_SECREL; - } - - fix_new_exp (frag, off, len, exp, 0, r); + if (flag_code == CODE_64BIT) + cons_sign = 1; + cons (size); + cons_sign = -1; } +#ifdef TE_PE static void pe_directive_secrel (dummy) int dummy ATTRIBUTE_UNUSED; @@ -3842,25 +4586,21 @@ pe_directive_secrel (dummy) input_line_pointer--; demand_empty_rest_of_line (); } - #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; -#ifndef LEX_AT char *gotfree_input_line; -#endif segT exp_seg = 0; expressionS *exp; + unsigned int types = ~0U; 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; } @@ -3873,11 +4613,9 @@ i386_immediate (imm_start) save_input_line_pointer = input_line_pointer; input_line_pointer = imm_start; -#ifndef LEX_AT - gotfree_input_line = lex_got (&i.reloc[this_operand], NULL); + gotfree_input_line = lex_got (&i.reloc[this_operand], NULL, &types); if (gotfree_input_line) input_line_pointer = gotfree_input_line; -#endif exp_seg = expression (exp); @@ -3886,10 +4624,8 @@ i386_immediate (imm_start) as_bad (_("junk `%s' after expression"), input_line_pointer); input_line_pointer = save_input_line_pointer; -#ifndef LEX_AT if (gotfree_input_line) free (gotfree_input_line); -#endif if (exp->X_op == O_absent || exp->X_op == O_big) { @@ -3906,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 @@ -3923,22 +4660,25 @@ i386_immediate (imm_start) return 0; } #endif + else if (!intel_syntax && exp->X_op == O_register) + { + as_bad (_("illegal immediate register operand %s"), imm_start); + return 0; + } else { /* This is an address. The size of the address will be determined later, depending on destination register, suffix, or the default for the section. */ i.types[this_operand] |= Imm8 | Imm16 | Imm32 | Imm32S | Imm64; + i.types[this_operand] &= types; } 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; @@ -3985,28 +4725,58 @@ 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; char *save_input_line_pointer; -#ifndef LEX_AT char *gotfree_input_line; -#endif - int bigdisp = Disp32; + 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))) + { + bigdisp = Disp32; + override = (i.prefix[ADDR_PREFIX] != 0); + } + else + { + /* For PC-relative branches, the width of the displacement + is dependent upon data size, not address size. */ + bigdisp = 0; + override = (i.prefix[DATA_PREFIX] != 0); + } if (flag_code == CODE_64BIT) { - if (i.prefix[ADDR_PREFIX] == 0) - bigdisp = Disp64; + if (!bigdisp) + bigdisp = ((override || i.suffix == WORD_MNEM_SUFFIX) + ? Disp16 + : Disp32S | Disp32); + else if (!override) + bigdisp = Disp64 | Disp32S | Disp32; + } + else + { + if (!bigdisp) + { + if (!override) + override = (i.suffix == (flag_code != CODE_16BIT + ? WORD_MNEM_SUFFIX + : LONG_MNEM_SUFFIX)); + bigdisp = Disp32; + } + if ((flag_code == CODE_16BIT) ^ override) + bigdisp = Disp16; } - else if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0)) - bigdisp = Disp16; i.types[this_operand] |= bigdisp; exp = &disp_expressions[i.disp_operands]; @@ -4060,11 +4830,9 @@ i386_displacement (disp_start, disp_end) *displacement_string_end = '0'; } #endif -#ifndef LEX_AT - gotfree_input_line = lex_got (&i.reloc[this_operand], NULL); + gotfree_input_line = lex_got (&i.reloc[this_operand], NULL, &types); if (gotfree_input_line) input_line_pointer = gotfree_input_line; -#endif exp_seg = expression (exp); @@ -4076,16 +4844,15 @@ i386_displacement (disp_start, disp_end) #endif RESTORE_END_STRING (disp_end); input_line_pointer = save_input_line_pointer; -#ifndef LEX_AT if (gotfree_input_line) free (gotfree_input_line); -#endif /* We do this to make sure that the section symbol is in the symbol table. We will ultimately change the relocation to be relative to the beginning of the section. */ if (i.reloc[this_operand] == BFD_RELOC_386_GOTOFF - || i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL) + || i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL + || i.reloc[this_operand] == BFD_RELOC_X86_64_GOTOFF64) { if (exp->X_op != O_symbol) { @@ -4103,6 +4870,8 @@ i386_displacement (disp_start, disp_end) exp->X_op_symbol = GOT_symbol; if (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL) i.reloc[this_operand] = BFD_RELOC_32_PCREL; + else if (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTOFF64) + i.reloc[this_operand] = BFD_RELOC_64; else i.reloc[this_operand] = BFD_RELOC_32; } @@ -4132,19 +4901,18 @@ i386_displacement (disp_start, disp_end) return 0; } #endif - else if (flag_code == CODE_64BIT) - i.types[this_operand] |= Disp32S | Disp32; + + if (!(i.types[this_operand] & ~Disp)) + i.types[this_operand] &= types; + 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 @@ -4153,18 +4921,41 @@ i386_index_check (operand_string) tryprefix: #endif ok = 1; - if (flag_code == CODE_64BIT) - { - unsigned RegXX = (i.prefix[ADDR_PREFIX] == 0 ? Reg64 : Reg32); - - if ((i.base_reg - && ((i.base_reg->reg_type & RegXX) == 0) - && (i.base_reg->reg_type != BaseIndex - || i.index_reg)) - || (i.index_reg - && ((i.index_reg->reg_type & (RegXX | BaseIndex)) - != (RegXX | BaseIndex)))) - ok = 0; + if ((current_templates->start->cpu_flags & CpuSVME) + && current_templates->end[-1].operand_types[0] == AnyMem) + { + /* Memory operands of SVME insns are special in that they only allow + rAX as their memory address and ignore any segment override. */ + unsigned RegXX; + + /* SKINIT is even more restrictive: it always requires EAX. */ + if (strcmp (current_templates->start->name, "skinit") == 0) + RegXX = Reg32; + else if (flag_code == CODE_64BIT) + RegXX = i.prefix[ADDR_PREFIX] == 0 ? Reg64 : Reg32; + else + RegXX = ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0) + ? Reg16 + : Reg32); + if (!i.base_reg + || !(i.base_reg->reg_type & Acc) + || !(i.base_reg->reg_type & RegXX) + || i.index_reg + || (i.types[0] & Disp)) + ok = 0; + } + else if (flag_code == CODE_64BIT) + { + unsigned RegXX = (i.prefix[ADDR_PREFIX] == 0 ? Reg64 : Reg32); + + if ((i.base_reg + && ((i.base_reg->reg_type & RegXX) == 0) + && (i.base_reg->reg_type != BaseIndex + || i.index_reg)) + || (i.index_reg + && ((i.index_reg->reg_type & (RegXX | BaseIndex)) + != (RegXX | BaseIndex)))) + ok = 0; } else { @@ -4206,8 +4997,9 @@ 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))) - 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; } @@ -4227,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; @@ -4248,8 +5039,7 @@ i386_operand (operand_string) } /* Check if operand is a register. */ - if ((*op_string == REGISTER_PREFIX || allow_naked_reg) - && (r = parse_register (op_string, &end_op)) != NULL) + if ((r = parse_register (op_string, &end_op)) != NULL) { /* Check for a segment override by searching for ':' after a segment register. */ @@ -4387,8 +5177,8 @@ i386_operand (operand_string) ++base_string; if (*base_string == ',' - || ((*base_string == REGISTER_PREFIX || allow_naked_reg) - && (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; @@ -4408,8 +5198,8 @@ i386_operand (operand_string) if (is_space_char (*base_string)) ++base_string; - if ((*base_string == REGISTER_PREFIX || allow_naked_reg) - && (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)) @@ -4422,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; } @@ -4446,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; } @@ -4534,7 +5328,7 @@ md_estimate_size_before_relax (fragP, segment) shared library. */ if (S_GET_SEGMENT (fragP->fr_symbol) != segment #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) - || (OUTPUT_FLAVOR == bfd_target_elf_flavour + || (IS_ELF && (S_IS_EXTERNAL (fragP->fr_symbol) || S_IS_WEAK (fragP->fr_symbol))) #endif @@ -4676,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) { @@ -4721,6 +5516,20 @@ md_convert_frag (abfd, sec, fragP) } } + /* If size if less then four we are sure that the operand fits, + but if it's 4, then it could be that the displacement is larger + then -/+ 2GB. */ + 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))) + { + as_bad_where (fragP->fr_file, fragP->fr_line, + _("jump target out of range")); + /* Make us emit 0. */ + displacement_from_opcode_start = extension; + } /* Now put displacement after opcode. */ md_number_to_chars ((char *) where_to_put_displacement, (valueT) (displacement_from_opcode_start - extension), @@ -4734,9 +5543,6 @@ int md_short_jump_size = 2; /* Size of dword displacement jmp. */ int md_long_jump_size = 5; -/* Size of relocation record. */ -const int md_reloc_size = 8; - void md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol) char *ptr; @@ -4774,7 +5580,7 @@ md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol) we are handling. */ void -md_apply_fix3 (fixP, valP, seg) +md_apply_fix (fixP, valP, seg) /* The fix we're to put in. */ fixS *fixP; /* Pointer to the value of the bits. */ @@ -4793,6 +5599,9 @@ md_apply_fix3 (fixP, valP, seg) default: break; + case BFD_RELOC_64: + fixP->fx_r_type = BFD_RELOC_64_PCREL; + break; case BFD_RELOC_32: case BFD_RELOC_X86_64_32S: fixP->fx_r_type = BFD_RELOC_32_PCREL; @@ -4808,6 +5617,7 @@ md_apply_fix3 (fixP, valP, seg) if (fixP->fx_addsy != NULL && (fixP->fx_r_type == BFD_RELOC_32_PCREL + || fixP->fx_r_type == BFD_RELOC_64_PCREL || fixP->fx_r_type == BFD_RELOC_16_PCREL || fixP->fx_r_type == BFD_RELOC_8_PCREL) && !use_rela_relocations) @@ -4817,7 +5627,7 @@ md_apply_fix3 (fixP, valP, seg) subtract the current location (for partial_inplace, PC relative relocations); see more below. */ #ifndef OBJ_AOUT - if (OUTPUT_FLAVOR == bfd_target_elf_flavour + if (IS_ELF #ifdef TE_PE || OUTPUT_FLAVOR == bfd_target_coff_flavour #endif @@ -4825,7 +5635,7 @@ md_apply_fix3 (fixP, valP, seg) value += fixP->fx_where + fixP->fx_frag->fr_address; #endif #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) - if (OUTPUT_FLAVOR == bfd_target_elf_flavour) + if (IS_ELF) { segT sym_seg = S_GET_SEGMENT (fixP->fx_addsy); @@ -4846,10 +5656,7 @@ md_apply_fix3 (fixP, valP, seg) /* For some reason, the PE format does not store a section address offset for a PC relative symbol. */ if (S_GET_SEGMENT (fixP->fx_addsy) != seg -#if defined(BFD_ASSEMBLER) || defined(S_IS_WEAK) - || S_IS_WEAK (fixP->fx_addsy) -#endif - ) + || S_IS_WEAK (fixP->fx_addsy)) value += md_pcrel_from (fixP); #endif } @@ -4857,8 +5664,7 @@ md_apply_fix3 (fixP, valP, seg) /* Fix a few things - the dynamic linker expects certain values here, and we must not disappoint it. */ #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) - if (OUTPUT_FLAVOR == bfd_target_elf_flavour - && fixP->fx_addsy) + if (IS_ELF && fixP->fx_addsy) switch (fixP->fx_r_type) { case BFD_RELOC_386_PLT32: @@ -4873,19 +5679,30 @@ md_apply_fix3 (fixP, valP, seg) case BFD_RELOC_386_TLS_IE_32: case BFD_RELOC_386_TLS_IE: case BFD_RELOC_386_TLS_GOTIE: + case BFD_RELOC_386_TLS_GOTDESC: case BFD_RELOC_X86_64_TLSGD: case BFD_RELOC_X86_64_TLSLD: case BFD_RELOC_X86_64_GOTTPOFF: + case BFD_RELOC_X86_64_GOTPC32_TLSDESC: value = 0; /* Fully resolved at runtime. No addend. */ /* Fallthrough */ case BFD_RELOC_386_TLS_LE: case BFD_RELOC_386_TLS_LDO_32: case BFD_RELOC_386_TLS_LE_32: case BFD_RELOC_X86_64_DTPOFF32: + case BFD_RELOC_X86_64_DTPOFF64: case BFD_RELOC_X86_64_TPOFF32: + case BFD_RELOC_X86_64_TPOFF64: S_SET_THREAD_LOCAL (fixP->fx_addsy); break; + case BFD_RELOC_386_TLS_DESC_CALL: + case BFD_RELOC_X86_64_TLSDESC_CALL: + value = 0; /* Fully resolved at runtime. No addend. */ + S_SET_THREAD_LOCAL (fixP->fx_addsy); + fixP->fx_done = 0; + return; + case BFD_RELOC_386_GOT32: case BFD_RELOC_X86_64_GOT32: value = 0; /* Fully resolved at runtime. No addend. */ @@ -4971,25 +5788,24 @@ md_atof (type, litP, sizeP) return 0; } -static char output_invalid_buf[8]; +static char output_invalid_buf[sizeof (unsigned char) * 2 + 6]; static char * -output_invalid (c) - int c; +output_invalid (int c) { if (ISPRINT (c)) - sprintf (output_invalid_buf, "'%c'", c); + snprintf (output_invalid_buf, sizeof (output_invalid_buf), + "'%c'", c); else - sprintf (output_invalid_buf, "(0x%x)", (unsigned) c); + snprintf (output_invalid_buf, sizeof (output_invalid_buf), + "(0x%x)", (unsigned char) c); return output_invalid_buf; } /* REG_STRING starts *before* REGISTER_PREFIX. */ static const reg_entry * -parse_register (reg_string, end_op) - char *reg_string; - char **end_op; +parse_real_register (char *reg_string, char **end_op) { char *s = reg_string; char *p; @@ -5033,14 +5849,16 @@ parse_register (reg_string, 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. */ @@ -5056,6 +5874,81 @@ parse_register (reg_string, end_op) return r; } + +/* REG_STRING starts *before* REGISTER_PREFIX. */ + +static const reg_entry * +parse_register (char *reg_string, char **end_op) +{ + const reg_entry *r; + + if (*reg_string == REGISTER_PREFIX || allow_naked_reg) + r = parse_real_register (reg_string, end_op); + else + r = NULL; + if (!r) + { + char *save = input_line_pointer; + char c; + symbolS *symbolP; + + input_line_pointer = reg_string; + c = get_symbol_end (); + symbolP = symbol_find (reg_string); + if (symbolP && S_GET_SEGMENT (symbolP) == reg_section) + { + 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 < i386_regtab_size); + r = i386_regtab + e->X_add_number; + *end_op = input_line_pointer; + } + *input_line_pointer = c; + input_line_pointer = save; + } + return r; +} + +int +i386_parse_name (char *name, expressionS *e, char *nextcharP) +{ + const reg_entry *r; + char *end = input_line_pointer; + + *end = *nextcharP; + r = parse_register (name, &input_line_pointer); + if (r && end <= input_line_pointer) + { + *nextcharP = *input_line_pointer; + *input_line_pointer = 0; + e->X_op = O_register; + e->X_add_number = r - i386_regtab; + return 1; + } + input_line_pointer = end; + *end = 0; + return 0; +} + +void +md_operand (expressionS *e) +{ + if (*input_line_pointer == REGISTER_PREFIX) + { + char *end; + const reg_entry *r = parse_real_register (input_line_pointer, &end); + + if (r) + { + e->X_op = O_register; + e->X_add_number = r - i386_regtab; + input_line_pointer = end; + } + } +} + #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) const char *md_shortopts = "kVQ:sqn"; @@ -5063,22 +5956,30 @@ const char *md_shortopts = "kVQ:sqn"; const char *md_shortopts = "qn"; #endif -struct option md_longopts[] = { #define OPTION_32 (OPTION_MD_BASE + 0) - {"32", no_argument, NULL, OPTION_32}, -#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) #define OPTION_64 (OPTION_MD_BASE + 1) +#define OPTION_DIVIDE (OPTION_MD_BASE + 2) +#define OPTION_MARCH (OPTION_MD_BASE + 3) +#define OPTION_MTUNE (OPTION_MD_BASE + 4) + +struct option md_longopts[] = +{ + {"32", no_argument, NULL, OPTION_32}, +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || defined(TE_PEP) {"64", no_argument, NULL, OPTION_64}, #endif + {"divide", no_argument, NULL, OPTION_DIVIDE}, + {"march", required_argument, NULL, OPTION_MARCH}, + {"mtune", required_argument, NULL, OPTION_MTUNE}, {NULL, no_argument, NULL, 0} }; size_t md_longopts_size = sizeof (md_longopts); int -md_parse_option (c, arg) - int c; - char *arg ATTRIBUTE_UNUSED; +md_parse_option (int c, char *arg) { + unsigned int i; + switch (c) { case 'n': @@ -5108,14 +6009,18 @@ md_parse_option (c, arg) /* -s: On i386 Solaris, this tells the native assembler to use .stab instead of .stab.excl. We always use .stab anyhow. */ break; - +#endif +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || defined(TE_PEP) case OPTION_64: { const char **list, **l; list = bfd_target_list (); for (l = list; *l != NULL; l++) - if (strcmp (*l, "elf64-x86-64") == 0) + if (CONST_STRNEQ (*l, "elf64-x86-64") + || strcmp (*l, "coff-x86-64") == 0 + || strcmp (*l, "pe-x86-64") == 0 + || strcmp (*l, "pei-x86-64") == 0) { default_arch = "x86_64"; break; @@ -5131,6 +6036,61 @@ md_parse_option (c, arg) default_arch = "i386"; break; + case OPTION_DIVIDE: +#ifdef SVR4_COMMENT_CHARS + { + char *n, *t; + const char *s; + + n = (char *) xmalloc (strlen (i386_comment_chars) + 1); + t = n; + for (s = i386_comment_chars; *s != '\0'; s++) + if (*s != '/') + *t++ = *s; + *t = '\0'; + i386_comment_chars = n; + } +#endif + break; + + case OPTION_MARCH: + if (*arg == '.') + as_fatal (_("Invalid -march= option: `%s'"), arg); + for (i = 0; i < ARRAY_SIZE (cpu_arch); i++) + { + if (strcmp (arg, cpu_arch [i].name) == 0) + { + cpu_arch_isa = cpu_arch[i].type; + cpu_arch_isa_flags = cpu_arch[i].flags; + if (!cpu_arch_tune_set) + { + cpu_arch_tune = cpu_arch_isa; + cpu_arch_tune_flags = cpu_arch_isa_flags; + } + break; + } + } + if (i >= ARRAY_SIZE (cpu_arch)) + as_fatal (_("Invalid -march= option: `%s'"), arg); + break; + + case OPTION_MTUNE: + if (*arg == '.') + as_fatal (_("Invalid -mtune= option: `%s'"), arg); + for (i = 0; i < ARRAY_SIZE (cpu_arch); i++) + { + if (strcmp (arg, cpu_arch [i].name) == 0) + { + cpu_arch_tune_set = 1; + cpu_arch_tune = cpu_arch [i].type; + cpu_arch_tune_flags = cpu_arch[i].flags; + break; + } + } + if (i >= ARRAY_SIZE (cpu_arch)) + as_fatal (_("Invalid -mtune= option: `%s'"), arg); + break; + default: return 0; } @@ -5145,33 +6105,70 @@ md_show_usage (stream) fprintf (stream, _("\ -Q ignored\n\ -V print assembler version number\n\ - -k ignored\n\ + -k ignored\n")); +#endif + fprintf (stream, _("\ -n Do not optimize code alignment\n\ - -q quieten some warnings\n\ + -q quieten some warnings\n")); +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + 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")); #else fprintf (stream, _("\ - -n Do not optimize code alignment\n\ - -q quieten some warnings\n")); + --divide ignored\n")); #endif + 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 (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")) - set_code_flag (CODE_64BIT); + { + set_code_flag (CODE_64BIT); + if (cpu_arch_isa_flags == 0) + cpu_arch_isa_flags = Cpu186|Cpu286|Cpu386|Cpu486 + |Cpu586|Cpu686|CpuP4|CpuMMX|CpuMMX2 + |CpuSSE|CpuSSE2; + if (cpu_arch_tune_flags == 0) + cpu_arch_tune_flags = Cpu186|Cpu286|Cpu386|Cpu486 + |Cpu586|Cpu686|CpuP4|CpuMMX|CpuMMX2 + |CpuSSE|CpuSSE2; + } else if (!strcmp (default_arch, "i386")) - set_code_flag (CODE_32BIT); + { + set_code_flag (CODE_32BIT); + if (cpu_arch_isa_flags == 0) + cpu_arch_isa_flags = Cpu186|Cpu286|Cpu386; + if (cpu_arch_tune_flags == 0) + cpu_arch_tune_flags = Cpu186|Cpu286|Cpu386; + } else 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; @@ -5184,8 +6181,11 @@ i386_target_format () case bfd_target_elf_flavour: { if (flag_code == CODE_64BIT) - use_rela_relocations = 1; - return flag_code == CODE_64BIT ? "elf64-x86-64" : ELF_TARGET_FORMAT; + { + object_64bit = 1; + use_rela_relocations = 1; + } + return flag_code == CODE_64BIT ? ELF_TARGET_FORMAT64 : ELF_TARGET_FORMAT; } #endif default: @@ -5197,10 +6197,10 @@ 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 (OUTPUT_FLAVOR == bfd_target_elf_flavour - && cpu_arch_name != NULL) + if (IS_ELF && cpu_arch_name != NULL) { char *p; asection *seg = now_seg; @@ -5289,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; } @@ -5298,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; @@ -5315,23 +6313,22 @@ 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) { - /* GOTOFF relocation are nonsense in 64bit mode. */ if (fixp->fx_r_type == BFD_RELOC_32_PCREL) { - if (flag_code != CODE_64BIT) + if (!object_64bit) abort (); fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL; } else { - if (flag_code == CODE_64BIT) - abort (); - fixp->fx_r_type = BFD_RELOC_386_GOTOFF; + if (!object_64bit) + fixp->fx_r_type = BFD_RELOC_386_GOTOFF; + else + fixp->fx_r_type = BFD_RELOC_X86_64_GOTOFF64; } fixp->fx_subsy = 0; } @@ -5362,11 +6359,24 @@ tc_gen_reloc (section, fixp) case BFD_RELOC_386_TLS_GOTIE: case BFD_RELOC_386_TLS_LE_32: case BFD_RELOC_386_TLS_LE: + case BFD_RELOC_386_TLS_GOTDESC: + case BFD_RELOC_386_TLS_DESC_CALL: case BFD_RELOC_X86_64_TLSGD: case BFD_RELOC_X86_64_TLSLD: case BFD_RELOC_X86_64_DTPOFF32: + case BFD_RELOC_X86_64_DTPOFF64: case BFD_RELOC_X86_64_GOTTPOFF: case BFD_RELOC_X86_64_TPOFF32: + case BFD_RELOC_X86_64_TPOFF64: + case BFD_RELOC_X86_64_GOTOFF64: + case BFD_RELOC_X86_64_GOTPC32: + case BFD_RELOC_X86_64_GOT64: + case BFD_RELOC_X86_64_GOTPCREL64: + case BFD_RELOC_X86_64_GOTPC64: + case BFD_RELOC_X86_64_GOTPLT64: + case BFD_RELOC_X86_64_PLTOFF64: + case BFD_RELOC_X86_64_GOTPC32_TLSDESC: + case BFD_RELOC_X86_64_TLSDESC_CALL: case BFD_RELOC_RVA: case BFD_RELOC_VTABLE_ENTRY: case BFD_RELOC_VTABLE_INHERIT: @@ -5396,6 +6406,9 @@ tc_gen_reloc (section, fixp) case 1: code = BFD_RELOC_8_PCREL; break; case 2: code = BFD_RELOC_16_PCREL; break; case 4: code = BFD_RELOC_32_PCREL; break; +#ifdef BFD64 + case 8: code = BFD_RELOC_64_PCREL; break; +#endif } } else @@ -5419,14 +6432,22 @@ tc_gen_reloc (section, fixp) break; } - if (code == BFD_RELOC_32 + if ((code == BFD_RELOC_32 + || code == BFD_RELOC_32_PCREL + || code == BFD_RELOC_X86_64_32S) && GOT_symbol && fixp->fx_addsy == GOT_symbol) { - /* We don't support GOTPC on 64bit targets. */ - if (flag_code == CODE_64BIT) - abort (); - code = BFD_RELOC_386_GOTPC; + if (!object_64bit) + code = BFD_RELOC_386_GOTPC; + else + code = BFD_RELOC_X86_64_GOTPC32; + } + if ((code == BFD_RELOC_64 || code == BFD_RELOC_64_PCREL) + && GOT_symbol + && fixp->fx_addsy == GOT_symbol) + { + code = BFD_RELOC_X86_64_GOTPC64; } rel = (arelent *) xmalloc (sizeof (arelent)); @@ -5458,6 +6479,8 @@ tc_gen_reloc (section, fixp) case BFD_RELOC_X86_64_TLSGD: case BFD_RELOC_X86_64_TLSLD: case BFD_RELOC_X86_64_GOTTPOFF: + case BFD_RELOC_X86_64_GOTPC32_TLSDESC: + case BFD_RELOC_X86_64_TLSDESC_CALL: rel->addend = fixp->fx_offset - fixp->fx_size; break; default: @@ -5639,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. */ @@ -5679,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; @@ -5784,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; @@ -5804,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 (); @@ -5815,7 +6835,7 @@ intel_expr () e04' addOp e05 e04' | Empty */ static int -intel_e04 () +intel_e04 (void) { int nregs = -1; @@ -5844,7 +6864,7 @@ intel_e04 () e05' binOp e06 e05' | Empty */ static int -intel_e05 () +intel_e05 (void) { int nregs = ~NUM_ADDRESS_REGS; @@ -5853,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]; @@ -5879,7 +6901,7 @@ intel_e05 () e06' mulOp e09 e06' | Empty */ static int -intel_e06 () +intel_e06 (void) { int nregs = ~NUM_ADDRESS_REGS; @@ -5888,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]; @@ -5903,7 +6927,7 @@ intel_e06 () else break; - intel_match_token (cur_token.code); + intel_match_token (cur_token.code); if (nregs < 0) nregs = ~nregs; @@ -5925,7 +6949,7 @@ intel_e06 () | : e10 e09' | Empty */ static int -intel_e09 () +intel_e09 (void) { int nregs = ~NUM_ADDRESS_REGS; int in_offset = 0; @@ -6015,7 +7039,7 @@ intel_e09 () suffix = WORD_MNEM_SUFFIX; else if (flag_code == CODE_16BIT && (current_templates->start->opcode_modifier - & (Jump|JumpDword|JumpInterSegment))) + & (Jump | JumpDword))) suffix = LONG_DOUBLE_MNEM_SUFFIX; else if (intel_parser.got_a_float == 1) /* "f..." */ suffix = SHORT_MNEM_SUFFIX; @@ -6067,6 +7091,11 @@ intel_e09 () return 0; } + /* Operands for jump/call using 'ptr' notation denote absolute + addresses. */ + if (current_templates->start->opcode_modifier & (Jump | JumpDword)) + i.types[this_operand] |= JumpAbsolute; + if (current_templates->start->base_opcode == 0x8d /* lea */) ; else if (!i.suffix) @@ -6134,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; @@ -6151,6 +7180,11 @@ intel_bracket_expr () if (!intel_parser.in_offset) { ++intel_parser.in_bracket; + + /* Operands for jump/call inside brackets denote absolute addresses. */ + if (current_templates->start->opcode_modifier & (Jump | JumpDword)) + i.types[this_operand] |= JumpAbsolute; + /* Unfortunately gas always diverged from MASM in a respect that can't be easily fixed without risking to break code sequences likely to be encountered (the testsuite even check for this): MASM doesn't consider @@ -6165,7 +7199,7 @@ intel_bracket_expr () intel_parser.op_modifier &= ~was_offset; } else - strcat (intel_parser.disp, "["); + strcat (intel_parser.disp, "["); /* Add a '+' to the displacement string if necessary. */ if (*intel_parser.disp != '\0' @@ -6190,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; @@ -6205,7 +7240,7 @@ intel_bracket_expr () e10' [ expr ] e10' | Empty */ static int -intel_e10 () +intel_e10 (void) { if (!intel_e11 ()) return 0; @@ -6235,7 +7270,7 @@ intel_e10 () | id | constant */ static int -intel_e11 () +intel_e11 (void) { switch (cur_token.code) { @@ -6253,13 +7288,6 @@ intel_e11 () /* e11 [ expr ] */ case '[': - /* Operands for jump/call inside brackets denote absolute addresses. - XXX This shouldn't be needed anymore (or if it should rather live - in intel_bracket_expr). */ - if (current_templates->start->opcode_modifier - & (Jump|JumpDword|JumpByte|JumpInterSegment)) - i.types[this_operand] |= JumpAbsolute; - return intel_bracket_expr (); /* e11 $ @@ -6287,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]) @@ -6366,7 +7395,7 @@ intel_e11 () /* No scaling. If this is a memory operand, the register is either a base register (first occurrence) or an index register (second occurrence). */ - else if (intel_parser.in_bracket && !(reg->reg_type & (SReg2 | SReg3))) + else if (intel_parser.in_bracket) { if (!i.base_reg) @@ -6382,16 +7411,8 @@ intel_e11 () i.types[this_operand] |= BaseIndex; } - /* Offset modifier. Add the register to the displacement string to be - parsed as an immediate expression after we're done. */ - else if (intel_parser.in_offset) - { - as_warn (_("Using register names in OFFSET expressions is deprecated")); - strcat (intel_parser.disp, reg->reg_name); - } - - /* It's neither base nor index nor offset. */ - else if (!intel_parser.is_mem) + /* It's neither base nor index. */ + else if (!intel_parser.in_offset && !intel_parser.is_mem) { i.types[this_operand] |= reg->reg_type & ~BaseIndex; i.op[this_operand].regs = reg; @@ -6485,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) @@ -6494,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. */ @@ -6551,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) { @@ -6568,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; @@ -6620,19 +7644,15 @@ intel_get_token () new_token.code = T_ID; } - else if ((*intel_parser.op_string == REGISTER_PREFIX || allow_naked_reg) - && ((reg = parse_register (intel_parser.op_string, &end_op)) != NULL)) + else if ((reg = parse_register (intel_parser.op_string, &end_op)) != NULL) { + size_t len = end_op - intel_parser.op_string; + new_token.code = T_REG; new_token.reg = reg; - if (*intel_parser.op_string == REGISTER_PREFIX) - { - new_token.str[0] = REGISTER_PREFIX; - new_token.str[1] = '\0'; - } - - strcat (new_token.str, reg->reg_name); + memcpy (new_token.str, intel_parser.op_string, len); + new_token.str[len] = '\0'; } else if (is_identifier_char (*intel_parser.op_string)) @@ -6757,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) { @@ -6773,25 +7793,48 @@ intel_putback_token () } int -tc_x86_regname_to_dw2regnum (const char *regname) +tc_x86_regname_to_dw2regnum (char *regname) { unsigned int regnum; unsigned int regnames_count; - char *regnames_32[] = + static const char *const regnames_32[] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", - "eip" + "eip", "eflags", NULL, + "st0", "st1", "st2", "st3", + "st4", "st5", "st6", "st7", + NULL, NULL, + "xmm0", "xmm1", "xmm2", "xmm3", + "xmm4", "xmm5", "xmm6", "xmm7", + "mm0", "mm1", "mm2", "mm3", + "mm4", "mm5", "mm6", "mm7", + "fcw", "fsw", "mxcsr", + "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL, + "tr", "ldtr" }; - char *regnames_64[] = + static const char *const regnames_64[] = { - "rax", "rbx", "rcx", "rdx", - "rdi", "rsi", "rbp", "rsp", - "r8", "r9", "r10", "r11", + "rax", "rdx", "rcx", "rbx", + "rsi", "rdi", "rbp", "rsp", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", - "rip" + "rip", + "xmm0", "xmm1", "xmm2", "xmm3", + "xmm4", "xmm5", "xmm6", "xmm7", + "xmm8", "xmm9", "xmm10", "xmm11", + "xmm12", "xmm13", "xmm14", "xmm15", + "st0", "st1", "st2", "st3", + "st4", "st5", "st6", "st7", + "mm0", "mm1", "mm2", "mm3", + "mm4", "mm5", "mm6", "mm7", + "rflags", + "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL, + "fs.base", "gs.base", NULL, NULL, + "tr", "ldtr", + "mxcsr", "fcw", "fsw" }; - char **regnames; + const char *const *regnames; if (flag_code == CODE_64BIT) { @@ -6805,7 +7848,8 @@ tc_x86_regname_to_dw2regnum (const char *regname) } for (regnum = 0; regnum < regnames_count; regnum++) - if (strcmp (regname, regnames[regnum]) == 0) + if (regnames[regnum] != NULL + && strcmp (regname, regnames[regnum]) == 0) return regnum; return -1; @@ -6847,3 +7891,71 @@ tc_pe_dwarf2_emit_offset (symbolS *symbol, unsigned int size) emit_expr (&expr, size); } #endif + +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) +/* For ELF on x86-64, add support for SHF_X86_64_LARGE. */ + +int +x86_64_section_letter (int letter, char **ptr_msg) +{ + if (flag_code == CODE_64BIT) + { + if (letter == 'l') + return SHF_X86_64_LARGE; + + *ptr_msg = _("Bad .section directive: want a,l,w,x,M,S,G,T in string"); + } + else + *ptr_msg = _("Bad .section directive: want a,w,x,M,S,G,T in string"); + return -1; +} + +int +x86_64_section_word (char *str, size_t len) +{ + if (len == 5 && flag_code == CODE_64BIT && CONST_STRNEQ (str, "large")) + return SHF_X86_64_LARGE; + + return -1; +} + +static void +handle_large_common (int small ATTRIBUTE_UNUSED) +{ + if (flag_code != CODE_64BIT) + { + s_comm_internal (0, elf_common_parse); + as_warn (_(".largecomm supported only in 64bit mode, producing .comm")); + } + else + { + static segT lbss_section; + asection *saved_com_section_ptr = elf_com_section_ptr; + asection *saved_bss_section = bss_section; + + if (lbss_section == NULL) + { + flagword applicable; + segT seg = now_seg; + subsegT subseg = now_subseg; + + /* The .lbss section is for local .largecomm symbols. */ + lbss_section = subseg_new (".lbss", 0); + applicable = bfd_applicable_section_flags (stdoutput); + bfd_set_section_flags (stdoutput, lbss_section, + applicable & SEC_ALLOC); + seg_info (lbss_section)->bss = 1; + + subseg_set (seg, subseg); + } + + elf_com_section_ptr = &_bfd_elf_large_com_section; + bss_section = lbss_section; + + s_comm_internal (0, elf_common_parse); + + elf_com_section_ptr = saved_com_section_ptr; + bss_section = saved_bss_section; + } +} +#endif /* OBJ_ELF || OBJ_MAYBE_ELF */