Back to index

cell-binutils  2.17cvs20070401
Classes | Defines | Enumerations | Functions | Variables
tc-sh.c File Reference
#include "as.h"
#include "subsegs.h"
#include "opcodes/sh-opc.h"
#include "safe-ctype.h"
#include "struc-symbol.h"
#include "dwarf2dbg.h"
#include "dw2gencfi.h"
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  sh_operand_info
struct  sh_count_relocs

Defines

#define DEFINE_TABLE
#define C(a, b)   ENCODE_RELAX(a,b)
#define ENCODE_RELAX(what, length)   (((what) << 4) + (length))
#define GET_WHAT(x)   ((x>>4))
#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
#define COND8_F   258
#define COND8_M   -252
#define COND8_LENGTH   2
#define COND12_F   4100
#define COND12_M   -4090
#define COND12_LENGTH   6
#define COND12_DELAY_LENGTH   4
#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
#define UNCOND32_F   (1<<30)
#define UNCOND32_M   -(1<<30)
#define UNCOND32_LENGTH   14
#define EMPTY   { 0, 0, 0, 0 }
#define IDENT_CHAR(c)   (ISALNUM (c) || (c) == '_')
#define DDT_BASE   0xf000 /* Base value for double data transfer insns */
#define MAX_LITTLENUMS   6

Enumerations

enum  options {
  OPTION_EB = OPTION_MD_BASE, OPTION_EL, OPTION_ARC5, OPTION_ARC6,
  OPTION_ARC7, OPTION_ARC8, OPTION_ARC, OPTION_ALL_OPCODES = OPTION_MD_BASE + 1,
  OPTION_NO_SKIP_BUG, OPTION_NO_WRAP, OPTION_NOWARNSWAP = OPTION_MD_BASE, OPTION_GSTABSPACKING,
  OPTION_NOGSTABSPACKING, OPTION_CPU_IP2022 = OPTION_MD_BASE, OPTION_CPU_IP2022EXT, OPTION_JSRI2BSR_ON = OPTION_MD_BASE,
  OPTION_JSRI2BSR_OFF, OPTION_SIFILTER_ON, OPTION_SIFILTER_OFF, OPTION_CPU,
  OPTION_EB, OPTION_EL, OPTION_RELAX = OPTION_MD_BASE, OPTION_BIG,
  OPTION_LITTLE, OPTION_SMALL, OPTION_DSP, OPTION_ISA,
  OPTION_RENESAS, OPTION_ALLOW_REG_PREFIX, OPTION_DUMMY, OPTION_MACH_Z80 = OPTION_MD_BASE,
  OPTION_MACH_R800, OPTION_MACH_IUD, OPTION_MACH_WUD, OPTION_MACH_FUD,
  OPTION_MACH_IUP, OPTION_MACH_WUP, OPTION_MACH_FUP
}

Functions

static void s_uses (int)
static void s_uacons (int)
static void big (int ignore ATTRIBUTE_UNUSED)
static void little (int ignore ATTRIBUTE_UNUSED)
void md_begin (void)
static unsigned int parse_reg_without_prefix (char *src, int *mode, int *reg)
static unsigned int parse_reg (char *src, int *mode, int *reg)
static char * parse_exp (char *s, sh_operand_info *op)
static char * parse_at (char *src, sh_operand_info *op)
static void get_operand (char **ptr, sh_operand_info *op)
static char * get_operands (sh_opcode_info *info, char *args, sh_operand_info *operand)
static sh_opcode_infoget_specific (sh_opcode_info *opcode, sh_operand_info *operands)
static void insert (char *where, int how, int pcrel, sh_operand_info *op)
static void insert4 (char *where, int how, int pcrel, sh_operand_info *op)
static void build_relax (sh_opcode_info *opcode, sh_operand_info *op)
static char * insert_loop_bounds (char *output, sh_operand_info *operand)
static unsigned int build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
static sh_opcode_infofind_cooked_opcode (char **str_p)
static unsigned int assemble_ppi (char *op_end, sh_opcode_info *opcode)
void md_assemble (char *str)
void sh_frob_label (symbolS *sym)
void sh_flush_pending_output (void)
symbolS * md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
char * md_atof (int type, char *litP, int *sizeP)
static void s_uses (int ignore ATTRIBUTE_UNUSED)
int md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
void md_show_usage (FILE *stream)
static void sh_count_relocs (bfd *abfd ATTRIBUTE_UNUSED, segT sec, void *data)
static void sh_frob_section (bfd *abfd ATTRIBUTE_UNUSED, segT sec, void *ignore ATTRIBUTE_UNUSED)
void sh_frob_file (void)
void md_convert_frag (bfd *headers ATTRIBUTE_UNUSED, segT seg, fragS *fragP)
valueT md_section_align (segT seg ATTRIBUTE_UNUSED, valueT size)
void sh_cons_align (int nbytes)
void sh_handle_align (fragS *frag)
static bfd_boolean sh_local_pcrel (fixS *fix)
int sh_force_relocation (fixS *fix)
static void apply_full_field_fix (fixS *fixP, char *buf, bfd_vma val, int size)
void md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
int md_estimate_size_before_relax (fragS *fragP, segT segment_type)
void md_number_to_chars (char *ptr, valueT use, int nbytes)
long md_pcrel_from (fixS *fixP)
long md_pcrel_from_section (fixS *fixP, segT sec)
arelenttc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)

Variables

const char comment_chars [] = "!"
const char line_separator_chars [] = ";"
const char line_comment_chars [] = "!#"
const pseudo_typeS md_pseudo_table []
int sh_relax
int sh_small
static int dont_adjust_reloc_32
static int allow_dollar_register_prefix
static unsigned int preset_target_arch
static unsigned int valid_arch
const char EXP_CHARS [] = "eE"
const char FLT_CHARS [] = "rRsSfFdDxXpP"
const relax_typeS md_relax_table [C(END, 0)]
static struct hash_controlopcode_hash_control
static int reg_m
static int reg_n
static int reg_x
static int reg_y
static int reg_efg
static int reg_b
const char * md_shortopts = ""
size_t md_longopts_size = sizeof (md_longopts)
static int sh_no_align_cons = 0

Class Documentation

struct sh_operand_info

Definition at line 38 of file tc-sh.c.

Collaboration diagram for sh_operand_info:
Class Members
expressionS immediate
int reg
sh_arg_type type
struct sh_count_relocs

Definition at line 3273 of file tc-sh.c.

Class Members
int count
symbolS * sym

Define Documentation

#define C (   a,
  b 
)    ENCODE_RELAX(a,b)

Definition at line 154 of file tc-sh.c.

#define COND12   2

Definition at line 193 of file tc-sh.c.

#define COND12_DELAY_LENGTH   4

Definition at line 230 of file tc-sh.c.

#define COND12_F   4100

Definition at line 226 of file tc-sh.c.

#define COND12_LENGTH   6

Definition at line 228 of file tc-sh.c.

#define COND12_M   -4090

Definition at line 227 of file tc-sh.c.

#define COND32   3

Definition at line 194 of file tc-sh.c.

#define COND32_F   (1<<30)

Definition at line 234 of file tc-sh.c.

#define COND32_LENGTH   14

Definition at line 236 of file tc-sh.c.

#define COND32_M   -(1<<30)

Definition at line 235 of file tc-sh.c.

#define COND8   1

Definition at line 192 of file tc-sh.c.

#define COND8_F   258

Definition at line 220 of file tc-sh.c.

#define COND8_LENGTH   2

Definition at line 222 of file tc-sh.c.

#define COND8_M   -252

Definition at line 221 of file tc-sh.c.

#define COND_JUMP   1

Definition at line 162 of file tc-sh.c.

#define COND_JUMP_DELAY   2

Definition at line 163 of file tc-sh.c.

#define DDT_BASE   0xf000 /* Base value for double data transfer insns */

Definition at line 2461 of file tc-sh.c.

#define DEFINE_TABLE

Definition at line 26 of file tc-sh.c.

#define EMPTY   { 0, 0, 0, 0 }

Definition at line 327 of file tc-sh.c.

#define ENCODE_RELAX (   what,
  length 
)    (((what) << 4) + (length))

Definition at line 156 of file tc-sh.c.

#define END   4

Definition at line 187 of file tc-sh.c.

#define GET_WHAT (   x)    ((x>>4))

Definition at line 157 of file tc-sh.c.

#define IDENT_CHAR (   c)    (ISALNUM (c) || (c) == '_')

Definition at line 870 of file tc-sh.c.

#define MAX_LITTLENUMS   6

Definition at line 2960 of file tc-sh.c.

#define UNCOND12   1

Definition at line 197 of file tc-sh.c.

#define UNCOND12_F   4098

Definition at line 238 of file tc-sh.c.

#define UNCOND12_LENGTH   2

Definition at line 240 of file tc-sh.c.

#define UNCOND12_M   -4092

Definition at line 239 of file tc-sh.c.

#define UNCOND32   2

Definition at line 198 of file tc-sh.c.

#define UNCOND32_F   (1<<30)

Definition at line 244 of file tc-sh.c.

#define UNCOND32_LENGTH   14

Definition at line 246 of file tc-sh.c.

#define UNCOND32_M   -(1<<30)

Definition at line 245 of file tc-sh.c.

#define UNCOND_JUMP   3

Definition at line 164 of file tc-sh.c.

#define UNDEF_DISP   0

Definition at line 191 of file tc-sh.c.

#define UNDEF_WORD_DISP   4

Definition at line 195 of file tc-sh.c.


Enumeration Type Documentation

enum options
Enumerator:
OPTION_EB 
OPTION_EL 
OPTION_ARC5 
OPTION_ARC6 
OPTION_ARC7 
OPTION_ARC8 
OPTION_ARC 
OPTION_ALL_OPCODES 
OPTION_NO_SKIP_BUG 
OPTION_NO_WRAP 
OPTION_NOWARNSWAP 
OPTION_GSTABSPACKING 
OPTION_NOGSTABSPACKING 
OPTION_CPU_IP2022 
OPTION_CPU_IP2022EXT 
OPTION_JSRI2BSR_ON 
OPTION_JSRI2BSR_OFF 
OPTION_SIFILTER_ON 
OPTION_SIFILTER_OFF 
OPTION_CPU 
OPTION_EB 
OPTION_EL 
OPTION_RELAX 
OPTION_BIG 
OPTION_LITTLE 
OPTION_SMALL 
OPTION_DSP 
OPTION_ISA 
OPTION_RENESAS 
OPTION_ALLOW_REG_PREFIX 
OPTION_DUMMY 
OPTION_MACH_Z80 
OPTION_MACH_R800 
OPTION_MACH_IUD 
OPTION_MACH_WUD 
OPTION_MACH_FUD 
OPTION_MACH_IUP 
OPTION_MACH_WUP 
OPTION_MACH_FUP 

Definition at line 3043 of file tc-sh.c.

{
  OPTION_RELAX = OPTION_MD_BASE,
  OPTION_BIG,
  OPTION_LITTLE,
  OPTION_SMALL,
  OPTION_DSP,
  OPTION_ISA,
  OPTION_RENESAS,
  OPTION_ALLOW_REG_PREFIX,
#ifdef HAVE_SH64
  OPTION_ABI,
  OPTION_NO_MIX,
  OPTION_SHCOMPACT_CONST_CRANGE,
  OPTION_NO_EXPAND,
  OPTION_PT32,
#endif
  OPTION_DUMMY  /* Not used.  This is just here to make it easy to add and subtract options from this enum.  */
};

Function Documentation

static void apply_full_field_fix ( fixS *  fixP,
char *  buf,
bfd_vma  val,
int  size 
) [static]

Definition at line 3809 of file tc-sh.c.

{
  reloc_howto_type *howto;

  if (fixP->fx_addsy != NULL || fixP->fx_pcrel)
    {
      howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
      if (howto && !howto->partial_inplace)
       {
         fixP->fx_addnumber = val;
         return;
       }
    }
  md_number_to_chars (buf, val, size);
}

Here is the caller graph for this function:

static unsigned int assemble_ppi ( char *  op_end,
sh_opcode_info opcode 
) [static]

Definition at line 2464 of file tc-sh.c.

{
  int movx = 0;
  int movy = 0;
  int cond = 0;
  int field_b = 0;
  char *output;
  int move_code;
  unsigned int size;

  for (;;)
    {
      sh_operand_info operand[3];

      /* Some insn ignore one or more register fields, e.g. psts machl,a0.
        Make sure we encode a defined insn pattern.  */
      reg_x = 0;
      reg_y = 0;
      reg_n = 0;

      if (opcode->arg[0] != A_END)
       op_end = get_operands (opcode, op_end, operand);
    try_another_opcode:
      opcode = get_specific (opcode, operand);
      if (opcode == 0)
       {
         /* Couldn't find an opcode which matched the operands.  */
         char *where = frag_more (2);
         size = 2;

         where[0] = 0x0;
         where[1] = 0x0;
         as_bad (_("invalid operands for opcode"));
         return size;
       }

      if (opcode->nibbles[0] != PPI)
       as_bad (_("insn can't be combined with parallel processing insn"));

      switch (opcode->nibbles[1])
       {

       case NOPX:
         if (movx)
           as_bad (_("multiple movx specifications"));
         movx = DDT_BASE;
         break;
       case NOPY:
         if (movy)
           as_bad (_("multiple movy specifications"));
         movy = DDT_BASE;
         break;

       case MOVX_NOPY:
         if (movx)
           as_bad (_("multiple movx specifications"));
         if ((reg_n < 4 || reg_n > 5)
             && (reg_n < 0 || reg_n > 1))
           as_bad (_("invalid movx address register"));
         if (movy && movy != DDT_BASE)
           as_bad (_("insn cannot be combined with non-nopy"));
         movx = ((((reg_n & 1) != 0) << 9)
                + (((reg_n & 4) == 0) << 8)
                + (reg_x << 6)
                + (opcode->nibbles[2] << 4)
                + opcode->nibbles[3]
                + DDT_BASE);
         break;

       case MOVY_NOPX:
         if (movy)
           as_bad (_("multiple movy specifications"));
         if ((reg_n < 6 || reg_n > 7)
             && (reg_n < 2 || reg_n > 3))
           as_bad (_("invalid movy address register"));
         if (movx && movx != DDT_BASE)
           as_bad (_("insn cannot be combined with non-nopx"));
         movy = ((((reg_n & 1) != 0) << 8)
                + (((reg_n & 4) == 0) << 9)
                + (reg_y << 6)
                + (opcode->nibbles[2] << 4)
                + opcode->nibbles[3]
                + DDT_BASE);
         break;

       case MOVX:
         if (movx)
           as_bad (_("multiple movx specifications"));
         if (movy & 0x2ac)
           as_bad (_("previous movy requires nopx"));
         if (reg_n < 4 || reg_n > 5)
           as_bad (_("invalid movx address register"));
         if (opcode->nibbles[2] & 8)
           {
             if (reg_m == A_A1_NUM)
              movx = 1 << 7;
             else if (reg_m != A_A0_NUM)
              as_bad (_("invalid movx dsp register"));
           }
         else
           {
             if (reg_x > 1)
              as_bad (_("invalid movx dsp register"));
             movx = reg_x << 7;
           }
         movx += ((reg_n - 4) << 9) + (opcode->nibbles[2] << 2) + DDT_BASE;
         break;

       case MOVY:
         if (movy)
           as_bad (_("multiple movy specifications"));
         if (movx & 0x153)
           as_bad (_("previous movx requires nopy"));
         if (opcode->nibbles[2] & 8)
           {
             /* Bit 3 in nibbles[2] is intended for bit 4 of the opcode,
               so add 8 more.  */
             movy = 8;
             if (reg_m == A_A1_NUM)
              movy += 1 << 6;
             else if (reg_m != A_A0_NUM)
              as_bad (_("invalid movy dsp register"));
           }
         else
           {
             if (reg_y > 1)
              as_bad (_("invalid movy dsp register"));
             movy = reg_y << 6;
           }
         if (reg_n < 6 || reg_n > 7)
           as_bad (_("invalid movy address register"));
         movy += ((reg_n - 6) << 8) + opcode->nibbles[2] + DDT_BASE;
         break;

       case PSH:
         if (operand[0].immediate.X_op != O_constant)
           as_bad (_("dsp immediate shift value not constant"));
         field_b = ((opcode->nibbles[2] << 12)
                   | (operand[0].immediate.X_add_number & 127) << 4
                   | reg_n);
         break;
       case PPI3NC:
         if (cond)
           {
             opcode++;
             goto try_another_opcode;
           }
         /* Fall through.  */
       case PPI3:
         if (field_b)
           as_bad (_("multiple parallel processing specifications"));
         field_b = ((opcode->nibbles[2] << 12) + (opcode->nibbles[3] << 8)
                   + (reg_x << 6) + (reg_y << 4) + reg_n);
         switch (opcode->nibbles[4])
           {
           case HEX_0:
           case HEX_XX00:
           case HEX_00YY:
             break;
           case HEX_1:
           case HEX_4:
             field_b += opcode->nibbles[4] << 4;
             break;
           default:
             abort ();
           }
         break;
       case PDC:
         if (cond)
           as_bad (_("multiple condition specifications"));
         cond = opcode->nibbles[2] << 8;
         if (*op_end)
           goto skip_cond_check;
         break;
       case PPIC:
         if (field_b)
           as_bad (_("multiple parallel processing specifications"));
         field_b = ((opcode->nibbles[2] << 12) + (opcode->nibbles[3] << 8)
                   + cond + (reg_x << 6) + (reg_y << 4) + reg_n);
         cond = 0;
         switch (opcode->nibbles[4])
           {
           case HEX_0:
           case HEX_XX00:
           case HEX_00YY:
             break;
           case HEX_1:
           case HEX_4:
             field_b += opcode->nibbles[4] << 4;
             break;
           default:
             abort ();
           }
         break;
       case PMUL:
         if (field_b)
           {
             if ((field_b & 0xef00) == 0xa100)
              field_b -= 0x8100;
             /* pclr Dz pmuls Se,Sf,Dg */
             else if ((field_b & 0xff00) == 0x8d00
                     && (SH_MERGE_ARCH_SET_VALID (valid_arch, arch_sh4al_dsp_up)))
              {
                valid_arch = SH_MERGE_ARCH_SET (valid_arch, arch_sh4al_dsp_up);
                field_b -= 0x8cf0;
              }
             else
              as_bad (_("insn cannot be combined with pmuls"));
             switch (field_b & 0xf)
              {
              case A_X0_NUM:
                field_b += 0 - A_X0_NUM;
                break;
              case A_Y0_NUM:
                field_b += 1 - A_Y0_NUM;
                break;
              case A_A0_NUM:
                field_b += 2 - A_A0_NUM;
                break;
              case A_A1_NUM:
                field_b += 3 - A_A1_NUM;
                break;
              default:
                as_bad (_("bad combined pmuls output operand"));
              }
              /* Generate warning if the destination register for padd / psub
                 and pmuls is the same ( only for A0 or A1 ).
                 If the last nibble is 1010 then A0 is used in both
                 padd / psub and pmuls. If it is 1111 then A1 is used
                 as destination register in both padd / psub and pmuls.  */

              if ((((field_b | reg_efg) & 0x000F) == 0x000A)
                  || (((field_b | reg_efg) & 0x000F) == 0x000F))
                as_warn (_("destination register is same for parallel insns"));
           }
         field_b += 0x4000 + reg_efg;
         break;
       default:
         abort ();
       }
      if (cond)
       {
         as_bad (_("condition not followed by conditionalizable insn"));
         cond = 0;
       }
      if (! *op_end)
       break;
    skip_cond_check:
      opcode = find_cooked_opcode (&op_end);
      if (opcode == NULL)
       {
         (as_bad
          (_("unrecognized characters at end of parallel processing insn")));
         break;
       }
    }

  move_code = movx | movy;
  if (field_b)
    {
      /* Parallel processing insn.  */
      unsigned long ppi_code = (movx | movy | 0xf800) << 16 | field_b;

      output = frag_more (4);
      size = 4;
      if (! target_big_endian)
       {
         output[3] = ppi_code >> 8;
         output[2] = ppi_code;
       }
      else
       {
         output[2] = ppi_code >> 8;
         output[3] = ppi_code;
       }
      move_code |= 0xf800;
    }
  else
    {
      /* Just a double data transfer.  */
      output = frag_more (2);
      size = 2;
    }
  if (! target_big_endian)
    {
      output[1] = move_code >> 8;
      output[0] = move_code;
    }
  else
    {
      output[0] = move_code >> 8;
      output[1] = move_code;
    }
  return size;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void big ( int ignore  ATTRIBUTE_UNUSED) [static]

Definition at line 60 of file tc-sh.c.

{
  if (! target_big_endian)
    as_bad (_("directive .big encountered when option -big required"));

  /* Stop further messages.  */
  target_big_endian = 1;
}

Here is the call graph for this function:

static unsigned int build_Mytes ( sh_opcode_info opcode,
sh_operand_info operand 
) [static]

Definition at line 2232 of file tc-sh.c.

{
  int index;
  char nbuf[8];
  char *output;
  unsigned int size = 2;
  int low_byte = target_big_endian ? 1 : 0;
  int max_index = 4;

  nbuf[0] = 0;
  nbuf[1] = 0;
  nbuf[2] = 0;
  nbuf[3] = 0;
  nbuf[4] = 0;
  nbuf[5] = 0;
  nbuf[6] = 0;
  nbuf[7] = 0;

  if (SH_MERGE_ARCH_SET (opcode->arch, arch_op32))
    {
      output = frag_more (4);
      size = 4;
      max_index = 8;
    }
  else
    output = frag_more (2);

  for (index = 0; index < max_index; index++)
    {
      sh_nibble_type i = opcode->nibbles[index];
      if (i < 16)
       {
         nbuf[index] = i;
       }
      else
       {
         switch (i)
           {
           case REG_N:
           case REG_N_D:
             nbuf[index] = reg_n;
             break;
           case REG_M:
             nbuf[index] = reg_m;
             break;
           case SDT_REG_N:
             if (reg_n < 2 || reg_n > 5)
              as_bad (_("Invalid register: 'r%d'"), reg_n);
             nbuf[index] = (reg_n & 3) | 4;
             break;
           case REG_NM:
             nbuf[index] = reg_n | (reg_m >> 2);
             break;
           case REG_B:
             nbuf[index] = reg_b | 0x08;
             break;
           case REG_N_B01:
             nbuf[index] = reg_n | 0x01;
             break;
           case IMM0_3s:
             nbuf[index] |= 0x08;
           case IMM0_3c:
             insert (output + low_byte, BFD_RELOC_SH_IMM3, 0, operand);
             break;
           case IMM0_3Us:
             nbuf[index] |= 0x80;
           case IMM0_3Uc:
             insert (output + low_byte, BFD_RELOC_SH_IMM3U, 0, operand);
             break;
           case DISP0_12:
             insert (output + 2, BFD_RELOC_SH_DISP12, 0, operand);
             break;
           case DISP0_12BY2:
             insert (output + 2, BFD_RELOC_SH_DISP12BY2, 0, operand);
             break;
           case DISP0_12BY4:
             insert (output + 2, BFD_RELOC_SH_DISP12BY4, 0, operand);
             break;
           case DISP0_12BY8:
             insert (output + 2, BFD_RELOC_SH_DISP12BY8, 0, operand);
             break;
           case DISP1_12:
             insert (output + 2, BFD_RELOC_SH_DISP12, 0, operand+1);
             break;
           case DISP1_12BY2:
             insert (output + 2, BFD_RELOC_SH_DISP12BY2, 0, operand+1);
             break;
           case DISP1_12BY4:
             insert (output + 2, BFD_RELOC_SH_DISP12BY4, 0, operand+1);
             break;
           case DISP1_12BY8:
             insert (output + 2, BFD_RELOC_SH_DISP12BY8, 0, operand+1);
             break;
           case IMM0_20_4:
             break;
           case IMM0_20:
             insert4 (output, BFD_RELOC_SH_DISP20, 0, operand);
             break;
           case IMM0_20BY8:
             insert4 (output, BFD_RELOC_SH_DISP20BY8, 0, operand);
             break;
           case IMM0_4BY4:
             insert (output + low_byte, BFD_RELOC_SH_IMM4BY4, 0, operand);
             break;
           case IMM0_4BY2:
             insert (output + low_byte, BFD_RELOC_SH_IMM4BY2, 0, operand);
             break;
           case IMM0_4:
             insert (output + low_byte, BFD_RELOC_SH_IMM4, 0, operand);
             break;
           case IMM1_4BY4:
             insert (output + low_byte, BFD_RELOC_SH_IMM4BY4, 0, operand + 1);
             break;
           case IMM1_4BY2:
             insert (output + low_byte, BFD_RELOC_SH_IMM4BY2, 0, operand + 1);
             break;
           case IMM1_4:
             insert (output + low_byte, BFD_RELOC_SH_IMM4, 0, operand + 1);
             break;
           case IMM0_8BY4:
             insert (output + low_byte, BFD_RELOC_SH_IMM8BY4, 0, operand);
             break;
           case IMM0_8BY2:
             insert (output + low_byte, BFD_RELOC_SH_IMM8BY2, 0, operand);
             break;
           case IMM0_8:
             insert (output + low_byte, BFD_RELOC_SH_IMM8, 0, operand);
             break;
           case IMM1_8BY4:
             insert (output + low_byte, BFD_RELOC_SH_IMM8BY4, 0, operand + 1);
             break;
           case IMM1_8BY2:
             insert (output + low_byte, BFD_RELOC_SH_IMM8BY2, 0, operand + 1);
             break;
           case IMM1_8:
             insert (output + low_byte, BFD_RELOC_SH_IMM8, 0, operand + 1);
             break;
           case PCRELIMM_8BY4:
             insert (output, BFD_RELOC_SH_PCRELIMM8BY4,
                    operand->type != A_DISP_PC_ABS, operand);
             break;
           case PCRELIMM_8BY2:
             insert (output, BFD_RELOC_SH_PCRELIMM8BY2,
                    operand->type != A_DISP_PC_ABS, operand);
             break;
           case REPEAT:
             output = insert_loop_bounds (output, operand);
             nbuf[index] = opcode->nibbles[3];
             operand += 2;
             break;
           default:
             printf (_("failed for %d\n"), i);
           }
       }
    }
  if (!target_big_endian)
    {
      output[1] = (nbuf[0] << 4) | (nbuf[1]);
      output[0] = (nbuf[2] << 4) | (nbuf[3]);
    }
  else
    {
      output[0] = (nbuf[0] << 4) | (nbuf[1]);
      output[1] = (nbuf[2] << 4) | (nbuf[3]);
    }
  if (SH_MERGE_ARCH_SET (opcode->arch, arch_op32))
    {
      if (!target_big_endian)
       {
         output[3] = (nbuf[4] << 4) | (nbuf[5]);
         output[2] = (nbuf[6] << 4) | (nbuf[7]);
       }
      else
       {
         output[2] = (nbuf[4] << 4) | (nbuf[5]);
         output[3] = (nbuf[6] << 4) | (nbuf[7]);
       }
    }
  return size;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void build_relax ( sh_opcode_info opcode,
sh_operand_info op 
) [static]

Definition at line 2150 of file tc-sh.c.

{
  int high_byte = target_big_endian ? 0 : 1;
  char *p;

  if (opcode->arg[0] == A_BDISP8)
    {
      int what = (opcode->nibbles[1] & 4) ? COND_JUMP_DELAY : COND_JUMP;
      p = frag_var (rs_machine_dependent,
                  md_relax_table[C (what, COND32)].rlx_length,
                  md_relax_table[C (what, COND8)].rlx_length,
                  C (what, 0),
                  op->immediate.X_add_symbol,
                  op->immediate.X_add_number,
                  0);
      p[high_byte] = (opcode->nibbles[0] << 4) | (opcode->nibbles[1]);
    }
  else if (opcode->arg[0] == A_BDISP12)
    {
      p = frag_var (rs_machine_dependent,
                  md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_length,
                  md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_length,
                  C (UNCOND_JUMP, 0),
                  op->immediate.X_add_symbol,
                  op->immediate.X_add_number,
                  0);
      p[high_byte] = (opcode->nibbles[0] << 4);
    }

}

Here is the call graph for this function:

Here is the caller graph for this function:

static sh_opcode_info* find_cooked_opcode ( char **  str_p) [static]

Definition at line 2417 of file tc-sh.c.

{
  char *str = *str_p;
  unsigned char *op_start;
  unsigned char *op_end;
  char name[20];
  int nlen = 0;

  /* Drop leading whitespace.  */
  while (*str == ' ')
    str++;

  /* Find the op code end.
     The pre-processor will eliminate whitespace in front of
     any '@' after the first argument; we may be called from
     assemble_ppi, so the opcode might be terminated by an '@'.  */
  for (op_start = op_end = (unsigned char *) str;
       *op_end
       && nlen < 20
       && !is_end_of_line[*op_end] && *op_end != ' ' && *op_end != '@';
       op_end++)
    {
      unsigned char c = op_start[nlen];

      /* The machine independent code will convert CMP/EQ into cmp/EQ
        because it thinks the '/' is the end of the symbol.  Moreover,
        all but the first sub-insn is a parallel processing insn won't
        be capitalized.  Instead of hacking up the machine independent
        code, we just deal with it here.  */
      c = TOLOWER (c);
      name[nlen] = c;
      nlen++;
    }

  name[nlen] = 0;
  *str_p = (char *) op_end;

  if (nlen == 0)
    as_bad (_("can't find opcode "));

  return (sh_opcode_info *) hash_find (opcode_hash_control, name);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void get_operand ( char **  ptr,
sh_operand_info op 
) [static]

Definition at line 1474 of file tc-sh.c.

{
  char *src = *ptr;
  int mode = -1;
  unsigned int len;

  if (src[0] == '#')
    {
      src++;
      *ptr = parse_exp (src, op);
      op->type = A_IMM;
      return;
    }

  else if (src[0] == '@')
    {
      *ptr = parse_at (src, op);
      return;
    }
  len = parse_reg (src, &mode, &(op->reg));
  if (len)
    {
      *ptr = src + len;
      op->type = mode;
      return;
    }
  else
    {
      /* Not a reg, the only thing left is a displacement.  */
      *ptr = parse_exp (src, op);
      op->type = A_DISP_PC;
      return;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static char* get_operands ( sh_opcode_info info,
char *  args,
sh_operand_info operand 
) [static]

Definition at line 1510 of file tc-sh.c.

{
  char *ptr = args;
  if (info->arg[0])
    {
      /* The pre-processor will eliminate whitespace in front of '@'
        after the first argument; we may be called multiple times
        from assemble_ppi, so don't insist on finding whitespace here.  */
      if (*ptr == ' ')
       ptr++;

      get_operand (&ptr, operand + 0);
      if (info->arg[1])
       {
         if (*ptr == ',')
           {
             ptr++;
           }
         get_operand (&ptr, operand + 1);
         /* ??? Hack: psha/pshl have a varying operand number depending on
            the type of the first operand.  We handle this by having the
            three-operand version first and reducing the number of operands
            parsed to two if we see that the first operand is an immediate.
             This works because no insn with three operands has an immediate
            as first operand.  */
         if (info->arg[2] && operand[0].type != A_IMM)
           {
             if (*ptr == ',')
              {
                ptr++;
              }
             get_operand (&ptr, operand + 2);
           }
         else
           {
             operand[2].type = 0;
           }
       }
      else
       {
         operand[1].type = 0;
         operand[2].type = 0;
       }
    }
  else
    {
      operand[0].type = 0;
      operand[1].type = 0;
      operand[2].type = 0;
    }
  return ptr;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static sh_opcode_info* get_specific ( sh_opcode_info opcode,
sh_operand_info operands 
) [static]

Definition at line 1568 of file tc-sh.c.

{
  sh_opcode_info *this_try = opcode;
  char *name = opcode->name;
  int n = 0;

  while (opcode->name)
    {
      this_try = opcode++;
      if ((this_try->name != name) && (strcmp (this_try->name, name) != 0))
       {
         /* We've looked so far down the table that we've run out of
            opcodes with the same name.  */
         return 0;
       }

      /* Look at both operands needed by the opcodes and provided by
         the user - since an arg test will often fail on the same arg
         again and again, we'll try and test the last failing arg the
         first on each opcode try.  */
      for (n = 0; this_try->arg[n]; n++)
       {
         sh_operand_info *user = operands + n;
         sh_arg_type arg = this_try->arg[n];

         if (SH_MERGE_ARCH_SET_VALID (valid_arch, arch_sh2a_nofpu_up)
             && (   arg == A_DISP_REG_M
                || arg == A_DISP_REG_N))
           {
             /* Check a few key IMM* fields for overflow.  */
             int opf;
             long val = user->immediate.X_add_number;

             for (opf = 0; opf < 4; opf ++)
              switch (this_try->nibbles[opf])
                {
                case IMM0_4:
                case IMM1_4:
                  if (val < 0 || val > 15)
                    goto fail;
                  break;
                case IMM0_4BY2:
                case IMM1_4BY2:
                  if (val < 0 || val > 15 * 2)
                    goto fail;
                  break;
                case IMM0_4BY4:
                case IMM1_4BY4:
                  if (val < 0 || val > 15 * 4)
                    goto fail;
                  break;
                default:
                  break;
                }
           }
         switch (arg)
           {
           case A_DISP_PC:
             if (user->type == A_DISP_PC_ABS)
              break;
             /* Fall through.  */
           case A_IMM:
           case A_BDISP12:
           case A_BDISP8:
           case A_DISP_GBR:
           case A_DISP2_TBR:
           case A_MACH:
           case A_PR:
           case A_MACL:
             if (user->type != arg)
              goto fail;
             break;
           case A_R0:
             /* opcode needs r0 */
             if (user->type != A_REG_N || user->reg != 0)
              goto fail;
             break;
           case A_R0_GBR:
             if (user->type != A_R0_GBR || user->reg != 0)
              goto fail;
             break;
           case F_FR0:
             if (user->type != F_REG_N || user->reg != 0)
              goto fail;
             break;

           case A_REG_N:
           case A_INC_N:
           case A_DEC_N:
           case A_IND_N:
           case A_IND_R0_REG_N:
           case A_DISP_REG_N:
           case F_REG_N:
           case D_REG_N:
           case X_REG_N:
           case V_REG_N:
           case FPUL_N:
           case FPSCR_N:
           case DSP_REG_N:
             /* Opcode needs rn */
             if (user->type != arg)
              goto fail;
             reg_n = user->reg;
             break;
           case DX_REG_N:
             if (user->type != D_REG_N && user->type != X_REG_N)
              goto fail;
             reg_n = user->reg;
             break;
           case A_GBR:
           case A_TBR:
           case A_SR:
           case A_VBR:
           case A_DSR:
           case A_MOD:
           case A_RE:
           case A_RS:
           case A_SSR:
           case A_SPC:
           case A_SGR:
           case A_DBR:
             if (user->type != arg)
              goto fail;
             break;

           case A_REG_B:
             if (user->type != arg)
              goto fail;
             reg_b = user->reg;
             break;

           case A_INC_R15:
             if (user->type != A_INC_N)
              goto fail;
             if (user->reg != 15)
              goto fail;
             reg_n = user->reg;
             break;

           case A_DEC_R15:
             if (user->type != A_DEC_N)
              goto fail;
             if (user->reg != 15)
              goto fail;
             reg_n = user->reg;
             break;

           case A_REG_M:
           case A_INC_M:
           case A_DEC_M:
           case A_IND_M:
           case A_IND_R0_REG_M:
           case A_DISP_REG_M:
           case DSP_REG_M:
             /* Opcode needs rn */
             if (user->type != arg - A_REG_M + A_REG_N)
              goto fail;
             reg_m = user->reg;
             break;

           case AS_DEC_N:
             if (user->type != A_DEC_N)
              goto fail;
             if (user->reg < 2 || user->reg > 5)
              goto fail;
             reg_n = user->reg;
             break;

           case AS_INC_N:
             if (user->type != A_INC_N)
              goto fail;
             if (user->reg < 2 || user->reg > 5)
              goto fail;
             reg_n = user->reg;
             break;

           case AS_IND_N:
             if (user->type != A_IND_N)
              goto fail;
             if (user->reg < 2 || user->reg > 5)
              goto fail;
             reg_n = user->reg;
             break;

           case AS_PMOD_N:
             if (user->type != AX_PMOD_N)
              goto fail;
             if (user->reg < 2 || user->reg > 5)
              goto fail;
             reg_n = user->reg;
             break;

           case AX_INC_N:
             if (user->type != A_INC_N)
              goto fail;
             if (user->reg < 4 || user->reg > 5)
              goto fail;
             reg_n = user->reg;
             break;

           case AX_IND_N:
             if (user->type != A_IND_N)
              goto fail;
             if (user->reg < 4 || user->reg > 5)
              goto fail;
             reg_n = user->reg;
             break;

           case AX_PMOD_N:
             if (user->type != AX_PMOD_N)
              goto fail;
             if (user->reg < 4 || user->reg > 5)
              goto fail;
             reg_n = user->reg;
             break;

           case AXY_INC_N:
             if (user->type != A_INC_N)
              goto fail;
             if ((user->reg < 4 || user->reg > 5)
                && (user->reg < 0 || user->reg > 1))
              goto fail;
             reg_n = user->reg;
             break;

           case AXY_IND_N:
             if (user->type != A_IND_N)
              goto fail;
             if ((user->reg < 4 || user->reg > 5)
                && (user->reg < 0 || user->reg > 1))
              goto fail;
             reg_n = user->reg;
             break;

           case AXY_PMOD_N:
             if (user->type != AX_PMOD_N)
              goto fail;
             if ((user->reg < 4 || user->reg > 5)
                && (user->reg < 0 || user->reg > 1))
              goto fail;
             reg_n = user->reg;
             break;

           case AY_INC_N:
             if (user->type != A_INC_N)
              goto fail;
             if (user->reg < 6 || user->reg > 7)
              goto fail;
             reg_n = user->reg;
             break;

           case AY_IND_N:
             if (user->type != A_IND_N)
              goto fail;
             if (user->reg < 6 || user->reg > 7)
              goto fail;
             reg_n = user->reg;
             break;

           case AY_PMOD_N:
             if (user->type != AY_PMOD_N)
              goto fail;
             if (user->reg < 6 || user->reg > 7)
              goto fail;
             reg_n = user->reg;
             break;

           case AYX_INC_N:
             if (user->type != A_INC_N)
              goto fail;
             if ((user->reg < 6 || user->reg > 7)
                && (user->reg < 2 || user->reg > 3))
              goto fail;
             reg_n = user->reg;
             break;

           case AYX_IND_N:
             if (user->type != A_IND_N)
              goto fail;
             if ((user->reg < 6 || user->reg > 7)
                && (user->reg < 2 || user->reg > 3))
              goto fail;
             reg_n = user->reg;
             break;

           case AYX_PMOD_N:
             if (user->type != AY_PMOD_N)
              goto fail;
             if ((user->reg < 6 || user->reg > 7)
                && (user->reg < 2 || user->reg > 3))
              goto fail;
             reg_n = user->reg;
             break;

           case DSP_REG_A_M:
             if (user->type != DSP_REG_N)
              goto fail;
             if (user->reg != A_A0_NUM
                && user->reg != A_A1_NUM)
              goto fail;
             reg_m = user->reg;
             break;

           case DSP_REG_AX:
             if (user->type != DSP_REG_N)
              goto fail;
             switch (user->reg)
              {
              case A_A0_NUM:
                reg_x = 0;
                break;
              case A_A1_NUM:
                reg_x = 2;
                break;
              case A_X0_NUM:
                reg_x = 1;
                break;
              case A_X1_NUM:
                reg_x = 3;
                break;
              default:
                goto fail;
              }
             break;

           case DSP_REG_XY:
             if (user->type != DSP_REG_N)
              goto fail;
             switch (user->reg)
              {
              case A_X0_NUM:
                reg_x = 0;
                break;
              case A_X1_NUM:
                reg_x = 2;
                break;
              case A_Y0_NUM:
                reg_x = 1;
                break;
              case A_Y1_NUM:
                reg_x = 3;
                break;
              default:
                goto fail;
              }
             break;

           case DSP_REG_AY:
             if (user->type != DSP_REG_N)
              goto fail;
             switch (user->reg)
              {
              case A_A0_NUM:
                reg_y = 0;
                break;
              case A_A1_NUM:
                reg_y = 1;
                break;
              case A_Y0_NUM:
                reg_y = 2;
                break;
              case A_Y1_NUM:
                reg_y = 3;
                break;
              default:
                goto fail;
              }
             break;

           case DSP_REG_YX:
             if (user->type != DSP_REG_N)
              goto fail;
             switch (user->reg)
              {
              case A_Y0_NUM:
                reg_y = 0;
                break;
              case A_Y1_NUM:
                reg_y = 1;
                break;
              case A_X0_NUM:
                reg_y = 2;
                break;
              case A_X1_NUM:
                reg_y = 3;
                break;
              default:
                goto fail;
              }
             break;

           case DSP_REG_X:
             if (user->type != DSP_REG_N)
              goto fail;
             switch (user->reg)
              {
              case A_X0_NUM:
                reg_x = 0;
                break;
              case A_X1_NUM:
                reg_x = 1;
                break;
              case A_A0_NUM:
                reg_x = 2;
                break;
              case A_A1_NUM:
                reg_x = 3;
                break;
              default:
                goto fail;
              }
             break;

           case DSP_REG_Y:
             if (user->type != DSP_REG_N)
              goto fail;
             switch (user->reg)
              {
              case A_Y0_NUM:
                reg_y = 0;
                break;
              case A_Y1_NUM:
                reg_y = 1;
                break;
              case A_M0_NUM:
                reg_y = 2;
                break;
              case A_M1_NUM:
                reg_y = 3;
                break;
              default:
                goto fail;
              }
             break;

           case DSP_REG_E:
             if (user->type != DSP_REG_N)
              goto fail;
             switch (user->reg)
              {
              case A_X0_NUM:
                reg_efg = 0 << 10;
                break;
              case A_X1_NUM:
                reg_efg = 1 << 10;
                break;
              case A_Y0_NUM:
                reg_efg = 2 << 10;
                break;
              case A_A1_NUM:
                reg_efg = 3 << 10;
                break;
              default:
                goto fail;
              }
             break;

           case DSP_REG_F:
             if (user->type != DSP_REG_N)
              goto fail;
             switch (user->reg)
              {
              case A_Y0_NUM:
                reg_efg |= 0 << 8;
                break;
              case A_Y1_NUM:
                reg_efg |= 1 << 8;
                break;
              case A_X0_NUM:
                reg_efg |= 2 << 8;
                break;
              case A_A1_NUM:
                reg_efg |= 3 << 8;
                break;
              default:
                goto fail;
              }
             break;

           case DSP_REG_G:
             if (user->type != DSP_REG_N)
              goto fail;
             switch (user->reg)
              {
              case A_M0_NUM:
                reg_efg |= 0 << 2;
                break;
              case A_M1_NUM:
                reg_efg |= 1 << 2;
                break;
              case A_A0_NUM:
                reg_efg |= 2 << 2;
                break;
              case A_A1_NUM:
                reg_efg |= 3 << 2;
                break;
              default:
                goto fail;
              }
             break;

           case A_A0:
             if (user->type != DSP_REG_N || user->reg != A_A0_NUM)
              goto fail;
             break;
           case A_X0:
             if (user->type != DSP_REG_N || user->reg != A_X0_NUM)
              goto fail;
             break;
           case A_X1:
             if (user->type != DSP_REG_N || user->reg != A_X1_NUM)
              goto fail;
             break;
           case A_Y0:
             if (user->type != DSP_REG_N || user->reg != A_Y0_NUM)
              goto fail;
             break;
           case A_Y1:
             if (user->type != DSP_REG_N || user->reg != A_Y1_NUM)
              goto fail;
             break;

           case F_REG_M:
           case D_REG_M:
           case X_REG_M:
           case V_REG_M:
           case FPUL_M:
           case FPSCR_M:
             /* Opcode needs rn */
             if (user->type != arg - F_REG_M + F_REG_N)
              goto fail;
             reg_m = user->reg;
             break;
           case DX_REG_M:
             if (user->type != D_REG_N && user->type != X_REG_N)
              goto fail;
             reg_m = user->reg;
             break;
           case XMTRX_M4:
             if (user->type != XMTRX_M4)
              goto fail;
             reg_m = 4;
             break;

           default:
             printf (_("unhandled %d\n"), arg);
             goto fail;
           }
       }
      if ( !SH_MERGE_ARCH_SET_VALID (valid_arch, this_try->arch))
       goto fail;
      valid_arch = SH_MERGE_ARCH_SET (valid_arch, this_try->arch);
      return this_try;
    fail:
      ;
    }

  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void insert ( char *  where,
int  how,
int  pcrel,
sh_operand_info op 
) [static]

Definition at line 2129 of file tc-sh.c.

{
  fix_new_exp (frag_now,
              where - frag_now->fr_literal,
              2,
              &op->immediate,
              pcrel,
              how);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void insert4 ( char *  where,
int  how,
int  pcrel,
sh_operand_info op 
) [static]

Definition at line 2140 of file tc-sh.c.

{
  fix_new_exp (frag_now,
              where - frag_now->fr_literal,
              4,
              & op->immediate,
              pcrel,
              how);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static char* insert_loop_bounds ( char *  output,
sh_operand_info operand 
) [static]

Definition at line 2184 of file tc-sh.c.

{
  char *name;
  symbolS *end_sym;

  /* Since the low byte of the opcode will be overwritten by the reloc, we
     can just stash the high byte into both bytes and ignore endianness.  */
  output[0] = 0x8c;
  output[1] = 0x8c;
  insert (output, BFD_RELOC_SH_LOOP_START, 1, operand);
  insert (output, BFD_RELOC_SH_LOOP_END, 1, operand + 1);

  if (sh_relax)
    {
      static int count = 0;

      /* If the last loop insn is a two-byte-insn, it is in danger of being
        swapped with the insn after it.  To prevent this, create a new
        symbol - complete with SH_LABEL reloc - after the last loop insn.
        If the last loop insn is four bytes long, the symbol will be
        right in the middle, but four byte insns are not swapped anyways.  */
      /* A REPEAT takes 6 bytes.  The SH has a 32 bit address space.
        Hence a 9 digit number should be enough to count all REPEATs.  */
      name = alloca (11);
      sprintf (name, "_R%x", count++ & 0x3fffffff);
      end_sym = symbol_new (name, undefined_section, 0, &zero_address_frag);
      /* Make this a local symbol.  */
#ifdef OBJ_COFF
      SF_SET_LOCAL (end_sym);
#endif /* OBJ_COFF */
      symbol_table_insert (end_sym);
      end_sym->sy_value = operand[1].immediate;
      end_sym->sy_value.X_add_number += 2;
      fix_new (frag_now, frag_now_fix (), 2, end_sym, 0, 1, BFD_RELOC_SH_LABEL);
    }

  output = frag_more (2);
  output[0] = 0x8e;
  output[1] = 0x8e;
  insert (output, BFD_RELOC_SH_LOOP_START, 1, operand);
  insert (output, BFD_RELOC_SH_LOOP_END, 1, operand + 1);

  return frag_more (2);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void little ( int ignore  ATTRIBUTE_UNUSED) [static]

Definition at line 70 of file tc-sh.c.

{
  if (target_big_endian)
    as_bad (_("directive .little encountered when option -little required"));

  /* Stop further messages.  */
  target_big_endian = 0;
}

Here is the call graph for this function:

void md_apply_fix ( fixS *  fixP,
valueT valP,
segT seg  ATTRIBUTE_UNUSED 
)

Definition at line 3828 of file tc-sh.c.

{
  char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
  int lowbyte = target_big_endian ? 1 : 0;
  int highbyte = target_big_endian ? 0 : 1;
  long val = (long) *valP;
  long max, min;
  int shift;

  /* A difference between two symbols, the second of which is in the
     current section, is transformed in a PC-relative relocation to
     the other symbol.  We have to adjust the relocation type here.  */
  if (fixP->fx_pcrel)
    {
      switch (fixP->fx_r_type)
       {
       default:
         break;

       case BFD_RELOC_32:
         fixP->fx_r_type = BFD_RELOC_32_PCREL;
         break;

         /* Currently, we only support 32-bit PCREL relocations.
            We'd need a new reloc type to handle 16_PCREL, and
            8_PCREL is already taken for R_SH_SWITCH8, which
            apparently does something completely different than what
            we need.  FIXME.  */
       case BFD_RELOC_16:
         bfd_set_error (bfd_error_bad_value);
         return;

       case BFD_RELOC_8:
         bfd_set_error (bfd_error_bad_value);
         return;
       }
    }

  /* The function adjust_reloc_syms won't convert a reloc against a weak
     symbol into a reloc against a section, but bfd_install_relocation
     will screw up if the symbol is defined, so we have to adjust val here
     to avoid the screw up later.

     For ordinary relocs, this does not happen for ELF, since for ELF,
     bfd_install_relocation uses the "special function" field of the
     howto, and does not execute the code that needs to be undone, as long
     as the special function does not return bfd_reloc_continue.
     It can happen for GOT- and PLT-type relocs the way they are
     described in elf32-sh.c as they use bfd_elf_generic_reloc, but it
     doesn't matter here since those relocs don't use VAL; see below.  */
  if (OUTPUT_FLAVOR != bfd_target_elf_flavour
      && fixP->fx_addsy != NULL
      && S_IS_WEAK (fixP->fx_addsy))
    val -= S_GET_VALUE  (fixP->fx_addsy);

  if (SWITCH_TABLE (fixP))
    val -= S_GET_VALUE  (fixP->fx_subsy);

  max = min = 0;
  shift = 0;
  switch (fixP->fx_r_type)
    {
    case BFD_RELOC_SH_IMM3:
      max = 0x7;
      * buf = (* buf & 0xf8) | (val & 0x7);
      break;
    case BFD_RELOC_SH_IMM3U:
      max = 0x7;
      * buf = (* buf & 0x8f) | ((val & 0x7) << 4);
      break;
    case BFD_RELOC_SH_DISP12:
      max = 0xfff;
      buf[lowbyte] = val & 0xff;
      buf[highbyte] |= (val >> 8) & 0x0f;
      break;
    case BFD_RELOC_SH_DISP12BY2:
      max = 0xfff;
      shift = 1;
      buf[lowbyte] = (val >> 1) & 0xff;
      buf[highbyte] |= (val >> 9) & 0x0f;
      break;
    case BFD_RELOC_SH_DISP12BY4:
      max = 0xfff;
      shift = 2;
      buf[lowbyte] = (val >> 2) & 0xff;
      buf[highbyte] |= (val >> 10) & 0x0f;
      break;
    case BFD_RELOC_SH_DISP12BY8:
      max = 0xfff;
      shift = 3;
      buf[lowbyte] = (val >> 3) & 0xff;
      buf[highbyte] |= (val >> 11) & 0x0f;
      break;
    case BFD_RELOC_SH_DISP20:
      if (! target_big_endian)
       abort();
      max = 0x7ffff;
      min = -0x80000;
      buf[1] = (buf[1] & 0x0f) | ((val >> 12) & 0xf0);
      buf[2] = (val >> 8) & 0xff;
      buf[3] = val & 0xff;
      break;
    case BFD_RELOC_SH_DISP20BY8:
      if (!target_big_endian)
       abort();
      max = 0x7ffff;
      min = -0x80000;
      shift = 8;
      buf[1] = (buf[1] & 0x0f) | ((val >> 20) & 0xf0);
      buf[2] = (val >> 16) & 0xff;
      buf[3] = (val >> 8) & 0xff;
      break;

    case BFD_RELOC_SH_IMM4:
      max = 0xf;
      *buf = (*buf & 0xf0) | (val & 0xf);
      break;

    case BFD_RELOC_SH_IMM4BY2:
      max = 0xf;
      shift = 1;
      *buf = (*buf & 0xf0) | ((val >> 1) & 0xf);
      break;

    case BFD_RELOC_SH_IMM4BY4:
      max = 0xf;
      shift = 2;
      *buf = (*buf & 0xf0) | ((val >> 2) & 0xf);
      break;

    case BFD_RELOC_SH_IMM8BY2:
      max = 0xff;
      shift = 1;
      *buf = val >> 1;
      break;

    case BFD_RELOC_SH_IMM8BY4:
      max = 0xff;
      shift = 2;
      *buf = val >> 2;
      break;

    case BFD_RELOC_8:
    case BFD_RELOC_SH_IMM8:
      /* Sometimes the 8 bit value is sign extended (e.g., add) and
         sometimes it is not (e.g., and).  We permit any 8 bit value.
         Note that adding further restrictions may invalidate
         reasonable looking assembly code, such as ``and -0x1,r0''.  */
      max = 0xff;
      min = -0xff;
      *buf++ = val;
      break;

    case BFD_RELOC_SH_PCRELIMM8BY4:
      /* The lower two bits of the PC are cleared before the
         displacement is added in.  We can assume that the destination
         is on a 4 byte boundary.  If this instruction is also on a 4
         byte boundary, then we want
          (target - here) / 4
        and target - here is a multiple of 4.
        Otherwise, we are on a 2 byte boundary, and we want
          (target - (here - 2)) / 4
        and target - here is not a multiple of 4.  Computing
          (target - (here - 2)) / 4 == (target - here + 2) / 4
        works for both cases, since in the first case the addition of
        2 will be removed by the division.  target - here is in the
        variable val.  */
      val = (val + 2) / 4;
      if (val & ~0xff)
       as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far"));
      buf[lowbyte] = val;
      break;

    case BFD_RELOC_SH_PCRELIMM8BY2:
      val /= 2;
      if (val & ~0xff)
       as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far"));
      buf[lowbyte] = val;
      break;

    case BFD_RELOC_SH_PCDISP8BY2:
      val /= 2;
      if (val < -0x80 || val > 0x7f)
       as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far"));
      buf[lowbyte] = val;
      break;

    case BFD_RELOC_SH_PCDISP12BY2:
      val /= 2;
      if (val < -0x800 || val > 0x7ff)
       as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far"));
      buf[lowbyte] = val & 0xff;
      buf[highbyte] |= (val >> 8) & 0xf;
      break;

    case BFD_RELOC_32:
    case BFD_RELOC_32_PCREL:
      apply_full_field_fix (fixP, buf, val, 4);
      break;

    case BFD_RELOC_16:
      apply_full_field_fix (fixP, buf, val, 2);
      break;

    case BFD_RELOC_SH_USES:
      /* Pass the value into sh_reloc().  */
      fixP->fx_addnumber = val;
      break;

    case BFD_RELOC_SH_COUNT:
    case BFD_RELOC_SH_ALIGN:
    case BFD_RELOC_SH_CODE:
    case BFD_RELOC_SH_DATA:
    case BFD_RELOC_SH_LABEL:
      /* Nothing to do here.  */
      break;

    case BFD_RELOC_SH_LOOP_START:
    case BFD_RELOC_SH_LOOP_END:

    case BFD_RELOC_VTABLE_INHERIT:
    case BFD_RELOC_VTABLE_ENTRY:
      fixP->fx_done = 0;
      return;

#ifdef OBJ_ELF
    case BFD_RELOC_32_PLT_PCREL:
      /* Make the jump instruction point to the address of the operand.  At
        runtime we merely add the offset to the actual PLT entry.  */
      * valP = 0xfffffffc;
      val = fixP->fx_offset;
      if (fixP->fx_subsy)
       val -= S_GET_VALUE (fixP->fx_subsy);
      apply_full_field_fix (fixP, buf, val, 4);
      break;

    case BFD_RELOC_SH_GOTPC:
      /* This is tough to explain.  We end up with this one if we have
         operands that look like "_GLOBAL_OFFSET_TABLE_+[.-.L284]".
         The goal here is to obtain the absolute address of the GOT,
         and it is strongly preferable from a performance point of
         view to avoid using a runtime relocation for this.  There are
         cases where you have something like:

         .long       _GLOBAL_OFFSET_TABLE_+[.-.L66]

         and here no correction would be required.  Internally in the
         assembler we treat operands of this form as not being pcrel
         since the '.' is explicitly mentioned, and I wonder whether
         it would simplify matters to do it this way.  Who knows.  In
         earlier versions of the PIC patches, the pcrel_adjust field
         was used to store the correction, but since the expression is
         not pcrel, I felt it would be confusing to do it this way.  */
      * valP -= 1;
      apply_full_field_fix (fixP, buf, val, 4);
      break;

    case BFD_RELOC_SH_TLS_GD_32:
    case BFD_RELOC_SH_TLS_LD_32:
    case BFD_RELOC_SH_TLS_IE_32:
      S_SET_THREAD_LOCAL (fixP->fx_addsy);
      /* Fallthrough */
    case BFD_RELOC_32_GOT_PCREL:
    case BFD_RELOC_SH_GOTPLT32:
      * valP = 0; /* Fully resolved at runtime.  No addend.  */
      apply_full_field_fix (fixP, buf, 0, 4);
      break;

    case BFD_RELOC_SH_TLS_LDO_32:
    case BFD_RELOC_SH_TLS_LE_32:
      S_SET_THREAD_LOCAL (fixP->fx_addsy);
      /* Fallthrough */
    case BFD_RELOC_32_GOTOFF:
      apply_full_field_fix (fixP, buf, val, 4);
      break;
#endif

    default:
#ifdef HAVE_SH64
      shmedia_md_apply_fix (fixP, valP);
      return;
#else
      abort ();
#endif
    }

  if (shift != 0)
    {
      if ((val & ((1 << shift) - 1)) != 0)
       as_bad_where (fixP->fx_file, fixP->fx_line, _("misaligned offset"));
      if (val >= 0)
       val >>= shift;
      else
       val = ((val >> shift)
              | ((long) -1 & ~ ((long) -1 >> shift)));
    }
  if (max != 0 && (val < min || val > max))
    as_bad_where (fixP->fx_file, fixP->fx_line, _("offset out of range"));
  else if (max != 0)
    /* Stop the generic code from trying to overlow check the value as well.
       It may not have the correct value anyway, as we do not store val back
       into *valP.  */
    fixP->fx_no_overflow = 1;

  if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
    fixP->fx_done = 1;
}

Here is the call graph for this function:

void md_assemble ( char *  str)

Definition at line 2765 of file tc-sh.c.

{
  char *op_end;
  sh_operand_info operand[3];
  sh_opcode_info *opcode;
  unsigned int size = 0;
  char *initial_str = str;

#ifdef HAVE_SH64
  if (sh64_isa_mode == sh64_isa_shmedia)
    {
      shmedia_md_assemble (str);
      return;
    }
  else
    {
      /* If we've seen pseudo-directives, make sure any emitted data or
        frags are marked as data.  */
      if (!seen_insn)
       {
         sh64_update_contents_mark (TRUE);
         sh64_set_contents_type (CRT_SH5_ISA16);
       }

      seen_insn = TRUE;
    }
#endif /* HAVE_SH64 */

  opcode = find_cooked_opcode (&str);
  op_end = str;

  if (opcode == NULL)
    {
      /* The opcode is not in the hash table.
        This means we definitely have an assembly failure,
        but the instruction may be valid in another CPU variant.
        In this case emit something better than 'unknown opcode'.
        Search the full table in sh-opc.h to check. */

      char *name = initial_str;
      int name_length = 0;
      const sh_opcode_info *op;
      int found = 0;

      /* identify opcode in string */
      while (ISSPACE (*name))
       {
         name++;
       }
      while (!ISSPACE (name[name_length]))
       {
         name_length++;
       }

      /* search for opcode in full list */
      for (op = sh_table; op->name; op++)
       {
         if (strncasecmp (op->name, name, name_length) == 0
             && op->name[name_length] == '\0')
           {
             found = 1;
             break;
           }
       }

      if ( found )
       {
         as_bad (_("opcode not valid for this cpu variant"));
       }
      else
       {
         as_bad (_("unknown opcode"));
       }
      return;
    }

  if (sh_relax
      && ! seg_info (now_seg)->tc_segment_info_data.in_code)
    {
      /* Output a CODE reloc to tell the linker that the following
         bytes are instructions, not data.  */
      fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0,
              BFD_RELOC_SH_CODE);
      seg_info (now_seg)->tc_segment_info_data.in_code = 1;
    }

  if (opcode->nibbles[0] == PPI)
    {
      size = assemble_ppi (op_end, opcode);
    }
  else
    {
      if (opcode->arg[0] == A_BDISP12
         || opcode->arg[0] == A_BDISP8)
       {
         /* Since we skip get_specific here, we have to check & update
            valid_arch now.  */
         if (SH_MERGE_ARCH_SET_VALID (valid_arch, opcode->arch))
           valid_arch = SH_MERGE_ARCH_SET (valid_arch, opcode->arch);
         else
           as_bad (_("Delayed branches not available on SH1"));
         parse_exp (op_end + 1, &operand[0]);
         build_relax (opcode, &operand[0]);

         /* All branches are currently 16 bit.  */
         size = 2;
       }
      else
       {
         if (opcode->arg[0] == A_END)
           {
             /* Ignore trailing whitespace.  If there is any, it has already
               been compressed to a single space.  */
             if (*op_end == ' ')
              op_end++;
           }
         else
           {
             op_end = get_operands (opcode, op_end, operand);
           }
         opcode = get_specific (opcode, operand);

         if (opcode == 0)
           {
             /* Couldn't find an opcode which matched the operands.  */
             char *where = frag_more (2);
             size = 2;

             where[0] = 0x0;
             where[1] = 0x0;
             as_bad (_("invalid operands for opcode"));
           }
         else
           {
             if (*op_end)
              as_bad (_("excess operands: '%s'"), op_end);

             size = build_Mytes (opcode, operand);
           }
       }
    }

  dwarf2_emit_insn (size);
}

Here is the call graph for this function:

char* md_atof ( int type  ,
char *  litP,
int sizeP 
)

Definition at line 2968 of file tc-sh.c.

{
  int prec;
  LITTLENUM_TYPE words[4];
  char *t;
  int i;

  switch (type)
    {
    case 'f':
      prec = 2;
      break;

    case 'd':
      prec = 4;
      break;

    default:
      *sizeP = 0;
      return _("bad call to md_atof");
    }

  t = atof_ieee (input_line_pointer, type, words);
  if (t)
    input_line_pointer = t;

  *sizeP = prec * 2;

  if (! target_big_endian)
    {
      for (i = prec - 1; i >= 0; i--)
       {
         md_number_to_chars (litP, (valueT) words[i], 2);
         litP += 2;
       }
    }
  else
    {
      for (i = 0; i < prec; i++)
       {
         md_number_to_chars (litP, (valueT) words[i], 2);
         litP += 2;
       }
    }

  return NULL;
}

Here is the call graph for this function:

void md_begin ( void  )

Definition at line 835 of file tc-sh.c.

{
  const sh_opcode_info *opcode;
  char *prev_name = "";
  unsigned int target_arch;

  target_arch
    = preset_target_arch ? preset_target_arch : arch_sh_up & ~arch_sh_has_dsp;
  valid_arch = target_arch;

#ifdef HAVE_SH64
  shmedia_md_begin ();
#endif

  opcode_hash_control = hash_new ();

  /* Insert unique names into hash table.  */
  for (opcode = sh_table; opcode->name; opcode++)
    {
      if (strcmp (prev_name, opcode->name) != 0)
       {
         if (!SH_MERGE_ARCH_SET_VALID (opcode->arch, target_arch))
           continue;
         prev_name = opcode->name;
         hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
       }
    }
}

Here is the call graph for this function:

void md_convert_frag ( bfd *headers  ATTRIBUTE_UNUSED,
segT seg  ,
fragS *  fragP 
)

Definition at line 3445 of file tc-sh.c.

{
  int donerelax = 0;

  switch (fragP->fr_subtype)
    {
    case C (COND_JUMP, COND8):
    case C (COND_JUMP_DELAY, COND8):
      subseg_change (seg, 0);
      fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
              1, BFD_RELOC_SH_PCDISP8BY2);
      fragP->fr_fix += 2;
      fragP->fr_var = 0;
      break;

    case C (UNCOND_JUMP, UNCOND12):
      subseg_change (seg, 0);
      fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
              1, BFD_RELOC_SH_PCDISP12BY2);
      fragP->fr_fix += 2;
      fragP->fr_var = 0;
      break;

    case C (UNCOND_JUMP, UNCOND32):
    case C (UNCOND_JUMP, UNDEF_WORD_DISP):
      if (fragP->fr_symbol == NULL)
       as_bad_where (fragP->fr_file, fragP->fr_line,
                    _("displacement overflows 12-bit field"));
      else if (S_IS_DEFINED (fragP->fr_symbol))
       as_bad_where (fragP->fr_file, fragP->fr_line,
                    _("displacement to defined symbol %s overflows 12-bit field"),
                    S_GET_NAME (fragP->fr_symbol));
      else
       as_bad_where (fragP->fr_file, fragP->fr_line,
                    _("displacement to undefined symbol %s overflows 12-bit field"),
                    S_GET_NAME (fragP->fr_symbol));
      /* Stabilize this frag, so we don't trip an assert.  */
      fragP->fr_fix += fragP->fr_var;
      fragP->fr_var = 0;
      break;

    case C (COND_JUMP, COND12):
    case C (COND_JUMP_DELAY, COND12):
      /* A bcond won't fit, so turn it into a b!cond; bra disp; nop.  */
      /* I found that a relax failure for gcc.c-torture/execute/930628-1.c
        was due to gas incorrectly relaxing an out-of-range conditional
        branch with delay slot.  It turned:
                     bf.s    L6              (slot mov.l   r12,@(44,r0))
         into:

2c:  8f 01 a0 8b     bf.s    32 <_main+32>   (slot bra       L6)
30:  00 09           nop
32:  10 cb           mov.l   r12,@(44,r0)
         Therefore, branches with delay slots have to be handled
        differently from ones without delay slots.  */
      {
       unsigned char *buffer =
         (unsigned char *) (fragP->fr_fix + fragP->fr_literal);
       int highbyte = target_big_endian ? 0 : 1;
       int lowbyte = target_big_endian ? 1 : 0;
       int delay = fragP->fr_subtype == C (COND_JUMP_DELAY, COND12);

       /* Toggle the true/false bit of the bcond.  */
       buffer[highbyte] ^= 0x2;

       /* If this is a delayed branch, we may not put the bra in the
          slot.  So we change it to a non-delayed branch, like that:
          b! cond slot_label; bra disp; slot_label: slot_insn
          ??? We should try if swapping the conditional branch and
          its delay-slot insn already makes the branch reach.  */

       /* Build a relocation to six / four bytes farther on.  */
       subseg_change (seg, 0);
       fix_new (fragP, fragP->fr_fix, 2, section_symbol (seg),
               fragP->fr_address + fragP->fr_fix + (delay ? 4 : 6),
               1, BFD_RELOC_SH_PCDISP8BY2);

       /* Set up a jump instruction.  */
       buffer[highbyte + 2] = 0xa0;
       buffer[lowbyte + 2] = 0;
       fix_new (fragP, fragP->fr_fix + 2, 2, fragP->fr_symbol,
               fragP->fr_offset, 1, BFD_RELOC_SH_PCDISP12BY2);

       if (delay)
         {
           buffer[highbyte] &= ~0x4; /* Removes delay slot from branch.  */
           fragP->fr_fix += 4;
         }
       else
         {
           /* Fill in a NOP instruction.  */
           buffer[highbyte + 4] = 0x0;
           buffer[lowbyte + 4] = 0x9;

           fragP->fr_fix += 6;
         }
       fragP->fr_var = 0;
       donerelax = 1;
      }
      break;

    case C (COND_JUMP, COND32):
    case C (COND_JUMP_DELAY, COND32):
    case C (COND_JUMP, UNDEF_WORD_DISP):
    case C (COND_JUMP_DELAY, UNDEF_WORD_DISP):
      if (fragP->fr_symbol == NULL)
       as_bad_where (fragP->fr_file, fragP->fr_line,
                    _("displacement overflows 8-bit field"));
      else if (S_IS_DEFINED (fragP->fr_symbol))
       as_bad_where (fragP->fr_file, fragP->fr_line,
                    _("displacement to defined symbol %s overflows 8-bit field"),
                    S_GET_NAME (fragP->fr_symbol));
      else
       as_bad_where (fragP->fr_file, fragP->fr_line,
                    _("displacement to undefined symbol %s overflows 8-bit field "),
                    S_GET_NAME (fragP->fr_symbol));
      /* Stabilize this frag, so we don't trip an assert.  */
      fragP->fr_fix += fragP->fr_var;
      fragP->fr_var = 0;
      break;

    default:
#ifdef HAVE_SH64
      shmedia_md_convert_frag (headers, seg, fragP, TRUE);
#else
      abort ();
#endif
    }

  if (donerelax && !sh_relax)
    as_warn_where (fragP->fr_file, fragP->fr_line,
                 _("overflow in branch to %s; converted into longer instruction sequence"),
                 (fragP->fr_symbol != NULL
                  ? S_GET_NAME (fragP->fr_symbol)
                  : ""));
}

Here is the call graph for this function:

int md_estimate_size_before_relax ( fragS *  fragP,
segT  segment_type 
)

Definition at line 4140 of file tc-sh.c.

{
  int what;

  switch (fragP->fr_subtype)
    {
    default:
#ifdef HAVE_SH64
      return shmedia_md_estimate_size_before_relax (fragP, segment_type);
#else
      abort ();
#endif


    case C (UNCOND_JUMP, UNDEF_DISP):
      /* Used to be a branch to somewhere which was unknown.  */
      if (!fragP->fr_symbol)
       {
         fragP->fr_subtype = C (UNCOND_JUMP, UNCOND12);
       }
      else if (S_GET_SEGMENT (fragP->fr_symbol) == segment_type)
       {
         fragP->fr_subtype = C (UNCOND_JUMP, UNCOND12);
       }
      else
       {
         fragP->fr_subtype = C (UNCOND_JUMP, UNDEF_WORD_DISP);
       }
      break;

    case C (COND_JUMP, UNDEF_DISP):
    case C (COND_JUMP_DELAY, UNDEF_DISP):
      what = GET_WHAT (fragP->fr_subtype);
      /* Used to be a branch to somewhere which was unknown.  */
      if (fragP->fr_symbol
         && S_GET_SEGMENT (fragP->fr_symbol) == segment_type)
       {
         /* Got a symbol and it's defined in this segment, become byte
            sized - maybe it will fix up.  */
         fragP->fr_subtype = C (what, COND8);
       }
      else if (fragP->fr_symbol)
       {
         /* Its got a segment, but its not ours, so it will always be long.  */
         fragP->fr_subtype = C (what, UNDEF_WORD_DISP);
       }
      else
       {
         /* We know the abs value.  */
         fragP->fr_subtype = C (what, COND8);
       }
      break;

    case C (UNCOND_JUMP, UNCOND12):
    case C (UNCOND_JUMP, UNCOND32):
    case C (UNCOND_JUMP, UNDEF_WORD_DISP):
    case C (COND_JUMP, COND8):
    case C (COND_JUMP, COND12):
    case C (COND_JUMP, COND32):
    case C (COND_JUMP, UNDEF_WORD_DISP):
    case C (COND_JUMP_DELAY, COND8):
    case C (COND_JUMP_DELAY, COND12):
    case C (COND_JUMP_DELAY, COND32):
    case C (COND_JUMP_DELAY, UNDEF_WORD_DISP):
      /* When relaxing a section for the second time, we don't need to
        do anything besides return the current size.  */
      break;
    }

  fragP->fr_var = md_relax_table[fragP->fr_subtype].rlx_length;
  return fragP->fr_var;
}

Here is the call graph for this function:

void md_number_to_chars ( char *  ptr,
valueT  use,
int  nbytes 
)

Definition at line 4216 of file tc-sh.c.

{
#ifdef HAVE_SH64
  /* We might need to set the contents type to data.  */
  sh64_flag_output ();
#endif

  if (! target_big_endian)
    number_to_chars_littleendian (ptr, use, nbytes);
  else
    number_to_chars_bigendian (ptr, use, nbytes);
}

Here is the call graph for this function:

int md_parse_option ( int c  ,
char *arg  ATTRIBUTE_UNUSED 
)

Definition at line 3092 of file tc-sh.c.

{
  switch (c)
    {
    case OPTION_RELAX:
      sh_relax = 1;
      break;

    case OPTION_BIG:
      target_big_endian = 1;
      break;

    case OPTION_LITTLE:
      target_big_endian = 0;
      break;

    case OPTION_SMALL:
      sh_small = 1;
      break;

    case OPTION_DSP:
      preset_target_arch = arch_sh_up & ~(arch_sh_sp_fpu|arch_sh_dp_fpu);
      break;

    case OPTION_RENESAS:
      dont_adjust_reloc_32 = 1;
      break;

    case OPTION_ALLOW_REG_PREFIX:
      allow_dollar_register_prefix = 1;
      break;

    case OPTION_ISA:
      if (strcasecmp (arg, "dsp") == 0)
       preset_target_arch = arch_sh_up & ~(arch_sh_sp_fpu|arch_sh_dp_fpu);
      else if (strcasecmp (arg, "fp") == 0)
       preset_target_arch = arch_sh_up & ~arch_sh_has_dsp;
      else if (strcasecmp (arg, "any") == 0)
       preset_target_arch = arch_sh_up;
#ifdef HAVE_SH64
      else if (strcasecmp (arg, "shmedia") == 0)
       {
         if (sh64_isa_mode == sh64_isa_shcompact)
           as_bad (_("Invalid combination: --isa=SHcompact with --isa=SHmedia"));
         sh64_isa_mode = sh64_isa_shmedia;
       }
      else if (strcasecmp (arg, "shcompact") == 0)
       {
         if (sh64_isa_mode == sh64_isa_shmedia)
           as_bad (_("Invalid combination: --isa=SHmedia with --isa=SHcompact"));
         if (sh64_abi == sh64_abi_64)
           as_bad (_("Invalid combination: --abi=64 with --isa=SHcompact"));
         sh64_isa_mode = sh64_isa_shcompact;
       }
#endif /* HAVE_SH64 */
      else
       {
         extern const bfd_arch_info_type bfd_sh_arch;
         bfd_arch_info_type const *bfd_arch = &bfd_sh_arch;

         preset_target_arch = 0;
         for (; bfd_arch; bfd_arch=bfd_arch->next)
           {
             int len = strlen(bfd_arch->printable_name);
             
             if (bfd_arch->mach == bfd_mach_sh5)
              continue;
             
             if (strncasecmp (bfd_arch->printable_name, arg, len) != 0)
              continue;

             if (arg[len] == '\0')
              preset_target_arch =
                sh_get_arch_from_bfd_mach (bfd_arch->mach);
             else if (strcasecmp(&arg[len], "-up") == 0)
              preset_target_arch =
                sh_get_arch_up_from_bfd_mach (bfd_arch->mach);
             else
              continue;
             break;
           }
         
         if (!preset_target_arch)
           as_bad ("Invalid argument to --isa option: %s", arg);
       }
      break;

#ifdef HAVE_SH64
    case OPTION_ABI:
      if (strcmp (arg, "32") == 0)
       {
         if (sh64_abi == sh64_abi_64)
           as_bad (_("Invalid combination: --abi=32 with --abi=64"));
         sh64_abi = sh64_abi_32;
       }
      else if (strcmp (arg, "64") == 0)
       {
         if (sh64_abi == sh64_abi_32)
           as_bad (_("Invalid combination: --abi=64 with --abi=32"));
         if (sh64_isa_mode == sh64_isa_shcompact)
           as_bad (_("Invalid combination: --isa=SHcompact with --abi=64"));
         sh64_abi = sh64_abi_64;
       }
      else
       as_bad ("Invalid argument to --abi option: %s", arg);
      break;

    case OPTION_NO_MIX:
      sh64_mix = FALSE;
      break;

    case OPTION_SHCOMPACT_CONST_CRANGE:
      sh64_shcompact_const_crange = TRUE;
      break;

    case OPTION_NO_EXPAND:
      sh64_expand = FALSE;
      break;

    case OPTION_PT32:
      sh64_pt32 = TRUE;
      break;
#endif /* HAVE_SH64 */

    default:
      return 0;
    }

  return 1;
}

Here is the call graph for this function:

long md_pcrel_from ( fixS *  fixP)

Definition at line 4232 of file tc-sh.c.

{
  return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address + 2;
}
long md_pcrel_from_section ( fixS *  fixP,
segT sec   
)

Definition at line 4238 of file tc-sh.c.

{
  if (! sh_local_pcrel (fixP)
      && fixP->fx_addsy != (symbolS *) NULL
      && (generic_force_reloc (fixP)
         || S_GET_SEGMENT (fixP->fx_addsy) != sec))
    {
      /* The symbol is undefined (or is defined but not in this section,
        or we're not sure about it being the final definition).  Let the
        linker figure it out.  We need to adjust the subtraction of a
        symbol to the position of the relocated data, though.  */
      return fixP->fx_subsy ? fixP->fx_where + fixP->fx_frag->fr_address : 0;
    }

  return md_pcrel_from (fixP);
}

Here is the call graph for this function:

valueT md_section_align ( segT seg  ATTRIBUTE_UNUSED,
valueT  size 
)

Definition at line 3583 of file tc-sh.c.

{
#ifdef OBJ_ELF
  return size;
#else /* ! OBJ_ELF */
  return ((size + (1 << bfd_get_section_alignment (stdoutput, seg)) - 1)
         & (-1 << bfd_get_section_alignment (stdoutput, seg)));
#endif /* ! OBJ_ELF */
}
void md_show_usage ( FILE *  stream)

Definition at line 3224 of file tc-sh.c.

{
  fprintf (stream, _("\
SH options:\n\
--little             generate little endian code\n\
--big                generate big endian code\n\
--relax                     alter jump instructions for long displacements\n\
--renesas            disable optimization with section symbol for\n\
                     compatibility with Renesas assembler.\n\
--small                     align sections to 4 byte boundaries, not 16\n\
--dsp                enable sh-dsp insns, and disable floating-point ISAs.\n\
--allow-reg-prefix   allow '$' as a register name prefix.\n\
--isa=[any           use most appropriate isa\n\
    | dsp               same as '-dsp'\n\
    | fp"));
  {
    extern const bfd_arch_info_type bfd_sh_arch;
    bfd_arch_info_type const *bfd_arch = &bfd_sh_arch;

    for (; bfd_arch; bfd_arch=bfd_arch->next)
      if (bfd_arch->mach != bfd_mach_sh5)
       {
         fprintf (stream, "\n    | %s", bfd_arch->printable_name);
         fprintf (stream, "\n    | %s-up", bfd_arch->printable_name);
       }
  }
  fprintf (stream, "]\n");
#ifdef HAVE_SH64
  fprintf (stream, _("\
--isa=[shmedia              set as the default instruction set for SH64\n\
    | SHmedia\n\
    | shcompact\n\
    | SHcompact]\n"));
  fprintf (stream, _("\
--abi=[32|64]        set size of expanded SHmedia operands and object\n\
                     file type\n\
--shcompact-const-crange  emit code-range descriptors for constants in\n\
                     SHcompact code sections\n\
--no-mix             disallow SHmedia code in the same section as\n\
                     constants and SHcompact code\n\
--no-expand          do not expand MOVI, PT, PTA or PTB instructions\n\
--expand-pt32        with -abi=64, expand PT, PTA and PTB instructions\n\
                     to 32 bits only\n"));
#endif /* HAVE_SH64 */
}

Here is the call graph for this function:

symbolS* md_undefined_symbol ( char *name  ATTRIBUTE_UNUSED)

Definition at line 2953 of file tc-sh.c.

{
  return 0;
}
static char* parse_at ( char *  src,
sh_operand_info op 
) [static]

Definition at line 1302 of file tc-sh.c.

{
  int len;
  int mode;
  src++;
  if (src[0] == '@')
    {
      src = parse_at (src, op);
      if (op->type == A_DISP_TBR)
       op->type = A_DISP2_TBR;
      else
       as_bad (_("illegal double indirection"));
    }
  else if (src[0] == '-')
    {
      /* Must be predecrement.  */
      src++;

      len = parse_reg (src, &mode, &(op->reg));
      if (mode != A_REG_N)
       as_bad (_("illegal register after @-"));

      op->type = A_DEC_N;
      src += len;
    }
  else if (src[0] == '(')
    {
      /* Could be @(disp, rn), @(disp, gbr), @(disp, pc),  @(r0, gbr) or
         @(r0, rn).  */
      src++;
      len = parse_reg (src, &mode, &(op->reg));
      if (len && mode == A_REG_N)
       {
         src += len;
         if (op->reg != 0)
           {
             as_bad (_("must be @(r0,...)"));
           }
         if (src[0] == ',')
           {
             src++;
             /* Now can be rn or gbr.  */
             len = parse_reg (src, &mode, &(op->reg));
           }
         else
           {
             len = 0;
           }
         if (len)
           {
             if (mode == A_GBR)
              {
                op->type = A_R0_GBR;
              }
             else if (mode == A_REG_N)
              {
                op->type = A_IND_R0_REG_N;
              }
             else
              {
                as_bad (_("syntax error in @(r0,...)"));
              }
           }
         else
           {
             as_bad (_("syntax error in @(r0...)"));
           }
       }
      else
       {
         /* Must be an @(disp,.. thing).  */
         src = parse_exp (src, op);
         if (src[0] == ',')
           src++;
         /* Now can be rn, gbr or pc.  */
         len = parse_reg (src, &mode, &op->reg);
         if (len)
           {
             if (mode == A_REG_N)
              {
                op->type = A_DISP_REG_N;
              }
             else if (mode == A_GBR)
              {
                op->type = A_DISP_GBR;
              }
             else if (mode == A_TBR)
              {
                op->type = A_DISP_TBR;
              }
             else if (mode == A_PC)
              {
                /* We want @(expr, pc) to uniformly address . + expr,
                   no matter if expr is a constant, or a more complex
                   expression, e.g. sym-. or sym1-sym2.
                   However, we also used to accept @(sym,pc)
                   as addressing sym, i.e. meaning the same as plain sym.
                   Some existing code does use the @(sym,pc) syntax, so
                   we give it the old semantics for now, but warn about
                   its use, so that users have some time to fix their code.

                   Note that due to this backward compatibility hack,
                   we'll get unexpected results when @(offset, pc) is used,
                   and offset is a symbol that is set later to an an address
                   difference, or an external symbol that is set to an
                   address difference in another source file, so we want to
                   eventually remove it.  */
                if (op->immediate.X_op == O_symbol)
                  {
                    op->type = A_DISP_PC;
                    as_warn (_("Deprecated syntax."));
                  }
                else
                  {
                    op->type = A_DISP_PC_ABS;
                    /* Such operands don't get corrected for PC==.+4, so
                      make the correction here.  */
                    op->immediate.X_add_number -= 4;
                  }
              }
             else
              {
                as_bad (_("syntax error in @(disp,[Rn, gbr, pc])"));
              }
           }
         else
           {
             as_bad (_("syntax error in @(disp,[Rn, gbr, pc])"));
           }
       }
      src += len;
      if (src[0] != ')')
       as_bad (_("expecting )"));
      else
       src++;
    }
  else
    {
      src += parse_reg (src, &mode, &(op->reg));
      if (mode != A_REG_N)
       as_bad (_("illegal register after @"));

      if (src[0] == '+')
       {
         char l0, l1;

         src++;
         l0 = TOLOWER (src[0]);
         l1 = TOLOWER (src[1]);

         if ((l0 == 'r' && l1 == '8')
             || (l0 == 'i' && (l1 == 'x' || l1 == 's')))
           {
             src += 2;
             op->type = AX_PMOD_N;
           }
         else if (   (l0 == 'r' && l1 == '9')
                 || (l0 == 'i' && l1 == 'y'))
           {
             src += 2;
             op->type = AY_PMOD_N;
           }
         else
           op->type = A_INC_N;
       }
      else
       op->type = A_IND_N;
    }
  return src;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static char* parse_exp ( char *  s,
sh_operand_info op 
) [static]

Definition at line 1261 of file tc-sh.c.

{
  char *save;
  char *new;

  save = input_line_pointer;
  input_line_pointer = s;
  expression (&op->immediate);
  if (op->immediate.X_op == O_absent)
    as_bad (_("missing operand"));
#ifdef OBJ_ELF
  else if (op->immediate.X_op == O_PIC_reloc
          || sh_PIC_related_p (op->immediate.X_add_symbol)
          || sh_PIC_related_p (op->immediate.X_op_symbol))
    as_bad (_("misplaced PIC operand"));
#endif
  new = input_line_pointer;
  input_line_pointer = save;
  return new;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static unsigned int parse_reg ( char *  src,
int mode,
int reg 
) [static]

Definition at line 1234 of file tc-sh.c.

{
  unsigned int prefix;
  unsigned int consumed;

  if (src[0] == '$')
    {
      if (allow_dollar_register_prefix)
       {
         src ++;
         prefix = 1;
       }
      else
       return 0;
    }
  else
    prefix = 0;
  
  consumed = parse_reg_without_prefix (src, mode, reg);

  if (consumed == 0)
    return 0;

  return consumed + prefix;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static unsigned int parse_reg_without_prefix ( char *  src,
int mode,
int reg 
) [static]

Definition at line 875 of file tc-sh.c.

{
  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]))
           {
             *mode = DSP_REG_N;
             *reg = A_A1G_NUM;
             return 3;
           }
       }

      if (l1 == 'x' && src[2] >= '0' && src[2] <= '1'
         && ! IDENT_CHAR ((unsigned char) src[3]))
       {
         *mode = A_REG_N;
         *reg = 4 + (l1 - '0');
         return 3;
       }
      if (l1 == 'y' && src[2] >= '0' && src[2] <= '1'
         && ! IDENT_CHAR ((unsigned char) src[3]))
       {
         *mode = A_REG_N;
         *reg = 6 + (l1 - '0');
         return 3;
       }
      if (l1 == 's' && src[2] >= '0' && src[2] <= '3'
         && ! IDENT_CHAR ((unsigned char) src[3]))
       {
         int n = l1 - '0';

         *mode = A_REG_N;
         *reg = n | ((~n & 2) << 1);
         return 3;
       }
    }

  if (l0 == 'i' && l1 && ! IDENT_CHAR ((unsigned char) src[2]))
    {
      if (l1 == 's')
       {
         *mode = A_REG_N;
         *reg = 8;
         return 2;
       }
      if (l1 == 'x')
       {
         *mode = A_REG_N;
         *reg = 8;
         return 2;
       }
      if (l1 == 'y')
       {
         *mode = A_REG_N;
         *reg = 9;
         return 2;
       }
    }

  if (l0 == 'x' && l1 >= '0' && l1 <= '1'
      && ! IDENT_CHAR ((unsigned char) src[2]))
    {
      *mode = DSP_REG_N;
      *reg = A_X0_NUM + l1 - '0';
      return 2;
    }

  if (l0 == 'y' && l1 >= '0' && l1 <= '1'
      && ! IDENT_CHAR ((unsigned char) src[2]))
    {
      *mode = DSP_REG_N;
      *reg = A_Y0_NUM + l1 - '0';
      return 2;
    }

  if (l0 == 'm' && l1 >= '0' && l1 <= '1'
      && ! IDENT_CHAR ((unsigned char) src[2]))
    {
      *mode = DSP_REG_N;
      *reg = l1 == '0' ? A_M0_NUM : A_M1_NUM;
      return 2;
    }

  if (l0 == 's'
      && l1 == 's'
      && TOLOWER (src[2]) == 'r' && ! IDENT_CHAR ((unsigned char) src[3]))
    {
      *mode = A_SSR;
      return 3;
    }

  if (l0 == 's' && l1 == 'p' && TOLOWER (src[2]) == 'c'
      && ! IDENT_CHAR ((unsigned char) src[3]))
    {
      *mode = A_SPC;
      return 3;
    }

  if (l0 == 's' && l1 == 'g' && TOLOWER (src[2]) == 'r'
      && ! IDENT_CHAR ((unsigned char) src[3]))
    {
      *mode = A_SGR;
      return 3;
    }

  if (l0 == 'd' && l1 == 's' && TOLOWER (src[2]) == 'r'
      && ! IDENT_CHAR ((unsigned char) src[3]))
    {
      *mode = A_DSR;
      return 3;
    }

  if (l0 == 'd' && l1 == 'b' && TOLOWER (src[2]) == 'r'
      && ! IDENT_CHAR ((unsigned char) src[3]))
    {
      *mode = A_DBR;
      return 3;
    }

  if (l0 == 's' && l1 == 'r' && ! IDENT_CHAR ((unsigned char) src[2]))
    {
      *mode = A_SR;
      return 2;
    }

  if (l0 == 's' && l1 == 'p' && ! IDENT_CHAR ((unsigned char) src[2]))
    {
      *mode = A_REG_N;
      *reg = 15;
      return 2;
    }

  if (l0 == 'p' && l1 == 'r' && ! IDENT_CHAR ((unsigned char) src[2]))
    {
      *mode = A_PR;
      return 2;
    }
  if (l0 == 'p' && l1 == 'c' && ! IDENT_CHAR ((unsigned char) src[2]))
    {
      /* Don't use A_DISP_PC here - that would accept stuff like 'mova pc,r0'
         and use an uninitialized immediate.  */
      *mode = A_PC;
      return 2;
    }
  if (l0 == 'g' && l1 == 'b' && TOLOWER (src[2]) == 'r'
      && ! IDENT_CHAR ((unsigned char) src[3]))
    {
      *mode = A_GBR;
      return 3;
    }
  if (l0 == 'v' && l1 == 'b' && TOLOWER (src[2]) == 'r'
      && ! IDENT_CHAR ((unsigned char) src[3]))
    {
      *mode = A_VBR;
      return 3;
    }

  if (l0 == 't' && l1 == 'b' && TOLOWER (src[2]) == 'r'
      && ! IDENT_CHAR ((unsigned char) src[3]))
    {
      *mode = A_TBR;
      return 3;
    }
  if (l0 == 'm' && l1 == 'a' && TOLOWER (src[2]) == 'c'
      && ! IDENT_CHAR ((unsigned char) src[4]))
    {
      if (TOLOWER (src[3]) == 'l')
       {
         *mode = A_MACL;
         return 4;
       }
      if (TOLOWER (src[3]) == 'h')
       {
         *mode = A_MACH;
         return 4;
       }
    }
  if (l0 == 'm' && l1 == 'o' && TOLOWER (src[2]) == 'd'
      && ! IDENT_CHAR ((unsigned char) src[3]))
    {
      *mode = A_MOD;
      return 3;
    }
  if (l0 == 'f' && l1 == 'r')
    {
      if (src[2] == '1')
       {
         if (src[3] >= '0' && src[3] <= '5'
             && ! IDENT_CHAR ((unsigned char) src[4]))
           {
             *mode = F_REG_N;
             *reg = 10 + src[3] - '0';
             return 4;
           }
       }
      if (src[2] >= '0' && src[2] <= '9'
         && ! IDENT_CHAR ((unsigned char) src[3]))
       {
         *mode = F_REG_N;
         *reg = (src[2] - '0');
         return 3;
       }
    }
  if (l0 == 'd' && l1 == 'r')
    {
      if (src[2] == '1')
       {
         if (src[3] >= '0' && src[3] <= '4' && ! ((src[3] - '0') & 1)
             && ! IDENT_CHAR ((unsigned char) src[4]))
           {
             *mode = D_REG_N;
             *reg = 10 + src[3] - '0';
             return 4;
           }
       }
      if (src[2] >= '0' && src[2] <= '8' && ! ((src[2] - '0') & 1)
         && ! IDENT_CHAR ((unsigned char) src[3]))
       {
         *mode = D_REG_N;
         *reg = (src[2] - '0');
         return 3;
       }
    }
  if (l0 == 'x' && l1 == 'd')
    {
      if (src[2] == '1')
       {
         if (src[3] >= '0' && src[3] <= '4' && ! ((src[3] - '0') & 1)
             && ! IDENT_CHAR ((unsigned char) src[4]))
           {
             *mode = X_REG_N;
             *reg = 11 + src[3] - '0';
             return 4;
           }
       }
      if (src[2] >= '0' && src[2] <= '8' && ! ((src[2] - '0') & 1)
         && ! IDENT_CHAR ((unsigned char) src[3]))
       {
         *mode = X_REG_N;
         *reg = (src[2] - '0') + 1;
         return 3;
       }
    }
  if (l0 == 'f' && l1 == 'v')
    {
      if (src[2] == '1'&& src[3] == '2' && ! IDENT_CHAR ((unsigned char) src[4]))
       {
         *mode = V_REG_N;
         *reg = 12;
         return 4;
       }
      if ((src[2] == '0' || src[2] == '4' || src[2] == '8')
         && ! IDENT_CHAR ((unsigned char) src[3]))
       {
         *mode = V_REG_N;
         *reg = (src[2] - '0');
         return 3;
       }
    }
  if (l0 == 'f' && l1 == 'p' && TOLOWER (src[2]) == 'u'
      && TOLOWER (src[3]) == 'l'
      && ! IDENT_CHAR ((unsigned char) src[4]))
    {
      *mode = FPUL_N;
      return 4;
    }

  if (l0 == 'f' && l1 == 'p' && TOLOWER (src[2]) == 's'
      && TOLOWER (src[3]) == 'c'
      && TOLOWER (src[4]) == 'r' && ! IDENT_CHAR ((unsigned char) src[5]))
    {
      *mode = FPSCR_N;
      return 5;
    }

  if (l0 == 'x' && l1 == 'm' && TOLOWER (src[2]) == 't'
      && TOLOWER (src[3]) == 'r'
      && TOLOWER (src[4]) == 'x' && ! IDENT_CHAR ((unsigned char) src[5]))
    {
      *mode = XMTRX_M4;
      return 5;
    }

  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void s_uacons ( int  bytes) [static]

Definition at line 3603 of file tc-sh.c.

{
  /* Tell sh_cons_align not to align this value.  */
  sh_no_align_cons = 1;
  cons (bytes);
}

Here is the call graph for this function:

static void s_uses ( int  ) [static]
static void s_uses ( int ignore  ATTRIBUTE_UNUSED) [static]

Definition at line 3022 of file tc-sh.c.

{
  expressionS ex;

  if (! sh_relax)
    as_warn (_(".uses pseudo-op seen when not relaxing"));

  expression (&ex);

  if (ex.X_op != O_symbol || ex.X_add_number != 0)
    {
      as_bad (_("bad .uses format"));
      ignore_rest_of_line ();
      return;
    }

  fix_new_exp (frag_now, frag_now_fix (), 2, &ex, 1, BFD_RELOC_SH_USES);

  demand_empty_rest_of_line ();
}

Here is the call graph for this function:

void sh_cons_align ( int  nbytes)

Definition at line 3617 of file tc-sh.c.

{
  int nalign;
  char *p;

  if (sh_no_align_cons)
    {
      /* This is an unaligned pseudo-op.  */
      sh_no_align_cons = 0;
      return;
    }

  nalign = 0;
  while ((nbytes & 1) == 0)
    {
      ++nalign;
      nbytes >>= 1;
    }

  if (nalign == 0)
    return;

  if (now_seg == absolute_section)
    {
      if ((abs_section_offset & ((1 << nalign) - 1)) != 0)
       as_warn (_("misaligned data"));
      return;
    }

  p = frag_var (rs_align_test, 1, 1, (relax_substateT) 0,
              (symbolS *) NULL, (offsetT) nalign, (char *) NULL);

  record_alignment (now_seg, nalign);
}

Here is the call graph for this function:

static void sh_count_relocs ( bfd *abfd  ATTRIBUTE_UNUSED,
segT  sec,
void *  data 
) [static]

Definition at line 3285 of file tc-sh.c.

{
  struct sh_count_relocs *info = (struct sh_count_relocs *) data;
  segment_info_type *seginfo;
  symbolS *sym;
  fixS *fix;

  seginfo = seg_info (sec);
  if (seginfo == NULL)
    return;

  sym = info->sym;
  for (fix = seginfo->fix_root; fix != NULL; fix = fix->fx_next)
    {
      if (fix->fx_addsy == sym)
       {
         ++info->count;
         fix->fx_tcbit = 1;
       }
    }
}
void sh_flush_pending_output ( void  )

Definition at line 2941 of file tc-sh.c.

{
  if (sh_relax
      && seg_info (now_seg)->tc_segment_info_data.in_code)
    {
      fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0,
              BFD_RELOC_SH_DATA);
      seg_info (now_seg)->tc_segment_info_data.in_code = 0;
    }
}

Here is the call graph for this function:

int sh_force_relocation ( fixS *  fix)

Definition at line 3722 of file tc-sh.c.

{
  /* These relocations can't make it into a DSO, so no use forcing
     them for global symbols.  */
  if (sh_local_pcrel (fix))
    return 0;

  /* Make sure some relocations get emitted.  */
  if (fix->fx_r_type == BFD_RELOC_SH_LOOP_START
      || fix->fx_r_type == BFD_RELOC_SH_LOOP_END
      || fix->fx_r_type == BFD_RELOC_SH_TLS_GD_32
      || fix->fx_r_type == BFD_RELOC_SH_TLS_LD_32
      || fix->fx_r_type == BFD_RELOC_SH_TLS_IE_32
      || fix->fx_r_type == BFD_RELOC_SH_TLS_LDO_32
      || fix->fx_r_type == BFD_RELOC_SH_TLS_LE_32
      || generic_force_reloc (fix))
    return 1;

  if (! sh_relax)
    return 0;

  return (fix->fx_pcrel
         || SWITCH_TABLE (fix)
         || fix->fx_r_type == BFD_RELOC_SH_COUNT
         || fix->fx_r_type == BFD_RELOC_SH_ALIGN
         || fix->fx_r_type == BFD_RELOC_SH_CODE
         || fix->fx_r_type == BFD_RELOC_SH_DATA
#ifdef HAVE_SH64
         || fix->fx_r_type == BFD_RELOC_SH_SHMEDIA_CODE
#endif
         || fix->fx_r_type == BFD_RELOC_SH_LABEL);
}

Here is the call graph for this function:

void sh_frob_file ( void  )

Definition at line 3429 of file tc-sh.c.

{
#ifdef HAVE_SH64
  shmedia_frob_file_before_adjust ();
#endif

  if (! sh_relax)
    return;

  bfd_map_over_sections (stdoutput, sh_frob_section, NULL);
}

Here is the call graph for this function:

void sh_frob_label ( symbolS *  sym)

Definition at line 2914 of file tc-sh.c.

{
  static fragS *last_label_frag;
  static int last_label_offset;

  if (sh_relax
      && seg_info (now_seg)->tc_segment_info_data.in_code)
    {
      int offset;

      offset = frag_now_fix ();
      if (frag_now != last_label_frag
         || offset != last_label_offset)
       {
         fix_new (frag_now, offset, 2, &abs_symbol, 0, 0, BFD_RELOC_SH_LABEL);
         last_label_frag = frag_now;
         last_label_offset = offset;
       }
    }

  dwarf2_emit_label (sym);
}

Here is the call graph for this function:

static void sh_frob_section ( bfd *abfd  ATTRIBUTE_UNUSED,
segT  sec,
void *ignore  ATTRIBUTE_UNUSED 
) [static]

Definition at line 3311 of file tc-sh.c.

{
  segment_info_type *seginfo;
  fixS *fix;

  seginfo = seg_info (sec);
  if (seginfo == NULL)
    return;

  for (fix = seginfo->fix_root; fix != NULL; fix = fix->fx_next)
    {
      symbolS *sym;

      sym = fix->fx_addsy;
      /* Check for a local_symbol.  */
      if (sym && sym->bsym == NULL)
       {
         struct local_symbol *ls = (struct local_symbol *)sym;
         /* See if it's been converted.  If so, canonicalize.  */
         if (local_symbol_converted_p (ls))
           fix->fx_addsy = local_symbol_get_real_symbol (ls);
       }
    }

  for (fix = seginfo->fix_root; fix != NULL; fix = fix->fx_next)
    {
      symbolS *sym;
      bfd_vma val;
      fixS *fscan;
      struct sh_count_relocs info;

      if (fix->fx_r_type != BFD_RELOC_SH_USES)
       continue;

      /* The BFD_RELOC_SH_USES reloc should refer to a defined local
        symbol in the same section.  */
      sym = fix->fx_addsy;
      if (sym == NULL
         || fix->fx_subsy != NULL
         || fix->fx_addnumber != 0
         || S_GET_SEGMENT (sym) != sec
         || S_IS_EXTERNAL (sym))
       {
         as_warn_where (fix->fx_file, fix->fx_line,
                      _(".uses does not refer to a local symbol in the same section"));
         continue;
       }

      /* Look through the fixups again, this time looking for one
        at the same location as sym.  */
      val = S_GET_VALUE (sym);
      for (fscan = seginfo->fix_root;
          fscan != NULL;
          fscan = fscan->fx_next)
       if (val == fscan->fx_frag->fr_address + fscan->fx_where
           && fscan->fx_r_type != BFD_RELOC_SH_ALIGN
           && fscan->fx_r_type != BFD_RELOC_SH_CODE
           && fscan->fx_r_type != BFD_RELOC_SH_DATA
           && fscan->fx_r_type != BFD_RELOC_SH_LABEL)
         break;
      if (fscan == NULL)
       {
         as_warn_where (fix->fx_file, fix->fx_line,
                      _("can't find fixup pointed to by .uses"));
         continue;
       }

      if (fscan->fx_tcbit)
       {
         /* We've already done this one.  */
         continue;
       }

      /* The variable fscan should also be a fixup to a local symbol
        in the same section.  */
      sym = fscan->fx_addsy;
      if (sym == NULL
         || fscan->fx_subsy != NULL
         || fscan->fx_addnumber != 0
         || S_GET_SEGMENT (sym) != sec
         || S_IS_EXTERNAL (sym))
       {
         as_warn_where (fix->fx_file, fix->fx_line,
                      _(".uses target does not refer to a local symbol in the same section"));
         continue;
       }

      /* Now we look through all the fixups of all the sections,
        counting the number of times we find a reference to sym.  */
      info.sym = sym;
      info.count = 0;
      bfd_map_over_sections (stdoutput, sh_count_relocs, &info);

      if (info.count < 1)
       abort ();

      /* Generate a BFD_RELOC_SH_COUNT fixup at the location of sym.
        We have already adjusted the value of sym to include the
        fragment address, so we undo that adjustment here.  */
      subseg_change (sec, 0);
      fix_new (fscan->fx_frag,
              S_GET_VALUE (sym) - fscan->fx_frag->fr_address,
              4, &abs_symbol, info.count, 0, BFD_RELOC_SH_COUNT);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void sh_handle_align ( fragS *  frag)

Definition at line 3657 of file tc-sh.c.

{
  int bytes = frag->fr_next->fr_address - frag->fr_address - frag->fr_fix;

  if (frag->fr_type == rs_align_code)
    {
      static const unsigned char big_nop_pattern[] = { 0x00, 0x09 };
      static const unsigned char little_nop_pattern[] = { 0x09, 0x00 };

      char *p = frag->fr_literal + frag->fr_fix;

      if (bytes & 1)
       {
         *p++ = 0;
         bytes--;
         frag->fr_fix += 1;
       }

      if (target_big_endian)
       {
         memcpy (p, big_nop_pattern, sizeof big_nop_pattern);
         frag->fr_var = sizeof big_nop_pattern;
       }
      else
       {
         memcpy (p, little_nop_pattern, sizeof little_nop_pattern);
         frag->fr_var = sizeof little_nop_pattern;
       }
    }
  else if (frag->fr_type == rs_align_test)
    {
      if (bytes != 0)
       as_warn_where (frag->fr_file, frag->fr_line, _("misaligned data"));
    }

  if (sh_relax
      && (frag->fr_type == rs_align
         || frag->fr_type == rs_align_code)
      && frag->fr_address + frag->fr_fix > 0
      && frag->fr_offset > 1
      && now_seg != bss_section)
    fix_new (frag, frag->fr_fix, 2, &abs_symbol, frag->fr_offset, 0,
            BFD_RELOC_SH_ALIGN);
}

Here is the call graph for this function:

static bfd_boolean sh_local_pcrel ( fixS *  fix) [static]
arelent* tc_gen_reloc ( asection *section  ATTRIBUTE_UNUSED,
fixS *  fixp 
)

Definition at line 4258 of file tc-sh.c.

{
  arelent *rel;
  bfd_reloc_code_real_type r_type;

  rel = (arelent *) xmalloc (sizeof (arelent));
  rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
  *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
  rel->address = fixp->fx_frag->fr_address + fixp->fx_where;

  r_type = fixp->fx_r_type;

  if (SWITCH_TABLE (fixp))
    {
      *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
      rel->addend = 0;
      if (r_type == BFD_RELOC_16)
       r_type = BFD_RELOC_SH_SWITCH16;
      else if (r_type == BFD_RELOC_8)
       r_type = BFD_RELOC_8_PCREL;
      else if (r_type == BFD_RELOC_32)
       r_type = BFD_RELOC_SH_SWITCH32;
      else
       abort ();
    }
  else if (r_type == BFD_RELOC_SH_USES)
    rel->addend = fixp->fx_addnumber;
  else if (r_type == BFD_RELOC_SH_COUNT)
    rel->addend = fixp->fx_offset;
  else if (r_type == BFD_RELOC_SH_ALIGN)
    rel->addend = fixp->fx_offset;
  else if (r_type == BFD_RELOC_VTABLE_INHERIT
           || r_type == BFD_RELOC_VTABLE_ENTRY)
    rel->addend = fixp->fx_offset;
  else if (r_type == BFD_RELOC_SH_LOOP_START
           || r_type == BFD_RELOC_SH_LOOP_END)
    rel->addend = fixp->fx_offset;
  else if (r_type == BFD_RELOC_SH_LABEL && fixp->fx_pcrel)
    {
      rel->addend = 0;
      rel->address = rel->addend = fixp->fx_offset;
    }
#ifdef HAVE_SH64
  else if (shmedia_init_reloc (rel, fixp))
    ;
#endif
  else
    rel->addend = fixp->fx_addnumber;

  rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);

  if (rel->howto == NULL)
    {
      as_bad_where (fixp->fx_file, fixp->fx_line,
                  _("Cannot represent relocation type %s"),
                  bfd_get_reloc_code_name (r_type));
      /* Set howto to a garbage value so that we can keep going.  */
      rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
      assert (rel->howto != NULL);
    }
#ifdef OBJ_ELF
  else if (rel->howto->type == R_SH_IND12W)
    rel->addend += fixp->fx_offset - 4;
#endif

  return rel;
}

Here is the call graph for this function:


Variable Documentation

Definition at line 137 of file tc-sh.c.

const char comment_chars[] = "!"

Definition at line 46 of file tc-sh.c.

Definition at line 133 of file tc-sh.c.

const char EXP_CHARS[] = "eE"

Definition at line 147 of file tc-sh.c.

const char FLT_CHARS[] = "rRsSfFdDxXpP"

Definition at line 152 of file tc-sh.c.

const char line_comment_chars[] = "!#"

Definition at line 48 of file tc-sh.c.

Definition at line 47 of file tc-sh.c.

size_t md_longopts_size = sizeof (md_longopts)

Definition at line 3089 of file tc-sh.c.

const pseudo_typeS md_pseudo_table[]

Definition at line 85 of file tc-sh.c.

const relax_typeS md_relax_table[C(END, 0)]

Definition at line 329 of file tc-sh.c.

const char* md_shortopts = ""

Definition at line 3063 of file tc-sh.c.

Definition at line 483 of file tc-sh.c.

Definition at line 141 of file tc-sh.c.

int reg_b [static]

Definition at line 868 of file tc-sh.c.

int reg_efg [static]

Definition at line 867 of file tc-sh.c.

int reg_m [static]

Definition at line 864 of file tc-sh.c.

int reg_n [static]

Definition at line 865 of file tc-sh.c.

int reg_x [static]

Definition at line 866 of file tc-sh.c.

int reg_y [static]

Definition at line 866 of file tc-sh.c.

int sh_no_align_cons = 0 [static]

Definition at line 3596 of file tc-sh.c.

Definition at line 125 of file tc-sh.c.

Definition at line 129 of file tc-sh.c.

Definition at line 145 of file tc-sh.c.