📄 tc-sh.c
字号:
/* 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 + -