tc-i386.c

来自「基于4个mips核的noc设计」· C语言 代码 · 共 2,311 行 · 第 1/5 页

C
2,311
字号
/* i386.c -- Assemble code for the Intel 80386   Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,   2000, 2001   Free Software Foundation, Inc.   This file is part of GAS, the GNU Assembler.   GAS is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 2, or (at your option)   any later version.   GAS is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.   You should have received a copy of the GNU General Public License   along with GAS; see the file COPYING.  If not, write to the Free   Software Foundation, 59 Temple Place - Suite 330, Boston, MA   02111-1307, USA.  *//* Intel 80386 machine specific gas.   Written by Eliot Dresselhaus (eliot@mgm.mit.edu).   x86_64 support by Jan Hubicka (jh@suse.cz)   Bugs & suggestions are completely welcome.  This is free software.   Please help us make it better.  */#include <ctype.h>#include "as.h"#include "subsegs.h"#include "dwarf2dbg.h"#include "opcode/i386.h"#ifndef REGISTER_WARNINGS#define REGISTER_WARNINGS 1#endif#ifndef INFER_ADDR_PREFIX#define INFER_ADDR_PREFIX 1#endif#ifndef SCALE1_WHEN_NO_INDEX/* Specifying a scale factor besides 1 when there is no index is   futile.  eg. `mov (%ebx,2),%al' does exactly the same as   `mov (%ebx),%al'.  To slavishly follow what the programmer   specified, set SCALE1_WHEN_NO_INDEX to 0.  */#define SCALE1_WHEN_NO_INDEX 1#endif#define true 1#define false 0static unsigned int mode_from_disp_size PARAMS ((unsigned int));static int fits_in_signed_byte PARAMS ((offsetT));static int fits_in_unsigned_byte PARAMS ((offsetT));static int fits_in_unsigned_word PARAMS ((offsetT));static int fits_in_signed_word PARAMS ((offsetT));static int fits_in_unsigned_long PARAMS ((offsetT));static int fits_in_signed_long PARAMS ((offsetT));static int smallest_imm_type PARAMS ((offsetT));static offsetT offset_in_range PARAMS ((offsetT, int));static int add_prefix PARAMS ((unsigned int));static void set_code_flag PARAMS ((int));static void set_16bit_gcc_code_flag PARAMS ((int));static void set_intel_syntax PARAMS ((int));static void set_cpu_arch PARAMS ((int));#ifdef BFD_ASSEMBLERstatic bfd_reloc_code_real_type reloc  PARAMS ((int, int, int, bfd_reloc_code_real_type));#define RELOC_ENUM enum bfd_reloc_code_real#else#define RELOC_ENUM int#endif#ifndef DEFAULT_ARCH#define DEFAULT_ARCH "i386"#endifstatic char *default_arch = DEFAULT_ARCH;/* 'md_assemble ()' gathers together information and puts it into a   i386_insn.  */union i386_op  {    expressionS *disps;    expressionS *imms;    const reg_entry *regs;  };struct _i386_insn  {    /* TM holds the template for the insn were currently assembling.  */    template tm;    /* SUFFIX holds the instruction mnemonic suffix if given.       (e.g. 'l' for 'movl')  */    char suffix;    /* OPERANDS gives the number of given operands.  */    unsigned int operands;    /* REG_OPERANDS, DISP_OPERANDS, MEM_OPERANDS, IMM_OPERANDS give the number       of given register, displacement, memory operands and immediate       operands.  */    unsigned int reg_operands, disp_operands, mem_operands, imm_operands;    /* TYPES [i] is the type (see above #defines) which tells us how to       use OP[i] for the corresponding operand.  */    unsigned int types[MAX_OPERANDS];    /* Displacement expression, immediate expression, or register for each       operand.  */    union i386_op op[MAX_OPERANDS];    /* Flags for operands.  */    unsigned int flags[MAX_OPERANDS];#define Operand_PCrel 1    /* Relocation type for operand */    RELOC_ENUM reloc[MAX_OPERANDS];    /* BASE_REG, INDEX_REG, and LOG2_SCALE_FACTOR are used to encode       the base index byte below.  */    const reg_entry *base_reg;    const reg_entry *index_reg;    unsigned int log2_scale_factor;    /* SEG gives the seg_entries of this insn.  They are zero unless       explicit segment overrides are given.  */    const seg_entry *seg[2];    /* PREFIX holds all the given prefix opcodes (usually null).       PREFIXES is the number of prefix opcodes.  */    unsigned int prefixes;    unsigned char prefix[MAX_PREFIXES];    /* RM and SIB are the modrm byte and the sib byte where the       addressing modes of this insn are encoded.  */    modrm_byte rm;    rex_byte rex;    sib_byte sib;  };typedef struct _i386_insn i386_insn;/* List of chars besides those in app.c:symbol_chars that can start an   operand.  Used to prevent the scrubber eating vital white-space.  */#ifdef LEX_ATconst char extra_symbol_chars[] = "*%-(@";#elseconst char extra_symbol_chars[] = "*%-(";#endif/* This array holds the chars that always start a comment.  If the   pre-processor is disabled, these aren't very useful.  */#if defined (TE_I386AIX) || ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) && ! defined (TE_LINUX) && !defined(TE_FreeBSD))/* Putting '/' here makes it impossible to use the divide operator.   However, we need it for compatibility with SVR4 systems.  */const char comment_chars[] = "#/";#define PREFIX_SEPARATOR '\\'#elseconst char comment_chars[] = "#";#define PREFIX_SEPARATOR '/'#endif/* This array holds the chars that only start a comment at the beginning of   a line.  If the line seems to have the form '# 123 filename'   .line and .file directives will appear in the pre-processed output.   Note that input_file.c hand checks for '#' at the beginning of the   first line of the input file.  This is because the compiler outputs   #NO_APP at the beginning of its output.   Also note that comments started like this one will always work if   '/' isn't otherwise defined.  */#if defined (TE_I386AIX) || ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) && ! defined (TE_LINUX) && !defined(TE_FreeBSD))const char line_comment_chars[] = "";#elseconst char line_comment_chars[] = "/";#endifconst char line_separator_chars[] = ";";/* Chars that can be used to separate mant from exp in floating point   nums.  */const char EXP_CHARS[] = "eE";/* Chars that mean this number is a floating point constant   As in 0f12.456   or    0d1.2345e12.  */const char FLT_CHARS[] = "fFdDxX";/* Tables for lexical analysis.  */static char mnemonic_chars[256];static char register_chars[256];static char operand_chars[256];static char identifier_chars[256];static char digit_chars[256];/* Lexical macros.  */#define is_mnemonic_char(x) (mnemonic_chars[(unsigned char) x])#define is_operand_char(x) (operand_chars[(unsigned char) x])#define is_register_char(x) (register_chars[(unsigned char) x])#define is_space_char(x) ((x) == ' ')#define is_identifier_char(x) (identifier_chars[(unsigned char) x])#define is_digit_char(x) (digit_chars[(unsigned char) x])/* All non-digit non-letter charcters that may occur in an operand.  */static char operand_special_chars[] = "%$-+(,)*._~/<>|&^!:[@]";/* md_assemble() always leaves the strings it's passed unaltered.  To   effect this we maintain a stack of saved characters that we've smashed   with '\0's (indicating end of strings for various sub-fields of the   assembler instruction).  */static char save_stack[32];static char *save_stack_p;#define END_STRING_AND_SAVE(s) \	do { *save_stack_p++ = *(s); *(s) = '\0'; } while (0)#define RESTORE_END_STRING(s) \	do { *(s) = *--save_stack_p; } while (0)/* The instruction we're assembling.  */static i386_insn i;/* Possible templates for current insn.  */static const templates *current_templates;/* Per instruction expressionS buffers: 2 displacements & 2 immediate max.  */static expressionS disp_expressions[2], im_expressions[2];/* Current operand we are working on.  */static int this_operand;/* We support four different modes.  FLAG_CODE variable is used to distinguish   these.  */enum flag_code {	CODE_32BIT,	CODE_16BIT,	CODE_64BIT };#define NUM_FLAG_CODE ((int) CODE_64BIT + 1)static enum flag_code flag_code;static int use_rela_relocations = 0;/* The names used to print error messages.  */static const char *flag_code_names[] =  {    "32",    "16",    "64"  };/* 1 for intel syntax,   0 if att syntax.  */static int intel_syntax = 0;/* 1 if register prefix % not required.  */static int allow_naked_reg = 0;/* Used in 16 bit gcc mode to add an l suffix to call, ret, enter,   leave, push, and pop instructions so that gcc has the same stack   frame as in 32 bit mode.  */static char stackop_size = '\0';/* Non-zero to quieten some warnings.  */static int quiet_warnings = 0;/* CPU name.  */static const char *cpu_arch_name = NULL;/* CPU feature flags.  */static unsigned int cpu_arch_flags = CpuUnknownFlags|CpuNo64;/* If set, conditional jumps are not automatically promoted to handle   larger than a byte offset.  */static unsigned int no_cond_jump_promotion = 0;/* Interface to relax_segment.   There are 3 major relax states for 386 jump insns because the   different types of jumps add different sizes to frags when we're   figuring out what sort of jump to choose to reach a given label.  *//* Types.  */#define UNCOND_JUMP 0#define COND_JUMP 1#define COND_JUMP86 2/* Sizes.  */#define CODE16	1#define SMALL	0#define SMALL16 (SMALL|CODE16)#define BIG	2#define BIG16	(BIG|CODE16)#ifndef INLINE#ifdef __GNUC__#define INLINE __inline__#else#define INLINE#endif#endif#define ENCODE_RELAX_STATE(type, size) \  ((relax_substateT) (((type) << 2) | (size)))#define TYPE_FROM_RELAX_STATE(s) \  ((s) >> 2)#define DISP_SIZE_FROM_RELAX_STATE(s) \    ((((s) & 3) == BIG ? 4 : (((s) & 3) == BIG16 ? 2 : 1)))/* This table is used by relax_frag to promote short jumps to long   ones where necessary.  SMALL (short) jumps may be promoted to BIG   (32 bit long) ones, and SMALL16 jumps to BIG16 (16 bit long).  We   don't allow a short jump in a 32 bit code segment to be promoted to   a 16 bit offset jump because it's slower (requires data size   prefix), and doesn't work, unless the destination is in the bottom   64k of the code segment (The top 16 bits of eip are zeroed).  */const relax_typeS md_relax_table[] ={  /* The fields are:     1) most positive reach of this state,     2) most negative reach of this state,     3) how many bytes this mode will have in the variable part of the frag     4) which index into the table to try if we can't fit into this one.  */  /* UNCOND_JUMP states.  */  {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (UNCOND_JUMP, BIG)},  {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (UNCOND_JUMP, BIG16)},  /* dword jmp adds 4 bytes to frag:     0 extra opcode bytes, 4 displacement bytes.  */  {0, 0, 4, 0},  /* word jmp adds 2 byte2 to frag:     0 extra opcode bytes, 2 displacement bytes.  */  {0, 0, 2, 0},  /* COND_JUMP states.  */  {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP, BIG)},  {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP, BIG16)},  /* dword conditionals adds 5 bytes to frag:     1 extra opcode byte, 4 displacement bytes.  */  {0, 0, 5, 0},  /* word conditionals add 3 bytes to frag:     1 extra opcode byte, 2 displacement bytes.  */  {0, 0, 3, 0},  /* COND_JUMP86 states.  */  {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP86, BIG)},  {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP86, BIG16)},  /* dword conditionals adds 5 bytes to frag:     1 extra opcode byte, 4 displacement bytes.  */  {0, 0, 5, 0},  /* word conditionals add 4 bytes to frag:     1 displacement byte and a 3 byte long branch insn.  */  {0, 0, 4, 0}};static const arch_entry cpu_arch[] = {  {"i8086",	Cpu086 },  {"i186",	Cpu086|Cpu186 },  {"i286",	Cpu086|Cpu186|Cpu286 },  {"i386",	Cpu086|Cpu186|Cpu286|Cpu386 },  {"i486",	Cpu086|Cpu186|Cpu286|Cpu386|Cpu486 },  {"i586",	Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuMMX },  {"i686",	Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX|CpuSSE },  {"pentium",	Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuMMX },  {"pentiumpro",Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX|CpuSSE },  {"pentium4",	Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX|CpuSSE|CpuSSE2 },  {"k6",	Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuK6|CpuMMX|Cpu3dnow },  {"athlon",	Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuAthlon|CpuMMX|Cpu3dnow },  {"sledgehammer",Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuAthlon|CpuSledgehammer|CpuMMX|Cpu3dnow|CpuSSE|CpuSSE2 },  {NULL, 0 }};voidi386_align_code (fragP, count)     fragS *fragP;     int count;{  /* Various efficient no-op patterns for aligning code labels.     Note: Don't try to assemble the instructions in the comments.     0L and 0w are not legal.  */  static const char f32_1[] =    {0x90};					/* nop			*/  static const char f32_2[] =    {0x89,0xf6};				/* movl %esi,%esi	*/  static const char f32_3[] =    {0x8d,0x76,0x00};				/* leal 0(%esi),%esi	*/  static const char f32_4[] =    {0x8d,0x74,0x26,0x00};			/* leal 0(%esi,1),%esi	*/  static const char f32_5[] =    {0x90,					/* nop			*/     0x8d,0x74,0x26,0x00};			/* leal 0(%esi,1),%esi	*/  static const char f32_6[] =    {0x8d,0xb6,0x00,0x00,0x00,0x00};		/* leal 0L(%esi),%esi	*/  static const char f32_7[] =    {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00};	/* leal 0L(%esi,1),%esi */  static const char f32_8[] =    {0x90,					/* nop			*/     0x8d,0xb4,0x26,0x00,0x00,0x00,0x00};	/* leal 0L(%esi,1),%esi */  static const char f32_9[] =    {0x89,0xf6,					/* movl %esi,%esi	*/     0x8d,0xbc,0x27,0x00,0x00,0x00,0x00};	/* leal 0L(%edi,1),%edi */  static const char f32_10[] =    {0x8d,0x76,0x00,				/* leal 0(%esi),%esi	*/     0x8d,0xbc,0x27,0x00,0x00,0x00,0x00};	/* leal 0L(%edi,1),%edi */  static const char f32_11[] =    {0x8d,0x74,0x26,0x00,			/* leal 0(%esi,1),%esi	*/     0x8d,0xbc,0x27,0x00,0x00,0x00,0x00};	/* leal 0L(%edi,1),%edi */  static const char f32_12[] =    {0x8d,0xb6,0x00,0x00,0x00,0x00,		/* leal 0L(%esi),%esi	*/     0x8d,0xbf,0x00,0x00,0x00,0x00};		/* leal 0L(%edi),%edi	*/  static const char f32_13[] =    {0x8d,0xb6,0x00,0x00,0x00,0x00,		/* leal 0L(%esi),%esi	*/     0x8d,0xbc,0x27,0x00,0x00,0x00,0x00};	/* leal 0L(%edi,1),%edi */  static const char f32_14[] =    {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00,	/* leal 0L(%esi,1),%esi */     0x8d,0xbc,0x27,0x00,0x00,0x00,0x00};	/* leal 0L(%edi,1),%edi */  static const char f32_15[] =    {0xeb,0x0d,0x90,0x90,0x90,0x90,0x90,	/* jmp .+15; lotsa nops	*/     0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90};  static const char f16_3[] =    {0x8d,0x74,0x00};				/* lea 0(%esi),%esi	*/  static const char f16_4[] =    {0x8d,0xb4,0x00,0x00};			/* lea 0w(%si),%si	*/  static const char f16_5[] =    {0x90,					/* nop			*/     0x8d,0xb4,0x00,0x00};			/* lea 0w(%si),%si	*/  static const char f16_6[] =    {0x89,0xf6,					/* mov %si,%si		*/     0x8d,0xbd,0x00,0x00};			/* lea 0w(%di),%di	*/  static const char f16_7[] =    {0x8d,0x74,0x00,				/* lea 0(%si),%si	*/     0x8d,0xbd,0x00,0x00};			/* lea 0w(%di),%di	*/  static const char f16_8[] =    {0x8d,0xb4,0x00,0x00,			/* lea 0w(%si),%si	*/     0x8d,0xbd,0x00,0x00};			/* lea 0w(%di),%di	*/  static const char *const f32_patt[] = {    f32_1, f32_2, f32_3, f32_4, f32_5, f32_6, f32_7, f32_8,    f32_9, f32_10, f32_11, f32_12, f32_13, f32_14, f32_15  };  static const char *const f16_patt[] = {    f32_1, f32_2, f16_3, f16_4, f16_5, f16_6, f16_7, f16_8,    f32_15, f32_15, f32_15, f32_15, f32_15, f32_15, f32_15  };  /* ??? We can't use these fillers for x86_64, since they often kills the     upper halves.  Solve later.  */  if (flag_code == CODE_64BIT)    count = 1;  if (count > 0 && count <= 15)    {      if (flag_code == CODE_16BIT)	{	  memcpy (fragP->fr_literal + fragP->fr_fix,		  f16_patt[count - 1], count);	  if (count > 8)	    /* Adjust jump offset.  */	    fragP->fr_literal[fragP->fr_fix + 1] = count - 2;	}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?