Home | History | Annotate | Download | only in config
      1 /* tc-xstormy16.c -- Assembler for the Sanyo XSTORMY16.
      2    Copyright (C) 2000-2016 Free Software Foundation, Inc.
      3 
      4    This file is part of GAS, the GNU Assembler.
      5 
      6    GAS is free software; you can redistribute it and/or modify
      7    it under the terms of the GNU General Public License as published by
      8    the Free Software Foundation; either version 3, or (at your option)
      9    any later version.
     10 
     11    GAS is distributed in the hope that it will be useful,
     12    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14    GNU General Public License for more details.
     15 
     16    You should have received a copy of the GNU General Public License
     17    along with GAS; see the file COPYING.  If not, write to
     18    the Free Software Foundation, 51 Franklin Street - Fifth Floor,
     19    Boston, MA 02110-1301, USA.  */
     20 
     21 #include "as.h"
     22 #include "subsegs.h"
     23 #include "symcat.h"
     24 #include "opcodes/xstormy16-desc.h"
     25 #include "opcodes/xstormy16-opc.h"
     26 #include "cgen.h"
     27 
     28 /* Structure to hold all of the different components describing
     29    an individual instruction.  */
     30 typedef struct
     31 {
     32   const CGEN_INSN *	insn;
     33   const CGEN_INSN *	orig_insn;
     34   CGEN_FIELDS		fields;
     35 #if CGEN_INT_INSN_P
     36   CGEN_INSN_INT         buffer [1];
     37 #define INSN_VALUE(buf) (*(buf))
     38 #else
     39   unsigned char         buffer [CGEN_MAX_INSN_SIZE];
     40 #define INSN_VALUE(buf) (buf)
     41 #endif
     42   char *		addr;
     43   fragS *		frag;
     44   int                   num_fixups;
     45   fixS *                fixups [GAS_CGEN_MAX_FIXUPS];
     46   int                   indices [MAX_OPERAND_INSTANCES];
     47 }
     48 xstormy16_insn;
     49 
     50 const char comment_chars[]        = ";";
     51 const char line_comment_chars[]   = "#";
     52 const char line_separator_chars[] = "|";
     53 const char EXP_CHARS[]            = "eE";
     54 const char FLT_CHARS[]            = "dD";
     55 
     56 #define O_fptr_symbol	(O_max + 1)
     57 
     58 #define XSTORMY16_SHORTOPTS ""
     60 const char * md_shortopts = XSTORMY16_SHORTOPTS;
     61 
     62 struct option md_longopts[] =
     63 {
     64   {NULL, no_argument, NULL, 0}
     65 };
     66 size_t md_longopts_size = sizeof (md_longopts);
     67 
     68 int
     69 md_parse_option (int    c ATTRIBUTE_UNUSED,
     70 		 const char * arg ATTRIBUTE_UNUSED)
     71 {
     72   return 0;
     73 }
     74 
     75 void
     76 md_show_usage (FILE * stream)
     77 {
     78   fprintf (stream, _(" XSTORMY16 specific command line options:\n"));
     79 }
     80 
     81 /* The target specific pseudo-ops which we support.  */
     82 const pseudo_typeS md_pseudo_table[] =
     83 {
     84   { "word",	cons,		4 },
     85   { NULL, 	NULL, 		0 }
     86 };
     87 
     88 
     89 void
     91 md_begin (void)
     92 {
     93   /* Initialize the `cgen' interface.  */
     94 
     95   /* Set the machine number and endian.  */
     96   gas_cgen_cpu_desc = xstormy16_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
     97 					  CGEN_CPU_OPEN_ENDIAN,
     98 					  CGEN_ENDIAN_LITTLE,
     99 					  CGEN_CPU_OPEN_END);
    100   xstormy16_cgen_init_asm (gas_cgen_cpu_desc);
    101 
    102   /* This is a callback from cgen to gas to parse operands.  */
    103   cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
    104 }
    105 
    106 static bfd_boolean skipping_fptr = FALSE;
    107 
    108 void
    109 md_assemble (char * str)
    110 {
    111   xstormy16_insn insn;
    112   char *    errmsg;
    113 
    114   /* Make sure that if we had an erroneous input line which triggered
    115      the skipping_fptr boolean that it does not affect following lines.  */
    116   skipping_fptr = FALSE;
    117 
    118   /* Initialize GAS's cgen interface for a new instruction.  */
    119   gas_cgen_init_parse ();
    120 
    121   insn.insn = xstormy16_cgen_assemble_insn
    122     (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
    123 
    124   if (!insn.insn)
    125     {
    126       as_bad ("%s", errmsg);
    127       return;
    128     }
    129 
    130   /* Doesn't really matter what we pass for RELAX_P here.  */
    131   gas_cgen_finish_insn (insn.insn, insn.buffer,
    132 			CGEN_FIELDS_BITSIZE (& insn.fields), 0, NULL);
    133 }
    134 
    135 void
    136 md_operand (expressionS * e)
    137 {
    138   if (*input_line_pointer != '@')
    139     return;
    140 
    141   if (strncmp (input_line_pointer + 1, "fptr", 4) == 0)
    142     {
    143       input_line_pointer += 5;
    144       SKIP_WHITESPACE ();
    145       if (*input_line_pointer != '(')
    146 	{
    147 	  as_bad (_("Expected '('"));
    148 	  goto err;
    149 	}
    150       input_line_pointer++;
    151 
    152       expression (e);
    153 
    154       if (*input_line_pointer != ')')
    155 	{
    156 	  as_bad (_("Missing ')'"));
    157 	  goto err;
    158 	}
    159       input_line_pointer++;
    160       SKIP_WHITESPACE ();
    161 
    162       if (e->X_op != O_symbol)
    163 	as_bad (_("Not a symbolic expression"));
    164       else if (* input_line_pointer == '-')
    165 	/* We are computing the difference of two function pointers
    166 	   like this:
    167 
    168 	    .hword  @fptr (foo) - @fptr (bar)
    169 
    170 	  In this situation we do not want to generate O_fptr_symbol
    171 	  operands because the result is an absolute value, not a
    172 	  function pointer.
    173 
    174 	  We need to make the check here, rather than when the fixup
    175 	  is generated as the function names (foo & bar in the above
    176 	  example) might be local symbols and we want the expression
    177 	  to be evaluated now.  This kind of thing can happen when
    178 	  gcc is generating computed gotos.  */
    179 	skipping_fptr = TRUE;
    180       else if (skipping_fptr)
    181 	skipping_fptr = FALSE;
    182       else
    183         e->X_op = O_fptr_symbol;
    184     }
    185 
    186   return;
    187  err:
    188   ignore_rest_of_line ();
    189 }
    190 
    191 /* Called while parsing data to create a fixup.
    192    Create BFD_RELOC_XSTORMY16_FPTR16 relocations.  */
    193 
    194 void
    195 xstormy16_cons_fix_new (fragS *f,
    196 			int where,
    197 			int nbytes,
    198 			expressionS *exp,
    199 			bfd_reloc_code_real_type code)
    200 {
    201   if (exp->X_op == O_fptr_symbol)
    202     {
    203       switch (nbytes)
    204 	{
    205  	case 4:
    206  	  /* This can happen when gcc is generating debug output.
    207  	     For example it can create a stab with the address of
    208  	     a function:
    209 
    210  	     	.stabs	"foo:F(0,21)",36,0,0,@fptr(foo)
    211 
    212  	     Since this does not involve switching code pages, we
    213  	     just allow the reloc to be generated without any
    214  	     @fptr behaviour.  */
    215  	  exp->X_op = O_symbol;
    216  	  code = BFD_RELOC_32;
    217  	  break;
    218 
    219  	case 2:
    220  	  exp->X_op = O_symbol;
    221  	  code = BFD_RELOC_XSTORMY16_FPTR16;
    222  	  break;
    223 
    224  	default:
    225 	  as_bad (_("unsupported fptr fixup size %d"), nbytes);
    226 	  return;
    227 	}
    228     }
    229   else if (nbytes == 1)
    230     code = BFD_RELOC_8;
    231   else if (nbytes == 2)
    232     code = BFD_RELOC_16;
    233   else if (nbytes == 4)
    234     code = BFD_RELOC_32;
    235   else
    236     {
    237       as_bad (_("unsupported fixup size %d"), nbytes);
    238       return;
    239     }
    240 
    241   fix_new_exp (f, where, nbytes, exp, 0, code);
    242 }
    243 
    244 /* Called while parsing an instruction to create a fixup.
    245    Create BFD_RELOC_XSTORMY16_FPTR16 relocations.  */
    246 
    247 fixS *
    248 xstormy16_cgen_record_fixup_exp (fragS *              frag,
    249 				 int                  where,
    250 				 const CGEN_INSN *    insn,
    251 				 int                  length,
    252 				 const CGEN_OPERAND * operand,
    253 				 int                  opinfo,
    254 				 expressionS *        exp)
    255 {
    256   fixS *fixP;
    257   operatorT op = exp->X_op;
    258 
    259   if (op == O_fptr_symbol)
    260     exp->X_op = O_symbol;
    261 
    262   fixP = gas_cgen_record_fixup_exp (frag, where, insn, length,
    263 				    operand, opinfo, exp);
    264 
    265   if (op == O_fptr_symbol)
    266     {
    267       if (operand->type != XSTORMY16_OPERAND_IMM16)
    268 	as_bad (_("unsupported fptr fixup"));
    269       else
    270 	{
    271 	  fixP->fx_r_type = BFD_RELOC_XSTORMY16_FPTR16;
    272 	  fixP->fx_where += 2;
    273 	}
    274     }
    275 
    276   return fixP;
    277 }
    278 
    279 valueT
    280 md_section_align (segT segment, valueT size)
    281 {
    282   int align = bfd_get_section_alignment (stdoutput, segment);
    283 
    284   return ((size + (1 << align) - 1) & -(1 << align));
    285 }
    286 
    287 symbolS *
    288 md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
    289 {
    290   return 0;
    291 }
    292 
    293 /* Return an initial guess of the length by which a fragment must grow to
    295    hold a branch to reach its destination.
    296    Also updates fr_type/fr_subtype as necessary.
    297 
    298    Called just before doing relaxation.
    299    Any symbol that is now undefined will not become defined.
    300    The guess for fr_var is ACTUALLY the growth beyond fr_fix.
    301    Whatever we do to grow fr_fix or fr_var contributes to our returned value.
    302    Although it may not be explicit in the frag, pretend fr_var starts with a
    303    0 value.  */
    304 
    305 int
    306 md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED,
    307 			       segT    segment ATTRIBUTE_UNUSED)
    308 {
    309   /* No assembler relaxation is defined (or necessary) for this port.  */
    310   abort ();
    311 }
    312 
    313 /* *fragP has been relaxed to its final size, and now needs to have
    314    the bytes inside it modified to conform to the new size.
    315 
    316    Called after relaxation is finished.
    317    fragP->fr_type == rs_machine_dependent.
    318    fragP->fr_subtype is the subtype of what the address relaxed to.  */
    319 
    320 void
    321 md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
    322 		 segT    sec ATTRIBUTE_UNUSED,
    323 		 fragS * fragP ATTRIBUTE_UNUSED)
    324 {
    325   /* No assembler relaxation is defined (or necessary) for this port.  */
    326   abort ();
    327 }
    328 
    329 /* Functions concerning relocs.  */
    331 
    332 /* The location from which a PC relative jump should be calculated,
    333    given a PC relative reloc.  */
    334 
    335 long
    336 md_pcrel_from_section (fixS * fixP, segT sec)
    337 {
    338   if ((fixP->fx_addsy != (symbolS *) NULL
    339        && (! S_IS_DEFINED (fixP->fx_addsy)
    340 	   || S_GET_SEGMENT (fixP->fx_addsy) != sec))
    341       || xstormy16_force_relocation (fixP))
    342     /* The symbol is undefined,
    343        or it is defined but not in this section,
    344        or the relocation will be relative to this symbol not the section symbol.
    345        Let the linker figure it out.  */
    346     return 0;
    347 
    348   return fixP->fx_frag->fr_address + fixP->fx_where;
    349 }
    350 
    351 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
    352    Returns BFD_RELOC_NONE if no reloc type can be found.
    353    *FIXP may be modified if desired.  */
    354 
    355 bfd_reloc_code_real_type
    356 md_cgen_lookup_reloc (const CGEN_INSN *    insn ATTRIBUTE_UNUSED,
    357 		      const CGEN_OPERAND * operand,
    358 		      fixS *               fixP)
    359 {
    360   switch (operand->type)
    361     {
    362     case XSTORMY16_OPERAND_IMM2:
    363     case XSTORMY16_OPERAND_IMM3:
    364     case XSTORMY16_OPERAND_IMM3B:
    365     case XSTORMY16_OPERAND_IMM4:
    366     case XSTORMY16_OPERAND_HMEM8:
    367       return BFD_RELOC_NONE;
    368 
    369     case XSTORMY16_OPERAND_IMM12:
    370       fixP->fx_where += 2;
    371       return BFD_RELOC_XSTORMY16_12;
    372 
    373     case XSTORMY16_OPERAND_IMM8:
    374     case XSTORMY16_OPERAND_LMEM8:
    375       return fixP->fx_pcrel ? BFD_RELOC_8_PCREL : BFD_RELOC_8;
    376 
    377     case XSTORMY16_OPERAND_IMM16:
    378       /* This might have been processed at parse time.  */
    379       fixP->fx_where += 2;
    380       if (fixP->fx_cgen.opinfo && fixP->fx_cgen.opinfo != BFD_RELOC_NONE)
    381 	return fixP->fx_cgen.opinfo;
    382       return fixP->fx_pcrel ? BFD_RELOC_16_PCREL : BFD_RELOC_16;
    383 
    384     case XSTORMY16_OPERAND_ABS24:
    385       return BFD_RELOC_XSTORMY16_24;
    386 
    387     case XSTORMY16_OPERAND_REL8_4:
    388       fixP->fx_addnumber -= 2;
    389     case XSTORMY16_OPERAND_REL8_2:
    390       fixP->fx_addnumber -= 2;
    391       fixP->fx_pcrel = 1;
    392       return BFD_RELOC_8_PCREL;
    393 
    394     case XSTORMY16_OPERAND_REL12:
    395       fixP->fx_where += 2;
    396       /* Fall through...  */
    397     case XSTORMY16_OPERAND_REL12A:
    398       fixP->fx_addnumber -= 2;
    399       fixP->fx_pcrel = 1;
    400       return BFD_RELOC_XSTORMY16_REL_12;
    401 
    402     default : /* avoid -Wall warning */
    403       abort ();
    404     }
    405 }
    406 
    407 /* See whether we need to force a relocation into the output file.
    408    This is used to force out switch and PC relative relocations when
    409    relaxing.  */
    410 
    411 int
    412 xstormy16_force_relocation (fixS * fix)
    413 {
    414   if (fix->fx_r_type == BFD_RELOC_XSTORMY16_FPTR16)
    415     return 1;
    416 
    417   return generic_force_reloc (fix);
    418 }
    419 
    420 /* Return true if a relocation against a symbol may be replaced with
    421    a relocation against section+offset.  */
    422 
    423 bfd_boolean
    424 xstormy16_fix_adjustable (fixS * fixP)
    425 {
    426   /* We need the symbol name for the VTABLE entries.  */
    427   if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
    428       || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
    429     return FALSE;
    430 
    431   if (fixP->fx_r_type == BFD_RELOC_XSTORMY16_FPTR16)
    432     return FALSE;
    433 
    434   return TRUE;
    435 }
    436 
    437 /* This is a copy of gas_cgen_md_apply_fix, with some enhancements to
    438    do various things that would not be valid for all ports.  */
    439 
    440 void
    441 xstormy16_md_apply_fix (fixS *   fixP,
    442 			 valueT * valueP,
    443 			 segT     seg ATTRIBUTE_UNUSED)
    444 {
    445   char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
    446   valueT value = *valueP;
    447   /* Canonical name, since used a lot.  */
    448   CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
    449 
    450   /* md_cgen_lookup_reloc() will adjust this to compensate for where
    451      in the opcode the relocation happens, for pcrel relocations.  We
    452      have no other way of keeping track of what this offset needs to
    453      be.  */
    454   fixP->fx_addnumber = 0;
    455 
    456   /* This port has pc-relative relocs and DIFF_EXPR_OK defined, so
    457      it must deal with turning a BFD_RELOC_{8,16,32,64} into a
    458      BFD_RELOC_*_PCREL for the case of
    459 
    460 	.word something-.  */
    461   if (fixP->fx_pcrel)
    462     switch (fixP->fx_r_type)
    463       {
    464       case BFD_RELOC_8:
    465 	fixP->fx_r_type = BFD_RELOC_8_PCREL;
    466 	break;
    467       case BFD_RELOC_16:
    468 	fixP->fx_r_type = BFD_RELOC_16_PCREL;
    469 	break;
    470       case BFD_RELOC_32:
    471 	fixP->fx_r_type = BFD_RELOC_32_PCREL;
    472 	break;
    473       case BFD_RELOC_64:
    474 	fixP->fx_r_type = BFD_RELOC_64_PCREL;
    475 	break;
    476       default:
    477 	break;
    478       }
    479 
    480   if (fixP->fx_addsy == (symbolS *) NULL)
    481     fixP->fx_done = 1;
    482 
    483   /* We don't actually support subtracting a symbol.  */
    484   if (fixP->fx_subsy != (symbolS *) NULL)
    485     as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
    486 
    487   if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
    488     {
    489       int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
    490       const CGEN_OPERAND *operand = cgen_operand_lookup_by_num (cd, opindex);
    491       const char *errmsg;
    492       bfd_reloc_code_real_type reloc_type;
    493       const CGEN_INSN *insn = fixP->fx_cgen.insn;
    494 
    495       /* If the reloc has been fully resolved finish the operand here.  */
    496       /* FIXME: This duplicates the capabilities of code in BFD.  */
    497       if (fixP->fx_done)
    498 	{
    499 	  CGEN_FIELDS *fields = xmalloc (CGEN_CPU_SIZEOF_FIELDS (cd));
    500 
    501 	  CGEN_CPU_SET_FIELDS_BITSIZE (cd) (fields, CGEN_INSN_BITSIZE (insn));
    502 	  CGEN_CPU_SET_VMA_OPERAND (cd) (cd, opindex, fields, (bfd_vma) value);
    503 
    504 #if CGEN_INT_INSN_P
    505 	  {
    506 	    CGEN_INSN_INT insn_value =
    507 	      cgen_get_insn_value (cd, (unsigned char *) where,
    508 				   CGEN_INSN_BITSIZE (insn));
    509 
    510 	    /* ??? 0 is passed for `pc'.  */
    511 	    errmsg = CGEN_CPU_INSERT_OPERAND (cd) (cd, opindex, fields,
    512 						   &insn_value, (bfd_vma) 0);
    513 	    cgen_put_insn_value (cd, (unsigned char *) where,
    514 				 CGEN_INSN_BITSIZE (insn), insn_value);
    515 	  }
    516 #else
    517 	  /* ??? 0 is passed for `pc'.  */
    518 	  errmsg = CGEN_CPU_INSERT_OPERAND (cd) (cd, opindex, fields,
    519 						 (unsigned char *) where,
    520 						 (bfd_vma) 0);
    521 #endif
    522 	  if (errmsg)
    523 	    as_bad_where (fixP->fx_file, fixP->fx_line, "%s", errmsg);
    524 
    525 	  free (fields);
    526 	}
    527 
    528       if (fixP->fx_done)
    529 	return;
    530 
    531       /* The operand isn't fully resolved.  Determine a BFD reloc value
    532 	 based on the operand information and leave it to
    533 	 bfd_install_relocation.  Note that this doesn't work when
    534 	 !partial_inplace.  */
    535 
    536       reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
    537       if (reloc_type != BFD_RELOC_NONE)
    538 	fixP->fx_r_type = reloc_type;
    539       else
    540 	{
    541 	  as_bad_where (fixP->fx_file, fixP->fx_line,
    542 			_("unresolved expression that must be resolved"));
    543 	  fixP->fx_done = 1;
    544 	  return;
    545 	}
    546     }
    547   else if (fixP->fx_done)
    548     {
    549       /* We're finished with this fixup.  Install it because
    550 	 bfd_install_relocation won't be called to do it.  */
    551       switch (fixP->fx_r_type)
    552 	{
    553 	case BFD_RELOC_8:
    554 	  md_number_to_chars (where, value, 1);
    555 	  break;
    556 	case BFD_RELOC_16:
    557 	  md_number_to_chars (where, value, 2);
    558 	  break;
    559 	case BFD_RELOC_32:
    560 	  md_number_to_chars (where, value, 4);
    561 	  break;
    562 	case BFD_RELOC_64:
    563 	  md_number_to_chars (where, value, 8);
    564 	  break;
    565 	default:
    566 	  as_bad_where (fixP->fx_file, fixP->fx_line,
    567 			_("internal error: can't install fix for reloc type %d (`%s')"),
    568 			fixP->fx_r_type, bfd_get_reloc_code_name (fixP->fx_r_type));
    569 	  break;
    570 	}
    571     }
    572   else
    573     {
    574       /* bfd_install_relocation will be called to finish things up.  */
    575     }
    576 
    577   /* This is a RELA port.  Thus, it does not need to store a
    578      value if it is going to make a reloc.  What's more, when
    579      assembling a line like
    580 
    581      .byte global-0x7f00
    582 
    583      we'll get a spurious error message if we try to stuff 0x7f00 into
    584      the byte.  */
    585   if (! fixP->fx_done)
    586     *valueP = 0;
    587 
    588   /* Tuck `value' away for use by tc_gen_reloc.
    589      See the comment describing fx_addnumber in write.h.
    590      This field is misnamed (or misused :-).  */
    591   fixP->fx_addnumber += value;
    592 }
    593 
    594 
    595 /* Write a value out to the object file, using the appropriate endianness.  */
    597 
    598 void
    599 md_number_to_chars (char * buf, valueT val, int n)
    600 {
    601   number_to_chars_littleendian (buf, val, n);
    602 }
    603 
    604 const char *
    605 md_atof (int type, char * litP, int * sizeP)
    606 {
    607   return ieee_md_atof (type, litP, sizeP, FALSE);
    608 }
    609