Back to index

cell-binutils  2.17cvs20070401
tc-xstormy16.c
Go to the documentation of this file.
00001 /* tc-xstormy16.c -- Assembler for the Sanyo XSTORMY16.
00002    Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006
00003    Free Software Foundation.
00004 
00005    This file is part of GAS, the GNU Assembler.
00006 
00007    GAS is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2, or (at your option)
00010    any later version.
00011 
00012    GAS is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with GAS; see the file COPYING.  If not, write to
00019    the Free Software Foundation, 51 Franklin Street - Fifth Floor,
00020    Boston, MA 02110-1301, USA.  */
00021 
00022 #include "as.h"
00023 #include "subsegs.h"
00024 #include "symcat.h"
00025 #include "opcodes/xstormy16-desc.h"
00026 #include "opcodes/xstormy16-opc.h"
00027 #include "cgen.h"
00028 
00029 /* Structure to hold all of the different components describing
00030    an individual instruction.  */
00031 typedef struct
00032 {
00033   const CGEN_INSN *  insn;
00034   const CGEN_INSN *  orig_insn;
00035   CGEN_FIELDS        fields;
00036 #if CGEN_INT_INSN_P
00037   CGEN_INSN_INT         buffer [1];
00038 #define INSN_VALUE(buf) (*(buf))
00039 #else
00040   unsigned char         buffer [CGEN_MAX_INSN_SIZE];
00041 #define INSN_VALUE(buf) (buf)
00042 #endif
00043   char *             addr;
00044   fragS *            frag;
00045   int                   num_fixups;
00046   fixS *                fixups [GAS_CGEN_MAX_FIXUPS];
00047   int                   indices [MAX_OPERAND_INSTANCES];
00048 }
00049 xstormy16_insn;
00050 
00051 const char comment_chars[]        = ";";
00052 const char line_comment_chars[]   = "#";
00053 const char line_separator_chars[] = "|";
00054 const char EXP_CHARS[]            = "eE";
00055 const char FLT_CHARS[]            = "dD";
00056 
00057 #define O_fptr_symbol       (O_max + 1)
00058 
00059 #define XSTORMY16_SHORTOPTS ""
00060 const char * md_shortopts = XSTORMY16_SHORTOPTS;
00061 
00062 struct option md_longopts[] =
00063 {
00064   {NULL, no_argument, NULL, 0}
00065 };
00066 size_t md_longopts_size = sizeof (md_longopts);
00067 
00068 int
00069 md_parse_option (int    c ATTRIBUTE_UNUSED,
00070                char * arg ATTRIBUTE_UNUSED)
00071 {
00072   return 0;
00073 }
00074 
00075 void
00076 md_show_usage (FILE * stream)
00077 {
00078   fprintf (stream, _(" XSTORMY16 specific command line options:\n"));
00079 }
00080 
00081 /* The target specific pseudo-ops which we support.  */
00082 const pseudo_typeS md_pseudo_table[] =
00083 {
00084   { "word",   cons,         4 },
00085   { NULL,     NULL,         0 }
00086 };
00087 
00088 
00089 void
00090 md_begin (void)
00091 {
00092   /* Initialize the `cgen' interface.  */
00093 
00094   /* Set the machine number and endian.  */
00095   gas_cgen_cpu_desc = xstormy16_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
00096                                      CGEN_CPU_OPEN_ENDIAN,
00097                                      CGEN_ENDIAN_LITTLE,
00098                                      CGEN_CPU_OPEN_END);
00099   xstormy16_cgen_init_asm (gas_cgen_cpu_desc);
00100 
00101   /* This is a callback from cgen to gas to parse operands.  */
00102   cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
00103 }
00104 
00105 static bfd_boolean skipping_fptr = FALSE;
00106 
00107 void
00108 md_assemble (char * str)
00109 {
00110   xstormy16_insn insn;
00111   char *    errmsg;
00112 
00113   /* Make sure that if we had an erroneous input line which triggered
00114      the skipping_fptr boolean that it does not affect following lines.  */
00115   skipping_fptr = FALSE;
00116 
00117   /* Initialize GAS's cgen interface for a new instruction.  */
00118   gas_cgen_init_parse ();
00119 
00120   insn.insn = xstormy16_cgen_assemble_insn
00121     (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
00122 
00123   if (!insn.insn)
00124     {
00125       as_bad (errmsg);
00126       return;
00127     }
00128 
00129   /* Doesn't really matter what we pass for RELAX_P here.  */
00130   gas_cgen_finish_insn (insn.insn, insn.buffer,
00131                      CGEN_FIELDS_BITSIZE (& insn.fields), 0, NULL);
00132 }
00133 
00134 void
00135 md_operand (expressionS * e)
00136 {
00137   if (*input_line_pointer != '@')
00138     return;
00139 
00140   if (strncmp (input_line_pointer + 1, "fptr", 4) == 0)
00141     {
00142       input_line_pointer += 5;
00143       SKIP_WHITESPACE ();
00144       if (*input_line_pointer != '(')
00145        {
00146          as_bad ("Expected '('");
00147          goto err;
00148        }
00149       input_line_pointer++;
00150 
00151       expression (e);
00152 
00153       if (*input_line_pointer != ')')
00154        {
00155          as_bad ("Missing ')'");
00156          goto err;
00157        }
00158       input_line_pointer++;
00159       SKIP_WHITESPACE ();
00160 
00161       if (e->X_op != O_symbol)
00162        as_bad ("Not a symbolic expression");
00163       else if (* input_line_pointer == '-')
00164        /* We are computing the difference of two function pointers
00165           like this:
00166 
00167            .hword  @fptr (foo) - @fptr (bar)
00168 
00169          In this situation we do not want to generate O_fptr_symbol
00170          operands because the result is an absolute value, not a
00171          function pointer.
00172 
00173          We need to make the check here, rather than when the fixup
00174          is generated as the function names (foo & bar in the above
00175          example) might be local symbols and we want the expression
00176          to be evaluated now.  This kind of thing can happen when
00177          gcc is generating computed gotos.  */
00178        skipping_fptr = TRUE;
00179       else if (skipping_fptr)
00180        skipping_fptr = FALSE;
00181       else
00182         e->X_op = O_fptr_symbol;
00183     }
00184 
00185   return;
00186  err:
00187   ignore_rest_of_line ();
00188 }
00189 
00190 /* Called while parsing data to create a fixup.
00191    Create BFD_RELOC_XSTORMY16_FPTR16 relocations.  */
00192 
00193 void
00194 xstormy16_cons_fix_new (fragS *f,
00195                      int where,
00196                      int nbytes,
00197                      expressionS *exp)
00198 {
00199   bfd_reloc_code_real_type code;
00200   fixS *fix;
00201 
00202   if (exp->X_op == O_fptr_symbol)
00203     {
00204       switch (nbytes)
00205        {
00206        case 4:
00207          /* This can happen when gcc is generating debug output.
00208             For example it can create a stab with the address of
00209             a function:
00210             
00211               .stabs "foo:F(0,21)",36,0,0,@fptr(foo)
00212  
00213             Since this does not involve switching code pages, we
00214             just allow the reloc to be generated without any
00215             @fptr behaviour.  */
00216          exp->X_op = O_symbol;
00217          code = BFD_RELOC_32;
00218          break;
00219 
00220        case 2:
00221          exp->X_op = O_symbol;
00222          code = BFD_RELOC_XSTORMY16_FPTR16;
00223          break;
00224 
00225        default:
00226          as_bad ("unsupported fptr fixup size %d", nbytes);
00227          return;
00228        }
00229     }
00230   else if (nbytes == 1)
00231     code = BFD_RELOC_8;
00232   else if (nbytes == 2)
00233     code = BFD_RELOC_16;
00234   else if (nbytes == 4)
00235     code = BFD_RELOC_32;
00236   else
00237     {
00238       as_bad ("unsupported fixup size %d", nbytes);
00239       return;
00240     }
00241 
00242   fix = fix_new_exp (f, where, nbytes, exp, 0, code);
00243 }
00244 
00245 /* Called while parsing an instruction to create a fixup.
00246    Create BFD_RELOC_XSTORMY16_FPTR16 relocations.  */
00247 
00248 fixS *
00249 xstormy16_cgen_record_fixup_exp (fragS *              frag,
00250                              int                  where,
00251                              const CGEN_INSN *    insn,
00252                              int                  length,
00253                              const CGEN_OPERAND * operand,
00254                              int                  opinfo,
00255                              expressionS *        exp)
00256 {
00257   fixS *fixP;
00258   operatorT op = exp->X_op;
00259 
00260   if (op == O_fptr_symbol)
00261     exp->X_op = O_symbol;
00262 
00263   fixP = gas_cgen_record_fixup_exp (frag, where, insn, length,
00264                                 operand, opinfo, exp);
00265 
00266   if (op == O_fptr_symbol)
00267     {
00268       if (operand->type != XSTORMY16_OPERAND_IMM16)
00269        as_bad ("unsupported fptr fixup");
00270       else
00271        {
00272          fixP->fx_r_type = BFD_RELOC_XSTORMY16_FPTR16;
00273          fixP->fx_where += 2;
00274        }
00275     }
00276 
00277   return fixP;
00278 }
00279 
00280 valueT
00281 md_section_align (segT segment, valueT size)
00282 {
00283   int align = bfd_get_section_alignment (stdoutput, segment);
00284 
00285   return ((size + (1 << align) - 1) & (-1 << align));
00286 }
00287 
00288 symbolS *
00289 md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
00290 {
00291   return 0;
00292 }
00293 
00294 /* Return an initial guess of the length by which a fragment must grow to
00295    hold a branch to reach its destination.
00296    Also updates fr_type/fr_subtype as necessary.
00297 
00298    Called just before doing relaxation.
00299    Any symbol that is now undefined will not become defined.
00300    The guess for fr_var is ACTUALLY the growth beyond fr_fix.
00301    Whatever we do to grow fr_fix or fr_var contributes to our returned value.
00302    Although it may not be explicit in the frag, pretend fr_var starts with a
00303    0 value.  */
00304 
00305 int
00306 md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED,
00307                             segT    segment ATTRIBUTE_UNUSED)
00308 {
00309   /* No assembler relaxation is defined (or necessary) for this port.  */
00310   abort ();
00311 }
00312 
00313 /* *fragP has been relaxed to its final size, and now needs to have
00314    the bytes inside it modified to conform to the new size.
00315 
00316    Called after relaxation is finished.
00317    fragP->fr_type == rs_machine_dependent.
00318    fragP->fr_subtype is the subtype of what the address relaxed to.  */
00319 
00320 void
00321 md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
00322                segT    sec ATTRIBUTE_UNUSED,
00323                fragS * fragP ATTRIBUTE_UNUSED)
00324 {
00325   /* No assembler relaxation is defined (or necessary) for this port.  */
00326   abort ();
00327 }
00328 
00329 /* Functions concerning relocs.  */
00330 
00331 /* The location from which a PC relative jump should be calculated,
00332    given a PC relative reloc.  */
00333 
00334 long
00335 md_pcrel_from_section (fixS * fixP, segT sec)
00336 {
00337   if ((fixP->fx_addsy != (symbolS *) NULL
00338        && (! S_IS_DEFINED (fixP->fx_addsy)
00339           || S_GET_SEGMENT (fixP->fx_addsy) != sec))
00340       || xstormy16_force_relocation (fixP))
00341     /* The symbol is undefined,
00342        or it is defined but not in this section,
00343        or the relocation will be relative to this symbol not the section symbol.     
00344        Let the linker figure it out.  */
00345     return 0;
00346 
00347   return fixP->fx_frag->fr_address + fixP->fx_where;
00348 }
00349 
00350 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
00351    Returns BFD_RELOC_NONE if no reloc type can be found.
00352    *FIXP may be modified if desired.  */
00353 
00354 bfd_reloc_code_real_type
00355 md_cgen_lookup_reloc (const CGEN_INSN *    insn ATTRIBUTE_UNUSED,
00356                     const CGEN_OPERAND * operand,
00357                     fixS *               fixP)
00358 {
00359   switch (operand->type)
00360     {
00361     case XSTORMY16_OPERAND_IMM2:
00362     case XSTORMY16_OPERAND_IMM3:
00363     case XSTORMY16_OPERAND_IMM3B:
00364     case XSTORMY16_OPERAND_IMM4:
00365     case XSTORMY16_OPERAND_HMEM8:
00366       return BFD_RELOC_NONE;
00367 
00368     case XSTORMY16_OPERAND_IMM12:
00369       fixP->fx_where += 2;
00370       return BFD_RELOC_XSTORMY16_12;
00371 
00372     case XSTORMY16_OPERAND_IMM8:
00373     case XSTORMY16_OPERAND_LMEM8:
00374       return fixP->fx_pcrel ? BFD_RELOC_8_PCREL : BFD_RELOC_8;
00375 
00376     case XSTORMY16_OPERAND_IMM16:
00377       /* This might have been processed at parse time.  */
00378       fixP->fx_where += 2;
00379       if (fixP->fx_cgen.opinfo && fixP->fx_cgen.opinfo != BFD_RELOC_NONE)
00380        return fixP->fx_cgen.opinfo;
00381       return fixP->fx_pcrel ? BFD_RELOC_16_PCREL : BFD_RELOC_16;
00382 
00383     case XSTORMY16_OPERAND_ABS24:
00384       return BFD_RELOC_XSTORMY16_24;
00385 
00386     case XSTORMY16_OPERAND_REL8_4:
00387       fixP->fx_addnumber -= 2;
00388     case XSTORMY16_OPERAND_REL8_2:
00389       fixP->fx_addnumber -= 2;
00390       fixP->fx_pcrel = 1;
00391       return BFD_RELOC_8_PCREL;
00392 
00393     case XSTORMY16_OPERAND_REL12:
00394       fixP->fx_where += 2;
00395       /* Fall through...  */
00396     case XSTORMY16_OPERAND_REL12A:
00397       fixP->fx_addnumber -= 2;
00398       fixP->fx_pcrel = 1;
00399       return BFD_RELOC_XSTORMY16_REL_12;
00400 
00401     default : /* avoid -Wall warning */
00402       abort ();
00403     }
00404 }
00405 
00406 /* See whether we need to force a relocation into the output file.
00407    This is used to force out switch and PC relative relocations when
00408    relaxing.  */
00409 
00410 int
00411 xstormy16_force_relocation (fixS * fix)
00412 {
00413   if (fix->fx_r_type == BFD_RELOC_XSTORMY16_FPTR16)
00414     return 1;
00415 
00416   return generic_force_reloc (fix);
00417 }
00418 
00419 /* Return true if a relocation against a symbol may be replaced with
00420    a relocation against section+offset.  */
00421 
00422 bfd_boolean
00423 xstormy16_fix_adjustable (fixS * fixP)
00424 {
00425   /* We need the symbol name for the VTABLE entries.  */
00426   if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
00427       || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
00428     return FALSE;
00429 
00430   if (fixP->fx_r_type == BFD_RELOC_XSTORMY16_FPTR16)
00431     return FALSE;
00432 
00433   return TRUE;
00434 }
00435 
00436 /* This is a copy of gas_cgen_md_apply_fix, with some enhancements to
00437    do various things that would not be valid for all ports.  */
00438 
00439 void
00440 xstormy16_md_apply_fix (fixS *   fixP,
00441                       valueT * valueP,
00442                       segT     seg ATTRIBUTE_UNUSED)
00443 {
00444   char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
00445   valueT value = *valueP;
00446   /* Canonical name, since used a lot.  */
00447   CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
00448 
00449   /* md_cgen_lookup_reloc() will adjust this to compensate for where
00450      in the opcode the relocation happens, for pcrel relocations.  We
00451      have no other way of keeping track of what this offset needs to
00452      be.  */
00453   fixP->fx_addnumber = 0;
00454 
00455   /* This port has pc-relative relocs and DIFF_EXPR_OK defined, so
00456      it must deal with turning a BFD_RELOC_{8,16,32,64} into a
00457      BFD_RELOC_*_PCREL for the case of
00458 
00459        .word something-.  */
00460   if (fixP->fx_pcrel)
00461     switch (fixP->fx_r_type)
00462       {
00463       case BFD_RELOC_8:
00464        fixP->fx_r_type = BFD_RELOC_8_PCREL;
00465        break;
00466       case BFD_RELOC_16:
00467        fixP->fx_r_type = BFD_RELOC_16_PCREL;
00468        break;
00469       case BFD_RELOC_32:
00470        fixP->fx_r_type = BFD_RELOC_32_PCREL;
00471        break;
00472       case BFD_RELOC_64:
00473        fixP->fx_r_type = BFD_RELOC_64_PCREL;
00474        break;
00475       default:
00476        break;
00477       }
00478 
00479   if (fixP->fx_addsy == (symbolS *) NULL)
00480     fixP->fx_done = 1;
00481 
00482   /* We don't actually support subtracting a symbol.  */
00483   if (fixP->fx_subsy != (symbolS *) NULL)
00484     as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
00485 
00486   if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
00487     {
00488       int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
00489       const CGEN_OPERAND *operand = cgen_operand_lookup_by_num (cd, opindex);
00490       const char *errmsg;
00491       bfd_reloc_code_real_type reloc_type;
00492       CGEN_FIELDS *fields = alloca (CGEN_CPU_SIZEOF_FIELDS (cd));
00493       const CGEN_INSN *insn = fixP->fx_cgen.insn;
00494 
00495       /* If the reloc has been fully resolved finish the operand here.  */
00496       /* FIXME: This duplicates the capabilities of code in BFD.  */
00497       if (fixP->fx_done)
00498        {
00499          CGEN_CPU_SET_FIELDS_BITSIZE (cd) (fields, CGEN_INSN_BITSIZE (insn));
00500          CGEN_CPU_SET_VMA_OPERAND (cd) (cd, opindex, fields, (bfd_vma) value);
00501 
00502 #if CGEN_INT_INSN_P
00503          {
00504            CGEN_INSN_INT insn_value =
00505              cgen_get_insn_value (cd, (unsigned char *) where,
00506                                CGEN_INSN_BITSIZE (insn));
00507 
00508            /* ??? 0 is passed for `pc'.  */
00509            errmsg = CGEN_CPU_INSERT_OPERAND (cd) (cd, opindex, fields,
00510                                              &insn_value, (bfd_vma) 0);
00511            cgen_put_insn_value (cd, (unsigned char *) where,
00512                              CGEN_INSN_BITSIZE (insn), insn_value);
00513          }
00514 #else
00515          /* ??? 0 is passed for `pc'.  */
00516          errmsg = CGEN_CPU_INSERT_OPERAND (cd) (cd, opindex, fields,
00517                                            (unsigned char *) where,
00518                                            (bfd_vma) 0);
00519 #endif
00520          if (errmsg)
00521            as_bad_where (fixP->fx_file, fixP->fx_line, "%s", errmsg);
00522        }
00523 
00524       if (fixP->fx_done)
00525        return;
00526 
00527       /* The operand isn't fully resolved.  Determine a BFD reloc value
00528         based on the operand information and leave it to
00529         bfd_install_relocation.  Note that this doesn't work when
00530         !partial_inplace.  */
00531 
00532       reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
00533       if (reloc_type != BFD_RELOC_NONE)
00534        fixP->fx_r_type = reloc_type;
00535       else
00536        {
00537          as_bad_where (fixP->fx_file, fixP->fx_line,
00538                      _("unresolved expression that must be resolved"));
00539          fixP->fx_done = 1;
00540          return;
00541        }
00542     }
00543   else if (fixP->fx_done)
00544     {
00545       /* We're finished with this fixup.  Install it because
00546         bfd_install_relocation won't be called to do it.  */
00547       switch (fixP->fx_r_type)
00548        {
00549        case BFD_RELOC_8:
00550          md_number_to_chars (where, value, 1);
00551          break;
00552        case BFD_RELOC_16:
00553          md_number_to_chars (where, value, 2);
00554          break;
00555        case BFD_RELOC_32:
00556          md_number_to_chars (where, value, 4);
00557          break;
00558        case BFD_RELOC_64:
00559          md_number_to_chars (where, value, 8);
00560          break;
00561        default:
00562          as_bad_where (fixP->fx_file, fixP->fx_line,
00563                      _("internal error: can't install fix for reloc type %d (`%s')"),
00564                      fixP->fx_r_type, bfd_get_reloc_code_name (fixP->fx_r_type));
00565          break;
00566        }
00567     }
00568   else
00569     {
00570       /* bfd_install_relocation will be called to finish things up.  */
00571     }
00572 
00573   /* This is a RELA port.  Thus, it does not need to store a
00574      value if it is going to make a reloc.  What's more, when
00575      assembling a line like
00576 
00577      .byte global-0x7f00
00578 
00579      we'll get a spurious error message if we try to stuff 0x7f00 into
00580      the byte.  */
00581   if (! fixP->fx_done)
00582     *valueP = 0;
00583 
00584   /* Tuck `value' away for use by tc_gen_reloc.
00585      See the comment describing fx_addnumber in write.h.
00586      This field is misnamed (or misused :-).  */
00587   fixP->fx_addnumber += value;
00588 }
00589 
00590 
00591 /* Write a value out to the object file, using the appropriate endianness.  */
00592 
00593 void
00594 md_number_to_chars (char * buf, valueT val, int n)
00595 {
00596   number_to_chars_littleendian (buf, val, n);
00597 }
00598 
00599 /* Turn a string in input_line_pointer into a floating point constant of type
00600    type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
00601    emitted is stored in *sizeP .  An error message is returned, or NULL on OK.
00602 */
00603 
00604 /* Equal to MAX_PRECISION in atof-ieee.c */
00605 #define MAX_LITTLENUMS 6
00606 
00607 char *
00608 md_atof (int type, char * litP, int * sizeP)
00609 {
00610   int              prec;
00611   LITTLENUM_TYPE   words [MAX_LITTLENUMS];
00612   LITTLENUM_TYPE   *wordP;
00613   char *           t;
00614 
00615   switch (type)
00616     {
00617     case 'f':
00618     case 'F':
00619       prec = 2;
00620       break;
00621 
00622     case 'd':
00623     case 'D':
00624       prec = 4;
00625       break;
00626 
00627    /* FIXME: Some targets allow other format chars for bigger sizes here.  */
00628 
00629     default:
00630       * sizeP = 0;
00631       return _("Bad call to md_atof()");
00632     }
00633 
00634   t = atof_ieee (input_line_pointer, type, words);
00635   if (t)
00636     input_line_pointer = t;
00637   * sizeP = prec * sizeof (LITTLENUM_TYPE);
00638 
00639   *sizeP = prec * sizeof (LITTLENUM_TYPE);
00640   /* This loops outputs the LITTLENUMs in REVERSE order; in accord with
00641      the littleendianness of the processor.  */
00642   for (wordP = words + prec - 1; prec--;)
00643     {
00644       md_number_to_chars (litP, (valueT) (*wordP--), sizeof (LITTLENUM_TYPE));
00645       litP += sizeof (LITTLENUM_TYPE);
00646     }
00647 
00648   return 0;
00649 }