1218822Sdim/* tc-i386.c -- Assemble code for the Intel 80386 278840Sobrien Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 3218822Sdim 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 477311Sobrien Free Software Foundation, Inc. 533965Sjdp 633965Sjdp This file is part of GAS, the GNU Assembler. 733965Sjdp 833965Sjdp GAS is free software; you can redistribute it and/or modify 933965Sjdp it under the terms of the GNU General Public License as published by 1033965Sjdp the Free Software Foundation; either version 2, or (at your option) 1133965Sjdp any later version. 1233965Sjdp 1333965Sjdp GAS is distributed in the hope that it will be useful, 1433965Sjdp but WITHOUT ANY WARRANTY; without even the implied warranty of 1533965Sjdp MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1633965Sjdp GNU General Public License for more details. 1733965Sjdp 1833965Sjdp You should have received a copy of the GNU General Public License 1933965Sjdp along with GAS; see the file COPYING. If not, write to the Free 20218822Sdim Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 21218822Sdim 02110-1301, USA. */ 2233965Sjdp 2377311Sobrien/* Intel 80386 machine specific gas. 2477311Sobrien Written by Eliot Dresselhaus (eliot@mgm.mit.edu). 2577311Sobrien x86_64 support by Jan Hubicka (jh@suse.cz) 26130570Sobrien VIA PadLock support by Michal Ludvig (mludvig@suse.cz) 2777311Sobrien Bugs & suggestions are completely welcome. This is free software. 2877311Sobrien Please help us make it better. */ 2977311Sobrien 3033965Sjdp#include "as.h" 3189867Sobrien#include "safe-ctype.h" 3233965Sjdp#include "subsegs.h" 3377311Sobrien#include "dwarf2dbg.h" 34130570Sobrien#include "dw2gencfi.h" 35218822Sdim#include "elf/x86-64.h" 3633965Sjdp 3760519Sobrien#ifndef REGISTER_WARNINGS 3860519Sobrien#define REGISTER_WARNINGS 1 3933965Sjdp#endif 4033965Sjdp 4160519Sobrien#ifndef INFER_ADDR_PREFIX 4260519Sobrien#define INFER_ADDR_PREFIX 1 4360519Sobrien#endif 4460519Sobrien 4560519Sobrien#ifndef SCALE1_WHEN_NO_INDEX 4660519Sobrien/* Specifying a scale factor besides 1 when there is no index is 4760519Sobrien futile. eg. `mov (%ebx,2),%al' does exactly the same as 4860519Sobrien `mov (%ebx),%al'. To slavishly follow what the programmer 4960519Sobrien specified, set SCALE1_WHEN_NO_INDEX to 0. */ 5060519Sobrien#define SCALE1_WHEN_NO_INDEX 1 5160519Sobrien#endif 5260519Sobrien 5394546Sobrien#ifndef DEFAULT_ARCH 5494546Sobrien#define DEFAULT_ARCH "i386" 5591054Sobrien#endif 5660519Sobrien 5794546Sobrien#ifndef INLINE 5894546Sobrien#if __GNUC__ >= 2 5994546Sobrien#define INLINE __inline__ 6094546Sobrien#else 6194546Sobrien#define INLINE 6294546Sobrien#endif 6394546Sobrien#endif 6494546Sobrien 65218822Sdimstatic void set_code_flag (int); 66218822Sdimstatic void set_16bit_gcc_code_flag (int); 67218822Sdimstatic void set_intel_syntax (int); 68218822Sdimstatic void set_cpu_arch (int); 69218822Sdim#ifdef TE_PE 70218822Sdimstatic void pe_directive_secrel (int); 71218822Sdim#endif 72218822Sdimstatic void signed_cons (int); 73218822Sdimstatic char *output_invalid (int c); 74218822Sdimstatic int i386_operand (char *); 75218822Sdimstatic int i386_intel_operand (char *, int); 76218822Sdimstatic const reg_entry *parse_register (char *, char **); 77218822Sdimstatic char *parse_insn (char *, char *); 78218822Sdimstatic char *parse_operands (char *, const char *); 79218822Sdimstatic void swap_operands (void); 80218822Sdimstatic void swap_2_operands (int, int); 81218822Sdimstatic void optimize_imm (void); 82218822Sdimstatic void optimize_disp (void); 83218822Sdimstatic int match_template (void); 84218822Sdimstatic int check_string (void); 85218822Sdimstatic int process_suffix (void); 86218822Sdimstatic int check_byte_reg (void); 87218822Sdimstatic int check_long_reg (void); 88218822Sdimstatic int check_qword_reg (void); 89218822Sdimstatic int check_word_reg (void); 90218822Sdimstatic int finalize_imm (void); 91218822Sdimstatic int process_operands (void); 92218822Sdimstatic const seg_entry *build_modrm_byte (void); 93218822Sdimstatic void output_insn (void); 94218822Sdimstatic void output_imm (fragS *, offsetT); 95218822Sdimstatic void output_disp (fragS *, offsetT); 9694546Sobrien#ifndef I386COFF 97218822Sdimstatic void s_bss (int); 9833965Sjdp#endif 99218822Sdim#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) 100218822Sdimstatic void handle_large_common (int small ATTRIBUTE_UNUSED); 101218822Sdim#endif 10233965Sjdp 10389867Sobrienstatic const char *default_arch = DEFAULT_ARCH; 10477311Sobrien 10533965Sjdp/* 'md_assemble ()' gathers together information and puts it into a 10677311Sobrien i386_insn. */ 10733965Sjdp 10860519Sobrienunion i386_op 10960519Sobrien { 11060519Sobrien expressionS *disps; 11160519Sobrien expressionS *imms; 11260519Sobrien const reg_entry *regs; 11360519Sobrien }; 11460519Sobrien 11533965Sjdpstruct _i386_insn 11633965Sjdp { 11777311Sobrien /* TM holds the template for the insn were currently assembling. */ 11833965Sjdp template tm; 11960519Sobrien 12060519Sobrien /* SUFFIX holds the instruction mnemonic suffix if given. 12160519Sobrien (e.g. 'l' for 'movl') */ 12233965Sjdp char suffix; 12333965Sjdp 12477311Sobrien /* OPERANDS gives the number of given operands. */ 12533965Sjdp unsigned int operands; 12633965Sjdp 12733965Sjdp /* REG_OPERANDS, DISP_OPERANDS, MEM_OPERANDS, IMM_OPERANDS give the number 12833965Sjdp of given register, displacement, memory operands and immediate 12977311Sobrien operands. */ 13033965Sjdp unsigned int reg_operands, disp_operands, mem_operands, imm_operands; 13133965Sjdp 13233965Sjdp /* TYPES [i] is the type (see above #defines) which tells us how to 13360519Sobrien use OP[i] for the corresponding operand. */ 13433965Sjdp unsigned int types[MAX_OPERANDS]; 13533965Sjdp 13660519Sobrien /* Displacement expression, immediate expression, or register for each 13760519Sobrien operand. */ 13860519Sobrien union i386_op op[MAX_OPERANDS]; 13933965Sjdp 14077311Sobrien /* Flags for operands. */ 14177311Sobrien unsigned int flags[MAX_OPERANDS]; 14277311Sobrien#define Operand_PCrel 1 14377311Sobrien 14433965Sjdp /* Relocation type for operand */ 145130570Sobrien enum bfd_reloc_code_real reloc[MAX_OPERANDS]; 14633965Sjdp 14733965Sjdp /* BASE_REG, INDEX_REG, and LOG2_SCALE_FACTOR are used to encode 14833965Sjdp the base index byte below. */ 14960519Sobrien const reg_entry *base_reg; 15060519Sobrien const reg_entry *index_reg; 15133965Sjdp unsigned int log2_scale_factor; 15233965Sjdp 15360519Sobrien /* SEG gives the seg_entries of this insn. They are zero unless 15477311Sobrien explicit segment overrides are given. */ 15577311Sobrien const seg_entry *seg[2]; 15633965Sjdp 15733965Sjdp /* PREFIX holds all the given prefix opcodes (usually null). 15860519Sobrien PREFIXES is the number of prefix opcodes. */ 15960519Sobrien unsigned int prefixes; 16033965Sjdp unsigned char prefix[MAX_PREFIXES]; 16133965Sjdp 16260519Sobrien /* RM and SIB are the modrm byte and the sib byte where the 16360519Sobrien addressing modes of this insn are encoded. */ 16433965Sjdp 16533965Sjdp modrm_byte rm; 16677311Sobrien rex_byte rex; 16760519Sobrien sib_byte sib; 16833965Sjdp }; 16933965Sjdp 17033965Sjdptypedef struct _i386_insn i386_insn; 17133965Sjdp 17260519Sobrien/* List of chars besides those in app.c:symbol_chars that can start an 17360519Sobrien operand. Used to prevent the scrubber eating vital white-space. */ 174218822Sdimconst char extra_symbol_chars[] = "*%-([" 17560519Sobrien#ifdef LEX_AT 176218822Sdim "@" 17760519Sobrien#endif 178218822Sdim#ifdef LEX_QM 179218822Sdim "?" 180218822Sdim#endif 181218822Sdim ; 18260519Sobrien 18394546Sobrien#if (defined (TE_I386AIX) \ 18494546Sobrien || ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) \ 185218822Sdim && !defined (TE_GNU) \ 18694546Sobrien && !defined (TE_LINUX) \ 187218822Sdim && !defined (TE_NETWARE) \ 18894546Sobrien && !defined (TE_FreeBSD) \ 18994546Sobrien && !defined (TE_NetBSD))) 19033965Sjdp/* This array holds the chars that always start a comment. If the 191218822Sdim pre-processor is disabled, these aren't very useful. The option 192218822Sdim --divide will remove '/' from this list. */ 193218822Sdimconst char *i386_comment_chars = "#/"; 194218822Sdim#define SVR4_COMMENT_CHARS 1 19560519Sobrien#define PREFIX_SEPARATOR '\\' 19633965Sjdp 197218822Sdim#else 198218822Sdimconst char *i386_comment_chars = "#"; 199218822Sdim#define PREFIX_SEPARATOR '/' 200218822Sdim#endif 201218822Sdim 20233965Sjdp/* This array holds the chars that only start a comment at the beginning of 20333965Sjdp a line. If the line seems to have the form '# 123 filename' 20477311Sobrien .line and .file directives will appear in the pre-processed output. 20577311Sobrien Note that input_file.c hand checks for '#' at the beginning of the 20633965Sjdp first line of the input file. This is because the compiler outputs 20777311Sobrien #NO_APP at the beginning of its output. 20877311Sobrien Also note that comments started like this one will always work if 20933965Sjdp '/' isn't otherwise defined. */ 210218822Sdimconst char line_comment_chars[] = "#/"; 21194546Sobrien 21277311Sobrienconst char line_separator_chars[] = ";"; 21333965Sjdp 21477311Sobrien/* Chars that can be used to separate mant from exp in floating point 21577311Sobrien nums. */ 21633965Sjdpconst char EXP_CHARS[] = "eE"; 21733965Sjdp 21877311Sobrien/* Chars that mean this number is a floating point constant 21977311Sobrien As in 0f12.456 22077311Sobrien or 0d1.2345e12. */ 22133965Sjdpconst char FLT_CHARS[] = "fFdDxX"; 22233965Sjdp 22377311Sobrien/* Tables for lexical analysis. */ 22460519Sobrienstatic char mnemonic_chars[256]; 22533965Sjdpstatic char register_chars[256]; 22633965Sjdpstatic char operand_chars[256]; 22733965Sjdpstatic char identifier_chars[256]; 22833965Sjdpstatic char digit_chars[256]; 22933965Sjdp 23077311Sobrien/* Lexical macros. */ 23160519Sobrien#define is_mnemonic_char(x) (mnemonic_chars[(unsigned char) x]) 23233965Sjdp#define is_operand_char(x) (operand_chars[(unsigned char) x]) 23333965Sjdp#define is_register_char(x) (register_chars[(unsigned char) x]) 23460519Sobrien#define is_space_char(x) ((x) == ' ') 23533965Sjdp#define is_identifier_char(x) (identifier_chars[(unsigned char) x]) 23633965Sjdp#define is_digit_char(x) (digit_chars[(unsigned char) x]) 23733965Sjdp 238130570Sobrien/* All non-digit non-letter characters that may occur in an operand. */ 23933965Sjdpstatic char operand_special_chars[] = "%$-+(,)*._~/<>|&^!:[@]"; 24033965Sjdp 24133965Sjdp/* md_assemble() always leaves the strings it's passed unaltered. To 24233965Sjdp effect this we maintain a stack of saved characters that we've smashed 24333965Sjdp with '\0's (indicating end of strings for various sub-fields of the 24477311Sobrien assembler instruction). */ 24533965Sjdpstatic char save_stack[32]; 24677311Sobrienstatic char *save_stack_p; 24760519Sobrien#define END_STRING_AND_SAVE(s) \ 24860519Sobrien do { *save_stack_p++ = *(s); *(s) = '\0'; } while (0) 24960519Sobrien#define RESTORE_END_STRING(s) \ 25060519Sobrien do { *(s) = *--save_stack_p; } while (0) 25133965Sjdp 25277311Sobrien/* The instruction we're assembling. */ 25333965Sjdpstatic i386_insn i; 25433965Sjdp 25560519Sobrien/* Possible templates for current insn. */ 25660519Sobrienstatic const templates *current_templates; 25760519Sobrien 258218822Sdim/* Per instruction expressionS buffers: max displacements & immediates. */ 259218822Sdimstatic expressionS disp_expressions[MAX_MEMORY_OPERANDS]; 260218822Sdimstatic expressionS im_expressions[MAX_IMMEDIATE_OPERANDS]; 26133965Sjdp 26277311Sobrien/* Current operand we are working on. */ 26377311Sobrienstatic int this_operand; 26433965Sjdp 26577311Sobrien/* We support four different modes. FLAG_CODE variable is used to distinguish 26677311Sobrien these. */ 26733965Sjdp 26877311Sobrienenum flag_code { 26977311Sobrien CODE_32BIT, 27077311Sobrien CODE_16BIT, 27177311Sobrien CODE_64BIT }; 27278840Sobrien#define NUM_FLAG_CODE ((int) CODE_64BIT + 1) 27333965Sjdp 27477311Sobrienstatic enum flag_code flag_code; 275218822Sdimstatic unsigned int object_64bit; 27677311Sobrienstatic int use_rela_relocations = 0; 27760519Sobrien 27877311Sobrien/* The names used to print error messages. */ 27977311Sobrienstatic const char *flag_code_names[] = 28077311Sobrien { 28177311Sobrien "32", 28277311Sobrien "16", 28377311Sobrien "64" 28477311Sobrien }; 28560519Sobrien 28677311Sobrien/* 1 for intel syntax, 28777311Sobrien 0 if att syntax. */ 28877311Sobrienstatic int intel_syntax = 0; 28960519Sobrien 29077311Sobrien/* 1 if register prefix % not required. */ 29177311Sobrienstatic int allow_naked_reg = 0; 29277311Sobrien 293218822Sdim/* Register prefix used for error message. */ 294218822Sdimstatic const char *register_prefix = "%"; 295218822Sdim 29677311Sobrien/* Used in 16 bit gcc mode to add an l suffix to call, ret, enter, 29777311Sobrien leave, push, and pop instructions so that gcc has the same stack 29877311Sobrien frame as in 32 bit mode. */ 29977311Sobrienstatic char stackop_size = '\0'; 30077311Sobrien 301130570Sobrien/* Non-zero to optimize code alignment. */ 302130570Sobrienint optimize_align_code = 1; 303130570Sobrien 30477311Sobrien/* Non-zero to quieten some warnings. */ 30577311Sobrienstatic int quiet_warnings = 0; 30677311Sobrien 30777311Sobrien/* CPU name. */ 30877311Sobrienstatic const char *cpu_arch_name = NULL; 309218822Sdimstatic const char *cpu_sub_arch_name = NULL; 31077311Sobrien 31177311Sobrien/* CPU feature flags. */ 31294546Sobrienstatic unsigned int cpu_arch_flags = CpuUnknownFlags | CpuNo64; 31377311Sobrien 314218822Sdim/* If we have selected a cpu we are generating instructions for. */ 315218822Sdimstatic int cpu_arch_tune_set = 0; 316218822Sdim 317218822Sdim/* Cpu we are generating instructions for. */ 318218822Sdimstatic enum processor_type cpu_arch_tune = PROCESSOR_UNKNOWN; 319218822Sdim 320218822Sdim/* CPU feature flags of cpu we are generating instructions for. */ 321218822Sdimstatic unsigned int cpu_arch_tune_flags = 0; 322218822Sdim 323218822Sdim/* CPU instruction set architecture used. */ 324218822Sdimstatic enum processor_type cpu_arch_isa = PROCESSOR_UNKNOWN; 325218822Sdim 326218822Sdim/* CPU feature flags of instruction set architecture used. */ 327218822Sdimstatic unsigned int cpu_arch_isa_flags = 0; 328218822Sdim 32978840Sobrien/* If set, conditional jumps are not automatically promoted to handle 33078840Sobrien larger than a byte offset. */ 33178840Sobrienstatic unsigned int no_cond_jump_promotion = 0; 33278840Sobrien 33394546Sobrien/* Pre-defined "_GLOBAL_OFFSET_TABLE_". */ 334218822Sdimstatic symbolS *GOT_symbol; 33594546Sobrien 336130570Sobrien/* The dwarf2 return column, adjusted for 32 or 64 bit. */ 337130570Sobrienunsigned int x86_dwarf2_return_column; 338130570Sobrien 339130570Sobrien/* The dwarf2 data alignment, adjusted for 32 or 64 bit. */ 340130570Sobrienint x86_cie_data_alignment; 341130570Sobrien 34233965Sjdp/* Interface to relax_segment. 34378840Sobrien There are 3 major relax states for 386 jump insns because the 34478840Sobrien different types of jumps add different sizes to frags when we're 34578840Sobrien figuring out what sort of jump to choose to reach a given label. */ 34633965Sjdp 34777311Sobrien/* Types. */ 34878840Sobrien#define UNCOND_JUMP 0 34977311Sobrien#define COND_JUMP 1 35078840Sobrien#define COND_JUMP86 2 35178840Sobrien 35277311Sobrien/* Sizes. */ 35360519Sobrien#define CODE16 1 35460519Sobrien#define SMALL 0 35594546Sobrien#define SMALL16 (SMALL | CODE16) 35660519Sobrien#define BIG 2 35794546Sobrien#define BIG16 (BIG | CODE16) 35833965Sjdp 35933965Sjdp#ifndef INLINE 36033965Sjdp#ifdef __GNUC__ 36133965Sjdp#define INLINE __inline__ 36233965Sjdp#else 36333965Sjdp#define INLINE 36433965Sjdp#endif 36533965Sjdp#endif 36633965Sjdp 36778840Sobrien#define ENCODE_RELAX_STATE(type, size) \ 36878840Sobrien ((relax_substateT) (((type) << 2) | (size))) 36978840Sobrien#define TYPE_FROM_RELAX_STATE(s) \ 37078840Sobrien ((s) >> 2) 37178840Sobrien#define DISP_SIZE_FROM_RELAX_STATE(s) \ 37278840Sobrien ((((s) & 3) == BIG ? 4 : (((s) & 3) == BIG16 ? 2 : 1))) 37333965Sjdp 37460519Sobrien/* This table is used by relax_frag to promote short jumps to long 37560519Sobrien ones where necessary. SMALL (short) jumps may be promoted to BIG 37660519Sobrien (32 bit long) ones, and SMALL16 jumps to BIG16 (16 bit long). We 37760519Sobrien don't allow a short jump in a 32 bit code segment to be promoted to 37860519Sobrien a 16 bit offset jump because it's slower (requires data size 37960519Sobrien prefix), and doesn't work, unless the destination is in the bottom 38060519Sobrien 64k of the code segment (The top 16 bits of eip are zeroed). */ 38160519Sobrien 38233965Sjdpconst relax_typeS md_relax_table[] = 38333965Sjdp{ 38460519Sobrien /* The fields are: 38560519Sobrien 1) most positive reach of this state, 38660519Sobrien 2) most negative reach of this state, 38778840Sobrien 3) how many bytes this mode will have in the variable part of the frag 38877311Sobrien 4) which index into the table to try if we can't fit into this one. */ 38933965Sjdp 39078840Sobrien /* UNCOND_JUMP states. */ 39178840Sobrien {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (UNCOND_JUMP, BIG)}, 39278840Sobrien {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (UNCOND_JUMP, BIG16)}, 39378840Sobrien /* dword jmp adds 4 bytes to frag: 39478840Sobrien 0 extra opcode bytes, 4 displacement bytes. */ 39533965Sjdp {0, 0, 4, 0}, 39678840Sobrien /* word jmp adds 2 byte2 to frag: 39778840Sobrien 0 extra opcode bytes, 2 displacement bytes. */ 39860519Sobrien {0, 0, 2, 0}, 39933965Sjdp 40078840Sobrien /* COND_JUMP states. */ 40178840Sobrien {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP, BIG)}, 40278840Sobrien {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP, BIG16)}, 40378840Sobrien /* dword conditionals adds 5 bytes to frag: 40478840Sobrien 1 extra opcode byte, 4 displacement bytes. */ 40578840Sobrien {0, 0, 5, 0}, 40678840Sobrien /* word conditionals add 3 bytes to frag: 40778840Sobrien 1 extra opcode byte, 2 displacement bytes. */ 40833965Sjdp {0, 0, 3, 0}, 40933965Sjdp 41078840Sobrien /* COND_JUMP86 states. */ 41178840Sobrien {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP86, BIG)}, 41278840Sobrien {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP86, BIG16)}, 41378840Sobrien /* dword conditionals adds 5 bytes to frag: 41478840Sobrien 1 extra opcode byte, 4 displacement bytes. */ 41578840Sobrien {0, 0, 5, 0}, 41678840Sobrien /* word conditionals add 4 bytes to frag: 41778840Sobrien 1 displacement byte and a 3 byte long branch insn. */ 41878840Sobrien {0, 0, 4, 0} 41933965Sjdp}; 42033965Sjdp 421218822Sdimstatic const arch_entry cpu_arch[] = 422218822Sdim{ 423218822Sdim {"generic32", PROCESSOR_GENERIC32, 424218822Sdim Cpu186|Cpu286|Cpu386}, 425218822Sdim {"generic64", PROCESSOR_GENERIC64, 426218822Sdim Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX 427218822Sdim |CpuMMX2|CpuSSE|CpuSSE2}, 428218822Sdim {"i8086", PROCESSOR_UNKNOWN, 429218822Sdim 0}, 430218822Sdim {"i186", PROCESSOR_UNKNOWN, 431218822Sdim Cpu186}, 432218822Sdim {"i286", PROCESSOR_UNKNOWN, 433218822Sdim Cpu186|Cpu286}, 434218822Sdim {"i386", PROCESSOR_GENERIC32, 435218822Sdim Cpu186|Cpu286|Cpu386}, 436218822Sdim {"i486", PROCESSOR_I486, 437218822Sdim Cpu186|Cpu286|Cpu386|Cpu486}, 438218822Sdim {"i586", PROCESSOR_PENTIUM, 439218822Sdim Cpu186|Cpu286|Cpu386|Cpu486|Cpu586}, 440218822Sdim {"i686", PROCESSOR_PENTIUMPRO, 441218822Sdim Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686}, 442218822Sdim {"pentium", PROCESSOR_PENTIUM, 443218822Sdim Cpu186|Cpu286|Cpu386|Cpu486|Cpu586}, 444218822Sdim {"pentiumpro",PROCESSOR_PENTIUMPRO, 445218822Sdim Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686}, 446218822Sdim {"pentiumii", PROCESSOR_PENTIUMPRO, 447218822Sdim Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX}, 448218822Sdim {"pentiumiii",PROCESSOR_PENTIUMPRO, 449218822Sdim Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX|CpuMMX2|CpuSSE}, 450218822Sdim {"pentium4", PROCESSOR_PENTIUM4, 451218822Sdim Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX 452218822Sdim |CpuMMX2|CpuSSE|CpuSSE2}, 453218822Sdim {"prescott", PROCESSOR_NOCONA, 454218822Sdim Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX 455218822Sdim |CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3}, 456218822Sdim {"nocona", PROCESSOR_NOCONA, 457218822Sdim Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX 458218822Sdim |CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3}, 459218822Sdim {"yonah", PROCESSOR_CORE, 460218822Sdim Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX 461218822Sdim |CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3}, 462218822Sdim {"core", PROCESSOR_CORE, 463218822Sdim Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX 464218822Sdim |CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3}, 465218822Sdim {"merom", PROCESSOR_CORE2, 466218822Sdim Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX 467218822Sdim |CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3}, 468218822Sdim {"core2", PROCESSOR_CORE2, 469218822Sdim Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX 470218822Sdim |CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3}, 471218822Sdim {"k6", PROCESSOR_K6, 472218822Sdim Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuK6|CpuMMX}, 473218822Sdim {"k6_2", PROCESSOR_K6, 474218822Sdim Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuK6|CpuMMX|Cpu3dnow}, 475218822Sdim {"athlon", PROCESSOR_ATHLON, 476218822Sdim Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6 477218822Sdim |CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA}, 478218822Sdim {"sledgehammer", PROCESSOR_K8, 479218822Sdim Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6 480218822Sdim |CpuSledgehammer|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2}, 481218822Sdim {"opteron", PROCESSOR_K8, 482218822Sdim Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6 483218822Sdim |CpuSledgehammer|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2}, 484218822Sdim {"k8", PROCESSOR_K8, 485218822Sdim Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6 486218822Sdim |CpuSledgehammer|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2}, 487218822Sdim {"amdfam10", PROCESSOR_AMDFAM10, 488218822Sdim Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuSledgehammer 489218822Sdim |CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2|CpuSSE3|CpuSSE4a 490218822Sdim |CpuABM}, 491218822Sdim {".mmx", PROCESSOR_UNKNOWN, 492218822Sdim CpuMMX}, 493218822Sdim {".sse", PROCESSOR_UNKNOWN, 494218822Sdim CpuMMX|CpuMMX2|CpuSSE}, 495218822Sdim {".sse2", PROCESSOR_UNKNOWN, 496218822Sdim CpuMMX|CpuMMX2|CpuSSE|CpuSSE2}, 497218822Sdim {".sse3", PROCESSOR_UNKNOWN, 498218822Sdim CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3}, 499218822Sdim {".ssse3", PROCESSOR_UNKNOWN, 500218822Sdim CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3}, 501218822Sdim {".sse4.1", PROCESSOR_UNKNOWN, 502218822Sdim CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuSSE4_1}, 503218822Sdim {".sse4.2", PROCESSOR_UNKNOWN, 504218822Sdim CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuSSE4}, 505218822Sdim {".sse4", PROCESSOR_UNKNOWN, 506218822Sdim CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuSSE4}, 507218822Sdim {".3dnow", PROCESSOR_UNKNOWN, 508218822Sdim CpuMMX|Cpu3dnow}, 509218822Sdim {".3dnowa", PROCESSOR_UNKNOWN, 510218822Sdim CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA}, 511218822Sdim {".padlock", PROCESSOR_UNKNOWN, 512218822Sdim CpuPadLock}, 513218822Sdim {".pacifica", PROCESSOR_UNKNOWN, 514218822Sdim CpuSVME}, 515218822Sdim {".svme", PROCESSOR_UNKNOWN, 516218822Sdim CpuSVME}, 517218822Sdim {".sse4a", PROCESSOR_UNKNOWN, 518218822Sdim CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSE4a}, 519218822Sdim {".abm", PROCESSOR_UNKNOWN, 520238123Sjhb CpuABM}, 521238123Sjhb {".xsave", PROCESSOR_UNKNOWN, 522238123Sjhb CpuXSAVE} 52377311Sobrien}; 52433965Sjdp 52594546Sobrienconst pseudo_typeS md_pseudo_table[] = 52694546Sobrien{ 52794546Sobrien#if !defined(OBJ_AOUT) && !defined(USE_ALIGN_PTWO) 52894546Sobrien {"align", s_align_bytes, 0}, 52994546Sobrien#else 53094546Sobrien {"align", s_align_ptwo, 0}, 53194546Sobrien#endif 53294546Sobrien {"arch", set_cpu_arch, 0}, 53394546Sobrien#ifndef I386COFF 53494546Sobrien {"bss", s_bss, 0}, 53594546Sobrien#endif 53694546Sobrien {"ffloat", float_cons, 'f'}, 53794546Sobrien {"dfloat", float_cons, 'd'}, 53894546Sobrien {"tfloat", float_cons, 'x'}, 53994546Sobrien {"value", cons, 2}, 540218822Sdim {"slong", signed_cons, 4}, 54194546Sobrien {"noopt", s_ignore, 0}, 54294546Sobrien {"optim", s_ignore, 0}, 54394546Sobrien {"code16gcc", set_16bit_gcc_code_flag, CODE_16BIT}, 54494546Sobrien {"code16", set_code_flag, CODE_16BIT}, 54594546Sobrien {"code32", set_code_flag, CODE_32BIT}, 54694546Sobrien {"code64", set_code_flag, CODE_64BIT}, 54794546Sobrien {"intel_syntax", set_intel_syntax, 1}, 54894546Sobrien {"att_syntax", set_intel_syntax, 0}, 549218822Sdim#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) 550218822Sdim {"largecomm", handle_large_common, 0}, 551218822Sdim#else 552218822Sdim {"file", (void (*) (int)) dwarf2_directive_file, 0}, 55394546Sobrien {"loc", dwarf2_directive_loc, 0}, 554218822Sdim {"loc_mark_labels", dwarf2_directive_loc_mark_labels, 0}, 555218822Sdim#endif 556218822Sdim#ifdef TE_PE 557218822Sdim {"secrel32", pe_directive_secrel, 0}, 558218822Sdim#endif 55994546Sobrien {0, 0, 0} 56094546Sobrien}; 56194546Sobrien 56294546Sobrien/* For interface with expression (). */ 56394546Sobrienextern char *input_line_pointer; 56494546Sobrien 56594546Sobrien/* Hash table for instruction mnemonic lookup. */ 56694546Sobrienstatic struct hash_control *op_hash; 56794546Sobrien 56894546Sobrien/* Hash table for register lookup. */ 56994546Sobrienstatic struct hash_control *reg_hash; 57094546Sobrien 57133965Sjdpvoid 572218822Sdimi386_align_code (fragS *fragP, int count) 57333965Sjdp{ 57477311Sobrien /* Various efficient no-op patterns for aligning code labels. 57577311Sobrien Note: Don't try to assemble the instructions in the comments. 57677311Sobrien 0L and 0w are not legal. */ 57733965Sjdp static const char f32_1[] = 57833965Sjdp {0x90}; /* nop */ 57933965Sjdp static const char f32_2[] = 580218822Sdim {0x66,0x90}; /* xchg %ax,%ax */ 58133965Sjdp static const char f32_3[] = 58233965Sjdp {0x8d,0x76,0x00}; /* leal 0(%esi),%esi */ 58333965Sjdp static const char f32_4[] = 58433965Sjdp {0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */ 58533965Sjdp static const char f32_5[] = 58633965Sjdp {0x90, /* nop */ 58733965Sjdp 0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */ 58833965Sjdp static const char f32_6[] = 58933965Sjdp {0x8d,0xb6,0x00,0x00,0x00,0x00}; /* leal 0L(%esi),%esi */ 59033965Sjdp static const char f32_7[] = 59133965Sjdp {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */ 59233965Sjdp static const char f32_8[] = 59333965Sjdp {0x90, /* nop */ 59433965Sjdp 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */ 59533965Sjdp static const char f32_9[] = 59633965Sjdp {0x89,0xf6, /* movl %esi,%esi */ 59733965Sjdp 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ 59833965Sjdp static const char f32_10[] = 59933965Sjdp {0x8d,0x76,0x00, /* leal 0(%esi),%esi */ 60033965Sjdp 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ 60133965Sjdp static const char f32_11[] = 60233965Sjdp {0x8d,0x74,0x26,0x00, /* leal 0(%esi,1),%esi */ 60333965Sjdp 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ 60433965Sjdp static const char f32_12[] = 60533965Sjdp {0x8d,0xb6,0x00,0x00,0x00,0x00, /* leal 0L(%esi),%esi */ 60633965Sjdp 0x8d,0xbf,0x00,0x00,0x00,0x00}; /* leal 0L(%edi),%edi */ 60733965Sjdp static const char f32_13[] = 60833965Sjdp {0x8d,0xb6,0x00,0x00,0x00,0x00, /* leal 0L(%esi),%esi */ 60933965Sjdp 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ 61033965Sjdp static const char f32_14[] = 61133965Sjdp {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00, /* leal 0L(%esi,1),%esi */ 61233965Sjdp 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ 61333965Sjdp static const char f32_15[] = 61433965Sjdp {0xeb,0x0d,0x90,0x90,0x90,0x90,0x90, /* jmp .+15; lotsa nops */ 61533965Sjdp 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90}; 61660519Sobrien static const char f16_3[] = 61760519Sobrien {0x8d,0x74,0x00}; /* lea 0(%esi),%esi */ 61833965Sjdp static const char f16_4[] = 61938891Sjdp {0x8d,0xb4,0x00,0x00}; /* lea 0w(%si),%si */ 62033965Sjdp static const char f16_5[] = 62133965Sjdp {0x90, /* nop */ 62238891Sjdp 0x8d,0xb4,0x00,0x00}; /* lea 0w(%si),%si */ 62333965Sjdp static const char f16_6[] = 62433965Sjdp {0x89,0xf6, /* mov %si,%si */ 62533965Sjdp 0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */ 62633965Sjdp static const char f16_7[] = 62738891Sjdp {0x8d,0x74,0x00, /* lea 0(%si),%si */ 62833965Sjdp 0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */ 62933965Sjdp static const char f16_8[] = 63038891Sjdp {0x8d,0xb4,0x00,0x00, /* lea 0w(%si),%si */ 63133965Sjdp 0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */ 63233965Sjdp static const char *const f32_patt[] = { 63333965Sjdp f32_1, f32_2, f32_3, f32_4, f32_5, f32_6, f32_7, f32_8, 63433965Sjdp f32_9, f32_10, f32_11, f32_12, f32_13, f32_14, f32_15 63533965Sjdp }; 63633965Sjdp static const char *const f16_patt[] = { 63760519Sobrien f32_1, f32_2, f16_3, f16_4, f16_5, f16_6, f16_7, f16_8, 63833965Sjdp f32_15, f32_15, f32_15, f32_15, f32_15, f32_15, f32_15 63933965Sjdp }; 640218822Sdim /* nopl (%[re]ax) */ 641218822Sdim static const char alt_3[] = 642218822Sdim {0x0f,0x1f,0x00}; 643218822Sdim /* nopl 0(%[re]ax) */ 644218822Sdim static const char alt_4[] = 645218822Sdim {0x0f,0x1f,0x40,0x00}; 646218822Sdim /* nopl 0(%[re]ax,%[re]ax,1) */ 647218822Sdim static const char alt_5[] = 648218822Sdim {0x0f,0x1f,0x44,0x00,0x00}; 649218822Sdim /* nopw 0(%[re]ax,%[re]ax,1) */ 650218822Sdim static const char alt_6[] = 651218822Sdim {0x66,0x0f,0x1f,0x44,0x00,0x00}; 652218822Sdim /* nopl 0L(%[re]ax) */ 653218822Sdim static const char alt_7[] = 654218822Sdim {0x0f,0x1f,0x80,0x00,0x00,0x00,0x00}; 655218822Sdim /* nopl 0L(%[re]ax,%[re]ax,1) */ 656218822Sdim static const char alt_8[] = 657218822Sdim {0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; 658218822Sdim /* nopw 0L(%[re]ax,%[re]ax,1) */ 659218822Sdim static const char alt_9[] = 660218822Sdim {0x66,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; 661218822Sdim /* nopw %cs:0L(%[re]ax,%[re]ax,1) */ 662218822Sdim static const char alt_10[] = 663218822Sdim {0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; 664218822Sdim /* data16 665218822Sdim nopw %cs:0L(%[re]ax,%[re]ax,1) */ 666218822Sdim static const char alt_long_11[] = 667218822Sdim {0x66, 668218822Sdim 0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; 669218822Sdim /* data16 670218822Sdim data16 671218822Sdim nopw %cs:0L(%[re]ax,%[re]ax,1) */ 672218822Sdim static const char alt_long_12[] = 673218822Sdim {0x66, 674218822Sdim 0x66, 675218822Sdim 0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; 676218822Sdim /* data16 677218822Sdim data16 678218822Sdim data16 679218822Sdim nopw %cs:0L(%[re]ax,%[re]ax,1) */ 680218822Sdim static const char alt_long_13[] = 681218822Sdim {0x66, 682218822Sdim 0x66, 683218822Sdim 0x66, 684218822Sdim 0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; 685218822Sdim /* data16 686218822Sdim data16 687218822Sdim data16 688218822Sdim data16 689218822Sdim nopw %cs:0L(%[re]ax,%[re]ax,1) */ 690218822Sdim static const char alt_long_14[] = 691218822Sdim {0x66, 692218822Sdim 0x66, 693218822Sdim 0x66, 694218822Sdim 0x66, 695218822Sdim 0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; 696218822Sdim /* data16 697218822Sdim data16 698218822Sdim data16 699218822Sdim data16 700218822Sdim data16 701218822Sdim nopw %cs:0L(%[re]ax,%[re]ax,1) */ 702218822Sdim static const char alt_long_15[] = 703218822Sdim {0x66, 704218822Sdim 0x66, 705218822Sdim 0x66, 706218822Sdim 0x66, 707218822Sdim 0x66, 708218822Sdim 0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; 709218822Sdim /* nopl 0(%[re]ax,%[re]ax,1) 710218822Sdim nopw 0(%[re]ax,%[re]ax,1) */ 711218822Sdim static const char alt_short_11[] = 712218822Sdim {0x0f,0x1f,0x44,0x00,0x00, 713218822Sdim 0x66,0x0f,0x1f,0x44,0x00,0x00}; 714218822Sdim /* nopw 0(%[re]ax,%[re]ax,1) 715218822Sdim nopw 0(%[re]ax,%[re]ax,1) */ 716218822Sdim static const char alt_short_12[] = 717218822Sdim {0x66,0x0f,0x1f,0x44,0x00,0x00, 718218822Sdim 0x66,0x0f,0x1f,0x44,0x00,0x00}; 719218822Sdim /* nopw 0(%[re]ax,%[re]ax,1) 720218822Sdim nopl 0L(%[re]ax) */ 721218822Sdim static const char alt_short_13[] = 722218822Sdim {0x66,0x0f,0x1f,0x44,0x00,0x00, 723218822Sdim 0x0f,0x1f,0x80,0x00,0x00,0x00,0x00}; 724218822Sdim /* nopl 0L(%[re]ax) 725218822Sdim nopl 0L(%[re]ax) */ 726218822Sdim static const char alt_short_14[] = 727218822Sdim {0x0f,0x1f,0x80,0x00,0x00,0x00,0x00, 728218822Sdim 0x0f,0x1f,0x80,0x00,0x00,0x00,0x00}; 729218822Sdim /* nopl 0L(%[re]ax) 730218822Sdim nopl 0L(%[re]ax,%[re]ax,1) */ 731218822Sdim static const char alt_short_15[] = 732218822Sdim {0x0f,0x1f,0x80,0x00,0x00,0x00,0x00, 733218822Sdim 0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; 734218822Sdim static const char *const alt_short_patt[] = { 735218822Sdim f32_1, f32_2, alt_3, alt_4, alt_5, alt_6, alt_7, alt_8, 736218822Sdim alt_9, alt_10, alt_short_11, alt_short_12, alt_short_13, 737218822Sdim alt_short_14, alt_short_15 738218822Sdim }; 739218822Sdim static const char *const alt_long_patt[] = { 740218822Sdim f32_1, f32_2, alt_3, alt_4, alt_5, alt_6, alt_7, alt_8, 741218822Sdim alt_9, alt_10, alt_long_11, alt_long_12, alt_long_13, 742218822Sdim alt_long_14, alt_long_15 743218822Sdim }; 74433965Sjdp 745130570Sobrien if (count <= 0 || count > 15) 746130570Sobrien return; 747130570Sobrien 748218822Sdim /* We need to decide which NOP sequence to use for 32bit and 749218822Sdim 64bit. When -mtune= is used: 750218822Sdim 751218822Sdim 1. For PROCESSOR_I486, PROCESSOR_PENTIUM and PROCESSOR_GENERIC32, 752218822Sdim f32_patt will be used. 753218822Sdim 2. For PROCESSOR_K8 and PROCESSOR_AMDFAM10 in 64bit, NOPs with 754218822Sdim 0x66 prefix will be used. 755218822Sdim 3. For PROCESSOR_CORE2, alt_long_patt will be used. 756218822Sdim 4. For PROCESSOR_PENTIUMPRO, PROCESSOR_PENTIUM4, PROCESSOR_NOCONA, 757218822Sdim PROCESSOR_CORE, PROCESSOR_CORE2, PROCESSOR_K6, PROCESSOR_ATHLON 758218822Sdim and PROCESSOR_GENERIC64, alt_short_patt will be used. 759218822Sdim 760218822Sdim When -mtune= isn't used, alt_short_patt will be used if 761218822Sdim cpu_arch_isa_flags has Cpu686. Otherwise, f32_patt will be used. 762218822Sdim 763218822Sdim When -march= or .arch is used, we can't use anything beyond 764218822Sdim cpu_arch_isa_flags. */ 765218822Sdim 766218822Sdim if (flag_code == CODE_16BIT) 767130570Sobrien { 768218822Sdim memcpy (fragP->fr_literal + fragP->fr_fix, 769218822Sdim f16_patt[count - 1], count); 770218822Sdim if (count > 8) 771218822Sdim /* Adjust jump offset. */ 772218822Sdim fragP->fr_literal[fragP->fr_fix + 1] = count - 2; 773218822Sdim } 774218822Sdim else if (flag_code == CODE_64BIT && cpu_arch_tune == PROCESSOR_K8) 775218822Sdim { 776130570Sobrien int i; 777130570Sobrien int nnops = (count + 3) / 4; 778130570Sobrien int len = count / nnops; 779130570Sobrien int remains = count - nnops * len; 780130570Sobrien int pos = 0; 78177311Sobrien 782218822Sdim /* The recommended way to pad 64bit code is to use NOPs preceded 783218822Sdim by maximally four 0x66 prefixes. Balance the size of nops. */ 784130570Sobrien for (i = 0; i < remains; i++) 78533965Sjdp { 786130570Sobrien memset (fragP->fr_literal + fragP->fr_fix + pos, 0x66, len); 787130570Sobrien fragP->fr_literal[fragP->fr_fix + pos + len] = 0x90; 788130570Sobrien pos += len + 1; 78933965Sjdp } 790130570Sobrien for (; i < nnops; i++) 791130570Sobrien { 792130570Sobrien memset (fragP->fr_literal + fragP->fr_fix + pos, 0x66, len - 1); 793130570Sobrien fragP->fr_literal[fragP->fr_fix + pos + len - 1] = 0x90; 794130570Sobrien pos += len; 795130570Sobrien } 796130570Sobrien } 797130570Sobrien else 798218822Sdim { 799218822Sdim const char *const *patt = NULL; 800218822Sdim 801218822Sdim if (cpu_arch_isa == PROCESSOR_UNKNOWN) 802218822Sdim { 803218822Sdim /* PROCESSOR_UNKNOWN means that all ISAs may be used. */ 804218822Sdim switch (cpu_arch_tune) 805218822Sdim { 806218822Sdim case PROCESSOR_UNKNOWN: 807218822Sdim /* We use cpu_arch_isa_flags to check if we SHOULD 808218822Sdim optimize for Cpu686. */ 809218822Sdim if ((cpu_arch_isa_flags & Cpu686) != 0) 810218822Sdim patt = alt_short_patt; 811218822Sdim else 812218822Sdim patt = f32_patt; 813218822Sdim break; 814218822Sdim case PROCESSOR_CORE2: 815218822Sdim patt = alt_long_patt; 816218822Sdim break; 817218822Sdim case PROCESSOR_PENTIUMPRO: 818218822Sdim case PROCESSOR_PENTIUM4: 819218822Sdim case PROCESSOR_NOCONA: 820218822Sdim case PROCESSOR_CORE: 821218822Sdim case PROCESSOR_K6: 822218822Sdim case PROCESSOR_ATHLON: 823218822Sdim case PROCESSOR_K8: 824218822Sdim case PROCESSOR_GENERIC64: 825218822Sdim case PROCESSOR_AMDFAM10: 826218822Sdim patt = alt_short_patt; 827218822Sdim break; 828218822Sdim case PROCESSOR_I486: 829218822Sdim case PROCESSOR_PENTIUM: 830218822Sdim case PROCESSOR_GENERIC32: 831218822Sdim patt = f32_patt; 832218822Sdim break; 833218822Sdim } 834218822Sdim } 835218822Sdim else 836218822Sdim { 837218822Sdim switch (cpu_arch_tune) 838218822Sdim { 839218822Sdim case PROCESSOR_UNKNOWN: 840218822Sdim /* When cpu_arch_isa is net, cpu_arch_tune shouldn't be 841218822Sdim PROCESSOR_UNKNOWN. */ 842218822Sdim abort (); 843218822Sdim break; 844218822Sdim 845218822Sdim case PROCESSOR_I486: 846218822Sdim case PROCESSOR_PENTIUM: 847218822Sdim case PROCESSOR_PENTIUMPRO: 848218822Sdim case PROCESSOR_PENTIUM4: 849218822Sdim case PROCESSOR_NOCONA: 850218822Sdim case PROCESSOR_CORE: 851218822Sdim case PROCESSOR_K6: 852218822Sdim case PROCESSOR_ATHLON: 853218822Sdim case PROCESSOR_K8: 854218822Sdim case PROCESSOR_AMDFAM10: 855218822Sdim case PROCESSOR_GENERIC32: 856218822Sdim /* We use cpu_arch_isa_flags to check if we CAN optimize 857218822Sdim for Cpu686. */ 858218822Sdim if ((cpu_arch_isa_flags & Cpu686) != 0) 859218822Sdim patt = alt_short_patt; 860218822Sdim else 861218822Sdim patt = f32_patt; 862218822Sdim break; 863218822Sdim case PROCESSOR_CORE2: 864218822Sdim if ((cpu_arch_isa_flags & Cpu686) != 0) 865218822Sdim patt = alt_long_patt; 866218822Sdim else 867218822Sdim patt = f32_patt; 868218822Sdim break; 869218822Sdim case PROCESSOR_GENERIC64: 870218822Sdim patt = alt_short_patt; 871218822Sdim break; 872218822Sdim } 873218822Sdim } 874218822Sdim 875130570Sobrien memcpy (fragP->fr_literal + fragP->fr_fix, 876218822Sdim patt[count - 1], count); 877218822Sdim } 878130570Sobrien fragP->fr_var = count; 87933965Sjdp} 88033965Sjdp 88160519Sobrienstatic INLINE unsigned int 882218822Sdimmode_from_disp_size (unsigned int t) 88333965Sjdp{ 88477311Sobrien return (t & Disp8) ? 1 : (t & (Disp16 | Disp32 | Disp32S)) ? 2 : 0; 88533965Sjdp} 88633965Sjdp 88733965Sjdpstatic INLINE int 888218822Sdimfits_in_signed_byte (offsetT num) 88933965Sjdp{ 89033965Sjdp return (num >= -128) && (num <= 127); 89177311Sobrien} 89233965Sjdp 89333965Sjdpstatic INLINE int 894218822Sdimfits_in_unsigned_byte (offsetT num) 89533965Sjdp{ 89633965Sjdp return (num & 0xff) == num; 89777311Sobrien} 89833965Sjdp 89933965Sjdpstatic INLINE int 900218822Sdimfits_in_unsigned_word (offsetT num) 90133965Sjdp{ 90233965Sjdp return (num & 0xffff) == num; 90377311Sobrien} 90433965Sjdp 90533965Sjdpstatic INLINE int 906218822Sdimfits_in_signed_word (offsetT num) 90733965Sjdp{ 90833965Sjdp return (-32768 <= num) && (num <= 32767); 90977311Sobrien} 910218822Sdim 91177311Sobrienstatic INLINE int 912218822Sdimfits_in_signed_long (offsetT num ATTRIBUTE_UNUSED) 91377311Sobrien{ 91477311Sobrien#ifndef BFD64 91577311Sobrien return 1; 91677311Sobrien#else 917286519Sdim return (!(-((offsetT) 1 << 31) & num) 918286519Sdim || (-((offsetT) 1 << 31) & num) == -((offsetT) 1 << 31)); 91977311Sobrien#endif 92077311Sobrien} /* fits_in_signed_long() */ 921218822Sdim 92277311Sobrienstatic INLINE int 923218822Sdimfits_in_unsigned_long (offsetT num ATTRIBUTE_UNUSED) 92477311Sobrien{ 92577311Sobrien#ifndef BFD64 92677311Sobrien return 1; 92777311Sobrien#else 92877311Sobrien return (num & (((offsetT) 2 << 31) - 1)) == num; 92977311Sobrien#endif 93077311Sobrien} /* fits_in_unsigned_long() */ 93133965Sjdp 932218822Sdimstatic unsigned int 933218822Sdimsmallest_imm_type (offsetT num) 93433965Sjdp{ 935218822Sdim if (cpu_arch_flags != (Cpu186 | Cpu286 | Cpu386 | Cpu486 | CpuNo64)) 93677311Sobrien { 93777311Sobrien /* This code is disabled on the 486 because all the Imm1 forms 93877311Sobrien in the opcode table are slower on the i486. They're the 93977311Sobrien versions with the implicitly specified single-position 94077311Sobrien displacement, which has another syntax if you really want to 94177311Sobrien use that form. */ 94277311Sobrien if (num == 1) 94377311Sobrien return Imm1 | Imm8 | Imm8S | Imm16 | Imm32 | Imm32S | Imm64; 94477311Sobrien } 94533965Sjdp return (fits_in_signed_byte (num) 94677311Sobrien ? (Imm8S | Imm8 | Imm16 | Imm32 | Imm32S | Imm64) 94733965Sjdp : fits_in_unsigned_byte (num) 94877311Sobrien ? (Imm8 | Imm16 | Imm32 | Imm32S | Imm64) 94933965Sjdp : (fits_in_signed_word (num) || fits_in_unsigned_word (num)) 95077311Sobrien ? (Imm16 | Imm32 | Imm32S | Imm64) 95177311Sobrien : fits_in_signed_long (num) 95277311Sobrien ? (Imm32 | Imm32S | Imm64) 95377311Sobrien : fits_in_unsigned_long (num) 95477311Sobrien ? (Imm32 | Imm64) 95577311Sobrien : Imm64); 95677311Sobrien} 95733965Sjdp 95877311Sobrienstatic offsetT 959218822Sdimoffset_in_range (offsetT val, int size) 96077311Sobrien{ 96177311Sobrien addressT mask; 96277311Sobrien 96377311Sobrien switch (size) 96477311Sobrien { 96577311Sobrien case 1: mask = ((addressT) 1 << 8) - 1; break; 96677311Sobrien case 2: mask = ((addressT) 1 << 16) - 1; break; 96777311Sobrien case 4: mask = ((addressT) 2 << 31) - 1; break; 96877311Sobrien#ifdef BFD64 96977311Sobrien case 8: mask = ((addressT) 2 << 63) - 1; break; 97077311Sobrien#endif 97177311Sobrien default: abort (); 97277311Sobrien } 97377311Sobrien 97477311Sobrien /* If BFD64, sign extend val. */ 97577311Sobrien if (!use_rela_relocations) 97677311Sobrien if ((val & ~(((addressT) 2 << 31) - 1)) == 0) 97777311Sobrien val = (val ^ ((addressT) 1 << 31)) - ((addressT) 1 << 31); 97877311Sobrien 97977311Sobrien if ((val & ~mask) != 0 && (val & ~mask) != ~mask) 98077311Sobrien { 98177311Sobrien char buf1[40], buf2[40]; 98277311Sobrien 98377311Sobrien sprint_value (buf1, val); 98477311Sobrien sprint_value (buf2, val & mask); 98577311Sobrien as_warn (_("%s shortened to %s"), buf1, buf2); 98677311Sobrien } 98777311Sobrien return val & mask; 98877311Sobrien} 98977311Sobrien 99060519Sobrien/* Returns 0 if attempting to add a prefix where one from the same 99160519Sobrien class already exists, 1 if non rep/repne added, 2 if rep/repne 99260519Sobrien added. */ 99360519Sobrienstatic int 994218822Sdimadd_prefix (unsigned int prefix) 99560519Sobrien{ 99660519Sobrien int ret = 1; 997218822Sdim unsigned int q; 99860519Sobrien 99994546Sobrien if (prefix >= REX_OPCODE && prefix < REX_OPCODE + 16 100094546Sobrien && flag_code == CODE_64BIT) 1001218822Sdim { 1002218822Sdim if ((i.prefix[REX_PREFIX] & prefix & REX_W) 1003218822Sdim || ((i.prefix[REX_PREFIX] & (REX_R | REX_X | REX_B)) 1004218822Sdim && (prefix & (REX_R | REX_X | REX_B)))) 1005218822Sdim ret = 0; 1006218822Sdim q = REX_PREFIX; 1007218822Sdim } 100877311Sobrien else 1009218822Sdim { 1010218822Sdim switch (prefix) 1011218822Sdim { 1012218822Sdim default: 1013218822Sdim abort (); 101460519Sobrien 1015218822Sdim case CS_PREFIX_OPCODE: 1016218822Sdim case DS_PREFIX_OPCODE: 1017218822Sdim case ES_PREFIX_OPCODE: 1018218822Sdim case FS_PREFIX_OPCODE: 1019218822Sdim case GS_PREFIX_OPCODE: 1020218822Sdim case SS_PREFIX_OPCODE: 1021218822Sdim q = SEG_PREFIX; 1022218822Sdim break; 102360519Sobrien 1024218822Sdim case REPNE_PREFIX_OPCODE: 1025218822Sdim case REPE_PREFIX_OPCODE: 1026218822Sdim ret = 2; 1027218822Sdim /* fall thru */ 1028218822Sdim case LOCK_PREFIX_OPCODE: 1029218822Sdim q = LOCKREP_PREFIX; 1030218822Sdim break; 103160519Sobrien 1032218822Sdim case FWAIT_OPCODE: 1033218822Sdim q = WAIT_PREFIX; 1034218822Sdim break; 103560519Sobrien 1036218822Sdim case ADDR_PREFIX_OPCODE: 1037218822Sdim q = ADDR_PREFIX; 1038218822Sdim break; 103960519Sobrien 1040218822Sdim case DATA_PREFIX_OPCODE: 1041218822Sdim q = DATA_PREFIX; 1042218822Sdim break; 1043218822Sdim } 1044218822Sdim if (i.prefix[q] != 0) 1045218822Sdim ret = 0; 1046218822Sdim } 104760519Sobrien 1048218822Sdim if (ret) 104960519Sobrien { 1050218822Sdim if (!i.prefix[q]) 1051218822Sdim ++i.prefixes; 1052218822Sdim i.prefix[q] |= prefix; 105360519Sobrien } 1054218822Sdim else 1055218822Sdim as_bad (_("same type of prefix used twice")); 105660519Sobrien 105760519Sobrien return ret; 105860519Sobrien} 105960519Sobrien 106033965Sjdpstatic void 1061218822Sdimset_code_flag (int value) 106233965Sjdp{ 106377311Sobrien flag_code = value; 106477311Sobrien cpu_arch_flags &= ~(Cpu64 | CpuNo64); 106577311Sobrien cpu_arch_flags |= (flag_code == CODE_64BIT ? Cpu64 : CpuNo64); 106677311Sobrien if (value == CODE_64BIT && !(cpu_arch_flags & CpuSledgehammer)) 106777311Sobrien { 106877311Sobrien as_bad (_("64bit mode not supported on this CPU.")); 106977311Sobrien } 107077311Sobrien if (value == CODE_32BIT && !(cpu_arch_flags & Cpu386)) 107177311Sobrien { 107277311Sobrien as_bad (_("32bit mode not supported on this CPU.")); 107377311Sobrien } 107460519Sobrien stackop_size = '\0'; 107533965Sjdp} 107633965Sjdp 107760519Sobrienstatic void 1078218822Sdimset_16bit_gcc_code_flag (int new_code_flag) 107960519Sobrien{ 108077311Sobrien flag_code = new_code_flag; 108177311Sobrien cpu_arch_flags &= ~(Cpu64 | CpuNo64); 108277311Sobrien cpu_arch_flags |= (flag_code == CODE_64BIT ? Cpu64 : CpuNo64); 1083218822Sdim stackop_size = LONG_MNEM_SUFFIX; 108460519Sobrien} 108560519Sobrien 108660519Sobrienstatic void 1087218822Sdimset_intel_syntax (int syntax_flag) 108860519Sobrien{ 108960519Sobrien /* Find out if register prefixing is specified. */ 109060519Sobrien int ask_naked_reg = 0; 109160519Sobrien 109260519Sobrien SKIP_WHITESPACE (); 109394546Sobrien if (!is_end_of_line[(unsigned char) *input_line_pointer]) 109460519Sobrien { 109560519Sobrien char *string = input_line_pointer; 109660519Sobrien int e = get_symbol_end (); 109760519Sobrien 109877311Sobrien if (strcmp (string, "prefix") == 0) 109960519Sobrien ask_naked_reg = 1; 110077311Sobrien else if (strcmp (string, "noprefix") == 0) 110160519Sobrien ask_naked_reg = -1; 110260519Sobrien else 110360519Sobrien as_bad (_("bad argument to syntax directive.")); 110460519Sobrien *input_line_pointer = e; 110560519Sobrien } 110660519Sobrien demand_empty_rest_of_line (); 110760519Sobrien 110860519Sobrien intel_syntax = syntax_flag; 110960519Sobrien 111060519Sobrien if (ask_naked_reg == 0) 1111130570Sobrien allow_naked_reg = (intel_syntax 1112130570Sobrien && (bfd_get_symbol_leading_char (stdoutput) != '\0')); 111360519Sobrien else 111460519Sobrien allow_naked_reg = (ask_naked_reg < 0); 1115218822Sdim 1116218822Sdim identifier_chars['%'] = intel_syntax && allow_naked_reg ? '%' : 0; 1117218822Sdim identifier_chars['$'] = intel_syntax ? '$' : 0; 1118218822Sdim register_prefix = allow_naked_reg ? "" : "%"; 111960519Sobrien} 112060519Sobrien 112177311Sobrienstatic void 1122218822Sdimset_cpu_arch (int dummy ATTRIBUTE_UNUSED) 112377311Sobrien{ 112477311Sobrien SKIP_WHITESPACE (); 112577311Sobrien 112694546Sobrien if (!is_end_of_line[(unsigned char) *input_line_pointer]) 112777311Sobrien { 112877311Sobrien char *string = input_line_pointer; 112977311Sobrien int e = get_symbol_end (); 1130218822Sdim unsigned int i; 113177311Sobrien 1132218822Sdim for (i = 0; i < ARRAY_SIZE (cpu_arch); i++) 113377311Sobrien { 113477311Sobrien if (strcmp (string, cpu_arch[i].name) == 0) 113577311Sobrien { 1136218822Sdim if (*string != '.') 1137218822Sdim { 1138218822Sdim cpu_arch_name = cpu_arch[i].name; 1139218822Sdim cpu_sub_arch_name = NULL; 1140218822Sdim cpu_arch_flags = (cpu_arch[i].flags 1141218822Sdim | (flag_code == CODE_64BIT 1142218822Sdim ? Cpu64 : CpuNo64)); 1143218822Sdim cpu_arch_isa = cpu_arch[i].type; 1144218822Sdim cpu_arch_isa_flags = cpu_arch[i].flags; 1145218822Sdim if (!cpu_arch_tune_set) 1146218822Sdim { 1147218822Sdim cpu_arch_tune = cpu_arch_isa; 1148218822Sdim cpu_arch_tune_flags = cpu_arch_isa_flags; 1149218822Sdim } 1150218822Sdim break; 1151218822Sdim } 1152218822Sdim if ((cpu_arch_flags | cpu_arch[i].flags) != cpu_arch_flags) 1153218822Sdim { 1154218822Sdim cpu_sub_arch_name = cpu_arch[i].name; 1155218822Sdim cpu_arch_flags |= cpu_arch[i].flags; 1156218822Sdim } 1157218822Sdim *input_line_pointer = e; 1158218822Sdim demand_empty_rest_of_line (); 1159218822Sdim return; 116077311Sobrien } 116177311Sobrien } 1162218822Sdim if (i >= ARRAY_SIZE (cpu_arch)) 116377311Sobrien as_bad (_("no such architecture: `%s'"), string); 116477311Sobrien 116577311Sobrien *input_line_pointer = e; 116677311Sobrien } 116777311Sobrien else 116877311Sobrien as_bad (_("missing cpu architecture")); 116977311Sobrien 117078840Sobrien no_cond_jump_promotion = 0; 117178840Sobrien if (*input_line_pointer == ',' 117294546Sobrien && !is_end_of_line[(unsigned char) input_line_pointer[1]]) 117378840Sobrien { 117478840Sobrien char *string = ++input_line_pointer; 117578840Sobrien int e = get_symbol_end (); 117678840Sobrien 117778840Sobrien if (strcmp (string, "nojumps") == 0) 117878840Sobrien no_cond_jump_promotion = 1; 117978840Sobrien else if (strcmp (string, "jumps") == 0) 118078840Sobrien ; 118178840Sobrien else 118278840Sobrien as_bad (_("no such architecture modifier: `%s'"), string); 118378840Sobrien 118478840Sobrien *input_line_pointer = e; 118578840Sobrien } 118678840Sobrien 118777311Sobrien demand_empty_rest_of_line (); 118877311Sobrien} 118977311Sobrien 119077311Sobrienunsigned long 119177311Sobrieni386_mach () 119277311Sobrien{ 119377311Sobrien if (!strcmp (default_arch, "x86_64")) 119477311Sobrien return bfd_mach_x86_64; 119577311Sobrien else if (!strcmp (default_arch, "i386")) 119677311Sobrien return bfd_mach_i386_i386; 119777311Sobrien else 119877311Sobrien as_fatal (_("Unknown architecture")); 119977311Sobrien} 120077311Sobrien 120133965Sjdpvoid 120233965Sjdpmd_begin () 120333965Sjdp{ 120433965Sjdp const char *hash_err; 120533965Sjdp 120677311Sobrien /* Initialize op_hash hash table. */ 120733965Sjdp op_hash = hash_new (); 120833965Sjdp 120933965Sjdp { 121094546Sobrien const template *optab; 121194546Sobrien templates *core_optab; 121233965Sjdp 121377311Sobrien /* Setup for loop. */ 121477311Sobrien optab = i386_optab; 121533965Sjdp core_optab = (templates *) xmalloc (sizeof (templates)); 121660519Sobrien core_optab->start = optab; 121733965Sjdp 121860519Sobrien while (1) 121933965Sjdp { 122060519Sobrien ++optab; 122160519Sobrien if (optab->name == NULL 122260519Sobrien || strcmp (optab->name, (optab - 1)->name) != 0) 122333965Sjdp { 122433965Sjdp /* different name --> ship out current template list; 122577311Sobrien add to hash table; & begin anew. */ 122660519Sobrien core_optab->end = optab; 122760519Sobrien hash_err = hash_insert (op_hash, 122860519Sobrien (optab - 1)->name, 122960519Sobrien (PTR) core_optab); 123033965Sjdp if (hash_err) 123133965Sjdp { 123260519Sobrien as_fatal (_("Internal Error: Can't hash %s: %s"), 123360519Sobrien (optab - 1)->name, 123433965Sjdp hash_err); 123533965Sjdp } 123660519Sobrien if (optab->name == NULL) 123760519Sobrien break; 123833965Sjdp core_optab = (templates *) xmalloc (sizeof (templates)); 123960519Sobrien core_optab->start = optab; 124033965Sjdp } 124133965Sjdp } 124233965Sjdp } 124333965Sjdp 124477311Sobrien /* Initialize reg_hash hash table. */ 124533965Sjdp reg_hash = hash_new (); 124633965Sjdp { 124794546Sobrien const reg_entry *regtab; 1248218822Sdim unsigned int regtab_size = i386_regtab_size; 124933965Sjdp 1250218822Sdim for (regtab = i386_regtab; regtab_size--; regtab++) 125133965Sjdp { 125233965Sjdp hash_err = hash_insert (reg_hash, regtab->reg_name, (PTR) regtab); 125333965Sjdp if (hash_err) 125477311Sobrien as_fatal (_("Internal Error: Can't hash %s: %s"), 125577311Sobrien regtab->reg_name, 125677311Sobrien hash_err); 125733965Sjdp } 125833965Sjdp } 125933965Sjdp 126077311Sobrien /* Fill in lexical tables: mnemonic_chars, operand_chars. */ 126133965Sjdp { 126294546Sobrien int c; 126394546Sobrien char *p; 126433965Sjdp 126533965Sjdp for (c = 0; c < 256; c++) 126633965Sjdp { 126789867Sobrien if (ISDIGIT (c)) 126833965Sjdp { 126960519Sobrien digit_chars[c] = c; 127060519Sobrien mnemonic_chars[c] = c; 127133965Sjdp register_chars[c] = c; 127260519Sobrien operand_chars[c] = c; 127333965Sjdp } 127489867Sobrien else if (ISLOWER (c)) 127533965Sjdp { 127660519Sobrien mnemonic_chars[c] = c; 127760519Sobrien register_chars[c] = c; 127860519Sobrien operand_chars[c] = c; 127933965Sjdp } 128089867Sobrien else if (ISUPPER (c)) 128133965Sjdp { 128289867Sobrien mnemonic_chars[c] = TOLOWER (c); 128360519Sobrien register_chars[c] = mnemonic_chars[c]; 128460519Sobrien operand_chars[c] = c; 128533965Sjdp } 128660519Sobrien 128789867Sobrien if (ISALPHA (c) || ISDIGIT (c)) 128860519Sobrien identifier_chars[c] = c; 128960519Sobrien else if (c >= 128) 129033965Sjdp { 129160519Sobrien identifier_chars[c] = c; 129260519Sobrien operand_chars[c] = c; 129333965Sjdp } 129460519Sobrien } 129533965Sjdp 129633965Sjdp#ifdef LEX_AT 129760519Sobrien identifier_chars['@'] = '@'; 129833965Sjdp#endif 1299218822Sdim#ifdef LEX_QM 1300218822Sdim identifier_chars['?'] = '?'; 1301218822Sdim operand_chars['?'] = '?'; 1302218822Sdim#endif 130360519Sobrien digit_chars['-'] = '-'; 1304218822Sdim mnemonic_chars['-'] = '-'; 1305218822Sdim mnemonic_chars['.'] = '.'; 130660519Sobrien identifier_chars['_'] = '_'; 130760519Sobrien identifier_chars['.'] = '.'; 130833965Sjdp 130933965Sjdp for (p = operand_special_chars; *p != '\0'; p++) 131033965Sjdp operand_chars[(unsigned char) *p] = *p; 131133965Sjdp } 131233965Sjdp 131333965Sjdp#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) 1314218822Sdim if (IS_ELF) 131533965Sjdp { 131633965Sjdp record_alignment (text_section, 2); 131733965Sjdp record_alignment (data_section, 2); 131833965Sjdp record_alignment (bss_section, 2); 131933965Sjdp } 132033965Sjdp#endif 1321130570Sobrien 1322130570Sobrien if (flag_code == CODE_64BIT) 1323130570Sobrien { 1324130570Sobrien x86_dwarf2_return_column = 16; 1325130570Sobrien x86_cie_data_alignment = -8; 1326130570Sobrien } 1327130570Sobrien else 1328130570Sobrien { 1329130570Sobrien x86_dwarf2_return_column = 8; 1330130570Sobrien x86_cie_data_alignment = -4; 1331130570Sobrien } 133233965Sjdp} 133333965Sjdp 133433965Sjdpvoid 1335218822Sdimi386_print_statistics (FILE *file) 133633965Sjdp{ 133733965Sjdp hash_print_statistics (file, "i386 opcode", op_hash); 133833965Sjdp hash_print_statistics (file, "i386 register", reg_hash); 133933965Sjdp} 134033965Sjdp 134133965Sjdp#ifdef DEBUG386 134233965Sjdp 134377311Sobrien/* Debugging routines for md_assemble. */ 1344218822Sdimstatic void pte (template *); 1345218822Sdimstatic void pt (unsigned int); 1346218822Sdimstatic void pe (expressionS *); 1347218822Sdimstatic void ps (symbolS *); 134833965Sjdp 134933965Sjdpstatic void 1350218822Sdimpi (char *line, i386_insn *x) 135133965Sjdp{ 135277311Sobrien unsigned int i; 135333965Sjdp 135433965Sjdp fprintf (stdout, "%s: template ", line); 135533965Sjdp pte (&x->tm); 135677311Sobrien fprintf (stdout, " address: base %s index %s scale %x\n", 135777311Sobrien x->base_reg ? x->base_reg->reg_name : "none", 135877311Sobrien x->index_reg ? x->index_reg->reg_name : "none", 135977311Sobrien x->log2_scale_factor); 136077311Sobrien fprintf (stdout, " modrm: mode %x reg %x reg/mem %x\n", 136133965Sjdp x->rm.mode, x->rm.reg, x->rm.regmem); 136277311Sobrien fprintf (stdout, " sib: base %x index %x scale %x\n", 136377311Sobrien x->sib.base, x->sib.index, x->sib.scale); 136477311Sobrien fprintf (stdout, " rex: 64bit %x extX %x extY %x extZ %x\n", 1365218822Sdim (x->rex & REX_W) != 0, 1366218822Sdim (x->rex & REX_R) != 0, 1367218822Sdim (x->rex & REX_X) != 0, 1368218822Sdim (x->rex & REX_B) != 0); 136933965Sjdp for (i = 0; i < x->operands; i++) 137033965Sjdp { 137133965Sjdp fprintf (stdout, " #%d: ", i + 1); 137233965Sjdp pt (x->types[i]); 137333965Sjdp fprintf (stdout, "\n"); 137433965Sjdp if (x->types[i] 137560519Sobrien & (Reg | SReg2 | SReg3 | Control | Debug | Test | RegMMX | RegXMM)) 137660519Sobrien fprintf (stdout, "%s\n", x->op[i].regs->reg_name); 137733965Sjdp if (x->types[i] & Imm) 137860519Sobrien pe (x->op[i].imms); 137960519Sobrien if (x->types[i] & Disp) 138060519Sobrien pe (x->op[i].disps); 138133965Sjdp } 138233965Sjdp} 138333965Sjdp 138433965Sjdpstatic void 1385218822Sdimpte (template *t) 138633965Sjdp{ 138777311Sobrien unsigned int i; 138833965Sjdp fprintf (stdout, " %d operands ", t->operands); 138977311Sobrien fprintf (stdout, "opcode %x ", t->base_opcode); 139033965Sjdp if (t->extension_opcode != None) 139133965Sjdp fprintf (stdout, "ext %x ", t->extension_opcode); 139233965Sjdp if (t->opcode_modifier & D) 139333965Sjdp fprintf (stdout, "D"); 139433965Sjdp if (t->opcode_modifier & W) 139533965Sjdp fprintf (stdout, "W"); 139633965Sjdp fprintf (stdout, "\n"); 139733965Sjdp for (i = 0; i < t->operands; i++) 139833965Sjdp { 139933965Sjdp fprintf (stdout, " #%d type ", i + 1); 140033965Sjdp pt (t->operand_types[i]); 140133965Sjdp fprintf (stdout, "\n"); 140233965Sjdp } 140333965Sjdp} 140433965Sjdp 140533965Sjdpstatic void 1406218822Sdimpe (expressionS *e) 140733965Sjdp{ 140860519Sobrien fprintf (stdout, " operation %d\n", e->X_op); 140960519Sobrien fprintf (stdout, " add_number %ld (%lx)\n", 141060519Sobrien (long) e->X_add_number, (long) e->X_add_number); 141133965Sjdp if (e->X_add_symbol) 141233965Sjdp { 141333965Sjdp fprintf (stdout, " add_symbol "); 141433965Sjdp ps (e->X_add_symbol); 141533965Sjdp fprintf (stdout, "\n"); 141633965Sjdp } 141733965Sjdp if (e->X_op_symbol) 141833965Sjdp { 141933965Sjdp fprintf (stdout, " op_symbol "); 142033965Sjdp ps (e->X_op_symbol); 142133965Sjdp fprintf (stdout, "\n"); 142233965Sjdp } 142333965Sjdp} 142433965Sjdp 142533965Sjdpstatic void 1426218822Sdimps (symbolS *s) 142733965Sjdp{ 142833965Sjdp fprintf (stdout, "%s type %s%s", 142933965Sjdp S_GET_NAME (s), 143033965Sjdp S_IS_EXTERNAL (s) ? "EXTERNAL " : "", 143133965Sjdp segment_name (S_GET_SEGMENT (s))); 143233965Sjdp} 143333965Sjdp 1434218822Sdimstatic struct type_name 143533965Sjdp { 143633965Sjdp unsigned int mask; 143733965Sjdp char *tname; 143833965Sjdp } 1439218822Sdimconst type_names[] = 144033965Sjdp{ 144133965Sjdp { Reg8, "r8" }, 144233965Sjdp { Reg16, "r16" }, 144333965Sjdp { Reg32, "r32" }, 144477311Sobrien { Reg64, "r64" }, 144533965Sjdp { Imm8, "i8" }, 144633965Sjdp { Imm8S, "i8s" }, 144733965Sjdp { Imm16, "i16" }, 144833965Sjdp { Imm32, "i32" }, 144977311Sobrien { Imm32S, "i32s" }, 145077311Sobrien { Imm64, "i64" }, 145160519Sobrien { Imm1, "i1" }, 145233965Sjdp { BaseIndex, "BaseIndex" }, 145333965Sjdp { Disp8, "d8" }, 145433965Sjdp { Disp16, "d16" }, 145533965Sjdp { Disp32, "d32" }, 145677311Sobrien { Disp32S, "d32s" }, 145777311Sobrien { Disp64, "d64" }, 145833965Sjdp { InOutPortReg, "InOutPortReg" }, 145933965Sjdp { ShiftCount, "ShiftCount" }, 146033965Sjdp { Control, "control reg" }, 146133965Sjdp { Test, "test reg" }, 146260519Sobrien { Debug, "debug reg" }, 146333965Sjdp { FloatReg, "FReg" }, 146433965Sjdp { FloatAcc, "FAcc" }, 146560519Sobrien { SReg2, "SReg2" }, 146660519Sobrien { SReg3, "SReg3" }, 146760519Sobrien { Acc, "Acc" }, 146833965Sjdp { JumpAbsolute, "Jump Absolute" }, 146933965Sjdp { RegMMX, "rMMX" }, 147060519Sobrien { RegXMM, "rXMM" }, 147160519Sobrien { EsSeg, "es" }, 147233965Sjdp { 0, "" } 147333965Sjdp}; 147433965Sjdp 147533965Sjdpstatic void 147633965Sjdppt (t) 147733965Sjdp unsigned int t; 147833965Sjdp{ 147994546Sobrien const struct type_name *ty; 148033965Sjdp 148177311Sobrien for (ty = type_names; ty->mask; ty++) 148277311Sobrien if (t & ty->mask) 148377311Sobrien fprintf (stdout, "%s, ", ty->tname); 148433965Sjdp fflush (stdout); 148533965Sjdp} 148633965Sjdp 148733965Sjdp#endif /* DEBUG386 */ 148833965Sjdp 148933965Sjdpstatic bfd_reloc_code_real_type 1490218822Sdimreloc (unsigned int size, 1491218822Sdim int pcrel, 1492218822Sdim int sign, 1493218822Sdim bfd_reloc_code_real_type other) 149433965Sjdp{ 149577311Sobrien if (other != NO_RELOC) 1496218822Sdim { 1497218822Sdim reloc_howto_type *reloc; 149833965Sjdp 1499218822Sdim if (size == 8) 1500218822Sdim switch (other) 1501218822Sdim { 1502218822Sdim case BFD_RELOC_X86_64_GOT32: 1503218822Sdim return BFD_RELOC_X86_64_GOT64; 1504218822Sdim break; 1505218822Sdim case BFD_RELOC_X86_64_PLTOFF64: 1506218822Sdim return BFD_RELOC_X86_64_PLTOFF64; 1507218822Sdim break; 1508218822Sdim case BFD_RELOC_X86_64_GOTPC32: 1509218822Sdim other = BFD_RELOC_X86_64_GOTPC64; 1510218822Sdim break; 1511218822Sdim case BFD_RELOC_X86_64_GOTPCREL: 1512218822Sdim other = BFD_RELOC_X86_64_GOTPCREL64; 1513218822Sdim break; 1514218822Sdim case BFD_RELOC_X86_64_TPOFF32: 1515218822Sdim other = BFD_RELOC_X86_64_TPOFF64; 1516218822Sdim break; 1517218822Sdim case BFD_RELOC_X86_64_DTPOFF32: 1518218822Sdim other = BFD_RELOC_X86_64_DTPOFF64; 1519218822Sdim break; 1520218822Sdim default: 1521218822Sdim break; 1522218822Sdim } 1523218822Sdim 1524218822Sdim /* Sign-checking 4-byte relocations in 16-/32-bit code is pointless. */ 1525218822Sdim if (size == 4 && flag_code != CODE_64BIT) 1526218822Sdim sign = -1; 1527218822Sdim 1528218822Sdim reloc = bfd_reloc_type_lookup (stdoutput, other); 1529218822Sdim if (!reloc) 1530218822Sdim as_bad (_("unknown relocation (%u)"), other); 1531218822Sdim else if (size != bfd_get_reloc_size (reloc)) 1532218822Sdim as_bad (_("%u-byte relocation cannot be applied to %u-byte field"), 1533218822Sdim bfd_get_reloc_size (reloc), 1534218822Sdim size); 1535218822Sdim else if (pcrel && !reloc->pc_relative) 1536218822Sdim as_bad (_("non-pc-relative relocation for pc-relative field")); 1537218822Sdim else if ((reloc->complain_on_overflow == complain_overflow_signed 1538218822Sdim && !sign) 1539218822Sdim || (reloc->complain_on_overflow == complain_overflow_unsigned 1540218822Sdim && sign > 0)) 1541218822Sdim as_bad (_("relocated field and relocation type differ in signedness")); 1542218822Sdim else 1543218822Sdim return other; 1544218822Sdim return NO_RELOC; 1545218822Sdim } 1546218822Sdim 154733965Sjdp if (pcrel) 154860519Sobrien { 154977311Sobrien if (!sign) 1550218822Sdim as_bad (_("there are no unsigned pc-relative relocations")); 155160519Sobrien switch (size) 155260519Sobrien { 155360519Sobrien case 1: return BFD_RELOC_8_PCREL; 155460519Sobrien case 2: return BFD_RELOC_16_PCREL; 155560519Sobrien case 4: return BFD_RELOC_32_PCREL; 1556218822Sdim case 8: return BFD_RELOC_64_PCREL; 155760519Sobrien } 1558218822Sdim as_bad (_("cannot do %u byte pc-relative relocation"), size); 155960519Sobrien } 156033965Sjdp else 156160519Sobrien { 1562218822Sdim if (sign > 0) 156377311Sobrien switch (size) 156477311Sobrien { 156577311Sobrien case 4: return BFD_RELOC_X86_64_32S; 156677311Sobrien } 156777311Sobrien else 156877311Sobrien switch (size) 156977311Sobrien { 157077311Sobrien case 1: return BFD_RELOC_8; 157177311Sobrien case 2: return BFD_RELOC_16; 157277311Sobrien case 4: return BFD_RELOC_32; 157377311Sobrien case 8: return BFD_RELOC_64; 157477311Sobrien } 1575218822Sdim as_bad (_("cannot do %s %u byte relocation"), 1576218822Sdim sign > 0 ? "signed" : "unsigned", size); 157760519Sobrien } 157833965Sjdp 157977311Sobrien abort (); 158033965Sjdp return BFD_RELOC_NONE; 158133965Sjdp} 158233965Sjdp 158377311Sobrien/* Here we decide which fixups can be adjusted to make them relative to 158477311Sobrien the beginning of the section instead of the symbol. Basically we need 158577311Sobrien to make sure that the dynamic relocations are done correctly, so in 158677311Sobrien some cases we force the original symbol to be used. */ 158777311Sobrien 158833965Sjdpint 1589218822Sdimtc_i386_fix_adjustable (fixS *fixP ATTRIBUTE_UNUSED) 159033965Sjdp{ 159177311Sobrien#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) 1592218822Sdim if (!IS_ELF) 1593104848Sobrien return 1; 1594104848Sobrien 1595130570Sobrien /* Don't adjust pc-relative references to merge sections in 64-bit 1596130570Sobrien mode. */ 1597130570Sobrien if (use_rela_relocations 1598130570Sobrien && (S_GET_SEGMENT (fixP->fx_addsy)->flags & SEC_MERGE) != 0 1599130570Sobrien && fixP->fx_pcrel) 160033965Sjdp return 0; 1601104848Sobrien 1602130570Sobrien /* The x86_64 GOTPCREL are represented as 32bit PCrel relocations 1603130570Sobrien and changed later by validate_fix. */ 1604130570Sobrien if (GOT_symbol && fixP->fx_subsy == GOT_symbol 1605130570Sobrien && fixP->fx_r_type == BFD_RELOC_32_PCREL) 1606130570Sobrien return 0; 1607130570Sobrien 160877311Sobrien /* adjust_reloc_syms doesn't know about the GOT. */ 160933965Sjdp if (fixP->fx_r_type == BFD_RELOC_386_GOTOFF 161033965Sjdp || fixP->fx_r_type == BFD_RELOC_386_PLT32 161160519Sobrien || fixP->fx_r_type == BFD_RELOC_386_GOT32 1612104848Sobrien || fixP->fx_r_type == BFD_RELOC_386_TLS_GD 1613104848Sobrien || fixP->fx_r_type == BFD_RELOC_386_TLS_LDM 1614104848Sobrien || fixP->fx_r_type == BFD_RELOC_386_TLS_LDO_32 1615104848Sobrien || fixP->fx_r_type == BFD_RELOC_386_TLS_IE_32 1616104848Sobrien || fixP->fx_r_type == BFD_RELOC_386_TLS_IE 1617104848Sobrien || fixP->fx_r_type == BFD_RELOC_386_TLS_GOTIE 1618104848Sobrien || fixP->fx_r_type == BFD_RELOC_386_TLS_LE_32 1619104848Sobrien || fixP->fx_r_type == BFD_RELOC_386_TLS_LE 1620218822Sdim || fixP->fx_r_type == BFD_RELOC_386_TLS_GOTDESC 1621218822Sdim || fixP->fx_r_type == BFD_RELOC_386_TLS_DESC_CALL 162277311Sobrien || fixP->fx_r_type == BFD_RELOC_X86_64_PLT32 162377311Sobrien || fixP->fx_r_type == BFD_RELOC_X86_64_GOT32 162477311Sobrien || fixP->fx_r_type == BFD_RELOC_X86_64_GOTPCREL 1625130570Sobrien || fixP->fx_r_type == BFD_RELOC_X86_64_TLSGD 1626130570Sobrien || fixP->fx_r_type == BFD_RELOC_X86_64_TLSLD 1627130570Sobrien || fixP->fx_r_type == BFD_RELOC_X86_64_DTPOFF32 1628218822Sdim || fixP->fx_r_type == BFD_RELOC_X86_64_DTPOFF64 1629130570Sobrien || fixP->fx_r_type == BFD_RELOC_X86_64_GOTTPOFF 1630130570Sobrien || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF32 1631218822Sdim || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF64 1632218822Sdim || fixP->fx_r_type == BFD_RELOC_X86_64_GOTOFF64 1633218822Sdim || fixP->fx_r_type == BFD_RELOC_X86_64_GOTPC32_TLSDESC 1634218822Sdim || fixP->fx_r_type == BFD_RELOC_X86_64_TLSDESC_CALL 163560519Sobrien || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT 163660519Sobrien || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) 163733965Sjdp return 0; 1638104848Sobrien#endif 163933965Sjdp return 1; 164033965Sjdp} 164133965Sjdp 164260519Sobrienstatic int 1643218822Sdimintel_float_operand (const char *mnemonic) 164460519Sobrien{ 1645218822Sdim /* Note that the value returned is meaningful only for opcodes with (memory) 1646218822Sdim operands, hence the code here is free to improperly handle opcodes that 1647218822Sdim have no operands (for better performance and smaller code). */ 164860519Sobrien 1649218822Sdim if (mnemonic[0] != 'f') 1650218822Sdim return 0; /* non-math */ 165160519Sobrien 1652218822Sdim switch (mnemonic[1]) 1653218822Sdim { 1654218822Sdim /* fclex, fdecstp, fdisi, femms, feni, fincstp, finit, fsetpm, and 1655218822Sdim the fs segment override prefix not currently handled because no 1656218822Sdim call path can make opcodes without operands get here */ 1657218822Sdim case 'i': 1658218822Sdim return 2 /* integer op */; 1659218822Sdim case 'l': 1660218822Sdim if (mnemonic[2] == 'd' && (mnemonic[3] == 'c' || mnemonic[3] == 'e')) 1661218822Sdim return 3; /* fldcw/fldenv */ 1662218822Sdim break; 1663218822Sdim case 'n': 1664218822Sdim if (mnemonic[2] != 'o' /* fnop */) 1665218822Sdim return 3; /* non-waiting control op */ 1666218822Sdim break; 1667218822Sdim case 'r': 1668218822Sdim if (mnemonic[2] == 's') 1669218822Sdim return 3; /* frstor/frstpm */ 1670218822Sdim break; 1671218822Sdim case 's': 1672218822Sdim if (mnemonic[2] == 'a') 1673218822Sdim return 3; /* fsave */ 1674218822Sdim if (mnemonic[2] == 't') 1675218822Sdim { 1676218822Sdim switch (mnemonic[3]) 1677218822Sdim { 1678218822Sdim case 'c': /* fstcw */ 1679218822Sdim case 'd': /* fstdw */ 1680218822Sdim case 'e': /* fstenv */ 1681218822Sdim case 's': /* fsts[gw] */ 1682218822Sdim return 3; 1683218822Sdim } 1684218822Sdim } 1685218822Sdim break; 1686218822Sdim case 'x': 1687218822Sdim if (mnemonic[2] == 'r' || mnemonic[2] == 's') 1688218822Sdim return 0; /* fxsave/fxrstor are not really math ops */ 1689218822Sdim break; 1690218822Sdim } 1691218822Sdim 1692218822Sdim return 1; 169360519Sobrien} 169460519Sobrien 169533965Sjdp/* This is the guts of the machine-dependent assembler. LINE points to a 169633965Sjdp machine dependent instruction. This function is supposed to emit 169733965Sjdp the frags/bytes it assembles to. */ 169833965Sjdp 169933965Sjdpvoid 170033965Sjdpmd_assemble (line) 170133965Sjdp char *line; 170233965Sjdp{ 170333965Sjdp int j; 170460519Sobrien char mnemonic[MAX_MNEM_SIZE]; 170538891Sjdp 170677311Sobrien /* Initialize globals. */ 170733965Sjdp memset (&i, '\0', sizeof (i)); 170833965Sjdp for (j = 0; j < MAX_OPERANDS; j++) 170978840Sobrien i.reloc[j] = NO_RELOC; 171033965Sjdp memset (disp_expressions, '\0', sizeof (disp_expressions)); 171133965Sjdp memset (im_expressions, '\0', sizeof (im_expressions)); 171277311Sobrien save_stack_p = save_stack; 171333965Sjdp 171460519Sobrien /* First parse an instruction mnemonic & call i386_operand for the operands. 171533965Sjdp We assume that the scrubber has arranged it so that line[0] is the valid 171677311Sobrien start of a (possibly prefixed) mnemonic. */ 171733965Sjdp 171894546Sobrien line = parse_insn (line, mnemonic); 171994546Sobrien if (line == NULL) 172094546Sobrien return; 172160519Sobrien 172294546Sobrien line = parse_operands (line, mnemonic); 172394546Sobrien if (line == NULL) 172494546Sobrien return; 172560519Sobrien 1726218822Sdim /* The order of the immediates should be reversed 1727218822Sdim for 2 immediates extrq and insertq instructions */ 1728218822Sdim if ((i.imm_operands == 2) 1729218822Sdim && ((strcmp (mnemonic, "extrq") == 0) 1730218822Sdim || (strcmp (mnemonic, "insertq") == 0))) 1731218822Sdim { 1732218822Sdim swap_2_operands (0, 1); 1733218822Sdim /* "extrq" and insertq" are the only two instructions whose operands 1734218822Sdim have to be reversed even though they have two immediate operands. 1735218822Sdim */ 1736218822Sdim if (intel_syntax) 1737218822Sdim swap_operands (); 1738218822Sdim } 1739218822Sdim 174094546Sobrien /* Now we've parsed the mnemonic into a set of templates, and have the 174194546Sobrien operands at hand. */ 174260519Sobrien 174394546Sobrien /* All intel opcodes have reversed operands except for "bound" and 174494546Sobrien "enter". We also don't reverse intersegment "jmp" and "call" 174594546Sobrien instructions with 2 immediate operands so that the immediate segment 1746218822Sdim precedes the offset, as it does when in AT&T mode. */ 1747218822Sdim if (intel_syntax 1748218822Sdim && i.operands > 1 174994546Sobrien && (strcmp (mnemonic, "bound") != 0) 1750218822Sdim && (strcmp (mnemonic, "invlpga") != 0) 175194546Sobrien && !((i.types[0] & Imm) && (i.types[1] & Imm))) 175294546Sobrien swap_operands (); 175333965Sjdp 175494546Sobrien if (i.imm_operands) 175594546Sobrien optimize_imm (); 175660519Sobrien 1757218822Sdim /* Don't optimize displacement for movabs since it only takes 64bit 1758218822Sdim displacement. */ 1759218822Sdim if (i.disp_operands 1760218822Sdim && (flag_code != CODE_64BIT 1761218822Sdim || strcmp (mnemonic, "movabs") != 0)) 176294546Sobrien optimize_disp (); 176333965Sjdp 176494546Sobrien /* Next, we find a template that matches the given insn, 176594546Sobrien making sure the overlap of the given operands types is consistent 176694546Sobrien with the template operand types. */ 176777311Sobrien 176894546Sobrien if (!match_template ()) 176994546Sobrien return; 177089867Sobrien 1771104848Sobrien if (intel_syntax) 1772104848Sobrien { 1773104848Sobrien /* Undo SYSV386_COMPAT brokenness when in Intel mode. See i386.h */ 1774104848Sobrien if (SYSV386_COMPAT 1775104848Sobrien && (i.tm.base_opcode & 0xfffffde0) == 0xdce0) 1776218822Sdim i.tm.base_opcode ^= Opcode_FloatR; 177794546Sobrien 1778104848Sobrien /* Zap movzx and movsx suffix. The suffix may have been set from 1779104848Sobrien "word ptr" or "byte ptr" on the source operand, but we'll use 1780104848Sobrien the suffix later to choose the destination register. */ 1781104848Sobrien if ((i.tm.base_opcode & ~9) == 0x0fb6) 1782218822Sdim { 1783218822Sdim if (i.reg_operands < 2 1784218822Sdim && !i.suffix 1785218822Sdim && (~i.tm.opcode_modifier 1786218822Sdim & (No_bSuf 1787218822Sdim | No_wSuf 1788218822Sdim | No_lSuf 1789218822Sdim | No_sSuf 1790218822Sdim | No_xSuf 1791218822Sdim | No_qSuf))) 1792218822Sdim as_bad (_("ambiguous operand size for `%s'"), i.tm.name); 1793218822Sdim 1794218822Sdim i.suffix = 0; 1795218822Sdim } 1796104848Sobrien } 1797104848Sobrien 179894546Sobrien if (i.tm.opcode_modifier & FWait) 179994546Sobrien if (!add_prefix (FWAIT_OPCODE)) 180094546Sobrien return; 180194546Sobrien 180294546Sobrien /* Check string instruction segment overrides. */ 180394546Sobrien if ((i.tm.opcode_modifier & IsString) != 0 && i.mem_operands != 0) 180494546Sobrien { 180594546Sobrien if (!check_string ()) 180633965Sjdp return; 180794546Sobrien } 180833965Sjdp 180994546Sobrien if (!process_suffix ()) 181094546Sobrien return; 181160519Sobrien 181294546Sobrien /* Make still unresolved immediate matches conform to size of immediate 181394546Sobrien given in i.suffix. */ 181494546Sobrien if (!finalize_imm ()) 181594546Sobrien return; 181660519Sobrien 181794546Sobrien if (i.types[0] & Imm1) 181894546Sobrien i.imm_operands = 0; /* kludge for shift insns. */ 181994546Sobrien if (i.types[0] & ImplicitRegister) 182094546Sobrien i.reg_operands--; 182194546Sobrien if (i.types[1] & ImplicitRegister) 182294546Sobrien i.reg_operands--; 182394546Sobrien if (i.types[2] & ImplicitRegister) 182494546Sobrien i.reg_operands--; 182560519Sobrien 182694546Sobrien if (i.tm.opcode_modifier & ImmExt) 182794546Sobrien { 1828130570Sobrien expressionS *exp; 1829130570Sobrien 1830261175Spfg if ((i.tm.cpu_flags & (CpuSSE3|CpuSMAP)) && i.operands > 0) 1831130570Sobrien { 1832218822Sdim /* Streaming SIMD extensions 3 Instructions have the fixed 1833130570Sobrien operands with an opcode suffix which is coded in the same 1834130570Sobrien place as an 8-bit immediate field would be. Here we check 1835130570Sobrien those operands and remove them afterwards. */ 1836130570Sobrien unsigned int x; 1837130570Sobrien 1838130570Sobrien for (x = 0; x < i.operands; x++) 1839130570Sobrien if (i.op[x].regs->reg_num != x) 1840218822Sdim as_bad (_("can't use register '%s%s' as operand %d in '%s'."), 1841218822Sdim register_prefix, 1842218822Sdim i.op[x].regs->reg_name, 1843218822Sdim x + 1, 1844218822Sdim i.tm.name); 1845130570Sobrien i.operands = 0; 1846130570Sobrien } 1847130570Sobrien 184894546Sobrien /* These AMD 3DNow! and Intel Katmai New Instructions have an 184994546Sobrien opcode suffix which is coded in the same place as an 8-bit 185094546Sobrien immediate field would be. Here we fake an 8-bit immediate 185194546Sobrien operand from the opcode suffix stored in tm.extension_opcode. */ 185260519Sobrien 185394546Sobrien assert (i.imm_operands == 0 && i.operands <= 2 && 2 < MAX_OPERANDS); 185433965Sjdp 185594546Sobrien exp = &im_expressions[i.imm_operands++]; 185694546Sobrien i.op[i.operands].imms = exp; 185794546Sobrien i.types[i.operands++] = Imm8; 185894546Sobrien exp->X_op = O_constant; 185994546Sobrien exp->X_add_number = i.tm.extension_opcode; 186094546Sobrien i.tm.extension_opcode = None; 186194546Sobrien } 186233965Sjdp 186394546Sobrien /* For insns with operands there are more diddles to do to the opcode. */ 186494546Sobrien if (i.operands) 186594546Sobrien { 186694546Sobrien if (!process_operands ()) 186794546Sobrien return; 186894546Sobrien } 186994546Sobrien else if (!quiet_warnings && (i.tm.opcode_modifier & Ugh) != 0) 187094546Sobrien { 187194546Sobrien /* UnixWare fsub no args is alias for fsubp, fadd -> faddp, etc. */ 187294546Sobrien as_warn (_("translating to `%sp'"), i.tm.name); 187394546Sobrien } 187433965Sjdp 187594546Sobrien /* Handle conversion of 'int $3' --> special int3 insn. */ 187694546Sobrien if (i.tm.base_opcode == INT_OPCODE && i.op[0].imms->X_add_number == 3) 187794546Sobrien { 187894546Sobrien i.tm.base_opcode = INT3_OPCODE; 187994546Sobrien i.imm_operands = 0; 188094546Sobrien } 188133965Sjdp 188294546Sobrien if ((i.tm.opcode_modifier & (Jump | JumpByte | JumpDword)) 188394546Sobrien && i.op[0].disps->X_op == O_constant) 188494546Sobrien { 188594546Sobrien /* Convert "jmp constant" (and "call constant") to a jump (call) to 188694546Sobrien the absolute address given by the constant. Since ix86 jumps and 188794546Sobrien calls are pc relative, we need to generate a reloc. */ 188894546Sobrien i.op[0].disps->X_add_symbol = &abs_symbol; 188994546Sobrien i.op[0].disps->X_op = O_symbol; 189094546Sobrien } 189133965Sjdp 189294546Sobrien if ((i.tm.opcode_modifier & Rex64) != 0) 1893218822Sdim i.rex |= REX_W; 189433965Sjdp 189594546Sobrien /* For 8 bit registers we need an empty rex prefix. Also if the 189694546Sobrien instruction already has a prefix, we need to convert old 189794546Sobrien registers to new ones. */ 189860519Sobrien 189994546Sobrien if (((i.types[0] & Reg8) != 0 190094546Sobrien && (i.op[0].regs->reg_flags & RegRex64) != 0) 190194546Sobrien || ((i.types[1] & Reg8) != 0 190294546Sobrien && (i.op[1].regs->reg_flags & RegRex64) != 0) 190394546Sobrien || (((i.types[0] & Reg8) != 0 || (i.types[1] & Reg8) != 0) 190494546Sobrien && i.rex != 0)) 190594546Sobrien { 190694546Sobrien int x; 190760519Sobrien 190894546Sobrien i.rex |= REX_OPCODE; 190994546Sobrien for (x = 0; x < 2; x++) 191094546Sobrien { 191194546Sobrien /* Look for 8 bit operand that uses old registers. */ 191294546Sobrien if ((i.types[x] & Reg8) != 0 191394546Sobrien && (i.op[x].regs->reg_flags & RegRex64) == 0) 191494546Sobrien { 191594546Sobrien /* In case it is "hi" register, give up. */ 191694546Sobrien if (i.op[x].regs->reg_num > 3) 1917218822Sdim as_bad (_("can't encode register '%s%s' in an " 1918218822Sdim "instruction requiring REX prefix."), 1919218822Sdim register_prefix, i.op[x].regs->reg_name); 192060519Sobrien 192194546Sobrien /* Otherwise it is equivalent to the extended register. 192294546Sobrien Since the encoding doesn't change this is merely 192394546Sobrien cosmetic cleanup for debug output. */ 192460519Sobrien 192594546Sobrien i.op[x].regs = i.op[x].regs + 8; 192694546Sobrien } 192794546Sobrien } 192894546Sobrien } 192960519Sobrien 193094546Sobrien if (i.rex != 0) 193194546Sobrien add_prefix (REX_OPCODE | i.rex); 193294546Sobrien 193394546Sobrien /* We are ready to output the insn. */ 193494546Sobrien output_insn (); 193594546Sobrien} 193694546Sobrien 193794546Sobrienstatic char * 1938218822Sdimparse_insn (char *line, char *mnemonic) 193994546Sobrien{ 194094546Sobrien char *l = line; 194194546Sobrien char *token_start = l; 194294546Sobrien char *mnem_p; 1943218822Sdim int supported; 1944218822Sdim const template *t; 194594546Sobrien 194694546Sobrien /* Non-zero if we found a prefix only acceptable with string insns. */ 194794546Sobrien const char *expecting_string_instruction = NULL; 194894546Sobrien 194994546Sobrien while (1) 195094546Sobrien { 195194546Sobrien mnem_p = mnemonic; 195294546Sobrien while ((*mnem_p = mnemonic_chars[(unsigned char) *l]) != 0) 195394546Sobrien { 195494546Sobrien mnem_p++; 195594546Sobrien if (mnem_p >= mnemonic + MAX_MNEM_SIZE) 195660519Sobrien { 195794546Sobrien as_bad (_("no such instruction: `%s'"), token_start); 195894546Sobrien return NULL; 195994546Sobrien } 196094546Sobrien l++; 196194546Sobrien } 196294546Sobrien if (!is_space_char (*l) 196394546Sobrien && *l != END_OF_INSN 1964218822Sdim && (intel_syntax 1965218822Sdim || (*l != PREFIX_SEPARATOR 1966218822Sdim && *l != ','))) 196794546Sobrien { 196894546Sobrien as_bad (_("invalid character %s in mnemonic"), 196994546Sobrien output_invalid (*l)); 197094546Sobrien return NULL; 197194546Sobrien } 197294546Sobrien if (token_start == l) 197394546Sobrien { 1974218822Sdim if (!intel_syntax && *l == PREFIX_SEPARATOR) 197594546Sobrien as_bad (_("expecting prefix; got nothing")); 197694546Sobrien else 197794546Sobrien as_bad (_("expecting mnemonic; got nothing")); 197894546Sobrien return NULL; 197994546Sobrien } 198077311Sobrien 198194546Sobrien /* Look up instruction (or prefix) via hash table. */ 198294546Sobrien current_templates = hash_find (op_hash, mnemonic); 198394546Sobrien 198494546Sobrien if (*l != END_OF_INSN 198594546Sobrien && (!is_space_char (*l) || l[1] != END_OF_INSN) 198694546Sobrien && current_templates 198794546Sobrien && (current_templates->start->opcode_modifier & IsPrefix)) 198894546Sobrien { 1989218822Sdim if (current_templates->start->cpu_flags 1990218822Sdim & (flag_code != CODE_64BIT ? Cpu64 : CpuNo64)) 1991218822Sdim { 1992218822Sdim as_bad ((flag_code != CODE_64BIT 1993218822Sdim ? _("`%s' is only supported in 64-bit mode") 1994218822Sdim : _("`%s' is not supported in 64-bit mode")), 1995218822Sdim current_templates->start->name); 1996218822Sdim return NULL; 1997218822Sdim } 199894546Sobrien /* If we are in 16-bit mode, do not allow addr16 or data16. 199994546Sobrien Similarly, in 32-bit mode, do not allow addr32 or data32. */ 200094546Sobrien if ((current_templates->start->opcode_modifier & (Size16 | Size32)) 200194546Sobrien && flag_code != CODE_64BIT 200294546Sobrien && (((current_templates->start->opcode_modifier & Size32) != 0) 200394546Sobrien ^ (flag_code == CODE_16BIT))) 200494546Sobrien { 200594546Sobrien as_bad (_("redundant %s prefix"), 200694546Sobrien current_templates->start->name); 200794546Sobrien return NULL; 200877311Sobrien } 200994546Sobrien /* Add prefix, checking for repeated prefixes. */ 201094546Sobrien switch (add_prefix (current_templates->start->base_opcode)) 201194546Sobrien { 201294546Sobrien case 0: 201394546Sobrien return NULL; 201494546Sobrien case 2: 201594546Sobrien expecting_string_instruction = current_templates->start->name; 201694546Sobrien break; 201794546Sobrien } 201894546Sobrien /* Skip past PREFIX_SEPARATOR and reset token_start. */ 201994546Sobrien token_start = ++l; 202094546Sobrien } 202194546Sobrien else 202294546Sobrien break; 202394546Sobrien } 202460519Sobrien 202594546Sobrien if (!current_templates) 202694546Sobrien { 202794546Sobrien /* See if we can get a match by trimming off a suffix. */ 202894546Sobrien switch (mnem_p[-1]) 202994546Sobrien { 203094546Sobrien case WORD_MNEM_SUFFIX: 2031218822Sdim if (intel_syntax && (intel_float_operand (mnemonic) & 2)) 2032218822Sdim i.suffix = SHORT_MNEM_SUFFIX; 2033218822Sdim else 203494546Sobrien case BYTE_MNEM_SUFFIX: 203594546Sobrien case QWORD_MNEM_SUFFIX: 203694546Sobrien i.suffix = mnem_p[-1]; 203794546Sobrien mnem_p[-1] = '\0'; 203894546Sobrien current_templates = hash_find (op_hash, mnemonic); 203994546Sobrien break; 204094546Sobrien case SHORT_MNEM_SUFFIX: 204194546Sobrien case LONG_MNEM_SUFFIX: 204294546Sobrien if (!intel_syntax) 204394546Sobrien { 204494546Sobrien i.suffix = mnem_p[-1]; 204594546Sobrien mnem_p[-1] = '\0'; 204694546Sobrien current_templates = hash_find (op_hash, mnemonic); 204794546Sobrien } 204894546Sobrien break; 204977311Sobrien 205094546Sobrien /* Intel Syntax. */ 205194546Sobrien case 'd': 205294546Sobrien if (intel_syntax) 205377311Sobrien { 2054218822Sdim if (intel_float_operand (mnemonic) == 1) 205594546Sobrien i.suffix = SHORT_MNEM_SUFFIX; 205694546Sobrien else 205794546Sobrien i.suffix = LONG_MNEM_SUFFIX; 205894546Sobrien mnem_p[-1] = '\0'; 205994546Sobrien current_templates = hash_find (op_hash, mnemonic); 206094546Sobrien } 206194546Sobrien break; 206294546Sobrien } 206394546Sobrien if (!current_templates) 206494546Sobrien { 206594546Sobrien as_bad (_("no such instruction: `%s'"), token_start); 206694546Sobrien return NULL; 206794546Sobrien } 206894546Sobrien } 206977311Sobrien 207094546Sobrien if (current_templates->start->opcode_modifier & (Jump | JumpByte)) 207194546Sobrien { 207294546Sobrien /* Check for a branch hint. We allow ",pt" and ",pn" for 207394546Sobrien predict taken and predict not taken respectively. 207494546Sobrien I'm not sure that branch hints actually do anything on loop 207594546Sobrien and jcxz insns (JumpByte) for current Pentium4 chips. They 207694546Sobrien may work in the future and it doesn't hurt to accept them 207794546Sobrien now. */ 207894546Sobrien if (l[0] == ',' && l[1] == 'p') 207994546Sobrien { 208094546Sobrien if (l[2] == 't') 208194546Sobrien { 208294546Sobrien if (!add_prefix (DS_PREFIX_OPCODE)) 208394546Sobrien return NULL; 208494546Sobrien l += 3; 208594546Sobrien } 208694546Sobrien else if (l[2] == 'n') 208794546Sobrien { 208894546Sobrien if (!add_prefix (CS_PREFIX_OPCODE)) 208994546Sobrien return NULL; 209094546Sobrien l += 3; 209194546Sobrien } 209294546Sobrien } 209394546Sobrien } 209494546Sobrien /* Any other comma loses. */ 209594546Sobrien if (*l == ',') 209694546Sobrien { 209794546Sobrien as_bad (_("invalid character %s in mnemonic"), 209894546Sobrien output_invalid (*l)); 209994546Sobrien return NULL; 210094546Sobrien } 210177311Sobrien 210294546Sobrien /* Check if instruction is supported on specified architecture. */ 2103218822Sdim supported = 0; 2104218822Sdim for (t = current_templates->start; t < current_templates->end; ++t) 210594546Sobrien { 2106218822Sdim if (!((t->cpu_flags & ~(Cpu64 | CpuNo64)) 2107218822Sdim & ~(cpu_arch_flags & ~(Cpu64 | CpuNo64)))) 2108218822Sdim supported |= 1; 2109218822Sdim if (!(t->cpu_flags & (flag_code == CODE_64BIT ? CpuNo64 : Cpu64))) 2110218822Sdim supported |= 2; 211194546Sobrien } 2112218822Sdim if (!(supported & 2)) 2113218822Sdim { 2114218822Sdim as_bad (flag_code == CODE_64BIT 2115218822Sdim ? _("`%s' is not supported in 64-bit mode") 2116218822Sdim : _("`%s' is only supported in 64-bit mode"), 2117218822Sdim current_templates->start->name); 2118218822Sdim return NULL; 2119218822Sdim } 2120218822Sdim if (!(supported & 1)) 2121218822Sdim { 2122218822Sdim as_warn (_("`%s' is not supported on `%s%s'"), 2123218822Sdim current_templates->start->name, 2124218822Sdim cpu_arch_name, 2125218822Sdim cpu_sub_arch_name ? cpu_sub_arch_name : ""); 2126218822Sdim } 212794546Sobrien else if ((Cpu386 & ~cpu_arch_flags) && (flag_code != CODE_16BIT)) 212894546Sobrien { 212994546Sobrien as_warn (_("use .code16 to ensure correct addressing mode")); 213094546Sobrien } 213194546Sobrien 213294546Sobrien /* Check for rep/repne without a string instruction. */ 2133218822Sdim if (expecting_string_instruction) 213494546Sobrien { 2135218822Sdim static templates override; 2136218822Sdim 2137218822Sdim for (t = current_templates->start; t < current_templates->end; ++t) 2138218822Sdim if (t->opcode_modifier & IsString) 2139218822Sdim break; 2140218822Sdim if (t >= current_templates->end) 2141218822Sdim { 2142218822Sdim as_bad (_("expecting string instruction after `%s'"), 2143218822Sdim expecting_string_instruction); 2144218822Sdim return NULL; 2145218822Sdim } 2146218822Sdim for (override.start = t; t < current_templates->end; ++t) 2147218822Sdim if (!(t->opcode_modifier & IsString)) 2148218822Sdim break; 2149218822Sdim override.end = t; 2150218822Sdim current_templates = &override; 215194546Sobrien } 215294546Sobrien 215394546Sobrien return l; 215494546Sobrien} 215594546Sobrien 215694546Sobrienstatic char * 2157218822Sdimparse_operands (char *l, const char *mnemonic) 215894546Sobrien{ 215994546Sobrien char *token_start; 216094546Sobrien 216194546Sobrien /* 1 if operand is pending after ','. */ 216294546Sobrien unsigned int expecting_operand = 0; 216394546Sobrien 216494546Sobrien /* Non-zero if operand parens not balanced. */ 216594546Sobrien unsigned int paren_not_balanced; 216694546Sobrien 216794546Sobrien while (*l != END_OF_INSN) 216894546Sobrien { 216994546Sobrien /* Skip optional white space before operand. */ 217094546Sobrien if (is_space_char (*l)) 217194546Sobrien ++l; 217294546Sobrien if (!is_operand_char (*l) && *l != END_OF_INSN) 217394546Sobrien { 217494546Sobrien as_bad (_("invalid character %s before operand %d"), 217594546Sobrien output_invalid (*l), 217694546Sobrien i.operands + 1); 217794546Sobrien return NULL; 217894546Sobrien } 217994546Sobrien token_start = l; /* after white space */ 218094546Sobrien paren_not_balanced = 0; 218194546Sobrien while (paren_not_balanced || *l != ',') 218294546Sobrien { 218394546Sobrien if (*l == END_OF_INSN) 218494546Sobrien { 218594546Sobrien if (paren_not_balanced) 218677311Sobrien { 218794546Sobrien if (!intel_syntax) 218894546Sobrien as_bad (_("unbalanced parenthesis in operand %d."), 218994546Sobrien i.operands + 1); 219094546Sobrien else 219194546Sobrien as_bad (_("unbalanced brackets in operand %d."), 219294546Sobrien i.operands + 1); 219394546Sobrien return NULL; 219477311Sobrien } 219594546Sobrien else 219694546Sobrien break; /* we are done */ 219760519Sobrien } 219894546Sobrien else if (!is_operand_char (*l) && !is_space_char (*l)) 219994546Sobrien { 220094546Sobrien as_bad (_("invalid character %s in operand %d"), 220194546Sobrien output_invalid (*l), 220294546Sobrien i.operands + 1); 220394546Sobrien return NULL; 220494546Sobrien } 220594546Sobrien if (!intel_syntax) 220694546Sobrien { 220794546Sobrien if (*l == '(') 220894546Sobrien ++paren_not_balanced; 220994546Sobrien if (*l == ')') 221094546Sobrien --paren_not_balanced; 221194546Sobrien } 221294546Sobrien else 221394546Sobrien { 221494546Sobrien if (*l == '[') 221594546Sobrien ++paren_not_balanced; 221694546Sobrien if (*l == ']') 221794546Sobrien --paren_not_balanced; 221894546Sobrien } 221994546Sobrien l++; 222094546Sobrien } 222194546Sobrien if (l != token_start) 222294546Sobrien { /* Yes, we've read in another operand. */ 222394546Sobrien unsigned int operand_ok; 222494546Sobrien this_operand = i.operands++; 222594546Sobrien if (i.operands > MAX_OPERANDS) 222694546Sobrien { 222794546Sobrien as_bad (_("spurious operands; (%d operands/instruction max)"), 222894546Sobrien MAX_OPERANDS); 222994546Sobrien return NULL; 223094546Sobrien } 223194546Sobrien /* Now parse operand adding info to 'i' as we go along. */ 223294546Sobrien END_STRING_AND_SAVE (l); 223360519Sobrien 223494546Sobrien if (intel_syntax) 223594546Sobrien operand_ok = 223694546Sobrien i386_intel_operand (token_start, 223794546Sobrien intel_float_operand (mnemonic)); 223894546Sobrien else 223994546Sobrien operand_ok = i386_operand (token_start); 224060519Sobrien 224194546Sobrien RESTORE_END_STRING (l); 224294546Sobrien if (!operand_ok) 224394546Sobrien return NULL; 224494546Sobrien } 224594546Sobrien else 224694546Sobrien { 224794546Sobrien if (expecting_operand) 224894546Sobrien { 224994546Sobrien expecting_operand_after_comma: 225094546Sobrien as_bad (_("expecting operand after ','; got nothing")); 225194546Sobrien return NULL; 225294546Sobrien } 225394546Sobrien if (*l == ',') 225494546Sobrien { 225594546Sobrien as_bad (_("expecting operand before ','; got nothing")); 225694546Sobrien return NULL; 225794546Sobrien } 225894546Sobrien } 225960519Sobrien 226094546Sobrien /* Now *l must be either ',' or END_OF_INSN. */ 226194546Sobrien if (*l == ',') 226294546Sobrien { 226394546Sobrien if (*++l == END_OF_INSN) 226494546Sobrien { 226594546Sobrien /* Just skip it, if it's \n complain. */ 226694546Sobrien goto expecting_operand_after_comma; 226794546Sobrien } 226894546Sobrien expecting_operand = 1; 226994546Sobrien } 227094546Sobrien } 227194546Sobrien return l; 227294546Sobrien} 227360519Sobrien 227494546Sobrienstatic void 2275218822Sdimswap_2_operands (int xchg1, int xchg2) 227694546Sobrien{ 227794546Sobrien union i386_op temp_op; 227894546Sobrien unsigned int temp_type; 2279130570Sobrien enum bfd_reloc_code_real temp_reloc; 228094546Sobrien 228194546Sobrien temp_type = i.types[xchg2]; 228294546Sobrien i.types[xchg2] = i.types[xchg1]; 228394546Sobrien i.types[xchg1] = temp_type; 228494546Sobrien temp_op = i.op[xchg2]; 228594546Sobrien i.op[xchg2] = i.op[xchg1]; 228694546Sobrien i.op[xchg1] = temp_op; 228794546Sobrien temp_reloc = i.reloc[xchg2]; 228894546Sobrien i.reloc[xchg2] = i.reloc[xchg1]; 228994546Sobrien i.reloc[xchg1] = temp_reloc; 2290218822Sdim} 229194546Sobrien 2292218822Sdimstatic void 2293218822Sdimswap_operands (void) 2294218822Sdim{ 2295218822Sdim switch (i.operands) 2296218822Sdim { 2297218822Sdim case 4: 2298218822Sdim swap_2_operands (1, i.operands - 2); 2299218822Sdim case 3: 2300218822Sdim case 2: 2301218822Sdim swap_2_operands (0, i.operands - 1); 2302218822Sdim break; 2303218822Sdim default: 2304218822Sdim abort (); 2305218822Sdim } 2306218822Sdim 230794546Sobrien if (i.mem_operands == 2) 230894546Sobrien { 230994546Sobrien const seg_entry *temp_seg; 231094546Sobrien temp_seg = i.seg[0]; 231194546Sobrien i.seg[0] = i.seg[1]; 231294546Sobrien i.seg[1] = temp_seg; 231394546Sobrien } 231494546Sobrien} 231594546Sobrien 231694546Sobrien/* Try to ensure constant immediates are represented in the smallest 231794546Sobrien opcode possible. */ 231894546Sobrienstatic void 2319218822Sdimoptimize_imm (void) 232094546Sobrien{ 232194546Sobrien char guess_suffix = 0; 232294546Sobrien int op; 232394546Sobrien 232494546Sobrien if (i.suffix) 232594546Sobrien guess_suffix = i.suffix; 232694546Sobrien else if (i.reg_operands) 232794546Sobrien { 232894546Sobrien /* Figure out a suffix from the last register operand specified. 232994546Sobrien We can't do this properly yet, ie. excluding InOutPortReg, 233094546Sobrien but the following works for instructions with immediates. 233194546Sobrien In any case, we can't set i.suffix yet. */ 233294546Sobrien for (op = i.operands; --op >= 0;) 233394546Sobrien if (i.types[op] & Reg) 233477311Sobrien { 233594546Sobrien if (i.types[op] & Reg8) 233694546Sobrien guess_suffix = BYTE_MNEM_SUFFIX; 233794546Sobrien else if (i.types[op] & Reg16) 233894546Sobrien guess_suffix = WORD_MNEM_SUFFIX; 233994546Sobrien else if (i.types[op] & Reg32) 234094546Sobrien guess_suffix = LONG_MNEM_SUFFIX; 234194546Sobrien else if (i.types[op] & Reg64) 234294546Sobrien guess_suffix = QWORD_MNEM_SUFFIX; 234377311Sobrien break; 234477311Sobrien } 234594546Sobrien } 234694546Sobrien else if ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0)) 234794546Sobrien guess_suffix = WORD_MNEM_SUFFIX; 234833965Sjdp 234994546Sobrien for (op = i.operands; --op >= 0;) 235094546Sobrien if (i.types[op] & Imm) 235194546Sobrien { 235294546Sobrien switch (i.op[op].imms->X_op) 235333965Sjdp { 235494546Sobrien case O_constant: 235594546Sobrien /* If a suffix is given, this operand may be shortened. */ 235694546Sobrien switch (guess_suffix) 235733965Sjdp { 235894546Sobrien case LONG_MNEM_SUFFIX: 235994546Sobrien i.types[op] |= Imm32 | Imm64; 236094546Sobrien break; 236194546Sobrien case WORD_MNEM_SUFFIX: 236294546Sobrien i.types[op] |= Imm16 | Imm32S | Imm32 | Imm64; 236394546Sobrien break; 236494546Sobrien case BYTE_MNEM_SUFFIX: 236594546Sobrien i.types[op] |= Imm16 | Imm8 | Imm8S | Imm32S | Imm32 | Imm64; 236694546Sobrien break; 236794546Sobrien } 236833965Sjdp 236994546Sobrien /* If this operand is at most 16 bits, convert it 237094546Sobrien to a signed 16 bit number before trying to see 237194546Sobrien whether it will fit in an even smaller size. 237294546Sobrien This allows a 16-bit operand such as $0xffe0 to 237394546Sobrien be recognised as within Imm8S range. */ 237494546Sobrien if ((i.types[op] & Imm16) 237594546Sobrien && (i.op[op].imms->X_add_number & ~(offsetT) 0xffff) == 0) 237694546Sobrien { 237794546Sobrien i.op[op].imms->X_add_number = 237894546Sobrien (((i.op[op].imms->X_add_number & 0xffff) ^ 0x8000) - 0x8000); 237960519Sobrien } 238094546Sobrien if ((i.types[op] & Imm32) 238194546Sobrien && ((i.op[op].imms->X_add_number & ~(((offsetT) 2 << 31) - 1)) 238294546Sobrien == 0)) 238333965Sjdp { 238494546Sobrien i.op[op].imms->X_add_number = ((i.op[op].imms->X_add_number 238594546Sobrien ^ ((offsetT) 1 << 31)) 238694546Sobrien - ((offsetT) 1 << 31)); 238794546Sobrien } 238894546Sobrien i.types[op] |= smallest_imm_type (i.op[op].imms->X_add_number); 238960519Sobrien 239094546Sobrien /* We must avoid matching of Imm32 templates when 64bit 239194546Sobrien only immediate is available. */ 239294546Sobrien if (guess_suffix == QWORD_MNEM_SUFFIX) 239394546Sobrien i.types[op] &= ~Imm32; 239494546Sobrien break; 239594546Sobrien 239694546Sobrien case O_absent: 239794546Sobrien case O_register: 239894546Sobrien abort (); 239994546Sobrien 240094546Sobrien /* Symbols and expressions. */ 240194546Sobrien default: 2402218822Sdim /* Convert symbolic operand to proper sizes for matching, but don't 2403218822Sdim prevent matching a set of insns that only supports sizes other 2404218822Sdim than those matching the insn suffix. */ 2405218822Sdim { 2406218822Sdim unsigned int mask, allowed = 0; 2407218822Sdim const template *t; 2408218822Sdim 2409218822Sdim for (t = current_templates->start; 2410218822Sdim t < current_templates->end; 2411218822Sdim ++t) 2412218822Sdim allowed |= t->operand_types[op]; 2413218822Sdim switch (guess_suffix) 2414218822Sdim { 2415218822Sdim case QWORD_MNEM_SUFFIX: 2416218822Sdim mask = Imm64 | Imm32S; 2417218822Sdim break; 2418218822Sdim case LONG_MNEM_SUFFIX: 2419218822Sdim mask = Imm32; 2420218822Sdim break; 2421218822Sdim case WORD_MNEM_SUFFIX: 2422218822Sdim mask = Imm16; 2423218822Sdim break; 2424218822Sdim case BYTE_MNEM_SUFFIX: 2425218822Sdim mask = Imm8; 2426218822Sdim break; 2427218822Sdim default: 2428218822Sdim mask = 0; 2429218822Sdim break; 2430218822Sdim } 2431218822Sdim if (mask & allowed) 2432218822Sdim i.types[op] &= mask; 2433218822Sdim } 243494546Sobrien break; 243533965Sjdp } 243677311Sobrien } 243794546Sobrien} 243894546Sobrien 243994546Sobrien/* Try to use the smallest displacement type too. */ 244094546Sobrienstatic void 2441218822Sdimoptimize_disp (void) 244294546Sobrien{ 244394546Sobrien int op; 244494546Sobrien 244594546Sobrien for (op = i.operands; --op >= 0;) 2446218822Sdim if (i.types[op] & Disp) 244777311Sobrien { 2448218822Sdim if (i.op[op].disps->X_op == O_constant) 244977311Sobrien { 2450218822Sdim offsetT disp = i.op[op].disps->X_add_number; 245194546Sobrien 2452218822Sdim if ((i.types[op] & Disp16) 2453218822Sdim && (disp & ~(offsetT) 0xffff) == 0) 2454218822Sdim { 2455218822Sdim /* If this operand is at most 16 bits, convert 2456218822Sdim to a signed 16 bit number and don't use 64bit 2457218822Sdim displacement. */ 2458218822Sdim disp = (((disp & 0xffff) ^ 0x8000) - 0x8000); 2459218822Sdim i.types[op] &= ~Disp64; 2460218822Sdim } 2461218822Sdim if ((i.types[op] & Disp32) 2462218822Sdim && (disp & ~(((offsetT) 2 << 31) - 1)) == 0) 2463218822Sdim { 2464218822Sdim /* If this operand is at most 32 bits, convert 2465218822Sdim to a signed 32 bit number and don't use 64bit 2466218822Sdim displacement. */ 2467218822Sdim disp &= (((offsetT) 2 << 31) - 1); 2468218822Sdim disp = (disp ^ ((offsetT) 1 << 31)) - ((addressT) 1 << 31); 2469218822Sdim i.types[op] &= ~Disp64; 2470218822Sdim } 2471218822Sdim if (!disp && (i.types[op] & BaseIndex)) 2472218822Sdim { 2473218822Sdim i.types[op] &= ~Disp; 2474218822Sdim i.op[op].disps = 0; 2475218822Sdim i.disp_operands--; 2476218822Sdim } 2477218822Sdim else if (flag_code == CODE_64BIT) 2478218822Sdim { 2479218822Sdim if (fits_in_signed_long (disp)) 2480218822Sdim { 2481218822Sdim i.types[op] &= ~Disp64; 2482218822Sdim i.types[op] |= Disp32S; 2483218822Sdim } 2484218822Sdim if (fits_in_unsigned_long (disp)) 2485218822Sdim i.types[op] |= Disp32; 2486218822Sdim } 2487218822Sdim if ((i.types[op] & (Disp32 | Disp32S | Disp16)) 2488218822Sdim && fits_in_signed_byte (disp)) 2489218822Sdim i.types[op] |= Disp8; 249077311Sobrien } 2491218822Sdim else if (i.reloc[op] == BFD_RELOC_386_TLS_DESC_CALL 2492218822Sdim || i.reloc[op] == BFD_RELOC_X86_64_TLSDESC_CALL) 249377311Sobrien { 2494218822Sdim fix_new_exp (frag_now, frag_more (0) - frag_now->fr_literal, 0, 2495218822Sdim i.op[op].disps, 0, i.reloc[op]); 2496218822Sdim i.types[op] &= ~Disp; 249777311Sobrien } 2498218822Sdim else 2499218822Sdim /* We only support 64bit displacement on constants. */ 2500218822Sdim i.types[op] &= ~Disp64; 250160519Sobrien } 250294546Sobrien} 250360519Sobrien 250494546Sobrienstatic int 2505218822Sdimmatch_template (void) 250694546Sobrien{ 250794546Sobrien /* Points to template once we've found it. */ 250894546Sobrien const template *t; 2509218822Sdim unsigned int overlap0, overlap1, overlap2, overlap3; 251094546Sobrien unsigned int found_reverse_match; 251194546Sobrien int suffix_check; 2512218822Sdim unsigned int operand_types [MAX_OPERANDS]; 2513218822Sdim int addr_prefix_disp; 2514218822Sdim unsigned int j; 251560519Sobrien 2516218822Sdim#if MAX_OPERANDS != 4 2517218822Sdim# error "MAX_OPERANDS must be 4." 2518218822Sdim#endif 2519218822Sdim 252094546Sobrien#define MATCH(overlap, given, template) \ 252194546Sobrien ((overlap & ~JumpAbsolute) \ 252294546Sobrien && (((given) & (BaseIndex | JumpAbsolute)) \ 252394546Sobrien == ((overlap) & (BaseIndex | JumpAbsolute)))) 252460519Sobrien 252594546Sobrien /* If given types r0 and r1 are registers they must be of the same type 252694546Sobrien unless the expected operand type register overlap is null. 252794546Sobrien Note that Acc in a template matches every size of reg. */ 252894546Sobrien#define CONSISTENT_REGISTER_MATCH(m0, g0, t0, m1, g1, t1) \ 252994546Sobrien (((g0) & Reg) == 0 || ((g1) & Reg) == 0 \ 253094546Sobrien || ((g0) & Reg) == ((g1) & Reg) \ 253194546Sobrien || ((((m0) & Acc) ? Reg : (t0)) & (((m1) & Acc) ? Reg : (t1)) & Reg) == 0 ) 253238891Sjdp 253394546Sobrien overlap0 = 0; 253494546Sobrien overlap1 = 0; 253594546Sobrien overlap2 = 0; 2536218822Sdim overlap3 = 0; 253794546Sobrien found_reverse_match = 0; 2538218822Sdim for (j = 0; j < MAX_OPERANDS; j++) 2539218822Sdim operand_types [j] = 0; 2540218822Sdim addr_prefix_disp = -1; 254194546Sobrien suffix_check = (i.suffix == BYTE_MNEM_SUFFIX 254294546Sobrien ? No_bSuf 254394546Sobrien : (i.suffix == WORD_MNEM_SUFFIX 254494546Sobrien ? No_wSuf 254594546Sobrien : (i.suffix == SHORT_MNEM_SUFFIX 254694546Sobrien ? No_sSuf 254794546Sobrien : (i.suffix == LONG_MNEM_SUFFIX 254894546Sobrien ? No_lSuf 254994546Sobrien : (i.suffix == QWORD_MNEM_SUFFIX 255094546Sobrien ? No_qSuf 255194546Sobrien : (i.suffix == LONG_DOUBLE_MNEM_SUFFIX 255294546Sobrien ? No_xSuf : 0)))))); 255360519Sobrien 2554218822Sdim for (t = current_templates->start; t < current_templates->end; t++) 255594546Sobrien { 2556218822Sdim addr_prefix_disp = -1; 2557218822Sdim 255894546Sobrien /* Must have right number of operands. */ 255994546Sobrien if (i.operands != t->operands) 256094546Sobrien continue; 256160519Sobrien 256294546Sobrien /* Check the suffix, except for some instructions in intel mode. */ 256394546Sobrien if ((t->opcode_modifier & suffix_check) 256494546Sobrien && !(intel_syntax 2565218822Sdim && (t->opcode_modifier & IgnoreSize))) 256694546Sobrien continue; 256794546Sobrien 2568218822Sdim for (j = 0; j < MAX_OPERANDS; j++) 2569218822Sdim operand_types [j] = t->operand_types [j]; 2570218822Sdim 2571218822Sdim /* In general, don't allow 64-bit operands in 32-bit mode. */ 2572218822Sdim if (i.suffix == QWORD_MNEM_SUFFIX 2573218822Sdim && flag_code != CODE_64BIT 2574218822Sdim && (intel_syntax 2575218822Sdim ? (!(t->opcode_modifier & IgnoreSize) 2576218822Sdim && !intel_float_operand (t->name)) 2577218822Sdim : intel_float_operand (t->name) != 2) 2578218822Sdim && (!(operand_types[0] & (RegMMX | RegXMM)) 2579218822Sdim || !(operand_types[t->operands > 1] & (RegMMX | RegXMM))) 2580218822Sdim && (t->base_opcode != 0x0fc7 2581218822Sdim || t->extension_opcode != 1 /* cmpxchg8b */)) 2582218822Sdim continue; 2583218822Sdim 258494546Sobrien /* Do not verify operands when there are none. */ 258594546Sobrien else if (!t->operands) 258694546Sobrien { 258794546Sobrien if (t->cpu_flags & ~cpu_arch_flags) 258894546Sobrien continue; 258994546Sobrien /* We've found a match; break out of loop. */ 259094546Sobrien break; 259194546Sobrien } 259294546Sobrien 2593218822Sdim /* Address size prefix will turn Disp64/Disp32/Disp16 operand 2594218822Sdim into Disp32/Disp16/Disp32 operand. */ 2595218822Sdim if (i.prefix[ADDR_PREFIX] != 0) 2596218822Sdim { 2597218822Sdim unsigned int DispOn = 0, DispOff = 0; 2598218822Sdim 2599218822Sdim switch (flag_code) 2600218822Sdim { 2601218822Sdim case CODE_16BIT: 2602218822Sdim DispOn = Disp32; 2603218822Sdim DispOff = Disp16; 2604218822Sdim break; 2605218822Sdim case CODE_32BIT: 2606218822Sdim DispOn = Disp16; 2607218822Sdim DispOff = Disp32; 2608218822Sdim break; 2609218822Sdim case CODE_64BIT: 2610218822Sdim DispOn = Disp32; 2611218822Sdim DispOff = Disp64; 2612218822Sdim break; 2613218822Sdim } 2614218822Sdim 2615218822Sdim for (j = 0; j < MAX_OPERANDS; j++) 2616218822Sdim { 2617218822Sdim /* There should be only one Disp operand. */ 2618218822Sdim if ((operand_types[j] & DispOff)) 2619218822Sdim { 2620218822Sdim addr_prefix_disp = j; 2621218822Sdim operand_types[j] |= DispOn; 2622218822Sdim operand_types[j] &= ~DispOff; 2623218822Sdim break; 2624218822Sdim } 2625218822Sdim } 2626218822Sdim } 2627218822Sdim 2628218822Sdim overlap0 = i.types[0] & operand_types[0]; 262994546Sobrien switch (t->operands) 263094546Sobrien { 263194546Sobrien case 1: 2632218822Sdim if (!MATCH (overlap0, i.types[0], operand_types[0])) 263394546Sobrien continue; 263494546Sobrien break; 263594546Sobrien case 2: 2636218822Sdim /* xchg %eax, %eax is a special case. It is an aliase for nop 2637218822Sdim only in 32bit mode and we can use opcode 0x90. In 64bit 2638218822Sdim mode, we can't use 0x90 for xchg %eax, %eax since it should 2639218822Sdim zero-extend %eax to %rax. */ 2640218822Sdim if (flag_code == CODE_64BIT 2641218822Sdim && t->base_opcode == 0x90 2642218822Sdim && i.types [0] == (Acc | Reg32) 2643218822Sdim && i.types [1] == (Acc | Reg32)) 2644218822Sdim continue; 264594546Sobrien case 3: 2646218822Sdim case 4: 2647218822Sdim overlap1 = i.types[1] & operand_types[1]; 2648218822Sdim if (!MATCH (overlap0, i.types[0], operand_types[0]) 2649218822Sdim || !MATCH (overlap1, i.types[1], operand_types[1]) 2650218822Sdim /* monitor in SSE3 is a very special case. The first 2651218822Sdim register and the second register may have different 2652218822Sdim sizes. The same applies to crc32 in SSE4.2. */ 2653218822Sdim || !((t->base_opcode == 0x0f01 2654218822Sdim && t->extension_opcode == 0xc8) 2655218822Sdim || t->base_opcode == 0xf20f38f1 2656218822Sdim || CONSISTENT_REGISTER_MATCH (overlap0, i.types[0], 2657218822Sdim operand_types[0], 2658218822Sdim overlap1, i.types[1], 2659218822Sdim operand_types[1]))) 266094546Sobrien { 266194546Sobrien /* Check if other direction is valid ... */ 266294546Sobrien if ((t->opcode_modifier & (D | FloatD)) == 0) 266394546Sobrien continue; 266494546Sobrien 266594546Sobrien /* Try reversing direction of operands. */ 2666218822Sdim overlap0 = i.types[0] & operand_types[1]; 2667218822Sdim overlap1 = i.types[1] & operand_types[0]; 2668218822Sdim if (!MATCH (overlap0, i.types[0], operand_types[1]) 2669218822Sdim || !MATCH (overlap1, i.types[1], operand_types[0]) 267094546Sobrien || !CONSISTENT_REGISTER_MATCH (overlap0, i.types[0], 2671218822Sdim operand_types[1], 267294546Sobrien overlap1, i.types[1], 2673218822Sdim operand_types[0])) 267494546Sobrien { 267594546Sobrien /* Does not match either direction. */ 267694546Sobrien continue; 267794546Sobrien } 267894546Sobrien /* found_reverse_match holds which of D or FloatDR 267994546Sobrien we've found. */ 2680218822Sdim if ((t->opcode_modifier & D)) 2681218822Sdim found_reverse_match = Opcode_D; 2682218822Sdim else if ((t->opcode_modifier & FloatD)) 2683218822Sdim found_reverse_match = Opcode_FloatD; 2684218822Sdim else 2685218822Sdim found_reverse_match = 0; 2686218822Sdim if ((t->opcode_modifier & FloatR)) 2687218822Sdim found_reverse_match |= Opcode_FloatR; 268894546Sobrien } 2689218822Sdim else 269094546Sobrien { 2691218822Sdim /* Found a forward 2 operand match here. */ 2692218822Sdim switch (t->operands) 2693218822Sdim { 2694218822Sdim case 4: 2695218822Sdim overlap3 = i.types[3] & operand_types[3]; 2696218822Sdim case 3: 2697218822Sdim overlap2 = i.types[2] & operand_types[2]; 2698218822Sdim break; 2699218822Sdim } 270094546Sobrien 2701218822Sdim switch (t->operands) 2702218822Sdim { 2703218822Sdim case 4: 2704218822Sdim if (!MATCH (overlap3, i.types[3], operand_types[3]) 2705218822Sdim || !CONSISTENT_REGISTER_MATCH (overlap2, 2706218822Sdim i.types[2], 2707218822Sdim operand_types[2], 2708218822Sdim overlap3, 2709218822Sdim i.types[3], 2710218822Sdim operand_types[3])) 2711218822Sdim continue; 2712218822Sdim case 3: 2713218822Sdim /* Here we make use of the fact that there are no 2714218822Sdim reverse match 3 operand instructions, and all 3 2715218822Sdim operand instructions only need to be checked for 2716218822Sdim register consistency between operands 2 and 3. */ 2717218822Sdim if (!MATCH (overlap2, i.types[2], operand_types[2]) 2718218822Sdim || !CONSISTENT_REGISTER_MATCH (overlap1, 2719218822Sdim i.types[1], 2720218822Sdim operand_types[1], 2721218822Sdim overlap2, 2722218822Sdim i.types[2], 2723218822Sdim operand_types[2])) 2724218822Sdim continue; 2725218822Sdim break; 2726218822Sdim } 272794546Sobrien } 2728218822Sdim /* Found either forward/reverse 2, 3 or 4 operand match here: 272994546Sobrien slip through to break. */ 273094546Sobrien } 273194546Sobrien if (t->cpu_flags & ~cpu_arch_flags) 273294546Sobrien { 273394546Sobrien found_reverse_match = 0; 273494546Sobrien continue; 273594546Sobrien } 273694546Sobrien /* We've found a match; break out of loop. */ 273794546Sobrien break; 273894546Sobrien } 273994546Sobrien 274094546Sobrien if (t == current_templates->end) 274194546Sobrien { 274294546Sobrien /* We found no match. */ 274394546Sobrien as_bad (_("suffix or operands invalid for `%s'"), 274494546Sobrien current_templates->start->name); 274594546Sobrien return 0; 274694546Sobrien } 274794546Sobrien 274894546Sobrien if (!quiet_warnings) 274994546Sobrien { 275094546Sobrien if (!intel_syntax 275194546Sobrien && ((i.types[0] & JumpAbsolute) 2752218822Sdim != (operand_types[0] & JumpAbsolute))) 275394546Sobrien { 275494546Sobrien as_warn (_("indirect %s without `*'"), t->name); 275594546Sobrien } 275694546Sobrien 275794546Sobrien if ((t->opcode_modifier & (IsPrefix | IgnoreSize)) 275894546Sobrien == (IsPrefix | IgnoreSize)) 275994546Sobrien { 276094546Sobrien /* Warn them that a data or address size prefix doesn't 276194546Sobrien affect assembly of the next line of code. */ 276294546Sobrien as_warn (_("stand-alone `%s' prefix"), t->name); 276394546Sobrien } 276494546Sobrien } 276594546Sobrien 276694546Sobrien /* Copy the template we found. */ 276794546Sobrien i.tm = *t; 2768218822Sdim 2769218822Sdim if (addr_prefix_disp != -1) 2770218822Sdim i.tm.operand_types[addr_prefix_disp] 2771218822Sdim = operand_types[addr_prefix_disp]; 2772218822Sdim 277394546Sobrien if (found_reverse_match) 277494546Sobrien { 277594546Sobrien /* If we found a reverse match we must alter the opcode 277694546Sobrien direction bit. found_reverse_match holds bits to change 277794546Sobrien (different for int & float insns). */ 277894546Sobrien 277994546Sobrien i.tm.base_opcode ^= found_reverse_match; 278094546Sobrien 2781218822Sdim i.tm.operand_types[0] = operand_types[1]; 2782218822Sdim i.tm.operand_types[1] = operand_types[0]; 278394546Sobrien } 278494546Sobrien 278594546Sobrien return 1; 278694546Sobrien} 278794546Sobrien 278894546Sobrienstatic int 2789218822Sdimcheck_string (void) 279094546Sobrien{ 279194546Sobrien int mem_op = (i.types[0] & AnyMem) ? 0 : 1; 279294546Sobrien if ((i.tm.operand_types[mem_op] & EsSeg) != 0) 279394546Sobrien { 279494546Sobrien if (i.seg[0] != NULL && i.seg[0] != &es) 279594546Sobrien { 279694546Sobrien as_bad (_("`%s' operand %d must use `%%es' segment"), 279794546Sobrien i.tm.name, 279894546Sobrien mem_op + 1); 279994546Sobrien return 0; 280094546Sobrien } 280194546Sobrien /* There's only ever one segment override allowed per instruction. 280294546Sobrien This instruction possibly has a legal segment override on the 280394546Sobrien second operand, so copy the segment to where non-string 280494546Sobrien instructions store it, allowing common code. */ 280594546Sobrien i.seg[0] = i.seg[1]; 280694546Sobrien } 280794546Sobrien else if ((i.tm.operand_types[mem_op + 1] & EsSeg) != 0) 280894546Sobrien { 280994546Sobrien if (i.seg[1] != NULL && i.seg[1] != &es) 281094546Sobrien { 281194546Sobrien as_bad (_("`%s' operand %d must use `%%es' segment"), 281294546Sobrien i.tm.name, 281394546Sobrien mem_op + 2); 281494546Sobrien return 0; 281594546Sobrien } 281694546Sobrien } 281794546Sobrien return 1; 281894546Sobrien} 281994546Sobrien 282094546Sobrienstatic int 2821218822Sdimprocess_suffix (void) 282294546Sobrien{ 282394546Sobrien /* If matched instruction specifies an explicit instruction mnemonic 282494546Sobrien suffix, use it. */ 282594546Sobrien if (i.tm.opcode_modifier & (Size16 | Size32 | Size64)) 282694546Sobrien { 282794546Sobrien if (i.tm.opcode_modifier & Size16) 282894546Sobrien i.suffix = WORD_MNEM_SUFFIX; 282994546Sobrien else if (i.tm.opcode_modifier & Size64) 283094546Sobrien i.suffix = QWORD_MNEM_SUFFIX; 283194546Sobrien else 283294546Sobrien i.suffix = LONG_MNEM_SUFFIX; 283394546Sobrien } 283494546Sobrien else if (i.reg_operands) 283594546Sobrien { 283694546Sobrien /* If there's no instruction mnemonic suffix we try to invent one 283794546Sobrien based on register operands. */ 283894546Sobrien if (!i.suffix) 283994546Sobrien { 284094546Sobrien /* We take i.suffix from the last register operand specified, 284194546Sobrien Destination register type is more significant than source 2842218822Sdim register type. crc32 in SSE4.2 prefers source register 2843218822Sdim type. */ 2844218822Sdim if (i.tm.base_opcode == 0xf20f38f1) 2845218822Sdim { 2846218822Sdim if ((i.types[0] & Reg)) 2847218822Sdim i.suffix = ((i.types[0] & Reg16) ? WORD_MNEM_SUFFIX : 284894546Sobrien LONG_MNEM_SUFFIX); 2849218822Sdim } 2850218822Sdim else if (i.tm.base_opcode == 0xf20f38f0) 2851218822Sdim { 2852218822Sdim if ((i.types[0] & Reg8)) 2853218822Sdim i.suffix = BYTE_MNEM_SUFFIX; 2854218822Sdim } 2855218822Sdim 2856218822Sdim if (!i.suffix) 2857218822Sdim { 2858218822Sdim int op; 2859218822Sdim 2860218822Sdim if (i.tm.base_opcode == 0xf20f38f1 2861218822Sdim || i.tm.base_opcode == 0xf20f38f0) 2862218822Sdim { 2863218822Sdim /* We have to know the operand size for crc32. */ 2864218822Sdim as_bad (_("ambiguous memory operand size for `%s`"), 2865218822Sdim i.tm.name); 2866218822Sdim return 0; 2867218822Sdim } 2868218822Sdim 2869218822Sdim for (op = i.operands; --op >= 0;) 2870218822Sdim if ((i.types[op] & Reg) 2871218822Sdim && !(i.tm.operand_types[op] & InOutPortReg)) 2872218822Sdim { 2873218822Sdim i.suffix = ((i.types[op] & Reg8) ? BYTE_MNEM_SUFFIX : 2874218822Sdim (i.types[op] & Reg16) ? WORD_MNEM_SUFFIX : 2875218822Sdim (i.types[op] & Reg64) ? QWORD_MNEM_SUFFIX : 2876218822Sdim LONG_MNEM_SUFFIX); 2877218822Sdim break; 2878218822Sdim } 2879218822Sdim } 288094546Sobrien } 288194546Sobrien else if (i.suffix == BYTE_MNEM_SUFFIX) 288294546Sobrien { 288394546Sobrien if (!check_byte_reg ()) 288494546Sobrien return 0; 288594546Sobrien } 288694546Sobrien else if (i.suffix == LONG_MNEM_SUFFIX) 288794546Sobrien { 288894546Sobrien if (!check_long_reg ()) 288994546Sobrien return 0; 289094546Sobrien } 289194546Sobrien else if (i.suffix == QWORD_MNEM_SUFFIX) 289294546Sobrien { 289394546Sobrien if (!check_qword_reg ()) 289494546Sobrien return 0; 289594546Sobrien } 289694546Sobrien else if (i.suffix == WORD_MNEM_SUFFIX) 289794546Sobrien { 289894546Sobrien if (!check_word_reg ()) 289994546Sobrien return 0; 290094546Sobrien } 290194546Sobrien else if (intel_syntax && (i.tm.opcode_modifier & IgnoreSize)) 290294546Sobrien /* Do nothing if the instruction is going to ignore the prefix. */ 290394546Sobrien ; 290494546Sobrien else 290594546Sobrien abort (); 290694546Sobrien } 2907218822Sdim else if ((i.tm.opcode_modifier & DefaultSize) 2908218822Sdim && !i.suffix 2909218822Sdim /* exclude fldenv/frstor/fsave/fstenv */ 2910218822Sdim && (i.tm.opcode_modifier & No_sSuf)) 291194546Sobrien { 291294546Sobrien i.suffix = stackop_size; 291394546Sobrien } 2914218822Sdim else if (intel_syntax 2915218822Sdim && !i.suffix 2916218822Sdim && ((i.tm.operand_types[0] & JumpAbsolute) 2917218822Sdim || (i.tm.opcode_modifier & (JumpByte|JumpInterSegment)) 2918218822Sdim || (i.tm.base_opcode == 0x0f01 /* [ls][gi]dt */ 2919218822Sdim && i.tm.extension_opcode <= 3))) 2920218822Sdim { 2921218822Sdim switch (flag_code) 2922218822Sdim { 2923218822Sdim case CODE_64BIT: 2924218822Sdim if (!(i.tm.opcode_modifier & No_qSuf)) 2925218822Sdim { 2926218822Sdim i.suffix = QWORD_MNEM_SUFFIX; 2927218822Sdim break; 2928218822Sdim } 2929218822Sdim case CODE_32BIT: 2930218822Sdim if (!(i.tm.opcode_modifier & No_lSuf)) 2931218822Sdim i.suffix = LONG_MNEM_SUFFIX; 2932218822Sdim break; 2933218822Sdim case CODE_16BIT: 2934218822Sdim if (!(i.tm.opcode_modifier & No_wSuf)) 2935218822Sdim i.suffix = WORD_MNEM_SUFFIX; 2936218822Sdim break; 2937218822Sdim } 2938218822Sdim } 293933965Sjdp 2940218822Sdim if (!i.suffix) 2941218822Sdim { 2942218822Sdim if (!intel_syntax) 2943218822Sdim { 2944218822Sdim if (i.tm.opcode_modifier & W) 2945218822Sdim { 2946218822Sdim as_bad (_("no instruction mnemonic suffix given and " 2947218822Sdim "no register operands; can't size instruction")); 2948218822Sdim return 0; 2949218822Sdim } 2950218822Sdim } 2951218822Sdim else 2952218822Sdim { 2953218822Sdim unsigned int suffixes = (~i.tm.opcode_modifier 2954218822Sdim & (No_bSuf 2955218822Sdim | No_wSuf 2956218822Sdim | No_lSuf 2957218822Sdim | No_sSuf 2958218822Sdim | No_xSuf 2959218822Sdim | No_qSuf)); 296094546Sobrien 2961218822Sdim if ((i.tm.opcode_modifier & W) 2962218822Sdim || ((suffixes & (suffixes - 1)) 2963218822Sdim && !(i.tm.opcode_modifier & (DefaultSize | IgnoreSize)))) 2964218822Sdim { 2965218822Sdim as_bad (_("ambiguous operand size for `%s'"), i.tm.name); 2966218822Sdim return 0; 2967218822Sdim } 2968218822Sdim } 296994546Sobrien } 297094546Sobrien 2971218822Sdim /* Change the opcode based on the operand size given by i.suffix; 2972218822Sdim We don't need to change things for byte insns. */ 2973218822Sdim 297494546Sobrien if (i.suffix && i.suffix != BYTE_MNEM_SUFFIX) 297594546Sobrien { 297694546Sobrien /* It's not a byte, select word/dword operation. */ 297794546Sobrien if (i.tm.opcode_modifier & W) 297894546Sobrien { 297994546Sobrien if (i.tm.opcode_modifier & ShortForm) 298094546Sobrien i.tm.base_opcode |= 8; 298194546Sobrien else 298294546Sobrien i.tm.base_opcode |= 1; 298394546Sobrien } 298499468Sobrien 298594546Sobrien /* Now select between word & dword operations via the operand 298694546Sobrien size prefix, except for instructions that will ignore this 298794546Sobrien prefix anyway. */ 2988218822Sdim if (i.tm.base_opcode == 0x0f01 && i.tm.extension_opcode == 0xc8) 298994546Sobrien { 2990218822Sdim /* monitor in SSE3 is a very special case. The default size 2991218822Sdim of AX is the size of mode. The address size override 2992218822Sdim prefix will change the size of AX. */ 2993218822Sdim if (i.op->regs[0].reg_type & 2994218822Sdim (flag_code == CODE_32BIT ? Reg16 : Reg32)) 2995218822Sdim if (!add_prefix (ADDR_PREFIX_OPCODE)) 2996218822Sdim return 0; 2997218822Sdim } 2998218822Sdim else if (i.suffix != QWORD_MNEM_SUFFIX 2999218822Sdim && i.suffix != LONG_DOUBLE_MNEM_SUFFIX 3000218822Sdim && !(i.tm.opcode_modifier & (IgnoreSize | FloatMF)) 3001218822Sdim && ((i.suffix == LONG_MNEM_SUFFIX) == (flag_code == CODE_16BIT) 3002218822Sdim || (flag_code == CODE_64BIT 3003218822Sdim && (i.tm.opcode_modifier & JumpByte)))) 3004218822Sdim { 300594546Sobrien unsigned int prefix = DATA_PREFIX_OPCODE; 3006218822Sdim 300794546Sobrien if (i.tm.opcode_modifier & JumpByte) /* jcxz, loop */ 300894546Sobrien prefix = ADDR_PREFIX_OPCODE; 300933965Sjdp 301094546Sobrien if (!add_prefix (prefix)) 301194546Sobrien return 0; 301294546Sobrien } 301394546Sobrien 301494546Sobrien /* Set mode64 for an operand. */ 301594546Sobrien if (i.suffix == QWORD_MNEM_SUFFIX 3016104848Sobrien && flag_code == CODE_64BIT 301794546Sobrien && (i.tm.opcode_modifier & NoRex64) == 0) 3018218822Sdim { 3019218822Sdim /* Special case for xchg %rax,%rax. It is NOP and doesn't 3020218822Sdim need rex64. */ 3021218822Sdim if (i.operands != 2 3022218822Sdim || i.types [0] != (Acc | Reg64) 3023218822Sdim || i.types [1] != (Acc | Reg64) 3024218822Sdim || i.tm.base_opcode != 0x90) 3025218822Sdim i.rex |= REX_W; 3026218822Sdim } 302794546Sobrien 302894546Sobrien /* Size floating point instruction. */ 302994546Sobrien if (i.suffix == LONG_MNEM_SUFFIX) 3030218822Sdim if (i.tm.opcode_modifier & FloatMF) 3031218822Sdim i.tm.base_opcode ^= 4; 303294546Sobrien } 303394546Sobrien 303494546Sobrien return 1; 303594546Sobrien} 303694546Sobrien 303794546Sobrienstatic int 3038218822Sdimcheck_byte_reg (void) 303994546Sobrien{ 304094546Sobrien int op; 3041218822Sdim 304294546Sobrien for (op = i.operands; --op >= 0;) 304394546Sobrien { 304494546Sobrien /* If this is an eight bit register, it's OK. If it's the 16 or 304594546Sobrien 32 bit version of an eight bit register, we will just use the 304694546Sobrien low portion, and that's OK too. */ 304794546Sobrien if (i.types[op] & Reg8) 304894546Sobrien continue; 304994546Sobrien 305094546Sobrien /* movzx and movsx should not generate this warning. */ 305194546Sobrien if (intel_syntax 305294546Sobrien && (i.tm.base_opcode == 0xfb7 305394546Sobrien || i.tm.base_opcode == 0xfb6 305494546Sobrien || i.tm.base_opcode == 0x63 305594546Sobrien || i.tm.base_opcode == 0xfbe 305694546Sobrien || i.tm.base_opcode == 0xfbf)) 305794546Sobrien continue; 305894546Sobrien 3059218822Sdim /* crc32 doesn't generate this warning. */ 3060218822Sdim if (i.tm.base_opcode == 0xf20f38f0) 3061218822Sdim continue; 3062218822Sdim 3063218822Sdim if ((i.types[op] & WordReg) && i.op[op].regs->reg_num < 4) 306494546Sobrien { 306594546Sobrien /* Prohibit these changes in the 64bit mode, since the 306694546Sobrien lowering is more complicated. */ 306794546Sobrien if (flag_code == CODE_64BIT 306894546Sobrien && (i.tm.operand_types[op] & InOutPortReg) == 0) 306994546Sobrien { 3070218822Sdim as_bad (_("Incorrect register `%s%s' used with `%c' suffix"), 3071218822Sdim register_prefix, i.op[op].regs->reg_name, 307294546Sobrien i.suffix); 307394546Sobrien return 0; 307494546Sobrien } 307560519Sobrien#if REGISTER_WARNINGS 307694546Sobrien if (!quiet_warnings 307794546Sobrien && (i.tm.operand_types[op] & InOutPortReg) == 0) 3078218822Sdim as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"), 3079218822Sdim register_prefix, 308094546Sobrien (i.op[op].regs + (i.types[op] & Reg16 308194546Sobrien ? REGNAM_AL - REGNAM_AX 308294546Sobrien : REGNAM_AL - REGNAM_EAX))->reg_name, 3083218822Sdim register_prefix, 308494546Sobrien i.op[op].regs->reg_name, 308594546Sobrien i.suffix); 308660519Sobrien#endif 308794546Sobrien continue; 308894546Sobrien } 308994546Sobrien /* Any other register is bad. */ 309094546Sobrien if (i.types[op] & (Reg | RegMMX | RegXMM 309194546Sobrien | SReg2 | SReg3 309294546Sobrien | Control | Debug | Test 309394546Sobrien | FloatReg | FloatAcc)) 309494546Sobrien { 3095218822Sdim as_bad (_("`%s%s' not allowed with `%s%c'"), 3096218822Sdim register_prefix, 309794546Sobrien i.op[op].regs->reg_name, 309894546Sobrien i.tm.name, 309994546Sobrien i.suffix); 310094546Sobrien return 0; 310194546Sobrien } 310294546Sobrien } 310394546Sobrien return 1; 310494546Sobrien} 310577311Sobrien 310694546Sobrienstatic int 3107218822Sdimcheck_long_reg (void) 310894546Sobrien{ 310994546Sobrien int op; 311077311Sobrien 311194546Sobrien for (op = i.operands; --op >= 0;) 311294546Sobrien /* Reject eight bit registers, except where the template requires 311394546Sobrien them. (eg. movzb) */ 311494546Sobrien if ((i.types[op] & Reg8) != 0 311594546Sobrien && (i.tm.operand_types[op] & (Reg16 | Reg32 | Acc)) != 0) 311660519Sobrien { 3117218822Sdim as_bad (_("`%s%s' not allowed with `%s%c'"), 3118218822Sdim register_prefix, 311994546Sobrien i.op[op].regs->reg_name, 312094546Sobrien i.tm.name, 312194546Sobrien i.suffix); 312294546Sobrien return 0; 312360519Sobrien } 312494546Sobrien /* Warn if the e prefix on a general reg is missing. */ 312594546Sobrien else if ((!quiet_warnings || flag_code == CODE_64BIT) 312694546Sobrien && (i.types[op] & Reg16) != 0 312794546Sobrien && (i.tm.operand_types[op] & (Reg32 | Acc)) != 0) 312833965Sjdp { 312994546Sobrien /* Prohibit these changes in the 64bit mode, since the 313094546Sobrien lowering is more complicated. */ 313194546Sobrien if (flag_code == CODE_64BIT) 313233965Sjdp { 3133218822Sdim as_bad (_("Incorrect register `%s%s' used with `%c' suffix"), 3134218822Sdim register_prefix, i.op[op].regs->reg_name, 313594546Sobrien i.suffix); 313694546Sobrien return 0; 313760519Sobrien } 313894546Sobrien#if REGISTER_WARNINGS 313994546Sobrien else 3140218822Sdim as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"), 3141218822Sdim register_prefix, 314294546Sobrien (i.op[op].regs + REGNAM_EAX - REGNAM_AX)->reg_name, 3143218822Sdim register_prefix, 314494546Sobrien i.op[op].regs->reg_name, 314594546Sobrien i.suffix); 314694546Sobrien#endif 314733965Sjdp } 314894546Sobrien /* Warn if the r prefix on a general reg is missing. */ 314994546Sobrien else if ((i.types[op] & Reg64) != 0 315094546Sobrien && (i.tm.operand_types[op] & (Reg32 | Acc)) != 0) 315133965Sjdp { 3152218822Sdim as_bad (_("Incorrect register `%s%s' used with `%c' suffix"), 3153218822Sdim register_prefix, i.op[op].regs->reg_name, 315494546Sobrien i.suffix); 315594546Sobrien return 0; 315633965Sjdp } 315794546Sobrien return 1; 315894546Sobrien} 315933965Sjdp 316094546Sobrienstatic int 3161218822Sdimcheck_qword_reg (void) 316294546Sobrien{ 316394546Sobrien int op; 316460519Sobrien 316594546Sobrien for (op = i.operands; --op >= 0; ) 316694546Sobrien /* Reject eight bit registers, except where the template requires 316794546Sobrien them. (eg. movzb) */ 316894546Sobrien if ((i.types[op] & Reg8) != 0 316994546Sobrien && (i.tm.operand_types[op] & (Reg16 | Reg32 | Acc)) != 0) 317033965Sjdp { 3171218822Sdim as_bad (_("`%s%s' not allowed with `%s%c'"), 3172218822Sdim register_prefix, 317394546Sobrien i.op[op].regs->reg_name, 317494546Sobrien i.tm.name, 317594546Sobrien i.suffix); 317694546Sobrien return 0; 317733965Sjdp } 317894546Sobrien /* Warn if the e prefix on a general reg is missing. */ 317994546Sobrien else if (((i.types[op] & Reg16) != 0 318094546Sobrien || (i.types[op] & Reg32) != 0) 318194546Sobrien && (i.tm.operand_types[op] & (Reg32 | Acc)) != 0) 318294546Sobrien { 318394546Sobrien /* Prohibit these changes in the 64bit mode, since the 318494546Sobrien lowering is more complicated. */ 3185218822Sdim as_bad (_("Incorrect register `%s%s' used with `%c' suffix"), 3186218822Sdim register_prefix, i.op[op].regs->reg_name, 318794546Sobrien i.suffix); 318894546Sobrien return 0; 318994546Sobrien } 319094546Sobrien return 1; 319194546Sobrien} 319233965Sjdp 319394546Sobrienstatic int 3194218822Sdimcheck_word_reg (void) 319594546Sobrien{ 319694546Sobrien int op; 319794546Sobrien for (op = i.operands; --op >= 0;) 319894546Sobrien /* Reject eight bit registers, except where the template requires 319994546Sobrien them. (eg. movzb) */ 320094546Sobrien if ((i.types[op] & Reg8) != 0 320194546Sobrien && (i.tm.operand_types[op] & (Reg16 | Reg32 | Acc)) != 0) 320233965Sjdp { 3203218822Sdim as_bad (_("`%s%s' not allowed with `%s%c'"), 3204218822Sdim register_prefix, 320594546Sobrien i.op[op].regs->reg_name, 320694546Sobrien i.tm.name, 320794546Sobrien i.suffix); 320894546Sobrien return 0; 320994546Sobrien } 321094546Sobrien /* Warn if the e prefix on a general reg is present. */ 321194546Sobrien else if ((!quiet_warnings || flag_code == CODE_64BIT) 321294546Sobrien && (i.types[op] & Reg32) != 0 321394546Sobrien && (i.tm.operand_types[op] & (Reg16 | Acc)) != 0) 321494546Sobrien { 321594546Sobrien /* Prohibit these changes in the 64bit mode, since the 321694546Sobrien lowering is more complicated. */ 321794546Sobrien if (flag_code == CODE_64BIT) 321833965Sjdp { 3219218822Sdim as_bad (_("Incorrect register `%s%s' used with `%c' suffix"), 3220218822Sdim register_prefix, i.op[op].regs->reg_name, 322194546Sobrien i.suffix); 322294546Sobrien return 0; 322333965Sjdp } 322494546Sobrien else 322594546Sobrien#if REGISTER_WARNINGS 3226218822Sdim as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"), 3227218822Sdim register_prefix, 322894546Sobrien (i.op[op].regs + REGNAM_AX - REGNAM_EAX)->reg_name, 3229218822Sdim register_prefix, 323094546Sobrien i.op[op].regs->reg_name, 323194546Sobrien i.suffix); 323294546Sobrien#endif 323394546Sobrien } 323494546Sobrien return 1; 323594546Sobrien} 323660519Sobrien 323794546Sobrienstatic int 3238218822Sdimfinalize_imm (void) 323994546Sobrien{ 324094546Sobrien unsigned int overlap0, overlap1, overlap2; 324177311Sobrien 324294546Sobrien overlap0 = i.types[0] & i.tm.operand_types[0]; 3243218822Sdim if ((overlap0 & (Imm8 | Imm8S | Imm16 | Imm32 | Imm32S | Imm64)) 324494546Sobrien && overlap0 != Imm8 && overlap0 != Imm8S 324594546Sobrien && overlap0 != Imm16 && overlap0 != Imm32S 324694546Sobrien && overlap0 != Imm32 && overlap0 != Imm64) 324794546Sobrien { 324894546Sobrien if (i.suffix) 324994546Sobrien { 325094546Sobrien overlap0 &= (i.suffix == BYTE_MNEM_SUFFIX 325194546Sobrien ? Imm8 | Imm8S 325294546Sobrien : (i.suffix == WORD_MNEM_SUFFIX 325394546Sobrien ? Imm16 325494546Sobrien : (i.suffix == QWORD_MNEM_SUFFIX 325594546Sobrien ? Imm64 | Imm32S 325694546Sobrien : Imm32))); 325794546Sobrien } 325894546Sobrien else if (overlap0 == (Imm16 | Imm32S | Imm32) 325994546Sobrien || overlap0 == (Imm16 | Imm32) 326094546Sobrien || overlap0 == (Imm16 | Imm32S)) 326194546Sobrien { 326294546Sobrien overlap0 = ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0) 326394546Sobrien ? Imm16 : Imm32S); 326494546Sobrien } 326594546Sobrien if (overlap0 != Imm8 && overlap0 != Imm8S 326694546Sobrien && overlap0 != Imm16 && overlap0 != Imm32S 326794546Sobrien && overlap0 != Imm32 && overlap0 != Imm64) 326894546Sobrien { 3269218822Sdim as_bad (_("no instruction mnemonic suffix given; " 3270218822Sdim "can't determine immediate size")); 327194546Sobrien return 0; 327294546Sobrien } 327394546Sobrien } 327494546Sobrien i.types[0] = overlap0; 327591054Sobrien 327694546Sobrien overlap1 = i.types[1] & i.tm.operand_types[1]; 3277218822Sdim if ((overlap1 & (Imm8 | Imm8S | Imm16 | Imm32S | Imm32 | Imm64)) 327894546Sobrien && overlap1 != Imm8 && overlap1 != Imm8S 327994546Sobrien && overlap1 != Imm16 && overlap1 != Imm32S 328094546Sobrien && overlap1 != Imm32 && overlap1 != Imm64) 328194546Sobrien { 328294546Sobrien if (i.suffix) 328394546Sobrien { 328494546Sobrien overlap1 &= (i.suffix == BYTE_MNEM_SUFFIX 328594546Sobrien ? Imm8 | Imm8S 328694546Sobrien : (i.suffix == WORD_MNEM_SUFFIX 328794546Sobrien ? Imm16 328894546Sobrien : (i.suffix == QWORD_MNEM_SUFFIX 328994546Sobrien ? Imm64 | Imm32S 329094546Sobrien : Imm32))); 329194546Sobrien } 329294546Sobrien else if (overlap1 == (Imm16 | Imm32 | Imm32S) 329394546Sobrien || overlap1 == (Imm16 | Imm32) 329494546Sobrien || overlap1 == (Imm16 | Imm32S)) 329594546Sobrien { 329694546Sobrien overlap1 = ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0) 329794546Sobrien ? Imm16 : Imm32S); 329894546Sobrien } 329994546Sobrien if (overlap1 != Imm8 && overlap1 != Imm8S 330094546Sobrien && overlap1 != Imm16 && overlap1 != Imm32S 330194546Sobrien && overlap1 != Imm32 && overlap1 != Imm64) 330294546Sobrien { 3303218822Sdim as_bad (_("no instruction mnemonic suffix given; " 3304218822Sdim "can't determine immediate size %x %c"), 3305218822Sdim overlap1, i.suffix); 330694546Sobrien return 0; 330794546Sobrien } 330894546Sobrien } 330994546Sobrien i.types[1] = overlap1; 331077311Sobrien 331194546Sobrien overlap2 = i.types[2] & i.tm.operand_types[2]; 331294546Sobrien assert ((overlap2 & Imm) == 0); 331394546Sobrien i.types[2] = overlap2; 331433965Sjdp 331594546Sobrien return 1; 331694546Sobrien} 331760519Sobrien 331894546Sobrienstatic int 3319218822Sdimprocess_operands (void) 332094546Sobrien{ 332194546Sobrien /* Default segment register this instruction will use for memory 332294546Sobrien accesses. 0 means unknown. This is only for optimizing out 332394546Sobrien unnecessary segment overrides. */ 332494546Sobrien const seg_entry *default_seg = 0; 332560519Sobrien 332694546Sobrien /* The imul $imm, %reg instruction is converted into 332794546Sobrien imul $imm, %reg, %reg, and the clr %reg instruction 332894546Sobrien is converted into xor %reg, %reg. */ 3329218822Sdim if (i.tm.opcode_modifier & RegKludge) 333094546Sobrien { 3331218822Sdim if ((i.tm.cpu_flags & CpuSSE4_1)) 3332218822Sdim { 3333218822Sdim /* The first operand in instruction blendvpd, blendvps and 3334218822Sdim pblendvb in SSE4.1 is implicit and must be xmm0. */ 3335218822Sdim assert (i.operands == 3 3336218822Sdim && i.reg_operands >= 2 3337218822Sdim && i.types[0] == RegXMM); 3338218822Sdim if (i.op[0].regs->reg_num != 0) 3339218822Sdim { 3340218822Sdim if (intel_syntax) 3341218822Sdim as_bad (_("the last operand of `%s' must be `%sxmm0'"), 3342218822Sdim i.tm.name, register_prefix); 3343218822Sdim else 3344218822Sdim as_bad (_("the first operand of `%s' must be `%sxmm0'"), 3345218822Sdim i.tm.name, register_prefix); 3346218822Sdim return 0; 3347218822Sdim } 3348218822Sdim i.op[0] = i.op[1]; 3349218822Sdim i.op[1] = i.op[2]; 3350218822Sdim i.types[0] = i.types[1]; 3351218822Sdim i.types[1] = i.types[2]; 3352218822Sdim i.operands--; 3353218822Sdim i.reg_operands--; 3354218822Sdim 3355218822Sdim /* We need to adjust fields in i.tm since they are used by 3356218822Sdim build_modrm_byte. */ 3357218822Sdim i.tm.operand_types [0] = i.tm.operand_types [1]; 3358218822Sdim i.tm.operand_types [1] = i.tm.operand_types [2]; 3359218822Sdim i.tm.operands--; 3360218822Sdim } 3361218822Sdim else 3362218822Sdim { 3363218822Sdim unsigned int first_reg_op = (i.types[0] & Reg) ? 0 : 1; 3364218822Sdim /* Pretend we saw the extra register operand. */ 3365218822Sdim assert (i.reg_operands == 1 3366218822Sdim && i.op[first_reg_op + 1].regs == 0); 3367218822Sdim i.op[first_reg_op + 1].regs = i.op[first_reg_op].regs; 3368218822Sdim i.types[first_reg_op + 1] = i.types[first_reg_op]; 3369218822Sdim i.operands++; 3370218822Sdim i.reg_operands++; 3371218822Sdim } 337294546Sobrien } 337360519Sobrien 337494546Sobrien if (i.tm.opcode_modifier & ShortForm) 337594546Sobrien { 3376218822Sdim if (i.types[0] & (SReg2 | SReg3)) 337794546Sobrien { 3378218822Sdim if (i.tm.base_opcode == POP_SEG_SHORT 3379218822Sdim && i.op[0].regs->reg_num == 1) 338094546Sobrien { 3381218822Sdim as_bad (_("you can't `pop %%cs'")); 3382218822Sdim return 0; 338394546Sobrien } 3384218822Sdim i.tm.base_opcode |= (i.op[0].regs->reg_num << 3); 3385218822Sdim if ((i.op[0].regs->reg_flags & RegRex) != 0) 3386218822Sdim i.rex |= REX_B; 3387218822Sdim } 3388218822Sdim else 3389218822Sdim { 3390218822Sdim /* The register or float register operand is in operand 0 or 1. */ 3391218822Sdim unsigned int op = (i.types[0] & (Reg | FloatReg)) ? 0 : 1; 3392218822Sdim /* Register goes in low 3 bits of opcode. */ 3393218822Sdim i.tm.base_opcode |= i.op[op].regs->reg_num; 3394218822Sdim if ((i.op[op].regs->reg_flags & RegRex) != 0) 3395218822Sdim i.rex |= REX_B; 3396218822Sdim if (!quiet_warnings && (i.tm.opcode_modifier & Ugh) != 0) 339794546Sobrien { 3398218822Sdim /* Warn about some common errors, but press on regardless. 3399218822Sdim The first case can be generated by gcc (<= 2.8.1). */ 3400218822Sdim if (i.operands == 2) 3401218822Sdim { 3402218822Sdim /* Reversed arguments on faddp, fsubp, etc. */ 3403218822Sdim as_warn (_("translating to `%s %s%s,%s%s'"), i.tm.name, 3404218822Sdim register_prefix, i.op[1].regs->reg_name, 3405218822Sdim register_prefix, i.op[0].regs->reg_name); 3406218822Sdim } 3407218822Sdim else 3408218822Sdim { 3409218822Sdim /* Extraneous `l' suffix on fp insn. */ 3410218822Sdim as_warn (_("translating to `%s %s%s'"), i.tm.name, 3411218822Sdim register_prefix, i.op[0].regs->reg_name); 3412218822Sdim } 341394546Sobrien } 341494546Sobrien } 341594546Sobrien } 341694546Sobrien else if (i.tm.opcode_modifier & Modrm) 341794546Sobrien { 341894546Sobrien /* The opcode is completed (modulo i.tm.extension_opcode which 3419104848Sobrien must be put into the modrm byte). Now, we make the modrm and 3420104848Sobrien index base bytes based on all the info we've collected. */ 342160519Sobrien 342294546Sobrien default_seg = build_modrm_byte (); 342394546Sobrien } 3424218822Sdim else if ((i.tm.base_opcode & ~0x3) == MOV_AX_DISP32) 342594546Sobrien { 342694546Sobrien default_seg = &ds; 342794546Sobrien } 342894546Sobrien else if ((i.tm.opcode_modifier & IsString) != 0) 342994546Sobrien { 343094546Sobrien /* For the string instructions that allow a segment override 343194546Sobrien on one of their operands, the default segment is ds. */ 343294546Sobrien default_seg = &ds; 343394546Sobrien } 343433965Sjdp 3435218822Sdim if ((i.tm.base_opcode == 0x8d /* lea */ 3436218822Sdim || (i.tm.cpu_flags & CpuSVME)) 3437218822Sdim && i.seg[0] && !quiet_warnings) 3438218822Sdim as_warn (_("segment override on `%s' is ineffectual"), i.tm.name); 3439104848Sobrien 3440104848Sobrien /* If a segment was explicitly specified, and the specified segment 3441104848Sobrien is not the default, use an opcode prefix to select it. If we 3442104848Sobrien never figured out what the default segment is, then default_seg 3443104848Sobrien will be zero at this point, and the specified segment prefix will 3444104848Sobrien always be used. */ 344594546Sobrien if ((i.seg[0]) && (i.seg[0] != default_seg)) 344694546Sobrien { 344794546Sobrien if (!add_prefix (i.seg[0]->seg_prefix)) 344894546Sobrien return 0; 344994546Sobrien } 345094546Sobrien return 1; 345194546Sobrien} 345233965Sjdp 345394546Sobrienstatic const seg_entry * 3454218822Sdimbuild_modrm_byte (void) 345594546Sobrien{ 345694546Sobrien const seg_entry *default_seg = 0; 345733965Sjdp 345894546Sobrien /* i.reg_operands MUST be the number of real register operands; 345994546Sobrien implicit registers do not count. */ 346094546Sobrien if (i.reg_operands == 2) 346194546Sobrien { 346294546Sobrien unsigned int source, dest; 3463218822Sdim 3464218822Sdim switch (i.operands) 3465218822Sdim { 3466218822Sdim case 2: 3467218822Sdim source = 0; 3468218822Sdim break; 3469218822Sdim case 3: 3470218822Sdim /* When there are 3 operands, one of them may be immediate, 3471218822Sdim which may be the first or the last operand. Otherwise, 3472218822Sdim the first operand must be shift count register (cl). */ 3473218822Sdim assert (i.imm_operands == 1 3474218822Sdim || (i.imm_operands == 0 3475218822Sdim && (i.types[0] & ShiftCount))); 3476218822Sdim source = (i.types[0] & (Imm | ShiftCount)) ? 1 : 0; 3477218822Sdim break; 3478218822Sdim case 4: 3479218822Sdim /* When there are 4 operands, the first two must be immediate 3480218822Sdim operands. The source operand will be the 3rd one. */ 3481218822Sdim assert (i.imm_operands == 2 3482218822Sdim && (i.types[0] & Imm) 3483218822Sdim && (i.types[1] & Imm)); 3484218822Sdim source = 2; 3485218822Sdim break; 3486218822Sdim default: 3487218822Sdim abort (); 3488218822Sdim } 3489218822Sdim 349094546Sobrien dest = source + 1; 349160519Sobrien 349294546Sobrien i.rm.mode = 3; 349394546Sobrien /* One of the register operands will be encoded in the i.tm.reg 349494546Sobrien field, the other in the combined i.tm.mode and i.tm.regmem 349594546Sobrien fields. If no form of this instruction supports a memory 349694546Sobrien destination operand, then we assume the source operand may 349794546Sobrien sometimes be a memory operand and so we need to store the 349894546Sobrien destination in the i.rm.reg field. */ 3499218822Sdim if ((i.tm.operand_types[dest] & (AnyMem | RegMem)) == 0) 350094546Sobrien { 350194546Sobrien i.rm.reg = i.op[dest].regs->reg_num; 350294546Sobrien i.rm.regmem = i.op[source].regs->reg_num; 350394546Sobrien if ((i.op[dest].regs->reg_flags & RegRex) != 0) 3504218822Sdim i.rex |= REX_R; 350594546Sobrien if ((i.op[source].regs->reg_flags & RegRex) != 0) 3506218822Sdim i.rex |= REX_B; 350794546Sobrien } 350894546Sobrien else 350994546Sobrien { 351094546Sobrien i.rm.reg = i.op[source].regs->reg_num; 351194546Sobrien i.rm.regmem = i.op[dest].regs->reg_num; 351294546Sobrien if ((i.op[dest].regs->reg_flags & RegRex) != 0) 3513218822Sdim i.rex |= REX_B; 351494546Sobrien if ((i.op[source].regs->reg_flags & RegRex) != 0) 3515218822Sdim i.rex |= REX_R; 351694546Sobrien } 3517218822Sdim if (flag_code != CODE_64BIT && (i.rex & (REX_R | REX_B))) 3518218822Sdim { 3519218822Sdim if (!((i.types[0] | i.types[1]) & Control)) 3520218822Sdim abort (); 3521218822Sdim i.rex &= ~(REX_R | REX_B); 3522218822Sdim add_prefix (LOCK_PREFIX_OPCODE); 3523218822Sdim } 352494546Sobrien } 352594546Sobrien else 352694546Sobrien { /* If it's not 2 reg operands... */ 352794546Sobrien if (i.mem_operands) 352894546Sobrien { 352994546Sobrien unsigned int fake_zero_displacement = 0; 3530218822Sdim unsigned int op; 353133965Sjdp 3532218822Sdim for (op = 0; op < i.operands; op++) 3533218822Sdim if ((i.types[op] & AnyMem)) 3534218822Sdim break; 3535218822Sdim assert (op < i.operands); 3536218822Sdim 353794546Sobrien default_seg = &ds; 353833965Sjdp 353994546Sobrien if (i.base_reg == 0) 354094546Sobrien { 354194546Sobrien i.rm.mode = 0; 354294546Sobrien if (!i.disp_operands) 354394546Sobrien fake_zero_displacement = 1; 354494546Sobrien if (i.index_reg == 0) 354594546Sobrien { 354694546Sobrien /* Operand is just <disp> */ 3547218822Sdim if (flag_code == CODE_64BIT) 354894546Sobrien { 354994546Sobrien /* 64bit mode overwrites the 32bit absolute 355094546Sobrien addressing by RIP relative addressing and 355194546Sobrien absolute addressing is encoded by one of the 355294546Sobrien redundant SIB forms. */ 355394546Sobrien i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; 355494546Sobrien i.sib.base = NO_BASE_REGISTER; 355594546Sobrien i.sib.index = NO_INDEX_REGISTER; 3556218822Sdim i.types[op] = ((i.prefix[ADDR_PREFIX] == 0) 3557218822Sdim ? Disp32S : Disp32); 355894546Sobrien } 3559218822Sdim else if ((flag_code == CODE_16BIT) 3560218822Sdim ^ (i.prefix[ADDR_PREFIX] != 0)) 3561218822Sdim { 3562218822Sdim i.rm.regmem = NO_BASE_REGISTER_16; 3563218822Sdim i.types[op] = Disp16; 3564218822Sdim } 3565218822Sdim else 3566218822Sdim { 3567218822Sdim i.rm.regmem = NO_BASE_REGISTER; 3568218822Sdim i.types[op] = Disp32; 3569218822Sdim } 357094546Sobrien } 357194546Sobrien else /* !i.base_reg && i.index_reg */ 357294546Sobrien { 357394546Sobrien i.sib.index = i.index_reg->reg_num; 357494546Sobrien i.sib.base = NO_BASE_REGISTER; 357594546Sobrien i.sib.scale = i.log2_scale_factor; 357694546Sobrien i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; 357794546Sobrien i.types[op] &= ~Disp; 357894546Sobrien if (flag_code != CODE_64BIT) 357994546Sobrien i.types[op] |= Disp32; /* Must be 32 bit */ 358094546Sobrien else 358194546Sobrien i.types[op] |= Disp32S; 358294546Sobrien if ((i.index_reg->reg_flags & RegRex) != 0) 3583218822Sdim i.rex |= REX_X; 358494546Sobrien } 358594546Sobrien } 358694546Sobrien /* RIP addressing for 64bit mode. */ 358794546Sobrien else if (i.base_reg->reg_type == BaseIndex) 358894546Sobrien { 358994546Sobrien i.rm.regmem = NO_BASE_REGISTER; 3590218822Sdim i.types[op] &= ~ Disp; 359194546Sobrien i.types[op] |= Disp32S; 3592218822Sdim i.flags[op] |= Operand_PCrel; 3593218822Sdim if (! i.disp_operands) 3594218822Sdim fake_zero_displacement = 1; 359594546Sobrien } 359694546Sobrien else if (i.base_reg->reg_type & Reg16) 359794546Sobrien { 359894546Sobrien switch (i.base_reg->reg_num) 359994546Sobrien { 360094546Sobrien case 3: /* (%bx) */ 360194546Sobrien if (i.index_reg == 0) 360294546Sobrien i.rm.regmem = 7; 360394546Sobrien else /* (%bx,%si) -> 0, or (%bx,%di) -> 1 */ 360494546Sobrien i.rm.regmem = i.index_reg->reg_num - 6; 360594546Sobrien break; 360694546Sobrien case 5: /* (%bp) */ 360794546Sobrien default_seg = &ss; 360894546Sobrien if (i.index_reg == 0) 360994546Sobrien { 361094546Sobrien i.rm.regmem = 6; 361194546Sobrien if ((i.types[op] & Disp) == 0) 361294546Sobrien { 361394546Sobrien /* fake (%bp) into 0(%bp) */ 361494546Sobrien i.types[op] |= Disp8; 361560519Sobrien fake_zero_displacement = 1; 361694546Sobrien } 361794546Sobrien } 361894546Sobrien else /* (%bp,%si) -> 2, or (%bp,%di) -> 3 */ 361994546Sobrien i.rm.regmem = i.index_reg->reg_num - 6 + 2; 362094546Sobrien break; 362194546Sobrien default: /* (%si) -> 4 or (%di) -> 5 */ 362294546Sobrien i.rm.regmem = i.base_reg->reg_num - 6 + 4; 362394546Sobrien } 362494546Sobrien i.rm.mode = mode_from_disp_size (i.types[op]); 362594546Sobrien } 362694546Sobrien else /* i.base_reg and 32/64 bit mode */ 362794546Sobrien { 362894546Sobrien if (flag_code == CODE_64BIT 362994546Sobrien && (i.types[op] & Disp)) 3630218822Sdim i.types[op] = ((i.types[op] & Disp8) 3631218822Sdim | (i.prefix[ADDR_PREFIX] == 0 3632218822Sdim ? Disp32S : Disp32)); 3633218822Sdim 363494546Sobrien i.rm.regmem = i.base_reg->reg_num; 363594546Sobrien if ((i.base_reg->reg_flags & RegRex) != 0) 3636218822Sdim i.rex |= REX_B; 363794546Sobrien i.sib.base = i.base_reg->reg_num; 363894546Sobrien /* x86-64 ignores REX prefix bit here to avoid decoder 363994546Sobrien complications. */ 364094546Sobrien if ((i.base_reg->reg_num & 7) == EBP_REG_NUM) 364194546Sobrien { 364294546Sobrien default_seg = &ss; 364394546Sobrien if (i.disp_operands == 0) 364494546Sobrien { 364594546Sobrien fake_zero_displacement = 1; 364694546Sobrien i.types[op] |= Disp8; 364794546Sobrien } 364894546Sobrien } 364994546Sobrien else if (i.base_reg->reg_num == ESP_REG_NUM) 365094546Sobrien { 365194546Sobrien default_seg = &ss; 365294546Sobrien } 365394546Sobrien i.sib.scale = i.log2_scale_factor; 365494546Sobrien if (i.index_reg == 0) 365594546Sobrien { 365694546Sobrien /* <disp>(%esp) becomes two byte modrm with no index 365794546Sobrien register. We've already stored the code for esp 365894546Sobrien in i.rm.regmem ie. ESCAPE_TO_TWO_BYTE_ADDRESSING. 365994546Sobrien Any base register besides %esp will not use the 366094546Sobrien extra modrm byte. */ 366194546Sobrien i.sib.index = NO_INDEX_REGISTER; 366294546Sobrien#if !SCALE1_WHEN_NO_INDEX 366394546Sobrien /* Another case where we force the second modrm byte. */ 366494546Sobrien if (i.log2_scale_factor) 366594546Sobrien i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; 366660519Sobrien#endif 366794546Sobrien } 366894546Sobrien else 366994546Sobrien { 367094546Sobrien i.sib.index = i.index_reg->reg_num; 367194546Sobrien i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; 367294546Sobrien if ((i.index_reg->reg_flags & RegRex) != 0) 3673218822Sdim i.rex |= REX_X; 367494546Sobrien } 3675218822Sdim 3676218822Sdim if (i.disp_operands 3677218822Sdim && (i.reloc[op] == BFD_RELOC_386_TLS_DESC_CALL 3678218822Sdim || i.reloc[op] == BFD_RELOC_X86_64_TLSDESC_CALL)) 3679218822Sdim i.rm.mode = 0; 3680218822Sdim else 3681218822Sdim i.rm.mode = mode_from_disp_size (i.types[op]); 368294546Sobrien } 368360519Sobrien 368494546Sobrien if (fake_zero_displacement) 368594546Sobrien { 368694546Sobrien /* Fakes a zero displacement assuming that i.types[op] 368794546Sobrien holds the correct displacement size. */ 368894546Sobrien expressionS *exp; 368960519Sobrien 369094546Sobrien assert (i.op[op].disps == 0); 369194546Sobrien exp = &disp_expressions[i.disp_operands++]; 369294546Sobrien i.op[op].disps = exp; 369394546Sobrien exp->X_op = O_constant; 369494546Sobrien exp->X_add_number = 0; 369594546Sobrien exp->X_add_symbol = (symbolS *) 0; 369694546Sobrien exp->X_op_symbol = (symbolS *) 0; 369794546Sobrien } 369894546Sobrien } 369933965Sjdp 370094546Sobrien /* Fill in i.rm.reg or i.rm.regmem field with register operand 370194546Sobrien (if any) based on i.tm.extension_opcode. Again, we must be 370294546Sobrien careful to make sure that segment/control/debug/test/MMX 370394546Sobrien registers are coded into the i.rm.reg field. */ 370494546Sobrien if (i.reg_operands) 370594546Sobrien { 3706218822Sdim unsigned int op; 3707218822Sdim 3708218822Sdim for (op = 0; op < i.operands; op++) 3709218822Sdim if ((i.types[op] & (Reg | RegMMX | RegXMM 3710218822Sdim | SReg2 | SReg3 3711218822Sdim | Control | Debug | Test))) 3712218822Sdim break; 3713218822Sdim assert (op < i.operands); 3714218822Sdim 371594546Sobrien /* If there is an extension opcode to put here, the register 371694546Sobrien number must be put into the regmem field. */ 371794546Sobrien if (i.tm.extension_opcode != None) 371894546Sobrien { 371994546Sobrien i.rm.regmem = i.op[op].regs->reg_num; 372094546Sobrien if ((i.op[op].regs->reg_flags & RegRex) != 0) 3721218822Sdim i.rex |= REX_B; 372294546Sobrien } 372394546Sobrien else 372494546Sobrien { 372594546Sobrien i.rm.reg = i.op[op].regs->reg_num; 372694546Sobrien if ((i.op[op].regs->reg_flags & RegRex) != 0) 3727218822Sdim i.rex |= REX_R; 372894546Sobrien } 372933965Sjdp 373094546Sobrien /* Now, if no memory operand has set i.rm.mode = 0, 1, 2 we 373194546Sobrien must set it to 3 to indicate this is a register operand 373294546Sobrien in the regmem field. */ 373394546Sobrien if (!i.mem_operands) 373494546Sobrien i.rm.mode = 3; 373594546Sobrien } 373633965Sjdp 373794546Sobrien /* Fill in i.rm.reg field with extension opcode (if any). */ 373894546Sobrien if (i.tm.extension_opcode != None) 373994546Sobrien i.rm.reg = i.tm.extension_opcode; 374094546Sobrien } 374194546Sobrien return default_seg; 374294546Sobrien} 374333965Sjdp 374494546Sobrienstatic void 3745218822Sdimoutput_branch (void) 374694546Sobrien{ 374794546Sobrien char *p; 374894546Sobrien int code16; 374994546Sobrien int prefix; 375094546Sobrien relax_substateT subtype; 375194546Sobrien symbolS *sym; 375294546Sobrien offsetT off; 375333965Sjdp 375494546Sobrien code16 = 0; 375594546Sobrien if (flag_code == CODE_16BIT) 375694546Sobrien code16 = CODE16; 375794546Sobrien 375894546Sobrien prefix = 0; 375994546Sobrien if (i.prefix[DATA_PREFIX] != 0) 376033965Sjdp { 376194546Sobrien prefix = 1; 376294546Sobrien i.prefixes -= 1; 376394546Sobrien code16 ^= CODE16; 376433965Sjdp } 376594546Sobrien /* Pentium4 branch hints. */ 376694546Sobrien if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE /* not taken */ 376794546Sobrien || i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE /* taken */) 376860519Sobrien { 376994546Sobrien prefix++; 377094546Sobrien i.prefixes--; 377160519Sobrien } 377294546Sobrien if (i.prefix[REX_PREFIX] != 0) 377394546Sobrien { 377494546Sobrien prefix++; 377594546Sobrien i.prefixes--; 377694546Sobrien } 377760519Sobrien 377894546Sobrien if (i.prefixes != 0 && !intel_syntax) 377994546Sobrien as_warn (_("skipping prefixes on this instruction")); 378077311Sobrien 378194546Sobrien /* It's always a symbol; End frag & setup for relax. 378294546Sobrien Make sure there is enough room in this frag for the largest 378394546Sobrien instruction we may generate in md_convert_frag. This is 2 378494546Sobrien bytes for the opcode and room for the prefix and largest 378594546Sobrien displacement. */ 378694546Sobrien frag_grow (prefix + 2 + 4); 378794546Sobrien /* Prefix and 1 opcode byte go in fr_fix. */ 378894546Sobrien p = frag_more (prefix + 1); 378994546Sobrien if (i.prefix[DATA_PREFIX] != 0) 379094546Sobrien *p++ = DATA_PREFIX_OPCODE; 379194546Sobrien if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE 379294546Sobrien || i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE) 379394546Sobrien *p++ = i.prefix[SEG_PREFIX]; 379494546Sobrien if (i.prefix[REX_PREFIX] != 0) 379594546Sobrien *p++ = i.prefix[REX_PREFIX]; 379694546Sobrien *p = i.tm.base_opcode; 379777311Sobrien 379894546Sobrien if ((unsigned char) *p == JUMP_PC_RELATIVE) 379994546Sobrien subtype = ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL); 380094546Sobrien else if ((cpu_arch_flags & Cpu386) != 0) 380194546Sobrien subtype = ENCODE_RELAX_STATE (COND_JUMP, SMALL); 380294546Sobrien else 380394546Sobrien subtype = ENCODE_RELAX_STATE (COND_JUMP86, SMALL); 380494546Sobrien subtype |= code16; 380577311Sobrien 380694546Sobrien sym = i.op[0].disps->X_add_symbol; 380794546Sobrien off = i.op[0].disps->X_add_number; 380877311Sobrien 380994546Sobrien if (i.op[0].disps->X_op != O_constant 381094546Sobrien && i.op[0].disps->X_op != O_symbol) 381194546Sobrien { 381294546Sobrien /* Handle complex expressions. */ 381394546Sobrien sym = make_expr_symbol (i.op[0].disps); 381494546Sobrien off = 0; 381577311Sobrien } 381677311Sobrien 381794546Sobrien /* 1 possible extra opcode + 4 byte displacement go in var part. 381894546Sobrien Pass reloc in fr_var. */ 381994546Sobrien frag_var (rs_machine_dependent, 5, i.reloc[0], subtype, sym, off, p); 382094546Sobrien} 382177311Sobrien 382294546Sobrienstatic void 3823218822Sdimoutput_jump (void) 382494546Sobrien{ 382594546Sobrien char *p; 382694546Sobrien int size; 3827104848Sobrien fixS *fixP; 382833965Sjdp 382994546Sobrien if (i.tm.opcode_modifier & JumpByte) 383094546Sobrien { 383194546Sobrien /* This is a loop or jecxz type instruction. */ 383294546Sobrien size = 1; 383394546Sobrien if (i.prefix[ADDR_PREFIX] != 0) 383494546Sobrien { 383594546Sobrien FRAG_APPEND_1_CHAR (ADDR_PREFIX_OPCODE); 383694546Sobrien i.prefixes -= 1; 383794546Sobrien } 383894546Sobrien /* Pentium4 branch hints. */ 383994546Sobrien if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE /* not taken */ 384094546Sobrien || i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE /* taken */) 384194546Sobrien { 384294546Sobrien FRAG_APPEND_1_CHAR (i.prefix[SEG_PREFIX]); 384394546Sobrien i.prefixes--; 384494546Sobrien } 384594546Sobrien } 384694546Sobrien else 384794546Sobrien { 384894546Sobrien int code16; 384978840Sobrien 385094546Sobrien code16 = 0; 385194546Sobrien if (flag_code == CODE_16BIT) 385294546Sobrien code16 = CODE16; 385333965Sjdp 385494546Sobrien if (i.prefix[DATA_PREFIX] != 0) 385594546Sobrien { 385694546Sobrien FRAG_APPEND_1_CHAR (DATA_PREFIX_OPCODE); 385794546Sobrien i.prefixes -= 1; 385894546Sobrien code16 ^= CODE16; 385994546Sobrien } 386060519Sobrien 386194546Sobrien size = 4; 386294546Sobrien if (code16) 386394546Sobrien size = 2; 386494546Sobrien } 386533965Sjdp 386694546Sobrien if (i.prefix[REX_PREFIX] != 0) 386794546Sobrien { 386894546Sobrien FRAG_APPEND_1_CHAR (i.prefix[REX_PREFIX]); 386994546Sobrien i.prefixes -= 1; 387094546Sobrien } 387133965Sjdp 387294546Sobrien if (i.prefixes != 0 && !intel_syntax) 387394546Sobrien as_warn (_("skipping prefixes on this instruction")); 387489867Sobrien 387594546Sobrien p = frag_more (1 + size); 387694546Sobrien *p++ = i.tm.base_opcode; 387789867Sobrien 3878104848Sobrien fixP = fix_new_exp (frag_now, p - frag_now->fr_literal, size, 3879104848Sobrien i.op[0].disps, 1, reloc (size, 1, 1, i.reloc[0])); 3880104848Sobrien 3881104848Sobrien /* All jumps handled here are signed, but don't use a signed limit 3882104848Sobrien check for 32 and 16 bit jumps as we want to allow wrap around at 3883104848Sobrien 4G and 64k respectively. */ 3884104848Sobrien if (size == 1) 3885104848Sobrien fixP->fx_signed = 1; 388694546Sobrien} 388789867Sobrien 388894546Sobrienstatic void 3889218822Sdimoutput_interseg_jump (void) 389094546Sobrien{ 389194546Sobrien char *p; 389294546Sobrien int size; 389394546Sobrien int prefix; 389494546Sobrien int code16; 389589867Sobrien 389694546Sobrien code16 = 0; 389794546Sobrien if (flag_code == CODE_16BIT) 389894546Sobrien code16 = CODE16; 389933965Sjdp 390094546Sobrien prefix = 0; 390194546Sobrien if (i.prefix[DATA_PREFIX] != 0) 390294546Sobrien { 390394546Sobrien prefix = 1; 390494546Sobrien i.prefixes -= 1; 390594546Sobrien code16 ^= CODE16; 390694546Sobrien } 390794546Sobrien if (i.prefix[REX_PREFIX] != 0) 390894546Sobrien { 390994546Sobrien prefix++; 391094546Sobrien i.prefixes -= 1; 391194546Sobrien } 391238891Sjdp 391394546Sobrien size = 4; 391494546Sobrien if (code16) 391594546Sobrien size = 2; 391638891Sjdp 391794546Sobrien if (i.prefixes != 0 && !intel_syntax) 391894546Sobrien as_warn (_("skipping prefixes on this instruction")); 391933965Sjdp 392094546Sobrien /* 1 opcode; 2 segment; offset */ 392194546Sobrien p = frag_more (prefix + 1 + 2 + size); 392233965Sjdp 392394546Sobrien if (i.prefix[DATA_PREFIX] != 0) 392494546Sobrien *p++ = DATA_PREFIX_OPCODE; 392577311Sobrien 392694546Sobrien if (i.prefix[REX_PREFIX] != 0) 392794546Sobrien *p++ = i.prefix[REX_PREFIX]; 392860519Sobrien 392994546Sobrien *p++ = i.tm.base_opcode; 393094546Sobrien if (i.op[1].imms->X_op == O_constant) 393194546Sobrien { 393294546Sobrien offsetT n = i.op[1].imms->X_add_number; 393333965Sjdp 393494546Sobrien if (size == 2 393594546Sobrien && !fits_in_unsigned_word (n) 393694546Sobrien && !fits_in_signed_word (n)) 393794546Sobrien { 393894546Sobrien as_bad (_("16-bit jump out of range")); 393994546Sobrien return; 394094546Sobrien } 394194546Sobrien md_number_to_chars (p, n, size); 394294546Sobrien } 394394546Sobrien else 394494546Sobrien fix_new_exp (frag_now, p - frag_now->fr_literal, size, 394594546Sobrien i.op[1].imms, 0, reloc (size, 0, 0, i.reloc[1])); 394694546Sobrien if (i.op[0].imms->X_op != O_constant) 394794546Sobrien as_bad (_("can't handle non absolute segment in `%s'"), 394894546Sobrien i.tm.name); 394994546Sobrien md_number_to_chars (p + size, (valueT) i.op[0].imms->X_add_number, 2); 395094546Sobrien} 395160519Sobrien 395294546Sobrienstatic void 3953218822Sdimoutput_insn (void) 395494546Sobrien{ 3955104848Sobrien fragS *insn_start_frag; 3956104848Sobrien offsetT insn_start_off; 3957104848Sobrien 395894546Sobrien /* Tie dwarf2 debug info to the address at the start of the insn. 395994546Sobrien We can't do this after the insn has been output as the current 396094546Sobrien frag may have been closed off. eg. by frag_var. */ 396194546Sobrien dwarf2_emit_insn (0); 396260519Sobrien 3963104848Sobrien insn_start_frag = frag_now; 3964104848Sobrien insn_start_off = frag_now_fix (); 3965104848Sobrien 396694546Sobrien /* Output jumps. */ 396794546Sobrien if (i.tm.opcode_modifier & Jump) 396894546Sobrien output_branch (); 396994546Sobrien else if (i.tm.opcode_modifier & (JumpByte | JumpDword)) 397094546Sobrien output_jump (); 397194546Sobrien else if (i.tm.opcode_modifier & JumpInterSegment) 397294546Sobrien output_interseg_jump (); 397394546Sobrien else 397494546Sobrien { 397594546Sobrien /* Output normal instructions here. */ 397694546Sobrien char *p; 397794546Sobrien unsigned char *q; 3978218822Sdim unsigned int prefix; 397933965Sjdp 3980218822Sdim /* All opcodes on i386 have either 1 or 2 bytes. SSSE3 and 3981218822Sdim SSE4 instructions have 3 bytes. We may use one more higher 3982218822Sdim byte to specify a prefix the instruction requires. Exclude 3983218822Sdim instructions which are in both SSE4 and ABM. */ 3984247012Sjmg if ((i.tm.cpu_flags & (CpuSSSE3 | CpuSSE4 | CpuAES | CpuPCLMUL)) != 0 3985218822Sdim && (i.tm.cpu_flags & CpuABM) == 0) 3986218822Sdim { 3987218822Sdim if (i.tm.base_opcode & 0xff000000) 3988218822Sdim { 3989218822Sdim prefix = (i.tm.base_opcode >> 24) & 0xff; 3990218822Sdim goto check_prefix; 3991218822Sdim } 3992218822Sdim } 3993255192Sjhb else if (i.tm.base_opcode == 0x660f3880 || i.tm.base_opcode == 0x660f3881 3994255192Sjhb || i.tm.base_opcode == 0x660f3882) 3995238167Sjhb { 3996238167Sjhb /* invept and invvpid are 3 byte instructions with a 3997238167Sjhb mandatory prefix. */ 3998238167Sjhb if (i.tm.base_opcode & 0xff000000) 3999238167Sjhb { 4000238167Sjhb prefix = (i.tm.base_opcode >> 24) & 0xff; 4001238167Sjhb add_prefix (prefix); 4002238167Sjhb } 4003238167Sjhb } 4004218822Sdim else if ((i.tm.base_opcode & 0xff0000) != 0) 4005218822Sdim { 4006218822Sdim prefix = (i.tm.base_opcode >> 16) & 0xff; 4007218822Sdim if ((i.tm.cpu_flags & CpuPadLock) != 0) 4008218822Sdim { 4009218822Sdim check_prefix: 4010218822Sdim if (prefix != REPE_PREFIX_OPCODE 4011218822Sdim || i.prefix[LOCKREP_PREFIX] != REPE_PREFIX_OPCODE) 4012218822Sdim add_prefix (prefix); 4013218822Sdim } 4014218822Sdim else 4015130570Sobrien add_prefix (prefix); 4016130570Sobrien } 4017130570Sobrien 401894546Sobrien /* The prefix bytes. */ 401994546Sobrien for (q = i.prefix; 402094546Sobrien q < i.prefix + sizeof (i.prefix) / sizeof (i.prefix[0]); 402194546Sobrien q++) 402294546Sobrien { 402394546Sobrien if (*q) 402494546Sobrien { 402594546Sobrien p = frag_more (1); 402694546Sobrien md_number_to_chars (p, (valueT) *q, 1); 402794546Sobrien } 402894546Sobrien } 402960519Sobrien 403094546Sobrien /* Now the opcode; be careful about word order here! */ 403194546Sobrien if (fits_in_unsigned_byte (i.tm.base_opcode)) 403294546Sobrien { 403394546Sobrien FRAG_APPEND_1_CHAR (i.tm.base_opcode); 403494546Sobrien } 403594546Sobrien else 403694546Sobrien { 4037247012Sjmg if ((i.tm.cpu_flags & (CpuSSSE3 | CpuSSE4 | CpuAES | CpuPCLMUL)) != 0 4038218822Sdim && (i.tm.cpu_flags & CpuABM) == 0) 4039130570Sobrien { 4040130570Sobrien p = frag_more (3); 4041130570Sobrien *p++ = (i.tm.base_opcode >> 16) & 0xff; 4042130570Sobrien } 4043238167Sjhb else if (i.tm.base_opcode == 0x660f3880 || 4044255192Sjhb i.tm.base_opcode == 0x660f3881 || 4045255192Sjhb i.tm.base_opcode == 0x660f3882) 4046238167Sjhb { 4047238167Sjhb p = frag_more (3); 4048238167Sjhb *p++ = (i.tm.base_opcode >> 16) & 0xff; 4049238167Sjhb } 4050130570Sobrien else 4051130570Sobrien p = frag_more (2); 4052130570Sobrien 405394546Sobrien /* Put out high byte first: can't use md_number_to_chars! */ 405494546Sobrien *p++ = (i.tm.base_opcode >> 8) & 0xff; 405594546Sobrien *p = i.tm.base_opcode & 0xff; 405694546Sobrien } 405777311Sobrien 405894546Sobrien /* Now the modrm byte and sib byte (if present). */ 405994546Sobrien if (i.tm.opcode_modifier & Modrm) 406094546Sobrien { 406194546Sobrien p = frag_more (1); 406294546Sobrien md_number_to_chars (p, 406394546Sobrien (valueT) (i.rm.regmem << 0 406494546Sobrien | i.rm.reg << 3 406594546Sobrien | i.rm.mode << 6), 406694546Sobrien 1); 406794546Sobrien /* If i.rm.regmem == ESP (4) 406894546Sobrien && i.rm.mode != (Register mode) 406994546Sobrien && not 16 bit 407094546Sobrien ==> need second modrm byte. */ 407194546Sobrien if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING 407294546Sobrien && i.rm.mode != 3 407394546Sobrien && !(i.base_reg && (i.base_reg->reg_type & Reg16) != 0)) 407494546Sobrien { 407594546Sobrien p = frag_more (1); 407694546Sobrien md_number_to_chars (p, 407794546Sobrien (valueT) (i.sib.base << 0 407894546Sobrien | i.sib.index << 3 407994546Sobrien | i.sib.scale << 6), 408094546Sobrien 1); 408194546Sobrien } 408294546Sobrien } 408377311Sobrien 408494546Sobrien if (i.disp_operands) 4085104848Sobrien output_disp (insn_start_frag, insn_start_off); 408677311Sobrien 408794546Sobrien if (i.imm_operands) 4088104848Sobrien output_imm (insn_start_frag, insn_start_off); 408994546Sobrien } 409060519Sobrien 409194546Sobrien#ifdef DEBUG386 409294546Sobrien if (flag_debug) 409394546Sobrien { 4094218822Sdim pi ("" /*line*/, &i); 409594546Sobrien } 409694546Sobrien#endif /* DEBUG386 */ 409794546Sobrien} 409833965Sjdp 4099218822Sdim/* Return the size of the displacement operand N. */ 4100218822Sdim 4101218822Sdimstatic int 4102218822Sdimdisp_size (unsigned int n) 4103218822Sdim{ 4104218822Sdim int size = 4; 4105218822Sdim if (i.types[n] & (Disp8 | Disp16 | Disp64)) 4106218822Sdim { 4107218822Sdim size = 2; 4108218822Sdim if (i.types[n] & Disp8) 4109218822Sdim size = 1; 4110218822Sdim if (i.types[n] & Disp64) 4111218822Sdim size = 8; 4112218822Sdim } 4113218822Sdim return size; 4114218822Sdim} 4115218822Sdim 4116218822Sdim/* Return the size of the immediate operand N. */ 4117218822Sdim 4118218822Sdimstatic int 4119218822Sdimimm_size (unsigned int n) 4120218822Sdim{ 4121218822Sdim int size = 4; 4122218822Sdim if (i.types[n] & (Imm8 | Imm8S | Imm16 | Imm64)) 4123218822Sdim { 4124218822Sdim size = 2; 4125218822Sdim if (i.types[n] & (Imm8 | Imm8S)) 4126218822Sdim size = 1; 4127218822Sdim if (i.types[n] & Imm64) 4128218822Sdim size = 8; 4129218822Sdim } 4130218822Sdim return size; 4131218822Sdim} 4132218822Sdim 413394546Sobrienstatic void 4134218822Sdimoutput_disp (fragS *insn_start_frag, offsetT insn_start_off) 413594546Sobrien{ 413694546Sobrien char *p; 413794546Sobrien unsigned int n; 413877311Sobrien 413994546Sobrien for (n = 0; n < i.operands; n++) 414094546Sobrien { 414194546Sobrien if (i.types[n] & Disp) 414294546Sobrien { 414394546Sobrien if (i.op[n].disps->X_op == O_constant) 414494546Sobrien { 4145218822Sdim int size = disp_size (n); 414694546Sobrien offsetT val; 414733965Sjdp 414894546Sobrien val = offset_in_range (i.op[n].disps->X_add_number, 414994546Sobrien size); 415094546Sobrien p = frag_more (size); 415194546Sobrien md_number_to_chars (p, val, size); 415294546Sobrien } 415394546Sobrien else 415494546Sobrien { 4155130570Sobrien enum bfd_reloc_code_real reloc_type; 4156218822Sdim int size = disp_size (n); 4157218822Sdim int sign = (i.types[n] & Disp32S) != 0; 415894546Sobrien int pcrel = (i.flags[n] & Operand_PCrel) != 0; 415933965Sjdp 4160218822Sdim /* We can't have 8 bit displacement here. */ 4161218822Sdim assert ((i.types[n] & Disp8) == 0); 4162218822Sdim 416394546Sobrien /* The PC relative address is computed relative 416494546Sobrien to the instruction boundary, so in case immediate 416594546Sobrien fields follows, we need to adjust the value. */ 416694546Sobrien if (pcrel && i.imm_operands) 416794546Sobrien { 416894546Sobrien unsigned int n1; 4169218822Sdim int sz = 0; 417033965Sjdp 417194546Sobrien for (n1 = 0; n1 < i.operands; n1++) 417294546Sobrien if (i.types[n1] & Imm) 417333965Sjdp { 4174218822Sdim /* Only one immediate is allowed for PC 4175218822Sdim relative address. */ 4176218822Sdim assert (sz == 0); 4177218822Sdim sz = imm_size (n1); 4178218822Sdim i.op[n].disps->X_add_number -= sz; 417933965Sjdp } 418094546Sobrien /* We should find the immediate. */ 4181218822Sdim assert (sz != 0); 418294546Sobrien } 418360519Sobrien 418494546Sobrien p = frag_more (size); 4185104848Sobrien reloc_type = reloc (size, pcrel, sign, i.reloc[n]); 4186218822Sdim if (GOT_symbol 4187104848Sobrien && GOT_symbol == i.op[n].disps->X_add_symbol 4188218822Sdim && (((reloc_type == BFD_RELOC_32 4189218822Sdim || reloc_type == BFD_RELOC_X86_64_32S 4190218822Sdim || (reloc_type == BFD_RELOC_64 4191218822Sdim && object_64bit)) 4192218822Sdim && (i.op[n].disps->X_op == O_symbol 4193218822Sdim || (i.op[n].disps->X_op == O_add 4194218822Sdim && ((symbol_get_value_expression 4195218822Sdim (i.op[n].disps->X_op_symbol)->X_op) 4196218822Sdim == O_subtract)))) 4197218822Sdim || reloc_type == BFD_RELOC_32_PCREL)) 4198104848Sobrien { 4199104848Sobrien offsetT add; 4200104848Sobrien 4201104848Sobrien if (insn_start_frag == frag_now) 4202104848Sobrien add = (p - frag_now->fr_literal) - insn_start_off; 4203104848Sobrien else 4204104848Sobrien { 4205104848Sobrien fragS *fr; 4206104848Sobrien 4207104848Sobrien add = insn_start_frag->fr_fix - insn_start_off; 4208104848Sobrien for (fr = insn_start_frag->fr_next; 4209104848Sobrien fr && fr != frag_now; fr = fr->fr_next) 4210104848Sobrien add += fr->fr_fix; 4211104848Sobrien add += p - frag_now->fr_literal; 4212104848Sobrien } 4213104848Sobrien 4214218822Sdim if (!object_64bit) 4215218822Sdim { 4216218822Sdim reloc_type = BFD_RELOC_386_GOTPC; 4217218822Sdim i.op[n].imms->X_add_number += add; 4218218822Sdim } 4219218822Sdim else if (reloc_type == BFD_RELOC_64) 4220218822Sdim reloc_type = BFD_RELOC_X86_64_GOTPC64; 4221218822Sdim else 4222218822Sdim /* Don't do the adjustment for x86-64, as there 4223218822Sdim the pcrel addressing is relative to the _next_ 4224218822Sdim insn, and that is taken care of in other code. */ 4225218822Sdim reloc_type = BFD_RELOC_X86_64_GOTPC32; 4226104848Sobrien } 422799468Sobrien fix_new_exp (frag_now, p - frag_now->fr_literal, size, 4228104848Sobrien i.op[n].disps, pcrel, reloc_type); 422994546Sobrien } 423094546Sobrien } 423194546Sobrien } 423294546Sobrien} 423377311Sobrien 423494546Sobrienstatic void 4235218822Sdimoutput_imm (fragS *insn_start_frag, offsetT insn_start_off) 423694546Sobrien{ 423794546Sobrien char *p; 423894546Sobrien unsigned int n; 423977311Sobrien 424094546Sobrien for (n = 0; n < i.operands; n++) 424194546Sobrien { 424294546Sobrien if (i.types[n] & Imm) 424394546Sobrien { 424494546Sobrien if (i.op[n].imms->X_op == O_constant) 424594546Sobrien { 4246218822Sdim int size = imm_size (n); 424794546Sobrien offsetT val; 424833965Sjdp 424994546Sobrien val = offset_in_range (i.op[n].imms->X_add_number, 425094546Sobrien size); 425194546Sobrien p = frag_more (size); 425294546Sobrien md_number_to_chars (p, val, size); 425394546Sobrien } 425494546Sobrien else 425594546Sobrien { 425694546Sobrien /* Not absolute_section. 425794546Sobrien Need a 32-bit fixup (don't support 8bit 425894546Sobrien non-absolute imms). Try to support other 425994546Sobrien sizes ... */ 4260130570Sobrien enum bfd_reloc_code_real reloc_type; 4261218822Sdim int size = imm_size (n); 4262218822Sdim int sign; 426333965Sjdp 426494546Sobrien if ((i.types[n] & (Imm32S)) 4265218822Sdim && (i.suffix == QWORD_MNEM_SUFFIX 4266218822Sdim || (!i.suffix && (i.tm.opcode_modifier & No_lSuf)))) 426794546Sobrien sign = 1; 4268218822Sdim else 4269218822Sdim sign = 0; 427060519Sobrien 427194546Sobrien p = frag_more (size); 427294546Sobrien reloc_type = reloc (size, 0, sign, i.reloc[n]); 4273130570Sobrien 4274104848Sobrien /* This is tough to explain. We end up with this one if we 4275104848Sobrien * have operands that look like 4276104848Sobrien * "_GLOBAL_OFFSET_TABLE_+[.-.L284]". The goal here is to 4277104848Sobrien * obtain the absolute address of the GOT, and it is strongly 4278104848Sobrien * preferable from a performance point of view to avoid using 4279104848Sobrien * a runtime relocation for this. The actual sequence of 4280104848Sobrien * instructions often look something like: 4281104848Sobrien * 4282104848Sobrien * call .L66 4283104848Sobrien * .L66: 4284104848Sobrien * popl %ebx 4285104848Sobrien * addl $_GLOBAL_OFFSET_TABLE_+[.-.L66],%ebx 4286104848Sobrien * 4287104848Sobrien * The call and pop essentially return the absolute address 4288104848Sobrien * of the label .L66 and store it in %ebx. The linker itself 4289104848Sobrien * will ultimately change the first operand of the addl so 4290104848Sobrien * that %ebx points to the GOT, but to keep things simple, the 4291104848Sobrien * .o file must have this operand set so that it generates not 4292104848Sobrien * the absolute address of .L66, but the absolute address of 4293104848Sobrien * itself. This allows the linker itself simply treat a GOTPC 4294104848Sobrien * relocation as asking for a pcrel offset to the GOT to be 4295104848Sobrien * added in, and the addend of the relocation is stored in the 4296104848Sobrien * operand field for the instruction itself. 4297104848Sobrien * 4298104848Sobrien * Our job here is to fix the operand so that it would add 4299104848Sobrien * the correct offset so that %ebx would point to itself. The 4300104848Sobrien * thing that is tricky is that .-.L66 will point to the 4301104848Sobrien * beginning of the instruction, so we need to further modify 4302104848Sobrien * the operand so that it will point to itself. There are 4303104848Sobrien * other cases where you have something like: 4304104848Sobrien * 4305104848Sobrien * .long $_GLOBAL_OFFSET_TABLE_+[.-.L66] 4306104848Sobrien * 4307104848Sobrien * and here no correction would be required. Internally in 4308104848Sobrien * the assembler we treat operands of this form as not being 4309104848Sobrien * pcrel since the '.' is explicitly mentioned, and I wonder 4310104848Sobrien * whether it would simplify matters to do it this way. Who 4311104848Sobrien * knows. In earlier versions of the PIC patches, the 4312104848Sobrien * pcrel_adjust field was used to store the correction, but 4313104848Sobrien * since the expression is not pcrel, I felt it would be 4314104848Sobrien * confusing to do it this way. */ 4315104848Sobrien 4316218822Sdim if ((reloc_type == BFD_RELOC_32 4317218822Sdim || reloc_type == BFD_RELOC_X86_64_32S 4318218822Sdim || reloc_type == BFD_RELOC_64) 431994546Sobrien && GOT_symbol 432094546Sobrien && GOT_symbol == i.op[n].imms->X_add_symbol 432194546Sobrien && (i.op[n].imms->X_op == O_symbol 432294546Sobrien || (i.op[n].imms->X_op == O_add 432394546Sobrien && ((symbol_get_value_expression 432494546Sobrien (i.op[n].imms->X_op_symbol)->X_op) 432594546Sobrien == O_subtract)))) 432694546Sobrien { 4327104848Sobrien offsetT add; 4328104848Sobrien 4329104848Sobrien if (insn_start_frag == frag_now) 4330104848Sobrien add = (p - frag_now->fr_literal) - insn_start_off; 4331104848Sobrien else 4332104848Sobrien { 4333104848Sobrien fragS *fr; 4334104848Sobrien 4335104848Sobrien add = insn_start_frag->fr_fix - insn_start_off; 4336104848Sobrien for (fr = insn_start_frag->fr_next; 4337104848Sobrien fr && fr != frag_now; fr = fr->fr_next) 4338104848Sobrien add += fr->fr_fix; 4339104848Sobrien add += p - frag_now->fr_literal; 4340104848Sobrien } 4341104848Sobrien 4342218822Sdim if (!object_64bit) 4343218822Sdim reloc_type = BFD_RELOC_386_GOTPC; 4344218822Sdim else if (size == 4) 4345218822Sdim reloc_type = BFD_RELOC_X86_64_GOTPC32; 4346218822Sdim else if (size == 8) 4347218822Sdim reloc_type = BFD_RELOC_X86_64_GOTPC64; 4348104848Sobrien i.op[n].imms->X_add_number += add; 434994546Sobrien } 435094546Sobrien fix_new_exp (frag_now, p - frag_now->fr_literal, size, 435194546Sobrien i.op[n].imms, 0, reloc_type); 435294546Sobrien } 435394546Sobrien } 435494546Sobrien } 435533965Sjdp} 435633965Sjdp 4357218822Sdim/* x86_cons_fix_new is called via the expression parsing code when a 4358218822Sdim reloc is needed. We use this hook to get the correct .got reloc. */ 4359218822Sdimstatic enum bfd_reloc_code_real got_reloc = NO_RELOC; 4360218822Sdimstatic int cons_sign = -1; 436178840Sobrien 4362218822Sdimvoid 4363218822Sdimx86_cons_fix_new (fragS *frag, unsigned int off, unsigned int len, 4364218822Sdim expressionS *exp) 4365218822Sdim{ 4366218822Sdim enum bfd_reloc_code_real r = reloc (len, 0, cons_sign, got_reloc); 4367218822Sdim 4368218822Sdim got_reloc = NO_RELOC; 4369218822Sdim 4370218822Sdim#ifdef TE_PE 4371218822Sdim if (exp->X_op == O_secrel) 4372218822Sdim { 4373218822Sdim exp->X_op = O_symbol; 4374218822Sdim r = BFD_RELOC_32_SECREL; 4375218822Sdim } 4376218822Sdim#endif 4377218822Sdim 4378218822Sdim fix_new_exp (frag, off, len, exp, 0, r); 4379218822Sdim} 4380218822Sdim 4381218822Sdim#if (!defined (OBJ_ELF) && !defined (OBJ_MAYBE_ELF)) || defined (LEX_AT) 4382218822Sdim# define lex_got(reloc, adjust, types) NULL 4383218822Sdim#else 438478840Sobrien/* Parse operands of the form 438578840Sobrien <symbol>@GOTOFF+<nnn> 438678840Sobrien and similar .plt or .got references. 438778840Sobrien 438878840Sobrien If we find one, set up the correct relocation in RELOC and copy the 438978840Sobrien input string, minus the `@GOTOFF' into a malloc'd buffer for 439078840Sobrien parsing by the calling routine. Return this buffer, and if ADJUST 439178840Sobrien is non-null set it to the length of the string we removed from the 439278840Sobrien input line. Otherwise return NULL. */ 439378840Sobrienstatic char * 4394218822Sdimlex_got (enum bfd_reloc_code_real *reloc, 4395218822Sdim int *adjust, 4396218822Sdim unsigned int *types) 439778840Sobrien{ 4398218822Sdim /* Some of the relocations depend on the size of what field is to 4399218822Sdim be relocated. But in our callers i386_immediate and i386_displacement 4400218822Sdim we don't yet know the operand size (this will be set by insn 4401218822Sdim matching). Hence we record the word32 relocation here, 4402218822Sdim and adjust the reloc according to the real size in reloc(). */ 440378840Sobrien static const struct { 440478840Sobrien const char *str; 4405218822Sdim const enum bfd_reloc_code_real rel[2]; 4406218822Sdim const unsigned int types64; 440778840Sobrien } gotrel[] = { 4408218822Sdim { "PLTOFF", { 0, 4409218822Sdim BFD_RELOC_X86_64_PLTOFF64 }, 4410218822Sdim Imm64 }, 4411218822Sdim { "PLT", { BFD_RELOC_386_PLT32, 4412218822Sdim BFD_RELOC_X86_64_PLT32 }, 4413218822Sdim Imm32 | Imm32S | Disp32 }, 4414218822Sdim { "GOTPLT", { 0, 4415218822Sdim BFD_RELOC_X86_64_GOTPLT64 }, 4416218822Sdim Imm64 | Disp64 }, 4417218822Sdim { "GOTOFF", { BFD_RELOC_386_GOTOFF, 4418218822Sdim BFD_RELOC_X86_64_GOTOFF64 }, 4419218822Sdim Imm64 | Disp64 }, 4420218822Sdim { "GOTPCREL", { 0, 4421218822Sdim BFD_RELOC_X86_64_GOTPCREL }, 4422218822Sdim Imm32 | Imm32S | Disp32 }, 4423218822Sdim { "TLSGD", { BFD_RELOC_386_TLS_GD, 4424218822Sdim BFD_RELOC_X86_64_TLSGD }, 4425218822Sdim Imm32 | Imm32S | Disp32 }, 4426218822Sdim { "TLSLDM", { BFD_RELOC_386_TLS_LDM, 4427218822Sdim 0 }, 4428218822Sdim 0 }, 4429218822Sdim { "TLSLD", { 0, 4430218822Sdim BFD_RELOC_X86_64_TLSLD }, 4431218822Sdim Imm32 | Imm32S | Disp32 }, 4432218822Sdim { "GOTTPOFF", { BFD_RELOC_386_TLS_IE_32, 4433218822Sdim BFD_RELOC_X86_64_GOTTPOFF }, 4434218822Sdim Imm32 | Imm32S | Disp32 }, 4435218822Sdim { "TPOFF", { BFD_RELOC_386_TLS_LE_32, 4436218822Sdim BFD_RELOC_X86_64_TPOFF32 }, 4437218822Sdim Imm32 | Imm32S | Imm64 | Disp32 | Disp64 }, 4438218822Sdim { "NTPOFF", { BFD_RELOC_386_TLS_LE, 4439218822Sdim 0 }, 4440218822Sdim 0 }, 4441218822Sdim { "DTPOFF", { BFD_RELOC_386_TLS_LDO_32, 4442218822Sdim BFD_RELOC_X86_64_DTPOFF32 }, 4443218822Sdim Imm32 | Imm32S | Imm64 | Disp32 | Disp64 }, 4444218822Sdim { "GOTNTPOFF",{ BFD_RELOC_386_TLS_GOTIE, 4445218822Sdim 0 }, 4446218822Sdim 0 }, 4447218822Sdim { "INDNTPOFF",{ BFD_RELOC_386_TLS_IE, 4448218822Sdim 0 }, 4449218822Sdim 0 }, 4450218822Sdim { "GOT", { BFD_RELOC_386_GOT32, 4451218822Sdim BFD_RELOC_X86_64_GOT32 }, 4452218822Sdim Imm32 | Imm32S | Disp32 | Imm64 }, 4453218822Sdim { "TLSDESC", { BFD_RELOC_386_TLS_GOTDESC, 4454218822Sdim BFD_RELOC_X86_64_GOTPC32_TLSDESC }, 4455218822Sdim Imm32 | Imm32S | Disp32 }, 4456218822Sdim { "TLSCALL", { BFD_RELOC_386_TLS_DESC_CALL, 4457218822Sdim BFD_RELOC_X86_64_TLSDESC_CALL }, 4458218822Sdim Imm32 | Imm32S | Disp32 } 445978840Sobrien }; 446078840Sobrien char *cp; 446178840Sobrien unsigned int j; 446278840Sobrien 4463218822Sdim if (!IS_ELF) 4464218822Sdim return NULL; 4465218822Sdim 446678840Sobrien for (cp = input_line_pointer; *cp != '@'; cp++) 446778840Sobrien if (is_end_of_line[(unsigned char) *cp]) 446878840Sobrien return NULL; 446978840Sobrien 447078840Sobrien for (j = 0; j < sizeof (gotrel) / sizeof (gotrel[0]); j++) 447178840Sobrien { 447278840Sobrien int len; 447378840Sobrien 447478840Sobrien len = strlen (gotrel[j].str); 447589867Sobrien if (strncasecmp (cp + 1, gotrel[j].str, len) == 0) 447678840Sobrien { 4477218822Sdim if (gotrel[j].rel[object_64bit] != 0) 447878840Sobrien { 447989867Sobrien int first, second; 448089867Sobrien char *tmpbuf, *past_reloc; 448178840Sobrien 4482218822Sdim *reloc = gotrel[j].rel[object_64bit]; 448389867Sobrien if (adjust) 448489867Sobrien *adjust = len; 448578840Sobrien 4486218822Sdim if (types) 4487218822Sdim { 4488218822Sdim if (flag_code != CODE_64BIT) 4489218822Sdim *types = Imm32 | Disp32; 4490218822Sdim else 4491218822Sdim *types = gotrel[j].types64; 4492218822Sdim } 4493218822Sdim 449478840Sobrien if (GOT_symbol == NULL) 449578840Sobrien GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME); 449678840Sobrien 449789867Sobrien /* The length of the first part of our input line. */ 449878840Sobrien first = cp - input_line_pointer; 449989867Sobrien 450089867Sobrien /* The second part goes from after the reloc token until 450189867Sobrien (and including) an end_of_line char. Don't use strlen 450289867Sobrien here as the end_of_line char may not be a NUL. */ 450389867Sobrien past_reloc = cp + 1 + len; 450489867Sobrien for (cp = past_reloc; !is_end_of_line[(unsigned char) *cp++]; ) 450589867Sobrien ; 450689867Sobrien second = cp - past_reloc; 450789867Sobrien 450889867Sobrien /* Allocate and copy string. The trailing NUL shouldn't 450989867Sobrien be necessary, but be safe. */ 451089867Sobrien tmpbuf = xmalloc (first + second + 2); 451178840Sobrien memcpy (tmpbuf, input_line_pointer, first); 4512218822Sdim if (second != 0 && *past_reloc != ' ') 4513218822Sdim /* Replace the relocation token with ' ', so that 4514218822Sdim errors like foo@GOTOFF1 will be detected. */ 4515218822Sdim tmpbuf[first++] = ' '; 4516218822Sdim memcpy (tmpbuf + first, past_reloc, second); 4517218822Sdim tmpbuf[first + second] = '\0'; 451878840Sobrien return tmpbuf; 451978840Sobrien } 452078840Sobrien 4521218822Sdim as_bad (_("@%s reloc is not supported with %d-bit output format"), 4522218822Sdim gotrel[j].str, 1 << (5 + object_64bit)); 452378840Sobrien return NULL; 452478840Sobrien } 452578840Sobrien } 452678840Sobrien 452778840Sobrien /* Might be a symbol version string. Don't as_bad here. */ 452878840Sobrien return NULL; 452978840Sobrien} 453078840Sobrien 453178840Sobrienvoid 4532218822Sdimx86_cons (expressionS *exp, int size) 453378840Sobrien{ 4534218822Sdim if (size == 4 || (object_64bit && size == 8)) 453578840Sobrien { 453678840Sobrien /* Handle @GOTOFF and the like in an expression. */ 453778840Sobrien char *save; 453878840Sobrien char *gotfree_input_line; 453978840Sobrien int adjust; 454078840Sobrien 454178840Sobrien save = input_line_pointer; 4542218822Sdim gotfree_input_line = lex_got (&got_reloc, &adjust, NULL); 454378840Sobrien if (gotfree_input_line) 454478840Sobrien input_line_pointer = gotfree_input_line; 454578840Sobrien 454678840Sobrien expression (exp); 454778840Sobrien 454878840Sobrien if (gotfree_input_line) 454978840Sobrien { 455078840Sobrien /* expression () has merrily parsed up to the end of line, 455178840Sobrien or a comma - in the wrong buffer. Transfer how far 455278840Sobrien input_line_pointer has moved to the right buffer. */ 455378840Sobrien input_line_pointer = (save 455478840Sobrien + (input_line_pointer - gotfree_input_line) 455578840Sobrien + adjust); 455678840Sobrien free (gotfree_input_line); 455778840Sobrien } 455878840Sobrien } 455978840Sobrien else 456078840Sobrien expression (exp); 456178840Sobrien} 456278840Sobrien#endif 456378840Sobrien 4564218822Sdimstatic void signed_cons (int size) 4565218822Sdim{ 4566218822Sdim if (flag_code == CODE_64BIT) 4567218822Sdim cons_sign = 1; 4568218822Sdim cons (size); 4569218822Sdim cons_sign = -1; 4570218822Sdim} 457160519Sobrien 4572218822Sdim#ifdef TE_PE 4573218822Sdimstatic void 4574218822Sdimpe_directive_secrel (dummy) 4575218822Sdim int dummy ATTRIBUTE_UNUSED; 4576218822Sdim{ 4577218822Sdim expressionS exp; 4578218822Sdim 4579218822Sdim do 4580218822Sdim { 4581218822Sdim expression (&exp); 4582218822Sdim if (exp.X_op == O_symbol) 4583218822Sdim exp.X_op = O_secrel; 4584218822Sdim 4585218822Sdim emit_expr (&exp, 4); 4586218822Sdim } 4587218822Sdim while (*input_line_pointer++ == ','); 4588218822Sdim 4589218822Sdim input_line_pointer--; 4590218822Sdim demand_empty_rest_of_line (); 4591218822Sdim} 4592218822Sdim#endif 4593218822Sdim 459460519Sobrienstatic int 4595218822Sdimi386_immediate (char *imm_start) 459660519Sobrien{ 459760519Sobrien char *save_input_line_pointer; 459878840Sobrien char *gotfree_input_line; 459960519Sobrien segT exp_seg = 0; 460077311Sobrien expressionS *exp; 4601218822Sdim unsigned int types = ~0U; 460260519Sobrien 460360519Sobrien if (i.imm_operands == MAX_IMMEDIATE_OPERANDS) 460460519Sobrien { 4605218822Sdim as_bad (_("at most %d immediate operands are allowed"), 4606218822Sdim MAX_IMMEDIATE_OPERANDS); 460760519Sobrien return 0; 460860519Sobrien } 460960519Sobrien 461060519Sobrien exp = &im_expressions[i.imm_operands++]; 461160519Sobrien i.op[this_operand].imms = exp; 461260519Sobrien 461360519Sobrien if (is_space_char (*imm_start)) 461460519Sobrien ++imm_start; 461560519Sobrien 461660519Sobrien save_input_line_pointer = input_line_pointer; 461760519Sobrien input_line_pointer = imm_start; 461860519Sobrien 4619218822Sdim gotfree_input_line = lex_got (&i.reloc[this_operand], NULL, &types); 462078840Sobrien if (gotfree_input_line) 462178840Sobrien input_line_pointer = gotfree_input_line; 462260519Sobrien 462360519Sobrien exp_seg = expression (exp); 462460519Sobrien 462560519Sobrien SKIP_WHITESPACE (); 462660519Sobrien if (*input_line_pointer) 462778840Sobrien as_bad (_("junk `%s' after expression"), input_line_pointer); 462860519Sobrien 462960519Sobrien input_line_pointer = save_input_line_pointer; 463078840Sobrien if (gotfree_input_line) 463178840Sobrien free (gotfree_input_line); 463260519Sobrien 463360519Sobrien if (exp->X_op == O_absent || exp->X_op == O_big) 463460519Sobrien { 463577311Sobrien /* Missing or bad expr becomes absolute 0. */ 463660519Sobrien as_bad (_("missing or invalid immediate expression `%s' taken as 0"), 463760519Sobrien imm_start); 463860519Sobrien exp->X_op = O_constant; 463960519Sobrien exp->X_add_number = 0; 464060519Sobrien exp->X_add_symbol = (symbolS *) 0; 464160519Sobrien exp->X_op_symbol = (symbolS *) 0; 464260519Sobrien } 464377311Sobrien else if (exp->X_op == O_constant) 464460519Sobrien { 464577311Sobrien /* Size it properly later. */ 464677311Sobrien i.types[this_operand] |= Imm64; 464777311Sobrien /* If BFD64, sign extend val. */ 4648218822Sdim if (!use_rela_relocations 4649218822Sdim && (exp->X_add_number & ~(((addressT) 2 << 31) - 1)) == 0) 4650218822Sdim exp->X_add_number 4651218822Sdim = (exp->X_add_number ^ ((addressT) 1 << 31)) - ((addressT) 1 << 31); 465260519Sobrien } 465360519Sobrien#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT)) 4654130570Sobrien else if (OUTPUT_FLAVOR == bfd_target_aout_flavour 4655104848Sobrien && exp_seg != absolute_section 465677311Sobrien && exp_seg != text_section 465760519Sobrien && exp_seg != data_section 465860519Sobrien && exp_seg != bss_section 465960519Sobrien && exp_seg != undefined_section 4660130570Sobrien && !bfd_is_com_section (exp_seg)) 466160519Sobrien { 466260519Sobrien as_bad (_("unimplemented segment %s in operand"), exp_seg->name); 466360519Sobrien return 0; 466460519Sobrien } 466560519Sobrien#endif 4666218822Sdim else if (!intel_syntax && exp->X_op == O_register) 4667218822Sdim { 4668218822Sdim as_bad (_("illegal immediate register operand %s"), imm_start); 4669218822Sdim return 0; 4670218822Sdim } 467160519Sobrien else 467260519Sobrien { 467360519Sobrien /* This is an address. The size of the address will be 467460519Sobrien determined later, depending on destination register, 467577311Sobrien suffix, or the default for the section. */ 467677311Sobrien i.types[this_operand] |= Imm8 | Imm16 | Imm32 | Imm32S | Imm64; 4677218822Sdim i.types[this_operand] &= types; 467860519Sobrien } 467960519Sobrien 468060519Sobrien return 1; 468160519Sobrien} 468260519Sobrien 468378840Sobrienstatic char * 4684218822Sdimi386_scale (char *scale) 468560519Sobrien{ 468678840Sobrien offsetT val; 468778840Sobrien char *save = input_line_pointer; 468860519Sobrien 468978840Sobrien input_line_pointer = scale; 469078840Sobrien val = get_absolute_expression (); 469178840Sobrien 469278840Sobrien switch (val) 469360519Sobrien { 469478840Sobrien case 1: 469560519Sobrien i.log2_scale_factor = 0; 469660519Sobrien break; 469778840Sobrien case 2: 469860519Sobrien i.log2_scale_factor = 1; 469960519Sobrien break; 470078840Sobrien case 4: 470160519Sobrien i.log2_scale_factor = 2; 470260519Sobrien break; 470378840Sobrien case 8: 470460519Sobrien i.log2_scale_factor = 3; 470560519Sobrien break; 470660519Sobrien default: 4707218822Sdim { 4708218822Sdim char sep = *input_line_pointer; 4709218822Sdim 4710218822Sdim *input_line_pointer = '\0'; 4711218822Sdim as_bad (_("expecting scale factor of 1, 2, 4, or 8: got `%s'"), 4712218822Sdim scale); 4713218822Sdim *input_line_pointer = sep; 4714218822Sdim input_line_pointer = save; 4715218822Sdim return NULL; 4716218822Sdim } 471760519Sobrien } 471894546Sobrien if (i.log2_scale_factor != 0 && i.index_reg == 0) 471960519Sobrien { 472060519Sobrien as_warn (_("scale factor of %d without an index register"), 472160519Sobrien 1 << i.log2_scale_factor); 472260519Sobrien#if SCALE1_WHEN_NO_INDEX 472360519Sobrien i.log2_scale_factor = 0; 472460519Sobrien#endif 472560519Sobrien } 472678840Sobrien scale = input_line_pointer; 472778840Sobrien input_line_pointer = save; 472878840Sobrien return scale; 472960519Sobrien} 473060519Sobrien 473160519Sobrienstatic int 4732218822Sdimi386_displacement (char *disp_start, char *disp_end) 473360519Sobrien{ 473494546Sobrien expressionS *exp; 473560519Sobrien segT exp_seg = 0; 473660519Sobrien char *save_input_line_pointer; 473778840Sobrien char *gotfree_input_line; 4738218822Sdim int bigdisp, override; 4739218822Sdim unsigned int types = Disp; 474060519Sobrien 4741218822Sdim if (i.disp_operands == MAX_MEMORY_OPERANDS) 4742218822Sdim { 4743218822Sdim as_bad (_("at most %d displacement operands are allowed"), 4744218822Sdim MAX_MEMORY_OPERANDS); 4745218822Sdim return 0; 4746218822Sdim } 4747218822Sdim 4748218822Sdim if ((i.types[this_operand] & JumpAbsolute) 4749218822Sdim || !(current_templates->start->opcode_modifier & (Jump | JumpDword))) 4750218822Sdim { 4751218822Sdim bigdisp = Disp32; 4752218822Sdim override = (i.prefix[ADDR_PREFIX] != 0); 4753218822Sdim } 4754218822Sdim else 4755218822Sdim { 4756218822Sdim /* For PC-relative branches, the width of the displacement 4757218822Sdim is dependent upon data size, not address size. */ 4758218822Sdim bigdisp = 0; 4759218822Sdim override = (i.prefix[DATA_PREFIX] != 0); 4760218822Sdim } 476191054Sobrien if (flag_code == CODE_64BIT) 476291054Sobrien { 4763218822Sdim if (!bigdisp) 4764218822Sdim bigdisp = ((override || i.suffix == WORD_MNEM_SUFFIX) 4765218822Sdim ? Disp16 4766218822Sdim : Disp32S | Disp32); 4767218822Sdim else if (!override) 4768218822Sdim bigdisp = Disp64 | Disp32S | Disp32; 476991054Sobrien } 4770218822Sdim else 4771218822Sdim { 4772218822Sdim if (!bigdisp) 4773218822Sdim { 4774218822Sdim if (!override) 4775218822Sdim override = (i.suffix == (flag_code != CODE_16BIT 4776218822Sdim ? WORD_MNEM_SUFFIX 4777218822Sdim : LONG_MNEM_SUFFIX)); 4778218822Sdim bigdisp = Disp32; 4779218822Sdim } 4780218822Sdim if ((flag_code == CODE_16BIT) ^ override) 4781218822Sdim bigdisp = Disp16; 4782218822Sdim } 478360519Sobrien i.types[this_operand] |= bigdisp; 478460519Sobrien 478560519Sobrien exp = &disp_expressions[i.disp_operands]; 478660519Sobrien i.op[this_operand].disps = exp; 478760519Sobrien i.disp_operands++; 478860519Sobrien save_input_line_pointer = input_line_pointer; 478960519Sobrien input_line_pointer = disp_start; 479060519Sobrien END_STRING_AND_SAVE (disp_end); 479160519Sobrien 479260519Sobrien#ifndef GCC_ASM_O_HACK 479360519Sobrien#define GCC_ASM_O_HACK 0 479460519Sobrien#endif 479560519Sobrien#if GCC_ASM_O_HACK 479660519Sobrien END_STRING_AND_SAVE (disp_end + 1); 479760519Sobrien if ((i.types[this_operand] & BaseIndex) != 0 479860519Sobrien && displacement_string_end[-1] == '+') 479960519Sobrien { 480060519Sobrien /* This hack is to avoid a warning when using the "o" 480160519Sobrien constraint within gcc asm statements. 480260519Sobrien For instance: 480360519Sobrien 480460519Sobrien #define _set_tssldt_desc(n,addr,limit,type) \ 480560519Sobrien __asm__ __volatile__ ( \ 480660519Sobrien "movw %w2,%0\n\t" \ 480760519Sobrien "movw %w1,2+%0\n\t" \ 480860519Sobrien "rorl $16,%1\n\t" \ 480960519Sobrien "movb %b1,4+%0\n\t" \ 481060519Sobrien "movb %4,5+%0\n\t" \ 481160519Sobrien "movb $0,6+%0\n\t" \ 481260519Sobrien "movb %h1,7+%0\n\t" \ 481360519Sobrien "rorl $16,%1" \ 481460519Sobrien : "=o"(*(n)) : "q" (addr), "ri"(limit), "i"(type)) 481560519Sobrien 481660519Sobrien This works great except that the output assembler ends 481760519Sobrien up looking a bit weird if it turns out that there is 481860519Sobrien no offset. You end up producing code that looks like: 481960519Sobrien 482060519Sobrien #APP 482160519Sobrien movw $235,(%eax) 482260519Sobrien movw %dx,2+(%eax) 482360519Sobrien rorl $16,%edx 482460519Sobrien movb %dl,4+(%eax) 482560519Sobrien movb $137,5+(%eax) 482660519Sobrien movb $0,6+(%eax) 482760519Sobrien movb %dh,7+(%eax) 482860519Sobrien rorl $16,%edx 482960519Sobrien #NO_APP 483060519Sobrien 483177311Sobrien So here we provide the missing zero. */ 483260519Sobrien 483360519Sobrien *displacement_string_end = '0'; 483460519Sobrien } 483560519Sobrien#endif 4836218822Sdim gotfree_input_line = lex_got (&i.reloc[this_operand], NULL, &types); 483778840Sobrien if (gotfree_input_line) 483878840Sobrien input_line_pointer = gotfree_input_line; 483960519Sobrien 484078840Sobrien exp_seg = expression (exp); 484160519Sobrien 484278840Sobrien SKIP_WHITESPACE (); 484378840Sobrien if (*input_line_pointer) 484478840Sobrien as_bad (_("junk `%s' after expression"), input_line_pointer); 484578840Sobrien#if GCC_ASM_O_HACK 484678840Sobrien RESTORE_END_STRING (disp_end + 1); 484760519Sobrien#endif 484878840Sobrien RESTORE_END_STRING (disp_end); 484978840Sobrien input_line_pointer = save_input_line_pointer; 485078840Sobrien if (gotfree_input_line) 485178840Sobrien free (gotfree_input_line); 485260519Sobrien 485360519Sobrien /* We do this to make sure that the section symbol is in 485460519Sobrien the symbol table. We will ultimately change the relocation 485577311Sobrien to be relative to the beginning of the section. */ 485678840Sobrien if (i.reloc[this_operand] == BFD_RELOC_386_GOTOFF 4857218822Sdim || i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL 4858218822Sdim || i.reloc[this_operand] == BFD_RELOC_X86_64_GOTOFF64) 485960519Sobrien { 486078840Sobrien if (exp->X_op != O_symbol) 486178840Sobrien { 486278840Sobrien as_bad (_("bad expression used with @%s"), 486378840Sobrien (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL 486478840Sobrien ? "GOTPCREL" 486578840Sobrien : "GOTOFF")); 486678840Sobrien return 0; 486778840Sobrien } 486878840Sobrien 486977311Sobrien if (S_IS_LOCAL (exp->X_add_symbol) 487060519Sobrien && S_GET_SEGMENT (exp->X_add_symbol) != undefined_section) 487160519Sobrien section_symbol (S_GET_SEGMENT (exp->X_add_symbol)); 487260519Sobrien exp->X_op = O_subtract; 487360519Sobrien exp->X_op_symbol = GOT_symbol; 487478840Sobrien if (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL) 487594546Sobrien i.reloc[this_operand] = BFD_RELOC_32_PCREL; 4876218822Sdim else if (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTOFF64) 4877218822Sdim i.reloc[this_operand] = BFD_RELOC_64; 487877311Sobrien else 487994546Sobrien i.reloc[this_operand] = BFD_RELOC_32; 488060519Sobrien } 488160519Sobrien 488260519Sobrien if (exp->X_op == O_absent || exp->X_op == O_big) 488360519Sobrien { 488477311Sobrien /* Missing or bad expr becomes absolute 0. */ 488560519Sobrien as_bad (_("missing or invalid displacement expression `%s' taken as 0"), 488660519Sobrien disp_start); 488760519Sobrien exp->X_op = O_constant; 488860519Sobrien exp->X_add_number = 0; 488960519Sobrien exp->X_add_symbol = (symbolS *) 0; 489060519Sobrien exp->X_op_symbol = (symbolS *) 0; 489160519Sobrien } 489260519Sobrien 489360519Sobrien#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT)) 489477311Sobrien if (exp->X_op != O_constant 489577311Sobrien && OUTPUT_FLAVOR == bfd_target_aout_flavour 4896104848Sobrien && exp_seg != absolute_section 489777311Sobrien && exp_seg != text_section 489877311Sobrien && exp_seg != data_section 489977311Sobrien && exp_seg != bss_section 4900104848Sobrien && exp_seg != undefined_section 4901130570Sobrien && !bfd_is_com_section (exp_seg)) 490260519Sobrien { 490360519Sobrien as_bad (_("unimplemented segment %s in operand"), exp_seg->name); 490460519Sobrien return 0; 490560519Sobrien } 490660519Sobrien#endif 4907218822Sdim 4908218822Sdim if (!(i.types[this_operand] & ~Disp)) 4909218822Sdim i.types[this_operand] &= types; 4910218822Sdim 491160519Sobrien return 1; 491260519Sobrien} 491360519Sobrien 491477311Sobrien/* Make sure the memory operand we've been dealt is valid. 491577311Sobrien Return 1 on success, 0 on a failure. */ 491677311Sobrien 491760519Sobrienstatic int 4918218822Sdimi386_index_check (const char *operand_string) 491960519Sobrien{ 492077311Sobrien int ok; 492177311Sobrien#if INFER_ADDR_PREFIX 492277311Sobrien int fudged = 0; 492360519Sobrien 492477311Sobrien tryprefix: 492577311Sobrien#endif 492677311Sobrien ok = 1; 4927218822Sdim if ((current_templates->start->cpu_flags & CpuSVME) 4928218822Sdim && current_templates->end[-1].operand_types[0] == AnyMem) 492960519Sobrien { 4930218822Sdim /* Memory operands of SVME insns are special in that they only allow 4931218822Sdim rAX as their memory address and ignore any segment override. */ 4932218822Sdim unsigned RegXX; 4933218822Sdim 4934218822Sdim /* SKINIT is even more restrictive: it always requires EAX. */ 4935218822Sdim if (strcmp (current_templates->start->name, "skinit") == 0) 4936218822Sdim RegXX = Reg32; 4937218822Sdim else if (flag_code == CODE_64BIT) 4938218822Sdim RegXX = i.prefix[ADDR_PREFIX] == 0 ? Reg64 : Reg32; 493991054Sobrien else 4940218822Sdim RegXX = ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0) 4941218822Sdim ? Reg16 4942218822Sdim : Reg32); 4943218822Sdim if (!i.base_reg 4944218822Sdim || !(i.base_reg->reg_type & Acc) 4945218822Sdim || !(i.base_reg->reg_type & RegXX) 4946218822Sdim || i.index_reg 4947218822Sdim || (i.types[0] & Disp)) 4948218822Sdim ok = 0; 494960519Sobrien } 4950218822Sdim else if (flag_code == CODE_64BIT) 4951218822Sdim { 4952218822Sdim unsigned RegXX = (i.prefix[ADDR_PREFIX] == 0 ? Reg64 : Reg32); 4953218822Sdim 4954218822Sdim if ((i.base_reg 4955218822Sdim && ((i.base_reg->reg_type & RegXX) == 0) 4956218822Sdim && (i.base_reg->reg_type != BaseIndex 4957218822Sdim || i.index_reg)) 4958218822Sdim || (i.index_reg 4959218822Sdim && ((i.index_reg->reg_type & (RegXX | BaseIndex)) 4960218822Sdim != (RegXX | BaseIndex)))) 4961218822Sdim ok = 0; 4962218822Sdim } 496360519Sobrien else 496460519Sobrien { 496577311Sobrien if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0)) 496660519Sobrien { 496777311Sobrien /* 16bit checks. */ 496877311Sobrien if ((i.base_reg 496994546Sobrien && ((i.base_reg->reg_type & (Reg16 | BaseIndex | RegRex)) 497094546Sobrien != (Reg16 | BaseIndex))) 497177311Sobrien || (i.index_reg 497294546Sobrien && (((i.index_reg->reg_type & (Reg16 | BaseIndex)) 497394546Sobrien != (Reg16 | BaseIndex)) 497494546Sobrien || !(i.base_reg 497594546Sobrien && i.base_reg->reg_num < 6 497694546Sobrien && i.index_reg->reg_num >= 6 497794546Sobrien && i.log2_scale_factor == 0)))) 497877311Sobrien ok = 0; 497960519Sobrien } 498077311Sobrien else 498177311Sobrien { 498277311Sobrien /* 32bit checks. */ 498377311Sobrien if ((i.base_reg 498477311Sobrien && (i.base_reg->reg_type & (Reg32 | RegRex)) != Reg32) 498577311Sobrien || (i.index_reg 498694546Sobrien && ((i.index_reg->reg_type & (Reg32 | BaseIndex | RegRex)) 498794546Sobrien != (Reg32 | BaseIndex)))) 498877311Sobrien ok = 0; 498977311Sobrien } 499060519Sobrien } 499177311Sobrien if (!ok) 499260519Sobrien { 499360519Sobrien#if INFER_ADDR_PREFIX 4994218822Sdim if (i.prefix[ADDR_PREFIX] == 0) 499560519Sobrien { 499660519Sobrien i.prefix[ADDR_PREFIX] = ADDR_PREFIX_OPCODE; 499760519Sobrien i.prefixes += 1; 499860519Sobrien /* Change the size of any displacement too. At most one of 499960519Sobrien Disp16 or Disp32 is set. 500060519Sobrien FIXME. There doesn't seem to be any real need for separate 500160519Sobrien Disp16 and Disp32 flags. The same goes for Imm16 and Imm32. 500277311Sobrien Removing them would probably clean up the code quite a lot. */ 5003218822Sdim if (flag_code != CODE_64BIT 5004218822Sdim && (i.types[this_operand] & (Disp16 | Disp32))) 5005218822Sdim i.types[this_operand] ^= (Disp16 | Disp32); 500660519Sobrien fudged = 1; 500760519Sobrien goto tryprefix; 500860519Sobrien } 500960519Sobrien if (fudged) 501060519Sobrien as_bad (_("`%s' is not a valid base/index expression"), 501160519Sobrien operand_string); 501260519Sobrien else 501360519Sobrien#endif 501460519Sobrien as_bad (_("`%s' is not a valid %s bit base/index expression"), 501560519Sobrien operand_string, 501677311Sobrien flag_code_names[flag_code]); 501760519Sobrien } 5018218822Sdim return ok; 501960519Sobrien} 502060519Sobrien 502133965Sjdp/* Parse OPERAND_STRING into the i386_insn structure I. Returns non-zero 502277311Sobrien on error. */ 502333965Sjdp 502433965Sjdpstatic int 5025218822Sdimi386_operand (char *operand_string) 502633965Sjdp{ 502760519Sobrien const reg_entry *r; 502860519Sobrien char *end_op; 502960519Sobrien char *op_string = operand_string; 503033965Sjdp 503160519Sobrien if (is_space_char (*op_string)) 503260519Sobrien ++op_string; 503333965Sjdp 503433965Sjdp /* We check for an absolute prefix (differentiating, 503577311Sobrien for example, 'jmp pc_relative_label' from 'jmp *absolute_label'. */ 503633965Sjdp if (*op_string == ABSOLUTE_PREFIX) 503733965Sjdp { 503860519Sobrien ++op_string; 503960519Sobrien if (is_space_char (*op_string)) 504060519Sobrien ++op_string; 504133965Sjdp i.types[this_operand] |= JumpAbsolute; 504233965Sjdp } 504333965Sjdp 504477311Sobrien /* Check if operand is a register. */ 5045218822Sdim if ((r = parse_register (op_string, &end_op)) != NULL) 504633965Sjdp { 504760519Sobrien /* Check for a segment override by searching for ':' after a 504860519Sobrien segment register. */ 504960519Sobrien op_string = end_op; 505060519Sobrien if (is_space_char (*op_string)) 505160519Sobrien ++op_string; 505260519Sobrien if (*op_string == ':' && (r->reg_type & (SReg2 | SReg3))) 505333965Sjdp { 505433965Sjdp switch (r->reg_num) 505533965Sjdp { 505633965Sjdp case 0: 505760519Sobrien i.seg[i.mem_operands] = &es; 505833965Sjdp break; 505933965Sjdp case 1: 506060519Sobrien i.seg[i.mem_operands] = &cs; 506133965Sjdp break; 506233965Sjdp case 2: 506360519Sobrien i.seg[i.mem_operands] = &ss; 506433965Sjdp break; 506533965Sjdp case 3: 506660519Sobrien i.seg[i.mem_operands] = &ds; 506733965Sjdp break; 506833965Sjdp case 4: 506960519Sobrien i.seg[i.mem_operands] = &fs; 507033965Sjdp break; 507133965Sjdp case 5: 507260519Sobrien i.seg[i.mem_operands] = &gs; 507333965Sjdp break; 507433965Sjdp } 507560519Sobrien 507660519Sobrien /* Skip the ':' and whitespace. */ 507760519Sobrien ++op_string; 507860519Sobrien if (is_space_char (*op_string)) 507960519Sobrien ++op_string; 508060519Sobrien 508160519Sobrien if (!is_digit_char (*op_string) 508260519Sobrien && !is_identifier_char (*op_string) 508360519Sobrien && *op_string != '(' 508460519Sobrien && *op_string != ABSOLUTE_PREFIX) 508533965Sjdp { 508660519Sobrien as_bad (_("bad memory operand `%s'"), op_string); 508733965Sjdp return 0; 508833965Sjdp } 508977311Sobrien /* Handle case of %es:*foo. */ 509033965Sjdp if (*op_string == ABSOLUTE_PREFIX) 509133965Sjdp { 509260519Sobrien ++op_string; 509360519Sobrien if (is_space_char (*op_string)) 509460519Sobrien ++op_string; 509533965Sjdp i.types[this_operand] |= JumpAbsolute; 509633965Sjdp } 509733965Sjdp goto do_memory_reference; 509833965Sjdp } 509960519Sobrien if (*op_string) 510060519Sobrien { 510160519Sobrien as_bad (_("junk `%s' after register"), op_string); 510260519Sobrien return 0; 510360519Sobrien } 510460519Sobrien i.types[this_operand] |= r->reg_type & ~BaseIndex; 510560519Sobrien i.op[this_operand].regs = r; 510633965Sjdp i.reg_operands++; 510733965Sjdp } 510860519Sobrien else if (*op_string == REGISTER_PREFIX) 510960519Sobrien { 511060519Sobrien as_bad (_("bad register name `%s'"), op_string); 511160519Sobrien return 0; 511260519Sobrien } 511333965Sjdp else if (*op_string == IMMEDIATE_PREFIX) 511477311Sobrien { 511560519Sobrien ++op_string; 511660519Sobrien if (i.types[this_operand] & JumpAbsolute) 511733965Sjdp { 511860519Sobrien as_bad (_("immediate operand illegal with absolute jump")); 511933965Sjdp return 0; 512033965Sjdp } 512160519Sobrien if (!i386_immediate (op_string)) 512260519Sobrien return 0; 512333965Sjdp } 512460519Sobrien else if (is_digit_char (*op_string) 512560519Sobrien || is_identifier_char (*op_string) 512677311Sobrien || *op_string == '(') 512733965Sjdp { 512877311Sobrien /* This is a memory reference of some sort. */ 512960519Sobrien char *base_string; 513033965Sjdp 513177311Sobrien /* Start and end of displacement string expression (if found). */ 513260519Sobrien char *displacement_string_start; 513360519Sobrien char *displacement_string_end; 513460519Sobrien 513533965Sjdp do_memory_reference: 513660519Sobrien if ((i.mem_operands == 1 513760519Sobrien && (current_templates->start->opcode_modifier & IsString) == 0) 513860519Sobrien || i.mem_operands == 2) 513933965Sjdp { 514060519Sobrien as_bad (_("too many memory references for `%s'"), 514160519Sobrien current_templates->start->name); 514233965Sjdp return 0; 514333965Sjdp } 514433965Sjdp 514533965Sjdp /* Check for base index form. We detect the base index form by 514633965Sjdp looking for an ')' at the end of the operand, searching 514733965Sjdp for the '(' matching it, and finding a REGISTER_PREFIX or ',' 514860519Sobrien after the '('. */ 514960519Sobrien base_string = op_string + strlen (op_string); 515060519Sobrien 515160519Sobrien --base_string; 515260519Sobrien if (is_space_char (*base_string)) 515360519Sobrien --base_string; 515460519Sobrien 515577311Sobrien /* If we only have a displacement, set-up for it to be parsed later. */ 515660519Sobrien displacement_string_start = op_string; 515760519Sobrien displacement_string_end = base_string + 1; 515860519Sobrien 515933965Sjdp if (*base_string == ')') 516033965Sjdp { 516160519Sobrien char *temp_string; 516233965Sjdp unsigned int parens_balanced = 1; 516333965Sjdp /* We've already checked that the number of left & right ()'s are 516477311Sobrien equal, so this loop will not be infinite. */ 516533965Sjdp do 516633965Sjdp { 516733965Sjdp base_string--; 516833965Sjdp if (*base_string == ')') 516933965Sjdp parens_balanced++; 517033965Sjdp if (*base_string == '(') 517133965Sjdp parens_balanced--; 517233965Sjdp } 517333965Sjdp while (parens_balanced); 517433965Sjdp 517560519Sobrien temp_string = base_string; 517633965Sjdp 517760519Sobrien /* Skip past '(' and whitespace. */ 517860519Sobrien ++base_string; 517960519Sobrien if (is_space_char (*base_string)) 518060519Sobrien ++base_string; 518133965Sjdp 518260519Sobrien if (*base_string == ',' 5183218822Sdim || ((i.base_reg = parse_register (base_string, &end_op)) 5184218822Sdim != NULL)) 518533965Sjdp { 518660519Sobrien displacement_string_end = temp_string; 518733965Sjdp 518860519Sobrien i.types[this_operand] |= BaseIndex; 518960519Sobrien 519060519Sobrien if (i.base_reg) 519133965Sjdp { 519260519Sobrien base_string = end_op; 519360519Sobrien if (is_space_char (*base_string)) 519460519Sobrien ++base_string; 519533965Sjdp } 519660519Sobrien 519760519Sobrien /* There may be an index reg or scale factor here. */ 519860519Sobrien if (*base_string == ',') 519933965Sjdp { 520060519Sobrien ++base_string; 520160519Sobrien if (is_space_char (*base_string)) 520260519Sobrien ++base_string; 520333965Sjdp 5204218822Sdim if ((i.index_reg = parse_register (base_string, &end_op)) 5205218822Sdim != NULL) 520660519Sobrien { 520760519Sobrien base_string = end_op; 520860519Sobrien if (is_space_char (*base_string)) 520960519Sobrien ++base_string; 521060519Sobrien if (*base_string == ',') 521160519Sobrien { 521260519Sobrien ++base_string; 521360519Sobrien if (is_space_char (*base_string)) 521460519Sobrien ++base_string; 521560519Sobrien } 521677311Sobrien else if (*base_string != ')') 521760519Sobrien { 5218218822Sdim as_bad (_("expecting `,' or `)' " 5219218822Sdim "after index register in `%s'"), 522060519Sobrien operand_string); 522160519Sobrien return 0; 522260519Sobrien } 522360519Sobrien } 522460519Sobrien else if (*base_string == REGISTER_PREFIX) 522560519Sobrien { 522660519Sobrien as_bad (_("bad register name `%s'"), base_string); 522760519Sobrien return 0; 522860519Sobrien } 522933965Sjdp 523077311Sobrien /* Check for scale factor. */ 523178840Sobrien if (*base_string != ')') 523260519Sobrien { 523378840Sobrien char *end_scale = i386_scale (base_string); 523478840Sobrien 523578840Sobrien if (!end_scale) 523660519Sobrien return 0; 523733965Sjdp 523878840Sobrien base_string = end_scale; 523960519Sobrien if (is_space_char (*base_string)) 524060519Sobrien ++base_string; 524160519Sobrien if (*base_string != ')') 524260519Sobrien { 5243218822Sdim as_bad (_("expecting `)' " 5244218822Sdim "after scale factor in `%s'"), 524560519Sobrien operand_string); 524660519Sobrien return 0; 524760519Sobrien } 524860519Sobrien } 524960519Sobrien else if (!i.index_reg) 525060519Sobrien { 5251218822Sdim as_bad (_("expecting index register or scale factor " 5252218822Sdim "after `,'; got '%c'"), 525360519Sobrien *base_string); 525460519Sobrien return 0; 525560519Sobrien } 525633965Sjdp } 525760519Sobrien else if (*base_string != ')') 525833965Sjdp { 5259218822Sdim as_bad (_("expecting `,' or `)' " 5260218822Sdim "after base register in `%s'"), 526160519Sobrien operand_string); 526233965Sjdp return 0; 526333965Sjdp } 526433965Sjdp } 526560519Sobrien else if (*base_string == REGISTER_PREFIX) 526633965Sjdp { 526760519Sobrien as_bad (_("bad register name `%s'"), base_string); 526860519Sobrien return 0; 526933965Sjdp } 527033965Sjdp } 527133965Sjdp 527260519Sobrien /* If there's an expression beginning the operand, parse it, 527360519Sobrien assuming displacement_string_start and 527460519Sobrien displacement_string_end are meaningful. */ 527560519Sobrien if (displacement_string_start != displacement_string_end) 527633965Sjdp { 527760519Sobrien if (!i386_displacement (displacement_string_start, 527860519Sobrien displacement_string_end)) 527960519Sobrien return 0; 528033965Sjdp } 528133965Sjdp 528260519Sobrien /* Special case for (%dx) while doing input/output op. */ 528360519Sobrien if (i.base_reg 528460519Sobrien && i.base_reg->reg_type == (Reg16 | InOutPortReg) 528560519Sobrien && i.index_reg == 0 528660519Sobrien && i.log2_scale_factor == 0 528760519Sobrien && i.seg[i.mem_operands] == 0 528860519Sobrien && (i.types[this_operand] & Disp) == 0) 528933965Sjdp { 529060519Sobrien i.types[this_operand] = InOutPortReg; 529133965Sjdp return 1; 529233965Sjdp } 529360519Sobrien 529460519Sobrien if (i386_index_check (operand_string) == 0) 529560519Sobrien return 0; 529660519Sobrien i.mem_operands++; 529733965Sjdp } 529833965Sjdp else 529977311Sobrien { 530077311Sobrien /* It's not a memory operand; argh! */ 530160519Sobrien as_bad (_("invalid char %s beginning operand %d `%s'"), 530260519Sobrien output_invalid (*op_string), 530360519Sobrien this_operand + 1, 530433965Sjdp op_string); 530533965Sjdp return 0; 530633965Sjdp } 530777311Sobrien return 1; /* Normal return. */ 530833965Sjdp} 530933965Sjdp 531061847Sobrien/* md_estimate_size_before_relax() 531161847Sobrien 531261847Sobrien Called just before relax() for rs_machine_dependent frags. The x86 531361847Sobrien assembler uses these frags to handle variable size jump 531461847Sobrien instructions. 531561847Sobrien 531661847Sobrien Any symbol that is now undefined will not become defined. 531761847Sobrien Return the correct fr_subtype in the frag. 531861847Sobrien Return the initial "guess for variable size of frag" to caller. 531961847Sobrien The guess is actually the growth beyond the fixed part. Whatever 532061847Sobrien we do to grow the fixed or variable part contributes to our 532161847Sobrien returned value. */ 532261847Sobrien 532333965Sjdpint 532433965Sjdpmd_estimate_size_before_relax (fragP, segment) 532594546Sobrien fragS *fragP; 532694546Sobrien segT segment; 532733965Sjdp{ 532860519Sobrien /* We've already got fragP->fr_subtype right; all we have to do is 532961847Sobrien check for un-relaxable symbols. On an ELF system, we can't relax 533061847Sobrien an externally visible symbol, because it may be overridden by a 533161847Sobrien shared library. */ 533261847Sobrien if (S_GET_SEGMENT (fragP->fr_symbol) != segment 533377311Sobrien#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) 5334218822Sdim || (IS_ELF 5335104848Sobrien && (S_IS_EXTERNAL (fragP->fr_symbol) 5336104848Sobrien || S_IS_WEAK (fragP->fr_symbol))) 533761847Sobrien#endif 533861847Sobrien ) 533933965Sjdp { 534061847Sobrien /* Symbol is undefined in this segment, or we need to keep a 534161847Sobrien reloc so that weak symbols can be overridden. */ 534261847Sobrien int size = (fragP->fr_subtype & CODE16) ? 2 : 4; 5343130570Sobrien enum bfd_reloc_code_real reloc_type; 534461847Sobrien unsigned char *opcode; 534561847Sobrien int old_fr_fix; 534660519Sobrien 534761847Sobrien if (fragP->fr_var != NO_RELOC) 534861847Sobrien reloc_type = fragP->fr_var; 534961847Sobrien else if (size == 2) 535060519Sobrien reloc_type = BFD_RELOC_16_PCREL; 535160519Sobrien else 535260519Sobrien reloc_type = BFD_RELOC_32_PCREL; 535360519Sobrien 535461847Sobrien old_fr_fix = fragP->fr_fix; 535561847Sobrien opcode = (unsigned char *) fragP->fr_opcode; 535661847Sobrien 535778840Sobrien switch (TYPE_FROM_RELAX_STATE (fragP->fr_subtype)) 535833965Sjdp { 535978840Sobrien case UNCOND_JUMP: 536078840Sobrien /* Make jmp (0xeb) a (d)word displacement jump. */ 536177311Sobrien opcode[0] = 0xe9; 536260519Sobrien fragP->fr_fix += size; 536399468Sobrien fix_new (fragP, old_fr_fix, size, 536499468Sobrien fragP->fr_symbol, 536599468Sobrien fragP->fr_offset, 1, 536699468Sobrien reloc_type); 536733965Sjdp break; 536833965Sjdp 536978840Sobrien case COND_JUMP86: 537099468Sobrien if (size == 2 537199468Sobrien && (!no_cond_jump_promotion || fragP->fr_var != NO_RELOC)) 537278840Sobrien { 537378840Sobrien /* Negate the condition, and branch past an 537478840Sobrien unconditional jump. */ 537578840Sobrien opcode[0] ^= 1; 537678840Sobrien opcode[1] = 3; 537778840Sobrien /* Insert an unconditional jump. */ 537878840Sobrien opcode[2] = 0xe9; 537978840Sobrien /* We added two extra opcode bytes, and have a two byte 538078840Sobrien offset. */ 538178840Sobrien fragP->fr_fix += 2 + 2; 538299468Sobrien fix_new (fragP, old_fr_fix + 2, 2, 538399468Sobrien fragP->fr_symbol, 538499468Sobrien fragP->fr_offset, 1, 538599468Sobrien reloc_type); 538678840Sobrien break; 538778840Sobrien } 538878840Sobrien /* Fall through. */ 538978840Sobrien 539078840Sobrien case COND_JUMP: 539199468Sobrien if (no_cond_jump_promotion && fragP->fr_var == NO_RELOC) 539299468Sobrien { 5393104848Sobrien fixS *fixP; 5394104848Sobrien 539599468Sobrien fragP->fr_fix += 1; 5396104848Sobrien fixP = fix_new (fragP, old_fr_fix, 1, 5397104848Sobrien fragP->fr_symbol, 5398104848Sobrien fragP->fr_offset, 1, 5399104848Sobrien BFD_RELOC_8_PCREL); 5400104848Sobrien fixP->fx_signed = 1; 540199468Sobrien break; 540299468Sobrien } 540378840Sobrien 540460519Sobrien /* This changes the byte-displacement jump 0x7N 540578840Sobrien to the (d)word-displacement jump 0x0f,0x8N. */ 540633965Sjdp opcode[1] = opcode[0] + 0x10; 540760519Sobrien opcode[0] = TWO_BYTE_OPCODE_ESCAPE; 540877311Sobrien /* We've added an opcode byte. */ 540977311Sobrien fragP->fr_fix += 1 + size; 541099468Sobrien fix_new (fragP, old_fr_fix + 1, size, 541199468Sobrien fragP->fr_symbol, 541299468Sobrien fragP->fr_offset, 1, 541399468Sobrien reloc_type); 541433965Sjdp break; 541578840Sobrien 541678840Sobrien default: 541778840Sobrien BAD_CASE (fragP->fr_subtype); 541878840Sobrien break; 541933965Sjdp } 542033965Sjdp frag_wane (fragP); 542161847Sobrien return fragP->fr_fix - old_fr_fix; 542233965Sjdp } 542378840Sobrien 542478840Sobrien /* Guess size depending on current relax state. Initially the relax 542578840Sobrien state will correspond to a short jump and we return 1, because 542678840Sobrien the variable part of the frag (the branch offset) is one byte 542778840Sobrien long. However, we can relax a section more than once and in that 542878840Sobrien case we must either set fr_subtype back to the unrelaxed state, 542978840Sobrien or return the value for the appropriate branch. */ 543078840Sobrien return md_relax_table[fragP->fr_subtype].rlx_length; 543161847Sobrien} 543261847Sobrien 543377311Sobrien/* Called after relax() is finished. 543477311Sobrien 543577311Sobrien In: Address of frag. 543677311Sobrien fr_type == rs_machine_dependent. 543777311Sobrien fr_subtype is what the address relaxed to. 543877311Sobrien 543977311Sobrien Out: Any fixSs and constants are set up. 544077311Sobrien Caller will turn frag into a ".space 0". */ 544177311Sobrien 544233965Sjdpvoid 544333965Sjdpmd_convert_frag (abfd, sec, fragP) 544460519Sobrien bfd *abfd ATTRIBUTE_UNUSED; 544560519Sobrien segT sec ATTRIBUTE_UNUSED; 544694546Sobrien fragS *fragP; 544733965Sjdp{ 544894546Sobrien unsigned char *opcode; 544933965Sjdp unsigned char *where_to_put_displacement = NULL; 545077311Sobrien offsetT target_address; 545177311Sobrien offsetT opcode_address; 545233965Sjdp unsigned int extension = 0; 545377311Sobrien offsetT displacement_from_opcode_start; 545433965Sjdp 545533965Sjdp opcode = (unsigned char *) fragP->fr_opcode; 545633965Sjdp 545777311Sobrien /* Address we want to reach in file space. */ 545833965Sjdp target_address = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset; 545933965Sjdp 546077311Sobrien /* Address opcode resides at in file space. */ 546133965Sjdp opcode_address = fragP->fr_address + fragP->fr_fix; 546233965Sjdp 546377311Sobrien /* Displacement from opcode start to fill into instruction. */ 546433965Sjdp displacement_from_opcode_start = target_address - opcode_address; 546533965Sjdp 546678840Sobrien if ((fragP->fr_subtype & BIG) == 0) 546733965Sjdp { 546877311Sobrien /* Don't have to change opcode. */ 546977311Sobrien extension = 1; /* 1 opcode + 1 displacement */ 547033965Sjdp where_to_put_displacement = &opcode[1]; 547178840Sobrien } 547278840Sobrien else 547378840Sobrien { 547478840Sobrien if (no_cond_jump_promotion 547578840Sobrien && TYPE_FROM_RELAX_STATE (fragP->fr_subtype) != UNCOND_JUMP) 5476218822Sdim as_warn_where (fragP->fr_file, fragP->fr_line, 5477218822Sdim _("long jump required")); 547833965Sjdp 547978840Sobrien switch (fragP->fr_subtype) 548078840Sobrien { 548178840Sobrien case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG): 548278840Sobrien extension = 4; /* 1 opcode + 4 displacement */ 548378840Sobrien opcode[0] = 0xe9; 548478840Sobrien where_to_put_displacement = &opcode[1]; 548578840Sobrien break; 548633965Sjdp 548778840Sobrien case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG16): 548878840Sobrien extension = 2; /* 1 opcode + 2 displacement */ 548978840Sobrien opcode[0] = 0xe9; 549078840Sobrien where_to_put_displacement = &opcode[1]; 549178840Sobrien break; 549233965Sjdp 549378840Sobrien case ENCODE_RELAX_STATE (COND_JUMP, BIG): 549478840Sobrien case ENCODE_RELAX_STATE (COND_JUMP86, BIG): 549578840Sobrien extension = 5; /* 2 opcode + 4 displacement */ 549678840Sobrien opcode[1] = opcode[0] + 0x10; 549778840Sobrien opcode[0] = TWO_BYTE_OPCODE_ESCAPE; 549878840Sobrien where_to_put_displacement = &opcode[2]; 549978840Sobrien break; 550033965Sjdp 550178840Sobrien case ENCODE_RELAX_STATE (COND_JUMP, BIG16): 550278840Sobrien extension = 3; /* 2 opcode + 2 displacement */ 550378840Sobrien opcode[1] = opcode[0] + 0x10; 550478840Sobrien opcode[0] = TWO_BYTE_OPCODE_ESCAPE; 550578840Sobrien where_to_put_displacement = &opcode[2]; 550678840Sobrien break; 550733965Sjdp 550878840Sobrien case ENCODE_RELAX_STATE (COND_JUMP86, BIG16): 550978840Sobrien extension = 4; 551078840Sobrien opcode[0] ^= 1; 551178840Sobrien opcode[1] = 3; 551278840Sobrien opcode[2] = 0xe9; 551378840Sobrien where_to_put_displacement = &opcode[3]; 551478840Sobrien break; 551578840Sobrien 551678840Sobrien default: 551778840Sobrien BAD_CASE (fragP->fr_subtype); 551878840Sobrien break; 551978840Sobrien } 552033965Sjdp } 552178840Sobrien 5522218822Sdim /* If size if less then four we are sure that the operand fits, 5523218822Sdim but if it's 4, then it could be that the displacement is larger 5524218822Sdim then -/+ 2GB. */ 5525218822Sdim if (DISP_SIZE_FROM_RELAX_STATE (fragP->fr_subtype) == 4 5526218822Sdim && object_64bit 5527218822Sdim && ((addressT) (displacement_from_opcode_start - extension 5528218822Sdim + ((addressT) 1 << 31)) 5529218822Sdim > (((addressT) 2 << 31) - 1))) 5530218822Sdim { 5531218822Sdim as_bad_where (fragP->fr_file, fragP->fr_line, 5532218822Sdim _("jump target out of range")); 5533218822Sdim /* Make us emit 0. */ 5534218822Sdim displacement_from_opcode_start = extension; 5535218822Sdim } 553677311Sobrien /* Now put displacement after opcode. */ 553733965Sjdp md_number_to_chars ((char *) where_to_put_displacement, 553833965Sjdp (valueT) (displacement_from_opcode_start - extension), 553978840Sobrien DISP_SIZE_FROM_RELAX_STATE (fragP->fr_subtype)); 554033965Sjdp fragP->fr_fix += extension; 554133965Sjdp} 554233965Sjdp 554377311Sobrien/* Size of byte displacement jmp. */ 554477311Sobrienint md_short_jump_size = 2; 554533965Sjdp 554677311Sobrien/* Size of dword displacement jmp. */ 554777311Sobrienint md_long_jump_size = 5; 554833965Sjdp 554933965Sjdpvoid 555033965Sjdpmd_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol) 555133965Sjdp char *ptr; 555233965Sjdp addressT from_addr, to_addr; 555360519Sobrien fragS *frag ATTRIBUTE_UNUSED; 555460519Sobrien symbolS *to_symbol ATTRIBUTE_UNUSED; 555533965Sjdp{ 555677311Sobrien offsetT offset; 555733965Sjdp 555833965Sjdp offset = to_addr - (from_addr + 2); 555977311Sobrien /* Opcode for byte-disp jump. */ 556077311Sobrien md_number_to_chars (ptr, (valueT) 0xeb, 1); 556133965Sjdp md_number_to_chars (ptr + 1, (valueT) offset, 1); 556233965Sjdp} 556333965Sjdp 556433965Sjdpvoid 556533965Sjdpmd_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol) 556633965Sjdp char *ptr; 556733965Sjdp addressT from_addr, to_addr; 556877311Sobrien fragS *frag ATTRIBUTE_UNUSED; 556977311Sobrien symbolS *to_symbol ATTRIBUTE_UNUSED; 557033965Sjdp{ 557177311Sobrien offsetT offset; 557233965Sjdp 557377311Sobrien offset = to_addr - (from_addr + 5); 557477311Sobrien md_number_to_chars (ptr, (valueT) 0xe9, 1); 557577311Sobrien md_number_to_chars (ptr + 1, (valueT) offset, 4); 557633965Sjdp} 557733965Sjdp 557833965Sjdp/* Apply a fixup (fixS) to segment data, once it has been determined 557933965Sjdp by our caller that we have all the info we need to fix it up. 558033965Sjdp 558133965Sjdp On the 386, immediates, displacements, and data pointers are all in 558233965Sjdp the same (little-endian) format, so we don't need to care about which 558333965Sjdp we are handling. */ 558433965Sjdp 558589867Sobrienvoid 5586218822Sdimmd_apply_fix (fixP, valP, seg) 558777311Sobrien /* The fix we're to put in. */ 558877311Sobrien fixS *fixP; 558977311Sobrien /* Pointer to the value of the bits. */ 5590104848Sobrien valueT *valP; 559177311Sobrien /* Segment fix is from. */ 559277311Sobrien segT seg ATTRIBUTE_UNUSED; 559333965Sjdp{ 559489867Sobrien char *p = fixP->fx_where + fixP->fx_frag->fr_literal; 5595104848Sobrien valueT value = *valP; 559633965Sjdp 5597130570Sobrien#if !defined (TE_Mach) 559860519Sobrien if (fixP->fx_pcrel) 559933965Sjdp { 560060519Sobrien switch (fixP->fx_r_type) 560160519Sobrien { 560260519Sobrien default: 560360519Sobrien break; 560460519Sobrien 5605218822Sdim case BFD_RELOC_64: 5606218822Sdim fixP->fx_r_type = BFD_RELOC_64_PCREL; 5607218822Sdim break; 560860519Sobrien case BFD_RELOC_32: 5609218822Sdim case BFD_RELOC_X86_64_32S: 561060519Sobrien fixP->fx_r_type = BFD_RELOC_32_PCREL; 561160519Sobrien break; 561260519Sobrien case BFD_RELOC_16: 561360519Sobrien fixP->fx_r_type = BFD_RELOC_16_PCREL; 561460519Sobrien break; 561560519Sobrien case BFD_RELOC_8: 561660519Sobrien fixP->fx_r_type = BFD_RELOC_8_PCREL; 561760519Sobrien break; 561860519Sobrien } 561960519Sobrien } 562060519Sobrien 5621130570Sobrien if (fixP->fx_addsy != NULL 5622104848Sobrien && (fixP->fx_r_type == BFD_RELOC_32_PCREL 5623218822Sdim || fixP->fx_r_type == BFD_RELOC_64_PCREL 5624104848Sobrien || fixP->fx_r_type == BFD_RELOC_16_PCREL 5625104848Sobrien || fixP->fx_r_type == BFD_RELOC_8_PCREL) 5626104848Sobrien && !use_rela_relocations) 562760519Sobrien { 5628104848Sobrien /* This is a hack. There should be a better way to handle this. 5629104848Sobrien This covers for the fact that bfd_install_relocation will 5630104848Sobrien subtract the current location (for partial_inplace, PC relative 5631104848Sobrien relocations); see more below. */ 563233965Sjdp#ifndef OBJ_AOUT 5633218822Sdim if (IS_ELF 563460519Sobrien#ifdef TE_PE 563560519Sobrien || OUTPUT_FLAVOR == bfd_target_coff_flavour 563660519Sobrien#endif 563760519Sobrien ) 563833965Sjdp value += fixP->fx_where + fixP->fx_frag->fr_address; 563933965Sjdp#endif 564033965Sjdp#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) 5641218822Sdim if (IS_ELF) 564233965Sjdp { 5643130570Sobrien segT sym_seg = S_GET_SEGMENT (fixP->fx_addsy); 564460519Sobrien 5645130570Sobrien if ((sym_seg == seg 564660519Sobrien || (symbol_section_p (fixP->fx_addsy) 5647130570Sobrien && sym_seg != absolute_section)) 5648130570Sobrien && !generic_force_reloc (fixP)) 564960519Sobrien { 565060519Sobrien /* Yes, we add the values in twice. This is because 5651130570Sobrien bfd_install_relocation subtracts them out again. I think 5652130570Sobrien bfd_install_relocation is broken, but I don't dare change 565360519Sobrien it. FIXME. */ 565460519Sobrien value += fixP->fx_where + fixP->fx_frag->fr_address; 565560519Sobrien } 565633965Sjdp } 565733965Sjdp#endif 565838891Sjdp#if defined (OBJ_COFF) && defined (TE_PE) 5659218822Sdim /* For some reason, the PE format does not store a 5660218822Sdim section address offset for a PC relative symbol. */ 5661218822Sdim if (S_GET_SEGMENT (fixP->fx_addsy) != seg 5662218822Sdim || S_IS_WEAK (fixP->fx_addsy)) 566338891Sjdp value += md_pcrel_from (fixP); 566438891Sjdp#endif 566533965Sjdp } 566633965Sjdp 566733965Sjdp /* Fix a few things - the dynamic linker expects certain values here, 5668130570Sobrien and we must not disappoint it. */ 566933965Sjdp#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) 5670218822Sdim if (IS_ELF && fixP->fx_addsy) 567177311Sobrien switch (fixP->fx_r_type) 567277311Sobrien { 567377311Sobrien case BFD_RELOC_386_PLT32: 567477311Sobrien case BFD_RELOC_X86_64_PLT32: 567577311Sobrien /* Make the jump instruction point to the address of the operand. At 567677311Sobrien runtime we merely add the offset to the actual PLT entry. */ 567777311Sobrien value = -4; 567877311Sobrien break; 567977311Sobrien 5680104848Sobrien case BFD_RELOC_386_TLS_GD: 5681104848Sobrien case BFD_RELOC_386_TLS_LDM: 5682104848Sobrien case BFD_RELOC_386_TLS_IE_32: 5683104848Sobrien case BFD_RELOC_386_TLS_IE: 5684104848Sobrien case BFD_RELOC_386_TLS_GOTIE: 5685218822Sdim case BFD_RELOC_386_TLS_GOTDESC: 5686130570Sobrien case BFD_RELOC_X86_64_TLSGD: 5687130570Sobrien case BFD_RELOC_X86_64_TLSLD: 5688130570Sobrien case BFD_RELOC_X86_64_GOTTPOFF: 5689218822Sdim case BFD_RELOC_X86_64_GOTPC32_TLSDESC: 5690130570Sobrien value = 0; /* Fully resolved at runtime. No addend. */ 5691130570Sobrien /* Fallthrough */ 5692130570Sobrien case BFD_RELOC_386_TLS_LE: 5693130570Sobrien case BFD_RELOC_386_TLS_LDO_32: 5694130570Sobrien case BFD_RELOC_386_TLS_LE_32: 5695130570Sobrien case BFD_RELOC_X86_64_DTPOFF32: 5696218822Sdim case BFD_RELOC_X86_64_DTPOFF64: 5697130570Sobrien case BFD_RELOC_X86_64_TPOFF32: 5698218822Sdim case BFD_RELOC_X86_64_TPOFF64: 5699130570Sobrien S_SET_THREAD_LOCAL (fixP->fx_addsy); 5700130570Sobrien break; 5701130570Sobrien 5702218822Sdim case BFD_RELOC_386_TLS_DESC_CALL: 5703218822Sdim case BFD_RELOC_X86_64_TLSDESC_CALL: 5704218822Sdim value = 0; /* Fully resolved at runtime. No addend. */ 5705218822Sdim S_SET_THREAD_LOCAL (fixP->fx_addsy); 5706218822Sdim fixP->fx_done = 0; 5707218822Sdim return; 5708218822Sdim 5709130570Sobrien case BFD_RELOC_386_GOT32: 571077311Sobrien case BFD_RELOC_X86_64_GOT32: 571177311Sobrien value = 0; /* Fully resolved at runtime. No addend. */ 571277311Sobrien break; 571360519Sobrien 571477311Sobrien case BFD_RELOC_VTABLE_INHERIT: 571577311Sobrien case BFD_RELOC_VTABLE_ENTRY: 571677311Sobrien fixP->fx_done = 0; 571789867Sobrien return; 571877311Sobrien 571977311Sobrien default: 572077311Sobrien break; 572177311Sobrien } 572277311Sobrien#endif /* defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) */ 5723104848Sobrien *valP = value; 5724130570Sobrien#endif /* !defined (TE_Mach) */ 572577311Sobrien 572677311Sobrien /* Are we finished with this relocation now? */ 5727104848Sobrien if (fixP->fx_addsy == NULL) 572877311Sobrien fixP->fx_done = 1; 572977311Sobrien else if (use_rela_relocations) 573077311Sobrien { 573177311Sobrien fixP->fx_no_overflow = 1; 573299468Sobrien /* Remember value for tc_gen_reloc. */ 573399468Sobrien fixP->fx_addnumber = value; 573477311Sobrien value = 0; 573577311Sobrien } 5736130570Sobrien 573777311Sobrien md_number_to_chars (p, value, fixP->fx_size); 573833965Sjdp} 573933965Sjdp 574033965Sjdp#define MAX_LITTLENUMS 6 574133965Sjdp 574277311Sobrien/* Turn the string pointed to by litP into a floating point constant 574377311Sobrien of type TYPE, and emit the appropriate bytes. The number of 574477311Sobrien LITTLENUMS emitted is stored in *SIZEP. An error message is 574577311Sobrien returned, or NULL on OK. */ 574677311Sobrien 574733965Sjdpchar * 574833965Sjdpmd_atof (type, litP, sizeP) 574960519Sobrien int type; 575033965Sjdp char *litP; 575133965Sjdp int *sizeP; 575233965Sjdp{ 575333965Sjdp int prec; 575433965Sjdp LITTLENUM_TYPE words[MAX_LITTLENUMS]; 575533965Sjdp LITTLENUM_TYPE *wordP; 575633965Sjdp char *t; 575733965Sjdp 575833965Sjdp switch (type) 575933965Sjdp { 576033965Sjdp case 'f': 576133965Sjdp case 'F': 576233965Sjdp prec = 2; 576333965Sjdp break; 576433965Sjdp 576533965Sjdp case 'd': 576633965Sjdp case 'D': 576733965Sjdp prec = 4; 576833965Sjdp break; 576933965Sjdp 577033965Sjdp case 'x': 577133965Sjdp case 'X': 577233965Sjdp prec = 5; 577333965Sjdp break; 577433965Sjdp 577533965Sjdp default: 577633965Sjdp *sizeP = 0; 577760519Sobrien return _("Bad call to md_atof ()"); 577833965Sjdp } 577933965Sjdp t = atof_ieee (input_line_pointer, type, words); 578033965Sjdp if (t) 578133965Sjdp input_line_pointer = t; 578233965Sjdp 578333965Sjdp *sizeP = prec * sizeof (LITTLENUM_TYPE); 578433965Sjdp /* This loops outputs the LITTLENUMs in REVERSE order; in accord with 578533965Sjdp the bigendian 386. */ 578633965Sjdp for (wordP = words + prec - 1; prec--;) 578733965Sjdp { 578833965Sjdp md_number_to_chars (litP, (valueT) (*wordP--), sizeof (LITTLENUM_TYPE)); 578933965Sjdp litP += sizeof (LITTLENUM_TYPE); 579033965Sjdp } 579133965Sjdp return 0; 579233965Sjdp} 579333965Sjdp 5794218822Sdimstatic char output_invalid_buf[sizeof (unsigned char) * 2 + 6]; 579533965Sjdp 579633965Sjdpstatic char * 5797218822Sdimoutput_invalid (int c) 579833965Sjdp{ 579989867Sobrien if (ISPRINT (c)) 5800218822Sdim snprintf (output_invalid_buf, sizeof (output_invalid_buf), 5801218822Sdim "'%c'", c); 580233965Sjdp else 5803218822Sdim snprintf (output_invalid_buf, sizeof (output_invalid_buf), 5804218822Sdim "(0x%x)", (unsigned char) c); 580533965Sjdp return output_invalid_buf; 580633965Sjdp} 580733965Sjdp 580860519Sobrien/* REG_STRING starts *before* REGISTER_PREFIX. */ 580960519Sobrien 581060519Sobrienstatic const reg_entry * 5811218822Sdimparse_real_register (char *reg_string, char **end_op) 581233965Sjdp{ 581360519Sobrien char *s = reg_string; 581460519Sobrien char *p; 581560519Sobrien char reg_name_given[MAX_REG_NAME_SIZE + 1]; 581660519Sobrien const reg_entry *r; 581733965Sjdp 581860519Sobrien /* Skip possible REGISTER_PREFIX and possible whitespace. */ 581960519Sobrien if (*s == REGISTER_PREFIX) 582060519Sobrien ++s; 582160519Sobrien 582260519Sobrien if (is_space_char (*s)) 582360519Sobrien ++s; 582460519Sobrien 582560519Sobrien p = reg_name_given; 582660519Sobrien while ((*p++ = register_chars[(unsigned char) *s]) != '\0') 582733965Sjdp { 582833965Sjdp if (p >= reg_name_given + MAX_REG_NAME_SIZE) 582960519Sobrien return (const reg_entry *) NULL; 583060519Sobrien s++; 583133965Sjdp } 583260519Sobrien 583377311Sobrien /* For naked regs, make sure that we are not dealing with an identifier. 583477311Sobrien This prevents confusing an identifier like `eax_var' with register 583577311Sobrien `eax'. */ 583677311Sobrien if (allow_naked_reg && identifier_chars[(unsigned char) *s]) 583777311Sobrien return (const reg_entry *) NULL; 583877311Sobrien 583960519Sobrien *end_op = s; 584060519Sobrien 584160519Sobrien r = (const reg_entry *) hash_find (reg_hash, reg_name_given); 584260519Sobrien 584360519Sobrien /* Handle floating point regs, allowing spaces in the (i) part. */ 584477311Sobrien if (r == i386_regtab /* %st is first entry of table */) 584560519Sobrien { 584660519Sobrien if (is_space_char (*s)) 584760519Sobrien ++s; 584860519Sobrien if (*s == '(') 584960519Sobrien { 585060519Sobrien ++s; 585160519Sobrien if (is_space_char (*s)) 585260519Sobrien ++s; 585360519Sobrien if (*s >= '0' && *s <= '7') 585460519Sobrien { 5855218822Sdim int fpr = *s - '0'; 585660519Sobrien ++s; 585760519Sobrien if (is_space_char (*s)) 585860519Sobrien ++s; 585960519Sobrien if (*s == ')') 586060519Sobrien { 586160519Sobrien *end_op = s + 1; 5862218822Sdim r = hash_find (reg_hash, "st(0)"); 5863218822Sdim know (r); 5864218822Sdim return r + fpr; 586560519Sobrien } 586660519Sobrien } 586777311Sobrien /* We have "%st(" then garbage. */ 586860519Sobrien return (const reg_entry *) NULL; 586960519Sobrien } 587060519Sobrien } 587160519Sobrien 587285824Sobrien if (r != NULL 5873218822Sdim && ((r->reg_flags & (RegRex64 | RegRex)) | (r->reg_type & Reg64)) != 0 5874218822Sdim && (r->reg_type != Control || !(cpu_arch_flags & CpuSledgehammer)) 587585824Sobrien && flag_code != CODE_64BIT) 5876218822Sdim return (const reg_entry *) NULL; 5877218822Sdim 5878218822Sdim return r; 5879218822Sdim} 5880218822Sdim 5881218822Sdim/* REG_STRING starts *before* REGISTER_PREFIX. */ 5882218822Sdim 5883218822Sdimstatic const reg_entry * 5884218822Sdimparse_register (char *reg_string, char **end_op) 5885218822Sdim{ 5886218822Sdim const reg_entry *r; 5887218822Sdim 5888218822Sdim if (*reg_string == REGISTER_PREFIX || allow_naked_reg) 5889218822Sdim r = parse_real_register (reg_string, end_op); 5890218822Sdim else 5891218822Sdim r = NULL; 5892218822Sdim if (!r) 589385824Sobrien { 5894218822Sdim char *save = input_line_pointer; 5895218822Sdim char c; 5896218822Sdim symbolS *symbolP; 5897218822Sdim 5898218822Sdim input_line_pointer = reg_string; 5899218822Sdim c = get_symbol_end (); 5900218822Sdim symbolP = symbol_find (reg_string); 5901218822Sdim if (symbolP && S_GET_SEGMENT (symbolP) == reg_section) 5902218822Sdim { 5903218822Sdim const expressionS *e = symbol_get_value_expression (symbolP); 5904218822Sdim 5905218822Sdim know (e->X_op == O_register); 5906218822Sdim know (e->X_add_number >= 0 5907218822Sdim && (valueT) e->X_add_number < i386_regtab_size); 5908218822Sdim r = i386_regtab + e->X_add_number; 5909218822Sdim *end_op = input_line_pointer; 5910218822Sdim } 5911218822Sdim *input_line_pointer = c; 5912218822Sdim input_line_pointer = save; 591385824Sobrien } 591460519Sobrien return r; 591533965Sjdp} 5916218822Sdim 5917218822Sdimint 5918218822Sdimi386_parse_name (char *name, expressionS *e, char *nextcharP) 5919218822Sdim{ 5920218822Sdim const reg_entry *r; 5921218822Sdim char *end = input_line_pointer; 5922218822Sdim 5923218822Sdim *end = *nextcharP; 5924218822Sdim r = parse_register (name, &input_line_pointer); 5925218822Sdim if (r && end <= input_line_pointer) 5926218822Sdim { 5927218822Sdim *nextcharP = *input_line_pointer; 5928218822Sdim *input_line_pointer = 0; 5929218822Sdim e->X_op = O_register; 5930218822Sdim e->X_add_number = r - i386_regtab; 5931218822Sdim return 1; 5932218822Sdim } 5933218822Sdim input_line_pointer = end; 5934218822Sdim *end = 0; 5935218822Sdim return 0; 5936218822Sdim} 5937218822Sdim 5938218822Sdimvoid 5939218822Sdimmd_operand (expressionS *e) 5940218822Sdim{ 5941218822Sdim if (*input_line_pointer == REGISTER_PREFIX) 5942218822Sdim { 5943218822Sdim char *end; 5944218822Sdim const reg_entry *r = parse_real_register (input_line_pointer, &end); 5945218822Sdim 5946218822Sdim if (r) 5947218822Sdim { 5948218822Sdim e->X_op = O_register; 5949218822Sdim e->X_add_number = r - i386_regtab; 5950218822Sdim input_line_pointer = end; 5951218822Sdim } 5952218822Sdim } 5953218822Sdim} 5954218822Sdim 595533965Sjdp 595660519Sobrien#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) 5957130570Sobrienconst char *md_shortopts = "kVQ:sqn"; 595833965Sjdp#else 5959130570Sobrienconst char *md_shortopts = "qn"; 596033965Sjdp#endif 596177311Sobrien 596277311Sobrien#define OPTION_32 (OPTION_MD_BASE + 0) 5963218822Sdim#define OPTION_64 (OPTION_MD_BASE + 1) 5964218822Sdim#define OPTION_DIVIDE (OPTION_MD_BASE + 2) 5965218822Sdim#define OPTION_MARCH (OPTION_MD_BASE + 3) 5966218822Sdim#define OPTION_MTUNE (OPTION_MD_BASE + 4) 5967218822Sdim 5968218822Sdimstruct option md_longopts[] = 5969218822Sdim{ 597077311Sobrien {"32", no_argument, NULL, OPTION_32}, 5971218822Sdim#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || defined(TE_PEP) 597277311Sobrien {"64", no_argument, NULL, OPTION_64}, 597377311Sobrien#endif 5974218822Sdim {"divide", no_argument, NULL, OPTION_DIVIDE}, 5975218822Sdim {"march", required_argument, NULL, OPTION_MARCH}, 5976218822Sdim {"mtune", required_argument, NULL, OPTION_MTUNE}, 597733965Sjdp {NULL, no_argument, NULL, 0} 597833965Sjdp}; 597960519Sobriensize_t md_longopts_size = sizeof (md_longopts); 598033965Sjdp 598133965Sjdpint 5982218822Sdimmd_parse_option (int c, char *arg) 598333965Sjdp{ 5984218822Sdim unsigned int i; 5985218822Sdim 598633965Sjdp switch (c) 598733965Sjdp { 5988130570Sobrien case 'n': 5989130570Sobrien optimize_align_code = 0; 5990130570Sobrien break; 5991130570Sobrien 599277311Sobrien case 'q': 599377311Sobrien quiet_warnings = 1; 599433965Sjdp break; 599533965Sjdp 599633965Sjdp#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) 599777311Sobrien /* -Qy, -Qn: SVR4 arguments controlling whether a .comment section 599877311Sobrien should be emitted or not. FIXME: Not implemented. */ 599977311Sobrien case 'Q': 600033965Sjdp break; 600133965Sjdp 600233965Sjdp /* -V: SVR4 argument to print version ID. */ 600333965Sjdp case 'V': 600433965Sjdp print_version_id (); 600533965Sjdp break; 600633965Sjdp 600777311Sobrien /* -k: Ignore for FreeBSD compatibility. */ 600877311Sobrien case 'k': 600933965Sjdp break; 601060519Sobrien 601160519Sobrien case 's': 601260519Sobrien /* -s: On i386 Solaris, this tells the native assembler to use 601394546Sobrien .stab instead of .stab.excl. We always use .stab anyhow. */ 601460519Sobrien break; 6015218822Sdim#endif 6016218822Sdim#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || defined(TE_PEP) 601777311Sobrien case OPTION_64: 601877311Sobrien { 601977311Sobrien const char **list, **l; 602077311Sobrien 602177311Sobrien list = bfd_target_list (); 602277311Sobrien for (l = list; *l != NULL; l++) 6023218822Sdim if (CONST_STRNEQ (*l, "elf64-x86-64") 6024218822Sdim || strcmp (*l, "coff-x86-64") == 0 6025218822Sdim || strcmp (*l, "pe-x86-64") == 0 6026218822Sdim || strcmp (*l, "pei-x86-64") == 0) 602777311Sobrien { 602877311Sobrien default_arch = "x86_64"; 602977311Sobrien break; 603077311Sobrien } 603177311Sobrien if (*l == NULL) 603277311Sobrien as_fatal (_("No compiled in support for x86_64")); 603377311Sobrien free (list); 603477311Sobrien } 603560519Sobrien break; 603633965Sjdp#endif 603733965Sjdp 603877311Sobrien case OPTION_32: 603977311Sobrien default_arch = "i386"; 604077311Sobrien break; 604177311Sobrien 6042218822Sdim case OPTION_DIVIDE: 6043218822Sdim#ifdef SVR4_COMMENT_CHARS 6044218822Sdim { 6045218822Sdim char *n, *t; 6046218822Sdim const char *s; 6047218822Sdim 6048218822Sdim n = (char *) xmalloc (strlen (i386_comment_chars) + 1); 6049218822Sdim t = n; 6050218822Sdim for (s = i386_comment_chars; *s != '\0'; s++) 6051218822Sdim if (*s != '/') 6052218822Sdim *t++ = *s; 6053218822Sdim *t = '\0'; 6054218822Sdim i386_comment_chars = n; 6055218822Sdim } 6056218822Sdim#endif 6057218822Sdim break; 6058218822Sdim 6059218822Sdim case OPTION_MARCH: 6060218822Sdim if (*arg == '.') 6061218822Sdim as_fatal (_("Invalid -march= option: `%s'"), arg); 6062218822Sdim for (i = 0; i < ARRAY_SIZE (cpu_arch); i++) 6063218822Sdim { 6064218822Sdim if (strcmp (arg, cpu_arch [i].name) == 0) 6065218822Sdim { 6066218822Sdim cpu_arch_isa = cpu_arch[i].type; 6067218822Sdim cpu_arch_isa_flags = cpu_arch[i].flags; 6068218822Sdim if (!cpu_arch_tune_set) 6069218822Sdim { 6070218822Sdim cpu_arch_tune = cpu_arch_isa; 6071218822Sdim cpu_arch_tune_flags = cpu_arch_isa_flags; 6072218822Sdim } 6073218822Sdim break; 6074218822Sdim } 6075218822Sdim } 6076218822Sdim if (i >= ARRAY_SIZE (cpu_arch)) 6077218822Sdim as_fatal (_("Invalid -march= option: `%s'"), arg); 6078218822Sdim break; 6079218822Sdim 6080218822Sdim case OPTION_MTUNE: 6081218822Sdim if (*arg == '.') 6082218822Sdim as_fatal (_("Invalid -mtune= option: `%s'"), arg); 6083218822Sdim for (i = 0; i < ARRAY_SIZE (cpu_arch); i++) 6084218822Sdim { 6085218822Sdim if (strcmp (arg, cpu_arch [i].name) == 0) 6086218822Sdim { 6087218822Sdim cpu_arch_tune_set = 1; 6088218822Sdim cpu_arch_tune = cpu_arch [i].type; 6089218822Sdim cpu_arch_tune_flags = cpu_arch[i].flags; 6090218822Sdim break; 6091218822Sdim } 6092218822Sdim } 6093218822Sdim if (i >= ARRAY_SIZE (cpu_arch)) 6094218822Sdim as_fatal (_("Invalid -mtune= option: `%s'"), arg); 6095218822Sdim break; 6096218822Sdim 609733965Sjdp default: 609833965Sjdp return 0; 609933965Sjdp } 610033965Sjdp return 1; 610133965Sjdp} 610233965Sjdp 610333965Sjdpvoid 610433965Sjdpmd_show_usage (stream) 610533965Sjdp FILE *stream; 610633965Sjdp{ 610760519Sobrien#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) 610860519Sobrien fprintf (stream, _("\ 610977311Sobrien -Q ignored\n\ 611077311Sobrien -V print assembler version number\n\ 6111218822Sdim -k ignored\n")); 6112218822Sdim#endif 6113218822Sdim fprintf (stream, _("\ 6114130570Sobrien -n Do not optimize code alignment\n\ 6115218822Sdim -q quieten some warnings\n")); 6116218822Sdim#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) 6117218822Sdim fprintf (stream, _("\ 611877311Sobrien -s ignored\n")); 6119218822Sdim#endif 6120218822Sdim#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || defined(TE_PEP) 6121218822Sdim fprintf (stream, _("\ 6122218822Sdim --32/--64 generate 32bit/64bit code\n")); 6123218822Sdim#endif 6124218822Sdim#ifdef SVR4_COMMENT_CHARS 6125218822Sdim fprintf (stream, _("\ 6126218822Sdim --divide do not treat `/' as a comment character\n")); 612777311Sobrien#else 612877311Sobrien fprintf (stream, _("\ 6129218822Sdim --divide ignored\n")); 613060519Sobrien#endif 6131218822Sdim fprintf (stream, _("\ 6132218822Sdim -march=CPU/-mtune=CPU generate code/optimize for CPU, where CPU is one of:\n\ 6133218822Sdim i386, i486, pentium, pentiumpro, pentium4, nocona,\n\ 6134218822Sdim core, core2, k6, athlon, k8, generic32, generic64\n")); 6135218822Sdim 613633965Sjdp} 613733965Sjdp 6138218822Sdim#if defined(TE_PEP) 6139218822Sdimconst char * 6140218822Sdimx86_64_target_format (void) 6141218822Sdim{ 6142218822Sdim if (strcmp (default_arch, "x86_64") == 0) 6143218822Sdim { 6144218822Sdim set_code_flag (CODE_64BIT); 6145218822Sdim return COFF_TARGET_FORMAT; 6146218822Sdim } 6147218822Sdim else if (strcmp (default_arch, "i386") == 0) 6148218822Sdim { 6149218822Sdim set_code_flag (CODE_32BIT); 6150218822Sdim return "coff-i386"; 6151218822Sdim } 6152218822Sdim 6153218822Sdim as_fatal (_("Unknown architecture")); 6154218822Sdim return NULL; 6155218822Sdim} 6156218822Sdim#endif 6157218822Sdim 615877311Sobrien#if ((defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT)) \ 615977311Sobrien || defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) 616033965Sjdp 616133965Sjdp/* Pick the target format to use. */ 616233965Sjdp 616377311Sobrienconst char * 6164218822Sdimi386_target_format (void) 616533965Sjdp{ 616677311Sobrien if (!strcmp (default_arch, "x86_64")) 6167218822Sdim { 6168218822Sdim set_code_flag (CODE_64BIT); 6169218822Sdim if (cpu_arch_isa_flags == 0) 6170218822Sdim cpu_arch_isa_flags = Cpu186|Cpu286|Cpu386|Cpu486 6171218822Sdim |Cpu586|Cpu686|CpuP4|CpuMMX|CpuMMX2 6172218822Sdim |CpuSSE|CpuSSE2; 6173218822Sdim if (cpu_arch_tune_flags == 0) 6174218822Sdim cpu_arch_tune_flags = Cpu186|Cpu286|Cpu386|Cpu486 6175218822Sdim |Cpu586|Cpu686|CpuP4|CpuMMX|CpuMMX2 6176218822Sdim |CpuSSE|CpuSSE2; 6177218822Sdim } 617877311Sobrien else if (!strcmp (default_arch, "i386")) 6179218822Sdim { 6180218822Sdim set_code_flag (CODE_32BIT); 6181218822Sdim if (cpu_arch_isa_flags == 0) 6182218822Sdim cpu_arch_isa_flags = Cpu186|Cpu286|Cpu386; 6183218822Sdim if (cpu_arch_tune_flags == 0) 6184218822Sdim cpu_arch_tune_flags = Cpu186|Cpu286|Cpu386; 6185218822Sdim } 618677311Sobrien else 618777311Sobrien as_fatal (_("Unknown architecture")); 618833965Sjdp switch (OUTPUT_FLAVOR) 618933965Sjdp { 619060519Sobrien#ifdef OBJ_MAYBE_AOUT 619160519Sobrien case bfd_target_aout_flavour: 619277311Sobrien return AOUT_TARGET_FORMAT; 619360519Sobrien#endif 619460519Sobrien#ifdef OBJ_MAYBE_COFF 619533965Sjdp case bfd_target_coff_flavour: 619633965Sjdp return "coff-i386"; 619760519Sobrien#endif 619877311Sobrien#if defined (OBJ_MAYBE_ELF) || defined (OBJ_ELF) 619933965Sjdp case bfd_target_elf_flavour: 620077311Sobrien { 620177311Sobrien if (flag_code == CODE_64BIT) 6202218822Sdim { 6203218822Sdim object_64bit = 1; 6204218822Sdim use_rela_relocations = 1; 6205218822Sdim } 6206218822Sdim return flag_code == CODE_64BIT ? ELF_TARGET_FORMAT64 : ELF_TARGET_FORMAT; 620777311Sobrien } 620860519Sobrien#endif 620933965Sjdp default: 621033965Sjdp abort (); 621133965Sjdp return NULL; 621233965Sjdp } 621333965Sjdp} 621433965Sjdp 621577311Sobrien#endif /* OBJ_MAYBE_ more than one */ 621689867Sobrien 621789867Sobrien#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) 6218218822Sdimvoid 6219218822Sdimi386_elf_emit_arch_note (void) 622089867Sobrien{ 6221218822Sdim if (IS_ELF && cpu_arch_name != NULL) 622289867Sobrien { 622389867Sobrien char *p; 622489867Sobrien asection *seg = now_seg; 622589867Sobrien subsegT subseg = now_subseg; 622689867Sobrien Elf_Internal_Note i_note; 622789867Sobrien Elf_External_Note e_note; 622889867Sobrien asection *note_secp; 622989867Sobrien int len; 623089867Sobrien 623189867Sobrien /* Create the .note section. */ 623289867Sobrien note_secp = subseg_new (".note", 0); 623389867Sobrien bfd_set_section_flags (stdoutput, 623489867Sobrien note_secp, 623589867Sobrien SEC_HAS_CONTENTS | SEC_READONLY); 623689867Sobrien 623789867Sobrien /* Process the arch string. */ 623889867Sobrien len = strlen (cpu_arch_name); 623989867Sobrien 624089867Sobrien i_note.namesz = len + 1; 624189867Sobrien i_note.descsz = 0; 624289867Sobrien i_note.type = NT_ARCH; 624389867Sobrien p = frag_more (sizeof (e_note.namesz)); 624489867Sobrien md_number_to_chars (p, (valueT) i_note.namesz, sizeof (e_note.namesz)); 624589867Sobrien p = frag_more (sizeof (e_note.descsz)); 624689867Sobrien md_number_to_chars (p, (valueT) i_note.descsz, sizeof (e_note.descsz)); 624789867Sobrien p = frag_more (sizeof (e_note.type)); 624889867Sobrien md_number_to_chars (p, (valueT) i_note.type, sizeof (e_note.type)); 624989867Sobrien p = frag_more (len + 1); 625089867Sobrien strcpy (p, cpu_arch_name); 625189867Sobrien 625289867Sobrien frag_align (2, 0, 0); 625389867Sobrien 625489867Sobrien subseg_set (seg, subseg); 625589867Sobrien } 625689867Sobrien} 625789867Sobrien#endif 625833965Sjdp 625933965SjdpsymbolS * 626033965Sjdpmd_undefined_symbol (name) 626133965Sjdp char *name; 626233965Sjdp{ 626360519Sobrien if (name[0] == GLOBAL_OFFSET_TABLE_NAME[0] 626460519Sobrien && name[1] == GLOBAL_OFFSET_TABLE_NAME[1] 626560519Sobrien && name[2] == GLOBAL_OFFSET_TABLE_NAME[2] 626660519Sobrien && strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0) 626760519Sobrien { 626860519Sobrien if (!GOT_symbol) 626960519Sobrien { 627060519Sobrien if (symbol_find (name)) 627160519Sobrien as_bad (_("GOT already in symbol table")); 627260519Sobrien GOT_symbol = symbol_new (name, undefined_section, 627360519Sobrien (valueT) 0, &zero_address_frag); 627460519Sobrien }; 627560519Sobrien return GOT_symbol; 627660519Sobrien } 627733965Sjdp return 0; 627833965Sjdp} 627933965Sjdp 628033965Sjdp/* Round up a section size to the appropriate boundary. */ 628177311Sobrien 628233965SjdpvalueT 628333965Sjdpmd_section_align (segment, size) 628460519Sobrien segT segment ATTRIBUTE_UNUSED; 628533965Sjdp valueT size; 628633965Sjdp{ 628760519Sobrien#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT)) 628860519Sobrien if (OUTPUT_FLAVOR == bfd_target_aout_flavour) 628960519Sobrien { 629060519Sobrien /* For a.out, force the section size to be aligned. If we don't do 629160519Sobrien this, BFD will align it for us, but it will not write out the 629260519Sobrien final bytes of the section. This may be a bug in BFD, but it is 629360519Sobrien easier to fix it here since that is how the other a.out targets 629460519Sobrien work. */ 629560519Sobrien int align; 629633965Sjdp 629760519Sobrien align = bfd_get_section_alignment (stdoutput, segment); 629860519Sobrien size = ((size + (1 << align) - 1) & ((valueT) -1 << align)); 629960519Sobrien } 630033965Sjdp#endif 630133965Sjdp 630233965Sjdp return size; 630333965Sjdp} 630433965Sjdp 630560519Sobrien/* On the i386, PC-relative offsets are relative to the start of the 630660519Sobrien next instruction. That is, the address of the offset, plus its 630760519Sobrien size, since the offset is always the last part of the insn. */ 630860519Sobrien 630933965Sjdplong 6310218822Sdimmd_pcrel_from (fixS *fixP) 631133965Sjdp{ 631233965Sjdp return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address; 631333965Sjdp} 631433965Sjdp 631533965Sjdp#ifndef I386COFF 631633965Sjdp 631733965Sjdpstatic void 6318218822Sdims_bss (int ignore ATTRIBUTE_UNUSED) 631933965Sjdp{ 632094546Sobrien int temp; 632133965Sjdp 6322218822Sdim#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) 6323218822Sdim if (IS_ELF) 6324218822Sdim obj_elf_section_change_hook (); 6325218822Sdim#endif 632633965Sjdp temp = get_absolute_expression (); 632733965Sjdp subseg_set (bss_section, (subsegT) temp); 632833965Sjdp demand_empty_rest_of_line (); 632933965Sjdp} 633033965Sjdp 633133965Sjdp#endif 633233965Sjdp 633333965Sjdpvoid 6334218822Sdimi386_validate_fix (fixS *fixp) 633533965Sjdp{ 633633965Sjdp if (fixp->fx_subsy && fixp->fx_subsy == GOT_symbol) 633733965Sjdp { 633877311Sobrien if (fixp->fx_r_type == BFD_RELOC_32_PCREL) 633977311Sobrien { 6340218822Sdim if (!object_64bit) 634177311Sobrien abort (); 634277311Sobrien fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL; 634377311Sobrien } 634477311Sobrien else 634577311Sobrien { 6346218822Sdim if (!object_64bit) 6347218822Sdim fixp->fx_r_type = BFD_RELOC_386_GOTOFF; 6348218822Sdim else 6349218822Sdim fixp->fx_r_type = BFD_RELOC_X86_64_GOTOFF64; 635077311Sobrien } 635133965Sjdp fixp->fx_subsy = 0; 635233965Sjdp } 635333965Sjdp} 635433965Sjdp 635533965Sjdparelent * 635633965Sjdptc_gen_reloc (section, fixp) 635760519Sobrien asection *section ATTRIBUTE_UNUSED; 635833965Sjdp fixS *fixp; 635933965Sjdp{ 636033965Sjdp arelent *rel; 636133965Sjdp bfd_reloc_code_real_type code; 636233965Sjdp 636360519Sobrien switch (fixp->fx_r_type) 636433965Sjdp { 636577311Sobrien case BFD_RELOC_X86_64_PLT32: 636677311Sobrien case BFD_RELOC_X86_64_GOT32: 636777311Sobrien case BFD_RELOC_X86_64_GOTPCREL: 636833965Sjdp case BFD_RELOC_386_PLT32: 636933965Sjdp case BFD_RELOC_386_GOT32: 637033965Sjdp case BFD_RELOC_386_GOTOFF: 637133965Sjdp case BFD_RELOC_386_GOTPC: 6372104848Sobrien case BFD_RELOC_386_TLS_GD: 6373104848Sobrien case BFD_RELOC_386_TLS_LDM: 6374104848Sobrien case BFD_RELOC_386_TLS_LDO_32: 6375104848Sobrien case BFD_RELOC_386_TLS_IE_32: 6376104848Sobrien case BFD_RELOC_386_TLS_IE: 6377104848Sobrien case BFD_RELOC_386_TLS_GOTIE: 6378104848Sobrien case BFD_RELOC_386_TLS_LE_32: 6379104848Sobrien case BFD_RELOC_386_TLS_LE: 6380218822Sdim case BFD_RELOC_386_TLS_GOTDESC: 6381218822Sdim case BFD_RELOC_386_TLS_DESC_CALL: 6382130570Sobrien case BFD_RELOC_X86_64_TLSGD: 6383130570Sobrien case BFD_RELOC_X86_64_TLSLD: 6384130570Sobrien case BFD_RELOC_X86_64_DTPOFF32: 6385218822Sdim case BFD_RELOC_X86_64_DTPOFF64: 6386130570Sobrien case BFD_RELOC_X86_64_GOTTPOFF: 6387130570Sobrien case BFD_RELOC_X86_64_TPOFF32: 6388218822Sdim case BFD_RELOC_X86_64_TPOFF64: 6389218822Sdim case BFD_RELOC_X86_64_GOTOFF64: 6390218822Sdim case BFD_RELOC_X86_64_GOTPC32: 6391218822Sdim case BFD_RELOC_X86_64_GOT64: 6392218822Sdim case BFD_RELOC_X86_64_GOTPCREL64: 6393218822Sdim case BFD_RELOC_X86_64_GOTPC64: 6394218822Sdim case BFD_RELOC_X86_64_GOTPLT64: 6395218822Sdim case BFD_RELOC_X86_64_PLTOFF64: 6396218822Sdim case BFD_RELOC_X86_64_GOTPC32_TLSDESC: 6397218822Sdim case BFD_RELOC_X86_64_TLSDESC_CALL: 639838891Sjdp case BFD_RELOC_RVA: 639960519Sobrien case BFD_RELOC_VTABLE_ENTRY: 640060519Sobrien case BFD_RELOC_VTABLE_INHERIT: 6401218822Sdim#ifdef TE_PE 6402218822Sdim case BFD_RELOC_32_SECREL: 6403218822Sdim#endif 640433965Sjdp code = fixp->fx_r_type; 640533965Sjdp break; 6406218822Sdim case BFD_RELOC_X86_64_32S: 6407218822Sdim if (!fixp->fx_pcrel) 6408218822Sdim { 6409218822Sdim /* Don't turn BFD_RELOC_X86_64_32S into BFD_RELOC_32. */ 6410218822Sdim code = fixp->fx_r_type; 6411218822Sdim break; 6412218822Sdim } 641333965Sjdp default: 641460519Sobrien if (fixp->fx_pcrel) 641533965Sjdp { 641660519Sobrien switch (fixp->fx_size) 641760519Sobrien { 641860519Sobrien default: 641989867Sobrien as_bad_where (fixp->fx_file, fixp->fx_line, 642089867Sobrien _("can not do %d byte pc-relative relocation"), 642189867Sobrien fixp->fx_size); 642260519Sobrien code = BFD_RELOC_32_PCREL; 642360519Sobrien break; 642460519Sobrien case 1: code = BFD_RELOC_8_PCREL; break; 642560519Sobrien case 2: code = BFD_RELOC_16_PCREL; break; 642660519Sobrien case 4: code = BFD_RELOC_32_PCREL; break; 6427218822Sdim#ifdef BFD64 6428218822Sdim case 8: code = BFD_RELOC_64_PCREL; break; 6429218822Sdim#endif 643060519Sobrien } 643133965Sjdp } 643260519Sobrien else 643360519Sobrien { 643460519Sobrien switch (fixp->fx_size) 643560519Sobrien { 643660519Sobrien default: 643789867Sobrien as_bad_where (fixp->fx_file, fixp->fx_line, 643889867Sobrien _("can not do %d byte relocation"), 643989867Sobrien fixp->fx_size); 644060519Sobrien code = BFD_RELOC_32; 644160519Sobrien break; 644260519Sobrien case 1: code = BFD_RELOC_8; break; 644360519Sobrien case 2: code = BFD_RELOC_16; break; 644460519Sobrien case 4: code = BFD_RELOC_32; break; 644594546Sobrien#ifdef BFD64 644677311Sobrien case 8: code = BFD_RELOC_64; break; 644794546Sobrien#endif 644860519Sobrien } 644960519Sobrien } 645060519Sobrien break; 645133965Sjdp } 645233965Sjdp 6453218822Sdim if ((code == BFD_RELOC_32 6454218822Sdim || code == BFD_RELOC_32_PCREL 6455218822Sdim || code == BFD_RELOC_X86_64_32S) 645633965Sjdp && GOT_symbol 645733965Sjdp && fixp->fx_addsy == GOT_symbol) 645877311Sobrien { 6459218822Sdim if (!object_64bit) 6460218822Sdim code = BFD_RELOC_386_GOTPC; 6461218822Sdim else 6462218822Sdim code = BFD_RELOC_X86_64_GOTPC32; 646377311Sobrien } 6464218822Sdim if ((code == BFD_RELOC_64 || code == BFD_RELOC_64_PCREL) 6465218822Sdim && GOT_symbol 6466218822Sdim && fixp->fx_addsy == GOT_symbol) 6467218822Sdim { 6468218822Sdim code = BFD_RELOC_X86_64_GOTPC64; 6469218822Sdim } 647033965Sjdp 647133965Sjdp rel = (arelent *) xmalloc (sizeof (arelent)); 647260519Sobrien rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); 647360519Sobrien *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); 647460519Sobrien 647533965Sjdp rel->address = fixp->fx_frag->fr_address + fixp->fx_where; 6476218822Sdim 647777311Sobrien if (!use_rela_relocations) 647877311Sobrien { 647977311Sobrien /* HACK: Since i386 ELF uses Rel instead of Rela, encode the 648077311Sobrien vtable entry to be used in the relocation's section offset. */ 648177311Sobrien if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) 648277311Sobrien rel->address = fixp->fx_offset; 648360519Sobrien 6484104848Sobrien rel->addend = 0; 648577311Sobrien } 648677311Sobrien /* Use the rela in 64bit mode. */ 648733965Sjdp else 648877311Sobrien { 648999468Sobrien if (!fixp->fx_pcrel) 649099468Sobrien rel->addend = fixp->fx_offset; 649199468Sobrien else 649299468Sobrien switch (code) 649399468Sobrien { 649499468Sobrien case BFD_RELOC_X86_64_PLT32: 649599468Sobrien case BFD_RELOC_X86_64_GOT32: 649699468Sobrien case BFD_RELOC_X86_64_GOTPCREL: 6497130570Sobrien case BFD_RELOC_X86_64_TLSGD: 6498130570Sobrien case BFD_RELOC_X86_64_TLSLD: 6499130570Sobrien case BFD_RELOC_X86_64_GOTTPOFF: 6500218822Sdim case BFD_RELOC_X86_64_GOTPC32_TLSDESC: 6501218822Sdim case BFD_RELOC_X86_64_TLSDESC_CALL: 650299468Sobrien rel->addend = fixp->fx_offset - fixp->fx_size; 650399468Sobrien break; 650499468Sobrien default: 650599468Sobrien rel->addend = (section->vma 650699468Sobrien - fixp->fx_size 650799468Sobrien + fixp->fx_addnumber 650899468Sobrien + md_pcrel_from (fixp)); 650999468Sobrien break; 651099468Sobrien } 651177311Sobrien } 651233965Sjdp 651333965Sjdp rel->howto = bfd_reloc_type_lookup (stdoutput, code); 651433965Sjdp if (rel->howto == NULL) 651533965Sjdp { 651633965Sjdp as_bad_where (fixp->fx_file, fixp->fx_line, 651760519Sobrien _("cannot represent relocation type %s"), 651833965Sjdp bfd_get_reloc_code_name (code)); 651933965Sjdp /* Set howto to a garbage value so that we can keep going. */ 652033965Sjdp rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32); 652133965Sjdp assert (rel->howto != NULL); 652233965Sjdp } 652333965Sjdp 652433965Sjdp return rel; 652533965Sjdp} 652633965Sjdp 652733965Sjdp 652877311Sobrien/* Parse operands using Intel syntax. This implements a recursive descent 652977311Sobrien parser based on the BNF grammar published in Appendix B of the MASM 6.1 653077311Sobrien Programmer's Guide. 653177311Sobrien 653277311Sobrien FIXME: We do not recognize the full operand grammar defined in the MASM 653377311Sobrien documentation. In particular, all the structure/union and 653477311Sobrien high-level macro operands are missing. 653577311Sobrien 653677311Sobrien Uppercase words are terminals, lower case words are non-terminals. 653777311Sobrien Objects surrounded by double brackets '[[' ']]' are optional. Vertical 653877311Sobrien bars '|' denote choices. Most grammar productions are implemented in 653977311Sobrien functions called 'intel_<production>'. 654077311Sobrien 654177311Sobrien Initial production is 'expr'. 654277311Sobrien 654377311Sobrien addOp + | - 654477311Sobrien 654577311Sobrien alpha [a-zA-Z] 654677311Sobrien 6547218822Sdim binOp & | AND | \| | OR | ^ | XOR 6548218822Sdim 654977311Sobrien byteRegister AL | AH | BL | BH | CL | CH | DL | DH 655077311Sobrien 655177311Sobrien constant digits [[ radixOverride ]] 655277311Sobrien 6553218822Sdim dataType BYTE | WORD | DWORD | FWORD | QWORD | TBYTE | OWORD | XMMWORD 655477311Sobrien 655577311Sobrien digits decdigit 655677311Sobrien | digits decdigit 655777311Sobrien | digits hexdigit 655877311Sobrien 655977311Sobrien decdigit [0-9] 656077311Sobrien 6561218822Sdim e04 e04 addOp e05 6562218822Sdim | e05 6563218822Sdim 6564218822Sdim e05 e05 binOp e06 656577311Sobrien | e06 656677311Sobrien 656777311Sobrien e06 e06 mulOp e09 656877311Sobrien | e09 656977311Sobrien 657077311Sobrien e09 OFFSET e10 6571218822Sdim | SHORT e10 6572218822Sdim | + e10 6573218822Sdim | - e10 6574218822Sdim | ~ e10 6575218822Sdim | NOT e10 657677311Sobrien | e09 PTR e10 657777311Sobrien | e09 : e10 657877311Sobrien | e10 657977311Sobrien 658077311Sobrien e10 e10 [ expr ] 658177311Sobrien | e11 658277311Sobrien 658377311Sobrien e11 ( expr ) 658477311Sobrien | [ expr ] 658577311Sobrien | constant 658677311Sobrien | dataType 658777311Sobrien | id 658877311Sobrien | $ 658977311Sobrien | register 659077311Sobrien 6591218822Sdim => expr expr cmpOp e04 6592218822Sdim | e04 659377311Sobrien 659477311Sobrien gpRegister AX | EAX | BX | EBX | CX | ECX | DX | EDX 659577311Sobrien | BP | EBP | SP | ESP | DI | EDI | SI | ESI 659677311Sobrien 659777311Sobrien hexdigit a | b | c | d | e | f 659877311Sobrien | A | B | C | D | E | F 659977311Sobrien 660077311Sobrien id alpha 660177311Sobrien | id alpha 660277311Sobrien | id decdigit 660377311Sobrien 6604218822Sdim mulOp * | / | % | MOD | << | SHL | >> | SHR 660577311Sobrien 660677311Sobrien quote " | ' 660777311Sobrien 660877311Sobrien register specialRegister 660977311Sobrien | gpRegister 661077311Sobrien | byteRegister 661177311Sobrien 661277311Sobrien segmentRegister CS | DS | ES | FS | GS | SS 661377311Sobrien 6614218822Sdim specialRegister CR0 | CR2 | CR3 | CR4 661577311Sobrien | DR0 | DR1 | DR2 | DR3 | DR6 | DR7 661677311Sobrien | TR3 | TR4 | TR5 | TR6 | TR7 661777311Sobrien 661877311Sobrien We simplify the grammar in obvious places (e.g., register parsing is 661977311Sobrien done by calling parse_register) and eliminate immediate left recursion 662077311Sobrien to implement a recursive-descent parser. 662177311Sobrien 6622218822Sdim expr e04 expr' 662377311Sobrien 6624218822Sdim expr' cmpOp e04 expr' 6625218822Sdim | Empty 6626218822Sdim 6627218822Sdim e04 e05 e04' 6628218822Sdim 6629218822Sdim e04' addOp e05 e04' 6630218822Sdim | Empty 6631218822Sdim 663277311Sobrien e05 e06 e05' 663377311Sobrien 6634218822Sdim e05' binOp e06 e05' 663577311Sobrien | Empty 663677311Sobrien 663777311Sobrien e06 e09 e06' 663877311Sobrien 663977311Sobrien e06' mulOp e09 e06' 664077311Sobrien | Empty 664177311Sobrien 664277311Sobrien e09 OFFSET e10 e09' 6643218822Sdim | SHORT e10' 6644218822Sdim | + e10' 6645218822Sdim | - e10' 6646218822Sdim | ~ e10' 6647218822Sdim | NOT e10' 664877311Sobrien | e10 e09' 664977311Sobrien 665077311Sobrien e09' PTR e10 e09' 665177311Sobrien | : e10 e09' 665277311Sobrien | Empty 665377311Sobrien 665477311Sobrien e10 e11 e10' 665577311Sobrien 665677311Sobrien e10' [ expr ] e10' 665777311Sobrien | Empty 665877311Sobrien 665977311Sobrien e11 ( expr ) 666077311Sobrien | [ expr ] 666177311Sobrien | BYTE 666277311Sobrien | WORD 666377311Sobrien | DWORD 6664218822Sdim | FWORD 666577311Sobrien | QWORD 6666218822Sdim | TBYTE 6667218822Sdim | OWORD 6668218822Sdim | XMMWORD 666977311Sobrien | . 667077311Sobrien | $ 667177311Sobrien | register 667277311Sobrien | id 667377311Sobrien | constant */ 667477311Sobrien 667577311Sobrien/* Parsing structure for the intel syntax parser. Used to implement the 667677311Sobrien semantic actions for the operand grammar. */ 667777311Sobrienstruct intel_parser_s 667877311Sobrien { 667977311Sobrien char *op_string; /* The string being parsed. */ 668077311Sobrien int got_a_float; /* Whether the operand is a float. */ 668177311Sobrien int op_modifier; /* Operand modifier. */ 668277311Sobrien int is_mem; /* 1 if operand is memory reference. */ 6683218822Sdim int in_offset; /* >=1 if parsing operand of offset. */ 6684218822Sdim int in_bracket; /* >=1 if parsing operand in brackets. */ 668577311Sobrien const reg_entry *reg; /* Last register reference found. */ 668677311Sobrien char *disp; /* Displacement string being built. */ 6687218822Sdim char *next_operand; /* Resume point when splitting operands. */ 668877311Sobrien }; 668977311Sobrien 669077311Sobrienstatic struct intel_parser_s intel_parser; 669177311Sobrien 669277311Sobrien/* Token structure for parsing intel syntax. */ 669377311Sobrienstruct intel_token 669477311Sobrien { 669577311Sobrien int code; /* Token code. */ 669677311Sobrien const reg_entry *reg; /* Register entry for register tokens. */ 669777311Sobrien char *str; /* String representation. */ 669877311Sobrien }; 669977311Sobrien 670077311Sobrienstatic struct intel_token cur_token, prev_token; 670177311Sobrien 670277311Sobrien/* Token codes for the intel parser. Since T_SHORT is already used 670377311Sobrien by COFF, undefine it first to prevent a warning. */ 670477311Sobrien#define T_NIL -1 670577311Sobrien#define T_CONST 1 670677311Sobrien#define T_REG 2 670777311Sobrien#define T_BYTE 3 670877311Sobrien#define T_WORD 4 6709218822Sdim#define T_DWORD 5 6710218822Sdim#define T_FWORD 6 6711218822Sdim#define T_QWORD 7 6712218822Sdim#define T_TBYTE 8 6713218822Sdim#define T_XMMWORD 9 671477311Sobrien#undef T_SHORT 6715218822Sdim#define T_SHORT 10 6716218822Sdim#define T_OFFSET 11 6717218822Sdim#define T_PTR 12 6718218822Sdim#define T_ID 13 6719218822Sdim#define T_SHL 14 6720218822Sdim#define T_SHR 15 672177311Sobrien 672277311Sobrien/* Prototypes for intel parser functions. */ 6723218822Sdimstatic int intel_match_token (int); 6724218822Sdimstatic void intel_putback_token (void); 6725218822Sdimstatic void intel_get_token (void); 6726218822Sdimstatic int intel_expr (void); 6727218822Sdimstatic int intel_e04 (void); 6728218822Sdimstatic int intel_e05 (void); 6729218822Sdimstatic int intel_e06 (void); 6730218822Sdimstatic int intel_e09 (void); 6731218822Sdimstatic int intel_e10 (void); 6732218822Sdimstatic int intel_e11 (void); 673377311Sobrien 673477311Sobrienstatic int 6735218822Sdimi386_intel_operand (char *operand_string, int got_a_float) 673677311Sobrien{ 673777311Sobrien int ret; 673877311Sobrien char *p; 673977311Sobrien 6740218822Sdim p = intel_parser.op_string = xstrdup (operand_string); 6741218822Sdim intel_parser.disp = (char *) xmalloc (strlen (operand_string) + 1); 674277311Sobrien 6743218822Sdim for (;;) 6744218822Sdim { 6745218822Sdim /* Initialize token holders. */ 6746218822Sdim cur_token.code = prev_token.code = T_NIL; 6747218822Sdim cur_token.reg = prev_token.reg = NULL; 6748218822Sdim cur_token.str = prev_token.str = NULL; 674977311Sobrien 6750218822Sdim /* Initialize parser structure. */ 6751218822Sdim intel_parser.got_a_float = got_a_float; 6752218822Sdim intel_parser.op_modifier = 0; 6753218822Sdim intel_parser.is_mem = 0; 6754218822Sdim intel_parser.in_offset = 0; 6755218822Sdim intel_parser.in_bracket = 0; 6756218822Sdim intel_parser.reg = NULL; 6757218822Sdim intel_parser.disp[0] = '\0'; 6758218822Sdim intel_parser.next_operand = NULL; 675977311Sobrien 6760218822Sdim /* Read the first token and start the parser. */ 6761218822Sdim intel_get_token (); 6762218822Sdim ret = intel_expr (); 6763218822Sdim 6764218822Sdim if (!ret) 6765218822Sdim break; 6766218822Sdim 6767218822Sdim if (cur_token.code != T_NIL) 6768218822Sdim { 6769218822Sdim as_bad (_("invalid operand for '%s' ('%s' unexpected)"), 6770218822Sdim current_templates->start->name, cur_token.str); 6771218822Sdim ret = 0; 6772218822Sdim } 677377311Sobrien /* If we found a memory reference, hand it over to i386_displacement 677477311Sobrien to fill in the rest of the operand fields. */ 6775218822Sdim else if (intel_parser.is_mem) 677677311Sobrien { 677777311Sobrien if ((i.mem_operands == 1 677877311Sobrien && (current_templates->start->opcode_modifier & IsString) == 0) 677977311Sobrien || i.mem_operands == 2) 678077311Sobrien { 678177311Sobrien as_bad (_("too many memory references for '%s'"), 678277311Sobrien current_templates->start->name); 678377311Sobrien ret = 0; 678477311Sobrien } 678577311Sobrien else 678677311Sobrien { 678777311Sobrien char *s = intel_parser.disp; 678877311Sobrien i.mem_operands++; 678977311Sobrien 6790218822Sdim if (!quiet_warnings && intel_parser.is_mem < 0) 6791218822Sdim /* See the comments in intel_bracket_expr. */ 6792218822Sdim as_warn (_("Treating `%s' as memory reference"), operand_string); 6793218822Sdim 679477311Sobrien /* Add the displacement expression. */ 679577311Sobrien if (*s != '\0') 6796130570Sobrien ret = i386_displacement (s, s + strlen (s)); 6797130570Sobrien if (ret) 6798218822Sdim { 6799218822Sdim /* Swap base and index in 16-bit memory operands like 6800218822Sdim [si+bx]. Since i386_index_check is also used in AT&T 6801218822Sdim mode we have to do that here. */ 6802218822Sdim if (i.base_reg 6803218822Sdim && i.index_reg 6804218822Sdim && (i.base_reg->reg_type & Reg16) 6805218822Sdim && (i.index_reg->reg_type & Reg16) 6806218822Sdim && i.base_reg->reg_num >= 6 6807218822Sdim && i.index_reg->reg_num < 6) 6808218822Sdim { 6809218822Sdim const reg_entry *base = i.index_reg; 6810218822Sdim 6811218822Sdim i.index_reg = i.base_reg; 6812218822Sdim i.base_reg = base; 6813218822Sdim } 6814218822Sdim ret = i386_index_check (operand_string); 6815218822Sdim } 681677311Sobrien } 681777311Sobrien } 681877311Sobrien 681977311Sobrien /* Constant and OFFSET expressions are handled by i386_immediate. */ 6820218822Sdim else if ((intel_parser.op_modifier & (1 << T_OFFSET)) 682177311Sobrien || intel_parser.reg == NULL) 682277311Sobrien ret = i386_immediate (intel_parser.disp); 6823218822Sdim 6824218822Sdim if (intel_parser.next_operand && this_operand >= MAX_OPERANDS - 1) 6825218822Sdim ret = 0; 6826218822Sdim if (!ret || !intel_parser.next_operand) 6827218822Sdim break; 6828218822Sdim intel_parser.op_string = intel_parser.next_operand; 6829218822Sdim this_operand = i.operands++; 683077311Sobrien } 683177311Sobrien 683277311Sobrien free (p); 683377311Sobrien free (intel_parser.disp); 683477311Sobrien 683577311Sobrien return ret; 683677311Sobrien} 683777311Sobrien 6838218822Sdim#define NUM_ADDRESS_REGS (!!i.base_reg + !!i.index_reg) 6839218822Sdim 6840218822Sdim/* expr e04 expr' 6841218822Sdim 6842218822Sdim expr' cmpOp e04 expr' 6843218822Sdim | Empty */ 684477311Sobrienstatic int 6845218822Sdimintel_expr (void) 684677311Sobrien{ 6847218822Sdim /* XXX Implement the comparison operators. */ 6848218822Sdim return intel_e04 (); 6849218822Sdim} 6850218822Sdim 6851218822Sdim/* e04 e05 e04' 6852218822Sdim 6853218822Sdim e04' addOp e05 e04' 6854218822Sdim | Empty */ 6855218822Sdimstatic int 6856218822Sdimintel_e04 (void) 6857218822Sdim{ 6858218822Sdim int nregs = -1; 6859218822Sdim 6860218822Sdim for (;;) 686177311Sobrien { 6862218822Sdim if (!intel_e05()) 6863218822Sdim return 0; 686477311Sobrien 6865218822Sdim if (nregs >= 0 && NUM_ADDRESS_REGS > nregs) 6866218822Sdim i.base_reg = i386_regtab + REGNAM_AL; /* al is invalid as base */ 6867218822Sdim 6868218822Sdim if (cur_token.code == '+') 6869218822Sdim nregs = -1; 6870218822Sdim else if (cur_token.code == '-') 6871218822Sdim nregs = NUM_ADDRESS_REGS; 6872218822Sdim else 6873218822Sdim return 1; 6874218822Sdim 6875218822Sdim strcat (intel_parser.disp, cur_token.str); 6876218822Sdim intel_match_token (cur_token.code); 687777311Sobrien } 687877311Sobrien} 687977311Sobrien 688077311Sobrien/* e05 e06 e05' 688177311Sobrien 6882218822Sdim e05' binOp e06 e05' 688377311Sobrien | Empty */ 688477311Sobrienstatic int 6885218822Sdimintel_e05 (void) 688677311Sobrien{ 6887218822Sdim int nregs = ~NUM_ADDRESS_REGS; 688877311Sobrien 6889218822Sdim for (;;) 689077311Sobrien { 6891218822Sdim if (!intel_e06()) 6892218822Sdim return 0; 6893218822Sdim 6894218822Sdim if (cur_token.code == '&' 6895218822Sdim || cur_token.code == '|' 6896218822Sdim || cur_token.code == '^') 6897218822Sdim { 6898218822Sdim char str[2]; 6899218822Sdim 6900218822Sdim str[0] = cur_token.code; 6901218822Sdim str[1] = 0; 6902218822Sdim strcat (intel_parser.disp, str); 6903218822Sdim } 6904218822Sdim else 6905218822Sdim break; 6906218822Sdim 690777311Sobrien intel_match_token (cur_token.code); 690877311Sobrien 6909218822Sdim if (nregs < 0) 6910218822Sdim nregs = ~nregs; 691177311Sobrien } 6912218822Sdim if (nregs >= 0 && NUM_ADDRESS_REGS > nregs) 6913218822Sdim i.base_reg = i386_regtab + REGNAM_AL + 1; /* cl is invalid as base */ 6914218822Sdim return 1; 691577311Sobrien} 691677311Sobrien 691777311Sobrien/* e06 e09 e06' 691877311Sobrien 691977311Sobrien e06' mulOp e09 e06' 692077311Sobrien | Empty */ 692177311Sobrienstatic int 6922218822Sdimintel_e06 (void) 692377311Sobrien{ 6924218822Sdim int nregs = ~NUM_ADDRESS_REGS; 692577311Sobrien 6926218822Sdim for (;;) 692777311Sobrien { 6928218822Sdim if (!intel_e09()) 6929218822Sdim return 0; 6930218822Sdim 6931218822Sdim if (cur_token.code == '*' 6932218822Sdim || cur_token.code == '/' 6933218822Sdim || cur_token.code == '%') 6934218822Sdim { 6935218822Sdim char str[2]; 6936218822Sdim 6937218822Sdim str[0] = cur_token.code; 6938218822Sdim str[1] = 0; 6939218822Sdim strcat (intel_parser.disp, str); 6940218822Sdim } 6941218822Sdim else if (cur_token.code == T_SHL) 6942218822Sdim strcat (intel_parser.disp, "<<"); 6943218822Sdim else if (cur_token.code == T_SHR) 6944218822Sdim strcat (intel_parser.disp, ">>"); 6945218822Sdim else 6946218822Sdim break; 6947218822Sdim 694877311Sobrien intel_match_token (cur_token.code); 694977311Sobrien 6950218822Sdim if (nregs < 0) 6951218822Sdim nregs = ~nregs; 695277311Sobrien } 6953218822Sdim if (nregs >= 0 && NUM_ADDRESS_REGS > nregs) 6954218822Sdim i.base_reg = i386_regtab + REGNAM_AL + 2; /* dl is invalid as base */ 6955218822Sdim return 1; 695677311Sobrien} 695777311Sobrien 6958218822Sdim/* e09 OFFSET e09 6959218822Sdim | SHORT e09 6960218822Sdim | + e09 6961218822Sdim | - e09 6962218822Sdim | ~ e09 6963218822Sdim | NOT e09 696477311Sobrien | e10 e09' 696577311Sobrien 696677311Sobrien e09' PTR e10 e09' 696777311Sobrien | : e10 e09' 696877311Sobrien | Empty */ 696977311Sobrienstatic int 6970218822Sdimintel_e09 (void) 697177311Sobrien{ 6972218822Sdim int nregs = ~NUM_ADDRESS_REGS; 6973218822Sdim int in_offset = 0; 6974218822Sdim 6975218822Sdim for (;;) 697677311Sobrien { 6977218822Sdim /* Don't consume constants here. */ 6978218822Sdim if (cur_token.code == '+' || cur_token.code == '-') 6979218822Sdim { 6980218822Sdim /* Need to look one token ahead - if the next token 6981218822Sdim is a constant, the current token is its sign. */ 6982218822Sdim int next_code; 698377311Sobrien 6984218822Sdim intel_match_token (cur_token.code); 6985218822Sdim next_code = cur_token.code; 6986218822Sdim intel_putback_token (); 6987218822Sdim if (next_code == T_CONST) 6988218822Sdim break; 6989218822Sdim } 699077311Sobrien 6991218822Sdim /* e09 OFFSET e09 */ 6992218822Sdim if (cur_token.code == T_OFFSET) 6993218822Sdim { 6994218822Sdim if (!in_offset++) 6995218822Sdim ++intel_parser.in_offset; 6996218822Sdim } 699777311Sobrien 6998218822Sdim /* e09 SHORT e09 */ 6999218822Sdim else if (cur_token.code == T_SHORT) 7000218822Sdim intel_parser.op_modifier |= 1 << T_SHORT; 700177311Sobrien 7002218822Sdim /* e09 + e09 */ 7003218822Sdim else if (cur_token.code == '+') 7004218822Sdim strcat (intel_parser.disp, "+"); 7005218822Sdim 7006218822Sdim /* e09 - e09 7007218822Sdim | ~ e09 7008218822Sdim | NOT e09 */ 7009218822Sdim else if (cur_token.code == '-' || cur_token.code == '~') 701077311Sobrien { 7011218822Sdim char str[2]; 7012218822Sdim 7013218822Sdim if (nregs < 0) 7014218822Sdim nregs = ~nregs; 7015218822Sdim str[0] = cur_token.code; 7016218822Sdim str[1] = 0; 7017218822Sdim strcat (intel_parser.disp, str); 701877311Sobrien } 701977311Sobrien 7020218822Sdim /* e09 e10 e09' */ 7021218822Sdim else 7022218822Sdim break; 7023218822Sdim 7024218822Sdim intel_match_token (cur_token.code); 7025218822Sdim } 7026218822Sdim 7027218822Sdim for (;;) 7028218822Sdim { 7029218822Sdim if (!intel_e10 ()) 7030218822Sdim return 0; 7031218822Sdim 7032218822Sdim /* e09' PTR e10 e09' */ 7033218822Sdim if (cur_token.code == T_PTR) 703477311Sobrien { 7035218822Sdim char suffix; 7036218822Sdim 7037218822Sdim if (prev_token.code == T_BYTE) 7038218822Sdim suffix = BYTE_MNEM_SUFFIX; 7039218822Sdim 7040218822Sdim else if (prev_token.code == T_WORD) 7041218822Sdim { 7042218822Sdim if (current_templates->start->name[0] == 'l' 7043218822Sdim && current_templates->start->name[2] == 's' 7044218822Sdim && current_templates->start->name[3] == 0) 7045218822Sdim suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */ 7046218822Sdim else if (intel_parser.got_a_float == 2) /* "fi..." */ 7047218822Sdim suffix = SHORT_MNEM_SUFFIX; 7048218822Sdim else 7049218822Sdim suffix = WORD_MNEM_SUFFIX; 7050218822Sdim } 7051218822Sdim 7052218822Sdim else if (prev_token.code == T_DWORD) 7053218822Sdim { 7054218822Sdim if (current_templates->start->name[0] == 'l' 7055218822Sdim && current_templates->start->name[2] == 's' 7056218822Sdim && current_templates->start->name[3] == 0) 7057218822Sdim suffix = WORD_MNEM_SUFFIX; 7058218822Sdim else if (flag_code == CODE_16BIT 7059218822Sdim && (current_templates->start->opcode_modifier 7060218822Sdim & (Jump | JumpDword))) 7061218822Sdim suffix = LONG_DOUBLE_MNEM_SUFFIX; 7062218822Sdim else if (intel_parser.got_a_float == 1) /* "f..." */ 7063218822Sdim suffix = SHORT_MNEM_SUFFIX; 7064218822Sdim else 7065218822Sdim suffix = LONG_MNEM_SUFFIX; 7066218822Sdim } 7067218822Sdim 7068218822Sdim else if (prev_token.code == T_FWORD) 7069218822Sdim { 7070218822Sdim if (current_templates->start->name[0] == 'l' 7071218822Sdim && current_templates->start->name[2] == 's' 7072218822Sdim && current_templates->start->name[3] == 0) 7073218822Sdim suffix = LONG_MNEM_SUFFIX; 7074218822Sdim else if (!intel_parser.got_a_float) 7075218822Sdim { 7076218822Sdim if (flag_code == CODE_16BIT) 7077218822Sdim add_prefix (DATA_PREFIX_OPCODE); 7078218822Sdim suffix = LONG_DOUBLE_MNEM_SUFFIX; 7079218822Sdim } 7080218822Sdim else 7081218822Sdim suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */ 7082218822Sdim } 7083218822Sdim 7084218822Sdim else if (prev_token.code == T_QWORD) 7085218822Sdim { 7086218822Sdim if (intel_parser.got_a_float == 1) /* "f..." */ 7087218822Sdim suffix = LONG_MNEM_SUFFIX; 7088218822Sdim else 7089218822Sdim suffix = QWORD_MNEM_SUFFIX; 7090218822Sdim } 7091218822Sdim 7092218822Sdim else if (prev_token.code == T_TBYTE) 7093218822Sdim { 7094218822Sdim if (intel_parser.got_a_float == 1) 7095218822Sdim suffix = LONG_DOUBLE_MNEM_SUFFIX; 7096218822Sdim else 7097218822Sdim suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */ 7098218822Sdim } 7099218822Sdim 7100218822Sdim else if (prev_token.code == T_XMMWORD) 7101218822Sdim { 7102218822Sdim /* XXX ignored for now, but accepted since gcc uses it */ 7103218822Sdim suffix = 0; 7104218822Sdim } 7105218822Sdim 710677311Sobrien else 7107218822Sdim { 7108218822Sdim as_bad (_("Unknown operand modifier `%s'"), prev_token.str); 7109218822Sdim return 0; 7110218822Sdim } 7111218822Sdim 7112218822Sdim /* Operands for jump/call using 'ptr' notation denote absolute 7113218822Sdim addresses. */ 7114218822Sdim if (current_templates->start->opcode_modifier & (Jump | JumpDword)) 7115218822Sdim i.types[this_operand] |= JumpAbsolute; 7116218822Sdim 7117218822Sdim if (current_templates->start->base_opcode == 0x8d /* lea */) 7118218822Sdim ; 7119218822Sdim else if (!i.suffix) 7120218822Sdim i.suffix = suffix; 7121218822Sdim else if (i.suffix != suffix) 7122218822Sdim { 7123218822Sdim as_bad (_("Conflicting operand modifiers")); 7124218822Sdim return 0; 7125218822Sdim } 7126218822Sdim 712777311Sobrien } 712877311Sobrien 7129218822Sdim /* e09' : e10 e09' */ 7130218822Sdim else if (cur_token.code == ':') 713177311Sobrien { 7132218822Sdim if (prev_token.code != T_REG) 7133218822Sdim { 7134218822Sdim /* While {call,jmp} SSSS:OOOO is MASM syntax only when SSSS is a 7135218822Sdim segment/group identifier (which we don't have), using comma 7136218822Sdim as the operand separator there is even less consistent, since 7137218822Sdim there all branches only have a single operand. */ 7138218822Sdim if (this_operand != 0 7139218822Sdim || intel_parser.in_offset 7140218822Sdim || intel_parser.in_bracket 7141218822Sdim || (!(current_templates->start->opcode_modifier 7142218822Sdim & (Jump|JumpDword|JumpInterSegment)) 7143218822Sdim && !(current_templates->start->operand_types[0] 7144218822Sdim & JumpAbsolute))) 7145218822Sdim return intel_match_token (T_NIL); 7146218822Sdim /* Remember the start of the 2nd operand and terminate 1st 7147218822Sdim operand here. 7148218822Sdim XXX This isn't right, yet (when SSSS:OOOO is right operand of 7149218822Sdim another expression), but it gets at least the simplest case 7150218822Sdim (a plain number or symbol on the left side) right. */ 7151218822Sdim intel_parser.next_operand = intel_parser.op_string; 7152218822Sdim *--intel_parser.op_string = '\0'; 7153218822Sdim return intel_match_token (':'); 7154218822Sdim } 715577311Sobrien } 715677311Sobrien 7157218822Sdim /* e09' Empty */ 7158218822Sdim else 7159218822Sdim break; 716077311Sobrien 7161218822Sdim intel_match_token (cur_token.code); 7162218822Sdim 7163218822Sdim } 7164218822Sdim 7165218822Sdim if (in_offset) 7166218822Sdim { 7167218822Sdim --intel_parser.in_offset; 7168218822Sdim if (nregs < 0) 7169218822Sdim nregs = ~nregs; 7170218822Sdim if (NUM_ADDRESS_REGS > nregs) 717177311Sobrien { 7172218822Sdim as_bad (_("Invalid operand to `OFFSET'")); 717377311Sobrien return 0; 717477311Sobrien } 7175218822Sdim intel_parser.op_modifier |= 1 << T_OFFSET; 7176218822Sdim } 717777311Sobrien 7178218822Sdim if (nregs >= 0 && NUM_ADDRESS_REGS > nregs) 7179218822Sdim i.base_reg = i386_regtab + REGNAM_AL + 3; /* bl is invalid as base */ 7180218822Sdim return 1; 7181218822Sdim} 718277311Sobrien 7183218822Sdimstatic int 7184218822Sdimintel_bracket_expr (void) 7185218822Sdim{ 7186218822Sdim int was_offset = intel_parser.op_modifier & (1 << T_OFFSET); 7187218822Sdim const char *start = intel_parser.op_string; 7188218822Sdim int len; 7189218822Sdim 7190218822Sdim if (i.op[this_operand].regs) 7191218822Sdim return intel_match_token (T_NIL); 7192218822Sdim 7193218822Sdim intel_match_token ('['); 7194218822Sdim 7195218822Sdim /* Mark as a memory operand only if it's not already known to be an 7196218822Sdim offset expression. If it's an offset expression, we need to keep 7197218822Sdim the brace in. */ 7198218822Sdim if (!intel_parser.in_offset) 7199218822Sdim { 7200218822Sdim ++intel_parser.in_bracket; 7201218822Sdim 7202218822Sdim /* Operands for jump/call inside brackets denote absolute addresses. */ 7203218822Sdim if (current_templates->start->opcode_modifier & (Jump | JumpDword)) 7204218822Sdim i.types[this_operand] |= JumpAbsolute; 7205218822Sdim 7206218822Sdim /* Unfortunately gas always diverged from MASM in a respect that can't 7207218822Sdim be easily fixed without risking to break code sequences likely to be 7208218822Sdim encountered (the testsuite even check for this): MASM doesn't consider 7209218822Sdim an expression inside brackets unconditionally as a memory reference. 7210218822Sdim When that is e.g. a constant, an offset expression, or the sum of the 7211218822Sdim two, this is still taken as a constant load. gas, however, always 7212218822Sdim treated these as memory references. As a compromise, we'll try to make 7213218822Sdim offset expressions inside brackets work the MASM way (since that's 7214218822Sdim less likely to be found in real world code), but make constants alone 7215218822Sdim continue to work the traditional gas way. In either case, issue a 7216218822Sdim warning. */ 7217218822Sdim intel_parser.op_modifier &= ~was_offset; 721877311Sobrien } 7219218822Sdim else 7220218822Sdim strcat (intel_parser.disp, "["); 722177311Sobrien 7222218822Sdim /* Add a '+' to the displacement string if necessary. */ 7223218822Sdim if (*intel_parser.disp != '\0' 7224218822Sdim && *(intel_parser.disp + strlen (intel_parser.disp) - 1) != '+') 7225218822Sdim strcat (intel_parser.disp, "+"); 7226218822Sdim 7227218822Sdim if (intel_expr () 7228218822Sdim && (len = intel_parser.op_string - start - 1, 7229218822Sdim intel_match_token (']'))) 723077311Sobrien { 7231218822Sdim /* Preserve brackets when the operand is an offset expression. */ 7232218822Sdim if (intel_parser.in_offset) 7233218822Sdim strcat (intel_parser.disp, "]"); 7234218822Sdim else 7235218822Sdim { 7236218822Sdim --intel_parser.in_bracket; 7237218822Sdim if (i.base_reg || i.index_reg) 7238218822Sdim intel_parser.is_mem = 1; 7239218822Sdim if (!intel_parser.is_mem) 7240218822Sdim { 7241218822Sdim if (!(intel_parser.op_modifier & (1 << T_OFFSET))) 7242218822Sdim /* Defer the warning until all of the operand was parsed. */ 7243218822Sdim intel_parser.is_mem = -1; 7244218822Sdim else if (!quiet_warnings) 7245218822Sdim as_warn (_("`[%.*s]' taken to mean just `%.*s'"), 7246218822Sdim len, start, len, start); 7247218822Sdim } 7248218822Sdim } 7249218822Sdim intel_parser.op_modifier |= was_offset; 725077311Sobrien 7251218822Sdim return 1; 725277311Sobrien } 7253218822Sdim return 0; 725477311Sobrien} 725577311Sobrien 725677311Sobrien/* e10 e11 e10' 725777311Sobrien 725877311Sobrien e10' [ expr ] e10' 725977311Sobrien | Empty */ 726077311Sobrienstatic int 7261218822Sdimintel_e10 (void) 726277311Sobrien{ 7263218822Sdim if (!intel_e11 ()) 7264218822Sdim return 0; 726577311Sobrien 7266218822Sdim while (cur_token.code == '[') 726777311Sobrien { 7268218822Sdim if (!intel_bracket_expr ()) 726977311Sobrien return 0; 727077311Sobrien } 727177311Sobrien 7272218822Sdim return 1; 727377311Sobrien} 727477311Sobrien 727577311Sobrien/* e11 ( expr ) 727677311Sobrien | [ expr ] 727777311Sobrien | BYTE 727877311Sobrien | WORD 727977311Sobrien | DWORD 7280218822Sdim | FWORD 728177311Sobrien | QWORD 7282218822Sdim | TBYTE 7283218822Sdim | OWORD 7284218822Sdim | XMMWORD 728577311Sobrien | $ 728677311Sobrien | . 728777311Sobrien | register 728877311Sobrien | id 728977311Sobrien | constant */ 729077311Sobrienstatic int 7291218822Sdimintel_e11 (void) 729277311Sobrien{ 7293218822Sdim switch (cur_token.code) 729477311Sobrien { 7295218822Sdim /* e11 ( expr ) */ 7296218822Sdim case '(': 729777311Sobrien intel_match_token ('('); 729877311Sobrien strcat (intel_parser.disp, "("); 729977311Sobrien 730077311Sobrien if (intel_expr () && intel_match_token (')')) 730177311Sobrien { 730277311Sobrien strcat (intel_parser.disp, ")"); 730377311Sobrien return 1; 730477311Sobrien } 7305218822Sdim return 0; 730677311Sobrien 7307218822Sdim /* e11 [ expr ] */ 7308218822Sdim case '[': 7309218822Sdim return intel_bracket_expr (); 731077311Sobrien 7311218822Sdim /* e11 $ 7312218822Sdim | . */ 7313218822Sdim case '.': 731477311Sobrien strcat (intel_parser.disp, cur_token.str); 731577311Sobrien intel_match_token (cur_token.code); 731677311Sobrien 731777311Sobrien /* Mark as a memory operand only if it's not already known to be an 731877311Sobrien offset expression. */ 7319218822Sdim if (!intel_parser.in_offset) 732077311Sobrien intel_parser.is_mem = 1; 732177311Sobrien 732277311Sobrien return 1; 732377311Sobrien 7324218822Sdim /* e11 register */ 7325218822Sdim case T_REG: 7326218822Sdim { 7327218822Sdim const reg_entry *reg = intel_parser.reg = cur_token.reg; 732877311Sobrien 7329218822Sdim intel_match_token (T_REG); 733077311Sobrien 7331218822Sdim /* Check for segment change. */ 7332218822Sdim if (cur_token.code == ':') 7333218822Sdim { 7334218822Sdim if (!(reg->reg_type & (SReg2 | SReg3))) 7335218822Sdim { 7336218822Sdim as_bad (_("`%s' is not a valid segment register"), 7337218822Sdim reg->reg_name); 7338218822Sdim return 0; 7339218822Sdim } 7340218822Sdim else if (i.seg[i.mem_operands]) 7341218822Sdim as_warn (_("Extra segment override ignored")); 7342218822Sdim else 7343218822Sdim { 7344218822Sdim if (!intel_parser.in_offset) 7345218822Sdim intel_parser.is_mem = 1; 7346218822Sdim switch (reg->reg_num) 7347218822Sdim { 7348218822Sdim case 0: 7349218822Sdim i.seg[i.mem_operands] = &es; 7350218822Sdim break; 7351218822Sdim case 1: 7352218822Sdim i.seg[i.mem_operands] = &cs; 7353218822Sdim break; 7354218822Sdim case 2: 7355218822Sdim i.seg[i.mem_operands] = &ss; 7356218822Sdim break; 7357218822Sdim case 3: 7358218822Sdim i.seg[i.mem_operands] = &ds; 7359218822Sdim break; 7360218822Sdim case 4: 7361218822Sdim i.seg[i.mem_operands] = &fs; 7362218822Sdim break; 7363218822Sdim case 5: 7364218822Sdim i.seg[i.mem_operands] = &gs; 7365218822Sdim break; 7366218822Sdim } 7367218822Sdim } 7368218822Sdim } 736977311Sobrien 7370218822Sdim /* Not a segment register. Check for register scaling. */ 7371218822Sdim else if (cur_token.code == '*') 7372218822Sdim { 7373218822Sdim if (!intel_parser.in_bracket) 7374218822Sdim { 7375218822Sdim as_bad (_("Register scaling only allowed in memory operands")); 7376218822Sdim return 0; 7377218822Sdim } 7378218822Sdim 7379218822Sdim if (reg->reg_type & Reg16) /* Disallow things like [si*1]. */ 7380218822Sdim reg = i386_regtab + REGNAM_AX + 4; /* sp is invalid as index */ 7381218822Sdim else if (i.index_reg) 7382218822Sdim reg = i386_regtab + REGNAM_EAX + 4; /* esp is invalid as index */ 7383218822Sdim 7384218822Sdim /* What follows must be a valid scale. */ 7385218822Sdim intel_match_token ('*'); 7386218822Sdim i.index_reg = reg; 7387218822Sdim i.types[this_operand] |= BaseIndex; 7388218822Sdim 7389218822Sdim /* Set the scale after setting the register (otherwise, 7390218822Sdim i386_scale will complain) */ 7391218822Sdim if (cur_token.code == '+' || cur_token.code == '-') 7392218822Sdim { 7393218822Sdim char *str, sign = cur_token.code; 7394218822Sdim intel_match_token (cur_token.code); 7395218822Sdim if (cur_token.code != T_CONST) 7396218822Sdim { 7397218822Sdim as_bad (_("Syntax error: Expecting a constant, got `%s'"), 7398218822Sdim cur_token.str); 7399218822Sdim return 0; 7400218822Sdim } 7401218822Sdim str = (char *) xmalloc (strlen (cur_token.str) + 2); 7402218822Sdim strcpy (str + 1, cur_token.str); 7403218822Sdim *str = sign; 7404218822Sdim if (!i386_scale (str)) 7405218822Sdim return 0; 7406218822Sdim free (str); 7407218822Sdim } 7408218822Sdim else if (!i386_scale (cur_token.str)) 740977311Sobrien return 0; 7410218822Sdim intel_match_token (cur_token.code); 7411218822Sdim } 741277311Sobrien 7413218822Sdim /* No scaling. If this is a memory operand, the register is either a 7414218822Sdim base register (first occurrence) or an index register (second 7415218822Sdim occurrence). */ 7416218822Sdim else if (intel_parser.in_bracket) 7417218822Sdim { 7418218822Sdim 7419218822Sdim if (!i.base_reg) 7420218822Sdim i.base_reg = reg; 7421218822Sdim else if (!i.index_reg) 742277311Sobrien i.index_reg = reg; 7423218822Sdim else 7424218822Sdim { 7425218822Sdim as_bad (_("Too many register references in memory operand")); 7426218822Sdim return 0; 7427218822Sdim } 742877311Sobrien 7429218822Sdim i.types[this_operand] |= BaseIndex; 7430218822Sdim } 743177311Sobrien 7432218822Sdim /* It's neither base nor index. */ 7433218822Sdim else if (!intel_parser.in_offset && !intel_parser.is_mem) 7434218822Sdim { 7435218822Sdim i.types[this_operand] |= reg->reg_type & ~BaseIndex; 7436218822Sdim i.op[this_operand].regs = reg; 7437218822Sdim i.reg_operands++; 7438218822Sdim } 7439218822Sdim else 7440218822Sdim { 7441218822Sdim as_bad (_("Invalid use of register")); 7442218822Sdim return 0; 7443218822Sdim } 744477311Sobrien 7445218822Sdim /* Since registers are not part of the displacement string (except 7446218822Sdim when we're parsing offset operands), we may need to remove any 7447218822Sdim preceding '+' from the displacement string. */ 7448218822Sdim if (*intel_parser.disp != '\0' 7449218822Sdim && !intel_parser.in_offset) 7450218822Sdim { 7451218822Sdim char *s = intel_parser.disp; 7452218822Sdim s += strlen (s) - 1; 7453218822Sdim if (*s == '+') 7454218822Sdim *s = '\0'; 7455218822Sdim } 745677311Sobrien 7457218822Sdim return 1; 7458218822Sdim } 745977311Sobrien 7460218822Sdim /* e11 BYTE 7461218822Sdim | WORD 7462218822Sdim | DWORD 7463218822Sdim | FWORD 7464218822Sdim | QWORD 7465218822Sdim | TBYTE 7466218822Sdim | OWORD 7467218822Sdim | XMMWORD */ 7468218822Sdim case T_BYTE: 7469218822Sdim case T_WORD: 7470218822Sdim case T_DWORD: 7471218822Sdim case T_FWORD: 7472218822Sdim case T_QWORD: 7473218822Sdim case T_TBYTE: 7474218822Sdim case T_XMMWORD: 7475218822Sdim intel_match_token (cur_token.code); 747677311Sobrien 7477218822Sdim if (cur_token.code == T_PTR) 7478218822Sdim return 1; 7479218822Sdim 7480218822Sdim /* It must have been an identifier. */ 7481218822Sdim intel_putback_token (); 7482218822Sdim cur_token.code = T_ID; 7483218822Sdim /* FALLTHRU */ 7484218822Sdim 7485218822Sdim /* e11 id 7486218822Sdim | constant */ 7487218822Sdim case T_ID: 7488218822Sdim if (!intel_parser.in_offset && intel_parser.is_mem <= 0) 748977311Sobrien { 7490218822Sdim symbolS *symbolP; 749177311Sobrien 7492218822Sdim /* The identifier represents a memory reference only if it's not 7493218822Sdim preceded by an offset modifier and if it's not an equate. */ 7494218822Sdim symbolP = symbol_find(cur_token.str); 7495218822Sdim if (!symbolP || S_GET_SEGMENT(symbolP) != absolute_section) 7496218822Sdim intel_parser.is_mem = 1; 749777311Sobrien } 7498218822Sdim /* FALLTHRU */ 749977311Sobrien 7500218822Sdim case T_CONST: 7501218822Sdim case '-': 7502218822Sdim case '+': 7503218822Sdim { 7504218822Sdim char *save_str, sign = 0; 750577311Sobrien 7506218822Sdim /* Allow constants that start with `+' or `-'. */ 7507218822Sdim if (cur_token.code == '-' || cur_token.code == '+') 7508218822Sdim { 7509218822Sdim sign = cur_token.code; 7510218822Sdim intel_match_token (cur_token.code); 7511218822Sdim if (cur_token.code != T_CONST) 7512218822Sdim { 7513218822Sdim as_bad (_("Syntax error: Expecting a constant, got `%s'"), 7514218822Sdim cur_token.str); 7515218822Sdim return 0; 7516218822Sdim } 7517218822Sdim } 751877311Sobrien 7519218822Sdim save_str = (char *) xmalloc (strlen (cur_token.str) + 2); 7520218822Sdim strcpy (save_str + !!sign, cur_token.str); 7521218822Sdim if (sign) 7522218822Sdim *save_str = sign; 752377311Sobrien 7524218822Sdim /* Get the next token to check for register scaling. */ 7525218822Sdim intel_match_token (cur_token.code); 752677311Sobrien 7527218822Sdim /* Check if this constant is a scaling factor for an 7528218822Sdim index register. */ 7529218822Sdim if (cur_token.code == '*') 7530218822Sdim { 7531218822Sdim if (intel_match_token ('*') && cur_token.code == T_REG) 7532218822Sdim { 7533218822Sdim const reg_entry *reg = cur_token.reg; 753477311Sobrien 7535218822Sdim if (!intel_parser.in_bracket) 7536218822Sdim { 7537218822Sdim as_bad (_("Register scaling only allowed " 7538218822Sdim "in memory operands")); 7539218822Sdim return 0; 7540218822Sdim } 754177311Sobrien 7542218822Sdim /* Disallow things like [1*si]. 7543218822Sdim sp and esp are invalid as index. */ 7544218822Sdim if (reg->reg_type & Reg16) 7545218822Sdim reg = i386_regtab + REGNAM_AX + 4; 7546218822Sdim else if (i.index_reg) 7547218822Sdim reg = i386_regtab + REGNAM_EAX + 4; 754877311Sobrien 7549218822Sdim /* The constant is followed by `* reg', so it must be 7550218822Sdim a valid scale. */ 7551218822Sdim i.index_reg = reg; 7552218822Sdim i.types[this_operand] |= BaseIndex; 755377311Sobrien 7554218822Sdim /* Set the scale after setting the register (otherwise, 7555218822Sdim i386_scale will complain) */ 7556218822Sdim if (!i386_scale (save_str)) 755777311Sobrien return 0; 7558218822Sdim intel_match_token (T_REG); 755977311Sobrien 7560218822Sdim /* Since registers are not part of the displacement 7561218822Sdim string, we may need to remove any preceding '+' from 7562218822Sdim the displacement string. */ 7563218822Sdim if (*intel_parser.disp != '\0') 7564218822Sdim { 7565218822Sdim char *s = intel_parser.disp; 7566218822Sdim s += strlen (s) - 1; 7567218822Sdim if (*s == '+') 7568218822Sdim *s = '\0'; 7569218822Sdim } 757077311Sobrien 7571218822Sdim free (save_str); 757277311Sobrien 7573218822Sdim return 1; 7574218822Sdim } 757577311Sobrien 7576218822Sdim /* The constant was not used for register scaling. Since we have 7577218822Sdim already consumed the token following `*' we now need to put it 7578218822Sdim back in the stream. */ 757977311Sobrien intel_putback_token (); 7580218822Sdim } 758177311Sobrien 7582218822Sdim /* Add the constant to the displacement string. */ 7583218822Sdim strcat (intel_parser.disp, save_str); 7584218822Sdim free (save_str); 758577311Sobrien 7586218822Sdim return 1; 7587218822Sdim } 758877311Sobrien } 758977311Sobrien 759077311Sobrien as_bad (_("Unrecognized token '%s'"), cur_token.str); 759177311Sobrien return 0; 759277311Sobrien} 759377311Sobrien 759477311Sobrien/* Match the given token against cur_token. If they match, read the next 759577311Sobrien token from the operand string. */ 759677311Sobrienstatic int 7597218822Sdimintel_match_token (int code) 759877311Sobrien{ 759977311Sobrien if (cur_token.code == code) 760077311Sobrien { 760177311Sobrien intel_get_token (); 760277311Sobrien return 1; 760377311Sobrien } 760477311Sobrien else 760577311Sobrien { 7606218822Sdim as_bad (_("Unexpected token `%s'"), cur_token.str); 760777311Sobrien return 0; 760877311Sobrien } 760977311Sobrien} 761077311Sobrien 761177311Sobrien/* Read a new token from intel_parser.op_string and store it in cur_token. */ 761277311Sobrienstatic void 7613218822Sdimintel_get_token (void) 761477311Sobrien{ 761577311Sobrien char *end_op; 761677311Sobrien const reg_entry *reg; 761777311Sobrien struct intel_token new_token; 761877311Sobrien 761977311Sobrien new_token.code = T_NIL; 762077311Sobrien new_token.reg = NULL; 762177311Sobrien new_token.str = NULL; 762277311Sobrien 762377311Sobrien /* Free the memory allocated to the previous token and move 762477311Sobrien cur_token to prev_token. */ 762577311Sobrien if (prev_token.str) 762677311Sobrien free (prev_token.str); 762777311Sobrien 762877311Sobrien prev_token = cur_token; 762977311Sobrien 763077311Sobrien /* Skip whitespace. */ 763177311Sobrien while (is_space_char (*intel_parser.op_string)) 763277311Sobrien intel_parser.op_string++; 763377311Sobrien 763477311Sobrien /* Return an empty token if we find nothing else on the line. */ 763577311Sobrien if (*intel_parser.op_string == '\0') 763677311Sobrien { 763777311Sobrien cur_token = new_token; 763877311Sobrien return; 763977311Sobrien } 764077311Sobrien 764177311Sobrien /* The new token cannot be larger than the remainder of the operand 764277311Sobrien string. */ 7643218822Sdim new_token.str = (char *) xmalloc (strlen (intel_parser.op_string) + 1); 764477311Sobrien new_token.str[0] = '\0'; 764577311Sobrien 764677311Sobrien if (strchr ("0123456789", *intel_parser.op_string)) 764777311Sobrien { 764877311Sobrien char *p = new_token.str; 764977311Sobrien char *q = intel_parser.op_string; 765077311Sobrien new_token.code = T_CONST; 765177311Sobrien 765277311Sobrien /* Allow any kind of identifier char to encompass floating point and 765377311Sobrien hexadecimal numbers. */ 765477311Sobrien while (is_identifier_char (*q)) 765577311Sobrien *p++ = *q++; 765677311Sobrien *p = '\0'; 765777311Sobrien 765877311Sobrien /* Recognize special symbol names [0-9][bf]. */ 765977311Sobrien if (strlen (intel_parser.op_string) == 2 766077311Sobrien && (intel_parser.op_string[1] == 'b' 766177311Sobrien || intel_parser.op_string[1] == 'f')) 766277311Sobrien new_token.code = T_ID; 766377311Sobrien } 766477311Sobrien 7665218822Sdim else if ((reg = parse_register (intel_parser.op_string, &end_op)) != NULL) 766677311Sobrien { 7667218822Sdim size_t len = end_op - intel_parser.op_string; 766877311Sobrien 766977311Sobrien new_token.code = T_REG; 767077311Sobrien new_token.reg = reg; 767177311Sobrien 7672218822Sdim memcpy (new_token.str, intel_parser.op_string, len); 7673218822Sdim new_token.str[len] = '\0'; 767477311Sobrien } 767577311Sobrien 767677311Sobrien else if (is_identifier_char (*intel_parser.op_string)) 767777311Sobrien { 767877311Sobrien char *p = new_token.str; 767977311Sobrien char *q = intel_parser.op_string; 768077311Sobrien 768177311Sobrien /* A '.' or '$' followed by an identifier char is an identifier. 768277311Sobrien Otherwise, it's operator '.' followed by an expression. */ 768377311Sobrien if ((*q == '.' || *q == '$') && !is_identifier_char (*(q + 1))) 768477311Sobrien { 7685218822Sdim new_token.code = '.'; 7686218822Sdim new_token.str[0] = '.'; 768777311Sobrien new_token.str[1] = '\0'; 768877311Sobrien } 768977311Sobrien else 769077311Sobrien { 769177311Sobrien while (is_identifier_char (*q) || *q == '@') 769277311Sobrien *p++ = *q++; 769377311Sobrien *p = '\0'; 769477311Sobrien 7695218822Sdim if (strcasecmp (new_token.str, "NOT") == 0) 7696218822Sdim new_token.code = '~'; 7697218822Sdim 7698218822Sdim else if (strcasecmp (new_token.str, "MOD") == 0) 7699218822Sdim new_token.code = '%'; 7700218822Sdim 7701218822Sdim else if (strcasecmp (new_token.str, "AND") == 0) 7702218822Sdim new_token.code = '&'; 7703218822Sdim 7704218822Sdim else if (strcasecmp (new_token.str, "OR") == 0) 7705218822Sdim new_token.code = '|'; 7706218822Sdim 7707218822Sdim else if (strcasecmp (new_token.str, "XOR") == 0) 7708218822Sdim new_token.code = '^'; 7709218822Sdim 7710218822Sdim else if (strcasecmp (new_token.str, "SHL") == 0) 7711218822Sdim new_token.code = T_SHL; 7712218822Sdim 7713218822Sdim else if (strcasecmp (new_token.str, "SHR") == 0) 7714218822Sdim new_token.code = T_SHR; 7715218822Sdim 7716218822Sdim else if (strcasecmp (new_token.str, "BYTE") == 0) 771777311Sobrien new_token.code = T_BYTE; 771877311Sobrien 771977311Sobrien else if (strcasecmp (new_token.str, "WORD") == 0) 772077311Sobrien new_token.code = T_WORD; 772177311Sobrien 772277311Sobrien else if (strcasecmp (new_token.str, "DWORD") == 0) 772377311Sobrien new_token.code = T_DWORD; 772477311Sobrien 7725218822Sdim else if (strcasecmp (new_token.str, "FWORD") == 0) 7726218822Sdim new_token.code = T_FWORD; 7727218822Sdim 772877311Sobrien else if (strcasecmp (new_token.str, "QWORD") == 0) 772977311Sobrien new_token.code = T_QWORD; 773077311Sobrien 7731218822Sdim else if (strcasecmp (new_token.str, "TBYTE") == 0 7732218822Sdim /* XXX remove (gcc still uses it) */ 7733218822Sdim || strcasecmp (new_token.str, "XWORD") == 0) 7734218822Sdim new_token.code = T_TBYTE; 773577311Sobrien 7736218822Sdim else if (strcasecmp (new_token.str, "XMMWORD") == 0 7737218822Sdim || strcasecmp (new_token.str, "OWORD") == 0) 7738218822Sdim new_token.code = T_XMMWORD; 7739218822Sdim 774077311Sobrien else if (strcasecmp (new_token.str, "PTR") == 0) 774177311Sobrien new_token.code = T_PTR; 774277311Sobrien 774377311Sobrien else if (strcasecmp (new_token.str, "SHORT") == 0) 774477311Sobrien new_token.code = T_SHORT; 774577311Sobrien 774677311Sobrien else if (strcasecmp (new_token.str, "OFFSET") == 0) 774777311Sobrien { 774877311Sobrien new_token.code = T_OFFSET; 774977311Sobrien 775077311Sobrien /* ??? This is not mentioned in the MASM grammar but gcc 775177311Sobrien makes use of it with -mintel-syntax. OFFSET may be 775277311Sobrien followed by FLAT: */ 775377311Sobrien if (strncasecmp (q, " FLAT:", 6) == 0) 775477311Sobrien strcat (new_token.str, " FLAT:"); 775577311Sobrien } 775677311Sobrien 775777311Sobrien /* ??? This is not mentioned in the MASM grammar. */ 775877311Sobrien else if (strcasecmp (new_token.str, "FLAT") == 0) 7759218822Sdim { 7760218822Sdim new_token.code = T_OFFSET; 7761218822Sdim if (*q == ':') 7762218822Sdim strcat (new_token.str, ":"); 7763218822Sdim else 7764218822Sdim as_bad (_("`:' expected")); 7765218822Sdim } 776677311Sobrien 776777311Sobrien else 776877311Sobrien new_token.code = T_ID; 776977311Sobrien } 777077311Sobrien } 777177311Sobrien 7772218822Sdim else if (strchr ("+-/*%|&^:[]()~", *intel_parser.op_string)) 7773218822Sdim { 7774218822Sdim new_token.code = *intel_parser.op_string; 7775218822Sdim new_token.str[0] = *intel_parser.op_string; 7776218822Sdim new_token.str[1] = '\0'; 7777218822Sdim } 7778218822Sdim 7779218822Sdim else if (strchr ("<>", *intel_parser.op_string) 7780218822Sdim && *intel_parser.op_string == *(intel_parser.op_string + 1)) 7781218822Sdim { 7782218822Sdim new_token.code = *intel_parser.op_string == '<' ? T_SHL : T_SHR; 7783218822Sdim new_token.str[0] = *intel_parser.op_string; 7784218822Sdim new_token.str[1] = *intel_parser.op_string; 7785218822Sdim new_token.str[2] = '\0'; 7786218822Sdim } 7787218822Sdim 778877311Sobrien else 7789218822Sdim as_bad (_("Unrecognized token `%s'"), intel_parser.op_string); 779077311Sobrien 779177311Sobrien intel_parser.op_string += strlen (new_token.str); 779277311Sobrien cur_token = new_token; 779377311Sobrien} 779477311Sobrien 779577311Sobrien/* Put cur_token back into the token stream and make cur_token point to 779677311Sobrien prev_token. */ 779777311Sobrienstatic void 7798218822Sdimintel_putback_token (void) 779977311Sobrien{ 7800218822Sdim if (cur_token.code != T_NIL) 7801218822Sdim { 7802218822Sdim intel_parser.op_string -= strlen (cur_token.str); 7803218822Sdim free (cur_token.str); 7804218822Sdim } 780577311Sobrien cur_token = prev_token; 780677311Sobrien 780777311Sobrien /* Forget prev_token. */ 780877311Sobrien prev_token.code = T_NIL; 780977311Sobrien prev_token.reg = NULL; 781077311Sobrien prev_token.str = NULL; 781177311Sobrien} 7812130570Sobrien 7813130570Sobrienint 7814218822Sdimtc_x86_regname_to_dw2regnum (char *regname) 7815130570Sobrien{ 7816130570Sobrien unsigned int regnum; 7817130570Sobrien unsigned int regnames_count; 7818218822Sdim static const char *const regnames_32[] = 7819130570Sobrien { 7820130570Sobrien "eax", "ecx", "edx", "ebx", 7821130570Sobrien "esp", "ebp", "esi", "edi", 7822218822Sdim "eip", "eflags", NULL, 7823218822Sdim "st0", "st1", "st2", "st3", 7824218822Sdim "st4", "st5", "st6", "st7", 7825218822Sdim NULL, NULL, 7826218822Sdim "xmm0", "xmm1", "xmm2", "xmm3", 7827218822Sdim "xmm4", "xmm5", "xmm6", "xmm7", 7828218822Sdim "mm0", "mm1", "mm2", "mm3", 7829218822Sdim "mm4", "mm5", "mm6", "mm7", 7830218822Sdim "fcw", "fsw", "mxcsr", 7831218822Sdim "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL, 7832218822Sdim "tr", "ldtr" 7833130570Sobrien }; 7834218822Sdim static const char *const regnames_64[] = 7835130570Sobrien { 7836218822Sdim "rax", "rdx", "rcx", "rbx", 7837218822Sdim "rsi", "rdi", "rbp", "rsp", 7838218822Sdim "r8", "r9", "r10", "r11", 7839130570Sobrien "r12", "r13", "r14", "r15", 7840218822Sdim "rip", 7841218822Sdim "xmm0", "xmm1", "xmm2", "xmm3", 7842218822Sdim "xmm4", "xmm5", "xmm6", "xmm7", 7843218822Sdim "xmm8", "xmm9", "xmm10", "xmm11", 7844218822Sdim "xmm12", "xmm13", "xmm14", "xmm15", 7845218822Sdim "st0", "st1", "st2", "st3", 7846218822Sdim "st4", "st5", "st6", "st7", 7847218822Sdim "mm0", "mm1", "mm2", "mm3", 7848218822Sdim "mm4", "mm5", "mm6", "mm7", 7849218822Sdim "rflags", 7850218822Sdim "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL, 7851218822Sdim "fs.base", "gs.base", NULL, NULL, 7852218822Sdim "tr", "ldtr", 7853218822Sdim "mxcsr", "fcw", "fsw" 7854130570Sobrien }; 7855218822Sdim const char *const *regnames; 7856130570Sobrien 7857130570Sobrien if (flag_code == CODE_64BIT) 7858130570Sobrien { 7859130570Sobrien regnames = regnames_64; 7860130570Sobrien regnames_count = ARRAY_SIZE (regnames_64); 7861130570Sobrien } 7862130570Sobrien else 7863130570Sobrien { 7864130570Sobrien regnames = regnames_32; 7865130570Sobrien regnames_count = ARRAY_SIZE (regnames_32); 7866130570Sobrien } 7867130570Sobrien 7868130570Sobrien for (regnum = 0; regnum < regnames_count; regnum++) 7869218822Sdim if (regnames[regnum] != NULL 7870218822Sdim && strcmp (regname, regnames[regnum]) == 0) 7871130570Sobrien return regnum; 7872130570Sobrien 7873130570Sobrien return -1; 7874130570Sobrien} 7875130570Sobrien 7876130570Sobrienvoid 7877130570Sobrientc_x86_frame_initial_instructions (void) 7878130570Sobrien{ 7879130570Sobrien static unsigned int sp_regno; 7880130570Sobrien 7881130570Sobrien if (!sp_regno) 7882130570Sobrien sp_regno = tc_x86_regname_to_dw2regnum (flag_code == CODE_64BIT 7883130570Sobrien ? "rsp" : "esp"); 7884130570Sobrien 7885130570Sobrien cfi_add_CFA_def_cfa (sp_regno, -x86_cie_data_alignment); 7886130570Sobrien cfi_add_CFA_offset (x86_dwarf2_return_column, x86_cie_data_alignment); 7887130570Sobrien} 7888218822Sdim 7889218822Sdimint 7890218822Sdimi386_elf_section_type (const char *str, size_t len) 7891218822Sdim{ 7892218822Sdim if (flag_code == CODE_64BIT 7893218822Sdim && len == sizeof ("unwind") - 1 7894218822Sdim && strncmp (str, "unwind", 6) == 0) 7895218822Sdim return SHT_X86_64_UNWIND; 7896218822Sdim 7897218822Sdim return -1; 7898218822Sdim} 7899218822Sdim 7900218822Sdim#ifdef TE_PE 7901218822Sdimvoid 7902218822Sdimtc_pe_dwarf2_emit_offset (symbolS *symbol, unsigned int size) 7903218822Sdim{ 7904218822Sdim expressionS expr; 7905218822Sdim 7906218822Sdim expr.X_op = O_secrel; 7907218822Sdim expr.X_add_symbol = symbol; 7908218822Sdim expr.X_add_number = 0; 7909218822Sdim emit_expr (&expr, size); 7910218822Sdim} 7911218822Sdim#endif 7912218822Sdim 7913218822Sdim#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) 7914218822Sdim/* For ELF on x86-64, add support for SHF_X86_64_LARGE. */ 7915218822Sdim 7916218822Sdimint 7917218822Sdimx86_64_section_letter (int letter, char **ptr_msg) 7918218822Sdim{ 7919218822Sdim if (flag_code == CODE_64BIT) 7920218822Sdim { 7921218822Sdim if (letter == 'l') 7922218822Sdim return SHF_X86_64_LARGE; 7923218822Sdim 7924218822Sdim *ptr_msg = _("Bad .section directive: want a,l,w,x,M,S,G,T in string"); 7925218822Sdim } 7926218822Sdim else 7927218822Sdim *ptr_msg = _("Bad .section directive: want a,w,x,M,S,G,T in string"); 7928218822Sdim return -1; 7929218822Sdim} 7930218822Sdim 7931218822Sdimint 7932218822Sdimx86_64_section_word (char *str, size_t len) 7933218822Sdim{ 7934218822Sdim if (len == 5 && flag_code == CODE_64BIT && CONST_STRNEQ (str, "large")) 7935218822Sdim return SHF_X86_64_LARGE; 7936218822Sdim 7937218822Sdim return -1; 7938218822Sdim} 7939218822Sdim 7940218822Sdimstatic void 7941218822Sdimhandle_large_common (int small ATTRIBUTE_UNUSED) 7942218822Sdim{ 7943218822Sdim if (flag_code != CODE_64BIT) 7944218822Sdim { 7945218822Sdim s_comm_internal (0, elf_common_parse); 7946218822Sdim as_warn (_(".largecomm supported only in 64bit mode, producing .comm")); 7947218822Sdim } 7948218822Sdim else 7949218822Sdim { 7950218822Sdim static segT lbss_section; 7951218822Sdim asection *saved_com_section_ptr = elf_com_section_ptr; 7952218822Sdim asection *saved_bss_section = bss_section; 7953218822Sdim 7954218822Sdim if (lbss_section == NULL) 7955218822Sdim { 7956218822Sdim flagword applicable; 7957218822Sdim segT seg = now_seg; 7958218822Sdim subsegT subseg = now_subseg; 7959218822Sdim 7960218822Sdim /* The .lbss section is for local .largecomm symbols. */ 7961218822Sdim lbss_section = subseg_new (".lbss", 0); 7962218822Sdim applicable = bfd_applicable_section_flags (stdoutput); 7963218822Sdim bfd_set_section_flags (stdoutput, lbss_section, 7964218822Sdim applicable & SEC_ALLOC); 7965218822Sdim seg_info (lbss_section)->bss = 1; 7966218822Sdim 7967218822Sdim subseg_set (seg, subseg); 7968218822Sdim } 7969218822Sdim 7970218822Sdim elf_com_section_ptr = &_bfd_elf_large_com_section; 7971218822Sdim bss_section = lbss_section; 7972218822Sdim 7973218822Sdim s_comm_internal (0, elf_common_parse); 7974218822Sdim 7975218822Sdim elf_com_section_ptr = saved_com_section_ptr; 7976218822Sdim bss_section = saved_bss_section; 7977218822Sdim } 7978218822Sdim} 7979218822Sdim#endif /* OBJ_ELF || OBJ_MAYBE_ELF */ 7980