⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tc-sh.c

📁 基于4个mips核的noc设计
💻 C
📖 第 1 页 / 共 5 页
字号:
/* tc-sh.c -- Assemble code for the Hitachi Super-H   Copyright 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.  *//* Written By Steve Chamberlain <sac@cygnus.com>  */#include <stdio.h>#include "as.h"#include "bfd.h"#include "subsegs.h"#define DEFINE_TABLE#include "opcodes/sh-opc.h"#include <ctype.h>#include "struc-symbol.h"#ifdef OBJ_ELF#include "elf/sh.h"#endif#include "dwarf2dbg.h"const char comment_chars[] = "!";const char line_separator_chars[] = ";";const char line_comment_chars[] = "!#";static void s_uses PARAMS ((int));static void sh_count_relocs PARAMS ((bfd *, segT, PTR));static void sh_frob_section PARAMS ((bfd *, segT, PTR));void cons ();void s_align_bytes ();static void s_uacons PARAMS ((int));static sh_opcode_info *find_cooked_opcode PARAMS ((char **));static unsigned int assemble_ppi PARAMS ((char *, sh_opcode_info *));#ifdef OBJ_ELFstatic void sh_elf_cons PARAMS ((int));symbolS *GOT_symbol;		/* Pre-defined "_GLOBAL_OFFSET_TABLE_" */#endifint shl = 0;static voidlittle (ignore)     int ignore ATTRIBUTE_UNUSED;{  shl = 1;  target_big_endian = 0;}/* This table describes all the machine specific pseudo-ops the assembler   has to support.  The fields are:   pseudo-op name without dot   function to call to execute this pseudo-op   Integer arg to pass to the function.  */const pseudo_typeS md_pseudo_table[] ={#ifdef OBJ_ELF  {"long", sh_elf_cons, 4},  {"int", sh_elf_cons, 4},  {"word", sh_elf_cons, 2},  {"short", sh_elf_cons, 2},#else  {"int", cons, 4},  {"word", cons, 2},#endif /* OBJ_ELF */  {"form", listing_psize, 0},  {"little", little, 0},  {"heading", listing_title, 0},  {"import", s_ignore, 0},  {"page", listing_eject, 0},  {"program", s_ignore, 0},  {"uses", s_uses, 0},  {"uaword", s_uacons, 2},  {"ualong", s_uacons, 4},  {"uaquad", s_uacons, 8},  {"2byte", s_uacons, 2},  {"4byte", s_uacons, 4},  {"8byte", s_uacons, 8},#ifdef BFD_ASSEMBLER  {"file", dwarf2_directive_file, 0 },  {"loc", dwarf2_directive_loc, 0 },#endif  {0, 0, 0}};/*int md_reloc_size; */int sh_relax;		/* set if -relax seen *//* Whether -small was seen.  */int sh_small;/* Whether -dsp was seen.  */static int sh_dsp;/* The bit mask of architectures that could   accomodate the insns seen so far.  */static int valid_arch;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[] = "rRsSfFdDxXpP";#define C(a,b) ENCODE_RELAX(a,b)#define ENCODE_RELAX(what,length) (((what) << 4) + (length))#define GET_WHAT(x) ((x>>4))/* These are the three types of relaxable instrction.  */#define COND_JUMP 1#define COND_JUMP_DELAY 2#define UNCOND_JUMP  3#define END 4#define UNDEF_DISP 0#define COND8  1#define COND12 2#define COND32 3#define UNDEF_WORD_DISP 4#define UNCOND12 1#define UNCOND32 2/* Branch displacements are from the address of the branch plus   four, thus all minimum and maximum values have 4 added to them.  */#define COND8_F 258#define COND8_M -252#define COND8_LENGTH 2/* There is one extra instruction before the branch, so we must add   two more bytes to account for it.  */#define COND12_F 4100#define COND12_M -4090#define COND12_LENGTH 6#define COND12_DELAY_LENGTH 4/* ??? The minimum and maximum values are wrong, but this does not matter   since this relocation type is not supported yet.  */#define COND32_F (1<<30)#define COND32_M -(1<<30)#define COND32_LENGTH 14#define UNCOND12_F 4098#define UNCOND12_M -4092#define UNCOND12_LENGTH 2/* ??? The minimum and maximum values are wrong, but this does not matter   since this relocation type is not supported yet.  */#define UNCOND32_F (1<<30)#define UNCOND32_M -(1<<30)#define UNCOND32_LENGTH 14#define EMPTY { 0, 0, 0, 0 }const relax_typeS md_relax_table[C (END, 0)] = {  EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,  EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,  EMPTY,  /* C (COND_JUMP, COND8) */  { COND8_F, COND8_M, COND8_LENGTH, C (COND_JUMP, COND12) },  /* C (COND_JUMP, COND12) */  { COND12_F, COND12_M, COND12_LENGTH, C (COND_JUMP, COND32), },  /* C (COND_JUMP, COND32) */  { COND32_F, COND32_M, COND32_LENGTH, 0, },  /* C (COND_JUMP, UNDEF_WORD_DISP) */  { 0, 0, COND32_LENGTH, 0, },  EMPTY, EMPTY, EMPTY,  EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,  EMPTY,  /* C (COND_JUMP_DELAY, COND8) */  { COND8_F, COND8_M, COND8_LENGTH, C (COND_JUMP_DELAY, COND12) },  /* C (COND_JUMP_DELAY, COND12) */  { COND12_F, COND12_M, COND12_DELAY_LENGTH, C (COND_JUMP_DELAY, COND32), },  /* C (COND_JUMP_DELAY, COND32) */  { COND32_F, COND32_M, COND32_LENGTH, 0, },  /* C (COND_JUMP_DELAY, UNDEF_WORD_DISP) */  { 0, 0, COND32_LENGTH, 0, },  EMPTY, EMPTY, EMPTY,  EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,  EMPTY,  /* C (UNCOND_JUMP, UNCOND12) */  { UNCOND12_F, UNCOND12_M, UNCOND12_LENGTH, C (UNCOND_JUMP, UNCOND32), },  /* C (UNCOND_JUMP, UNCOND32) */  { UNCOND32_F, UNCOND32_M, UNCOND32_LENGTH, 0, },  EMPTY,  /* C (UNCOND_JUMP, UNDEF_WORD_DISP) */  { 0, 0, UNCOND32_LENGTH, 0, },  EMPTY, EMPTY, EMPTY,  EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,};#undef EMPTYstatic struct hash_control *opcode_hash_control;	/* Opcode mnemonics */#ifdef OBJ_ELF/* Parse @got, etc. and return the desired relocation.   If we have additional arithmetic expression, then we fill in new_exp_p.  */static bfd_reloc_code_real_typesh_elf_suffix (str_p, exp_p, new_exp_p)     char **str_p;     expressionS *exp_p, *new_exp_p;{  struct map_bfd {    char *string;    int length;    bfd_reloc_code_real_type reloc;  };  char ident[20];  char *str = *str_p;  char *str2;  int ch;  int len;  struct map_bfd *ptr;#define MAP(str,reloc) { str, sizeof (str)-1, reloc }  static struct map_bfd mapping[] = {    MAP ("got",		BFD_RELOC_32_GOT_PCREL),    MAP ("plt",		BFD_RELOC_32_PLT_PCREL),    MAP ("gotoff",	BFD_RELOC_32_GOTOFF),    { (char *)0,	0,	BFD_RELOC_UNUSED }  };  if (*str++ != '@')    return BFD_RELOC_UNUSED;  for (ch = *str, str2 = ident;       (str2 < ident + sizeof (ident) - 1	&& (isalnum (ch) || ch == '@'));       ch = *++str)    {      *str2++ = (islower (ch)) ? ch : tolower (ch);    }  *str2 = '\0';  len = str2 - ident;  ch = ident[0];  for (ptr = &mapping[0]; ptr->length > 0; ptr++)    if (ch == ptr->string[0]	&& len == ptr->length	&& memcmp (ident, ptr->string, ptr->length) == 0)      {	/* Now check for identifier@suffix+constant */	if (*str == '-' || *str == '+')	  {	    char *orig_line = input_line_pointer;	    input_line_pointer = str;	    expression (new_exp_p);	    if (new_exp_p->X_op == O_constant)	      {		exp_p->X_add_number += new_exp_p->X_add_number;		str = input_line_pointer;	      }	    if (new_exp_p->X_op == O_subtract)	      str = input_line_pointer;	    if (&input_line_pointer != str_p)	      input_line_pointer = orig_line;	  }	*str_p = str;	return ptr->reloc;      }  return BFD_RELOC_UNUSED;}/* The regular cons() function, that reads constants, doesn't support   suffixes such as @GOT, @GOTOFF and @PLT, that generate   machine-specific relocation types.  So we must define it here.  *//* Clobbers input_line_pointer, checks end-of-line.  */static voidsh_elf_cons (nbytes)     register int nbytes;	/* 1=.byte, 2=.word, 4=.long */{  expressionS exp, new_exp;  bfd_reloc_code_real_type reloc;  const char *name;  if (is_it_end_of_statement ())    {      demand_empty_rest_of_line ();      return;    }  do    {      expression (&exp);      new_exp.X_op = O_absent;      new_exp.X_add_symbol = new_exp.X_op_symbol = NULL;      /* If the _GLOBAL_OFFSET_TABLE_ symbol hasn't been found yet,	 use the name of the symbol to tell whether it's the	 _GLOBAL_OFFSET_TABLE_.  If it has, comparing the symbols is	 sufficient.  */      if (! GOT_symbol && exp.X_add_symbol)	name = S_GET_NAME (exp.X_add_symbol);      else	name = NULL;      /* Check whether this expression involves the	 _GLOBAL_OFFSET_TABLE_ symbol, by itself or added to a	 difference of two other symbols.  */      if (((GOT_symbol && GOT_symbol == exp.X_add_symbol)	   || (! GOT_symbol && name	       && strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0))	  && (exp.X_op == O_symbol	      || (exp.X_op == O_add		  && ((symbol_get_value_expression (exp.X_op_symbol)->X_op)		      == O_subtract))))	{	  reloc_howto_type *reloc_howto = bfd_reloc_type_lookup (stdoutput,								 BFD_RELOC_32);	  int size = bfd_get_reloc_size (reloc_howto);	  if (GOT_symbol == NULL)	    GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);	  if (size > nbytes)	    as_bad (_("%s relocations do not fit in %d bytes\n"),		    reloc_howto->name, nbytes);	  else	    {	      register char *p = frag_more ((int) nbytes);	      int offset = nbytes - size;	      fix_new_exp (frag_now, p - frag_now->fr_literal + offset,			   size, &exp, 0, TC_RELOC_GLOBAL_OFFSET_TABLE);	    }	}      /* Check if this symbol involves one of the magic suffixes, such	 as @GOT, @GOTOFF or @PLT, and determine which relocation type	 to use.  */      else if ((exp.X_op == O_symbol || (exp.X_op == O_add && exp.X_op_symbol))	  && *input_line_pointer == '@'	  && ((reloc = sh_elf_suffix (&input_line_pointer, &exp, &new_exp))	      != BFD_RELOC_UNUSED))	{	  reloc_howto_type *reloc_howto = bfd_reloc_type_lookup (stdoutput,								 reloc);	  int size = bfd_get_reloc_size (reloc_howto);	  /* Force a GOT to be generated.  */	  if (GOT_symbol == NULL)	    GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);	  if (size > nbytes)	    as_bad (_("%s relocations do not fit in %d bytes\n"),		    reloc_howto->name, nbytes);	  else	    {	      register char *p = frag_more ((int) nbytes);	      int offset = nbytes - size;	      fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size,			   &exp, 0, reloc);	      if (new_exp.X_op != O_absent)		fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size,			     &new_exp, 0, BFD_RELOC_32);	    }	}      else	emit_expr (&exp, (unsigned int) nbytes);    }  while (*input_line_pointer++ == ',');  input_line_pointer--;		/* Put terminator back into stream.  */  if (*input_line_pointer == '#' || *input_line_pointer == '!')    {       while (! is_end_of_line[(unsigned char) *input_line_pointer++]);    }  else    demand_empty_rest_of_line ();}#endif /* OBJ_ELF *//* This function is called once, at assembler startup time.  This should   set up all the tables, etc that the MD part of the assembler needs.  */voidmd_begin (){  sh_opcode_info *opcode;  char *prev_name = "";  int target_arch;#ifdef TE_PE  /* The WinCE OS only supports little endian executables.  */  target_big_endian = 0;#else  if (! shl)    target_big_endian = 1;#endif  target_arch = arch_sh1_up & ~(sh_dsp ? arch_sh3e_up : arch_sh_dsp_up);  valid_arch = target_arch;  opcode_hash_control = hash_new ();  /* Insert unique names into hash table.  */  for (opcode = sh_table; opcode->name; opcode++)    {      if (strcmp (prev_name, opcode->name))	{	  if (! (opcode->arch & target_arch))	    continue;	  prev_name = opcode->name;	  hash_insert (opcode_hash_control, opcode->name, (char *) opcode);	}      else	{	  /* Make all the opcodes with the same name point to the same	     string.  */	  opcode->name = prev_name;	}    }}static int reg_m;static int reg_n;static int reg_x, reg_y;static int reg_efg;static int reg_b;typedef struct  {    sh_arg_type type;    int reg;    expressionS immediate;  }sh_operand_info;#define IDENT_CHAR(c) (isalnum (c) || (c) == '_')/* Try to parse a reg name.  Return the number of chars consumed.  */static intparse_reg (src, mode, reg)     char *src;     int *mode;     int *reg;{  char l0 = tolower (src[0]);  char l1 = l0 ? tolower (src[1]) : 0;  /* We use ! IDENT_CHAR for the next character after the register name, to     make sure that we won't accidentally recognize a symbol name such as     'sram' or sr_ram as being a reference to the register 'sr'.  */  if (l0 == 'r')    {      if (l1 == '1')	{	  if (src[2] >= '0' && src[2] <= '5'	      && ! IDENT_CHAR ((unsigned char) src[3]))	    {	      *mode = A_REG_N;	      *reg = 10 + src[2] - '0';	      return 3;	    }	}      if (l1 >= '0' && l1 <= '9'	  && ! IDENT_CHAR ((unsigned char) src[2]))	{	  *mode = A_REG_N;	  *reg = (l1 - '0');	  return 2;	}      if (l1 >= '0' && l1 <= '7' && strncasecmp (&src[2], "_bank", 5) == 0	  && ! IDENT_CHAR ((unsigned char) src[7]))	{	  *mode = A_REG_B;	  *reg  = (l1 - '0');	  return 7;	}      if (l1 == 'e' && ! IDENT_CHAR ((unsigned char) src[2]))	{	  *mode = A_RE;	  return 2;	}      if (l1 == 's' && ! IDENT_CHAR ((unsigned char) src[2]))	{	  *mode = A_RS;	  return 2;	}    }  if (l0 == 'a')    {      if (l1 == '0')	{	  if (! IDENT_CHAR ((unsigned char) src[2]))	    {	      *mode = DSP_REG_N;	      *reg = A_A0_NUM;	      return 2;	    }	  if (tolower (src[2]) == 'g' && ! IDENT_CHAR ((unsigned char) src[3]))	    {	      *mode = DSP_REG_N;	      *reg = A_A0G_NUM;	      return 3;	    }	}      if (l1 == '1')	{	  if (! IDENT_CHAR ((unsigned char) src[2]))	    {	      *mode = DSP_REG_N;	      *reg = A_A1_NUM;	      return 2;	    }	  if (tolower (src[2]) == 'g' && ! IDENT_CHAR ((unsigned char) src[3]))	    {

⌨️ 快捷键说明

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