Back to index

cell-binutils  2.17cvs20070401
tc-pj.c
Go to the documentation of this file.
00001 /*-
00002    tc-pj.c -- Assemble code for Pico Java
00003    Copyright 1999, 2000, 2001, 2002, 2003, 2005
00004    Free Software Foundation, Inc.
00005 
00006    This file is part of GAS, the GNU Assembler.
00007 
00008    GAS is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2, or (at your option)
00011    any later version.
00012 
00013    GAS is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017 
00018    You should have received a copy of the GNU General Public License
00019    along with GAS; see the file COPYING.  If not, write to
00020    the Free Software Foundation, 51 Franklin Street - Fifth Floor,
00021    Boston, MA 02110-1301, USA.  */
00022 
00023 /* Contributed by Steve Chamberlain of Transmeta <sac@pobox.com>.  */
00024 
00025 #include "as.h"
00026 #include "safe-ctype.h"
00027 #include "opcode/pj.h"
00028 
00029 extern const pj_opc_info_t pj_opc_info[512];
00030 
00031 const char comment_chars[]        = "!/";
00032 const char line_separator_chars[] = ";";
00033 const char line_comment_chars[]   = "/!#";
00034 
00035 static int pending_reloc;
00036 static struct hash_control *opcode_hash_control;
00037 
00038 static void
00039 little (int ignore ATTRIBUTE_UNUSED)
00040 {
00041   target_big_endian = 0;
00042 }
00043 
00044 static void
00045 big (int ignore ATTRIBUTE_UNUSED)
00046 {
00047   target_big_endian = 1;
00048 }
00049 
00050 const pseudo_typeS md_pseudo_table[] =
00051 {
00052   {"ml",    little, 0},
00053   {"mb",    big,    0},
00054   {0, 0, 0}
00055 };
00056 
00057 const char FLT_CHARS[] = "rRsSfFdDxXpP";
00058 const char EXP_CHARS[] = "eE";
00059 
00060 void
00061 md_operand (expressionS *op)
00062 {
00063   if (strncmp (input_line_pointer, "%hi16", 5) == 0)
00064     {
00065       if (pending_reloc)
00066        as_bad (_("confusing relocation expressions"));
00067       pending_reloc = BFD_RELOC_PJ_CODE_HI16;
00068       input_line_pointer += 5;
00069       expression (op);
00070     }
00071 
00072   if (strncmp (input_line_pointer, "%lo16", 5) == 0)
00073     {
00074       if (pending_reloc)
00075        as_bad (_("confusing relocation expressions"));
00076       pending_reloc = BFD_RELOC_PJ_CODE_LO16;
00077       input_line_pointer += 5;
00078       expression (op);
00079     }
00080 }
00081 
00082 /* Parse an expression and then restore the input line pointer.  */
00083 
00084 static char *
00085 parse_exp_save_ilp (char *s, expressionS *op)
00086 {
00087   char *save = input_line_pointer;
00088 
00089   input_line_pointer = s;
00090   expression (op);
00091   s = input_line_pointer;
00092   input_line_pointer = save;
00093   return s;
00094 }
00095 
00096 /* This is called by emit_expr via TC_CONS_FIX_NEW when creating a
00097    reloc for a cons.  We could use the definition there, except that
00098    we want to handle magic pending reloc expressions specially.  */
00099 
00100 void
00101 pj_cons_fix_new_pj (fragS *frag, int where, int nbytes, expressionS *exp)
00102 {
00103   static int rv[5][2] =
00104   { { 0, 0 },
00105     { BFD_RELOC_8, BFD_RELOC_8 },
00106     { BFD_RELOC_PJ_CODE_DIR16, BFD_RELOC_16 },
00107     { 0, 0 },
00108     { BFD_RELOC_PJ_CODE_DIR32, BFD_RELOC_32 }};
00109 
00110   fix_new_exp (frag, where, nbytes, exp, 0,
00111               pending_reloc ? pending_reloc
00112               : rv[nbytes][(now_seg->flags & SEC_CODE) ? 0 : 1]);
00113 
00114   pending_reloc = 0;
00115 }
00116 
00117 /* Turn a reloc description character from the pj-opc.h table into
00118    code which BFD can handle.  */
00119 
00120 static int
00121 c_to_r (int x)
00122 {
00123   switch (x)
00124     {
00125     case O_R8:
00126       return BFD_RELOC_8_PCREL;
00127     case O_U8:
00128     case O_8:
00129       return BFD_RELOC_8;
00130     case O_R16:
00131       return BFD_RELOC_PJ_CODE_REL16;
00132     case O_U16:
00133     case O_16:
00134       return BFD_RELOC_PJ_CODE_DIR16;
00135     case O_R32:
00136       return BFD_RELOC_PJ_CODE_REL32;
00137     case O_32:
00138       return BFD_RELOC_PJ_CODE_DIR32;
00139     }
00140   abort ();
00141   return 0;
00142 }
00143 
00144 /* Handler for the ipush fake opcode,
00145    turns ipush <foo> into sipush lo16<foo>, sethi hi16<foo>.  */
00146 
00147 static void
00148 ipush_code (pj_opc_info_t *opcode ATTRIBUTE_UNUSED, char *str)
00149 {
00150   char *b = frag_more (6);
00151   expressionS arg;
00152 
00153   b[0] = 0x11;
00154   b[3] = 0xed;
00155   parse_exp_save_ilp (str + 1, &arg);
00156   if (pending_reloc)
00157     {
00158       as_bad (_("can't have relocation for ipush"));
00159       pending_reloc = 0;
00160     }
00161 
00162   fix_new_exp (frag_now, b - frag_now->fr_literal + 1, 2,
00163               &arg, 0, BFD_RELOC_PJ_CODE_DIR16);
00164   fix_new_exp (frag_now, b - frag_now->fr_literal + 4, 2,
00165               &arg, 0, BFD_RELOC_PJ_CODE_HI16);
00166 }
00167 
00168 /* Insert names into the opcode table which are really mini macros,
00169    not opcodes.  The fakeness is indicated with an opcode of -1.  */
00170 
00171 static void
00172 fake_opcode (const char *name,
00173             void (*func) (struct pj_opc_info_t *, char *))
00174 {
00175   pj_opc_info_t * fake = xmalloc (sizeof (pj_opc_info_t));
00176 
00177   fake->opcode = -1;
00178   fake->opcode_next = -1;
00179   fake->u.func = func;
00180   hash_insert (opcode_hash_control, name, (char *) fake);
00181 }
00182 
00183 /* Enter another entry into the opcode hash table so the same opcode
00184    can have another name.  */
00185 
00186 static void
00187 alias (const char *new, const char *old)
00188 {
00189   hash_insert (opcode_hash_control, new,
00190               (char *) hash_find (opcode_hash_control, old));
00191 }
00192 
00193 /* This function is called once, at assembler startup time.  It sets
00194    up the hash table with all the opcodes in it, and also initializes
00195    some aliases for compatibility with other assemblers.  */
00196 
00197 void
00198 md_begin (void)
00199 {
00200   const pj_opc_info_t *opcode;
00201   opcode_hash_control = hash_new ();
00202 
00203   /* Insert names into hash table.  */
00204   for (opcode = pj_opc_info; opcode->u.name; opcode++)
00205     hash_insert (opcode_hash_control, opcode->u.name, (char *) opcode);
00206 
00207   /* Insert the only fake opcode.  */
00208   fake_opcode ("ipush", ipush_code);
00209 
00210   /* Add some aliases for opcode names.  */
00211   alias ("ifeq_s", "ifeq");
00212   alias ("ifne_s", "ifne");
00213   alias ("if_icmpge_s", "if_icmpge");
00214   alias ("if_icmpne_s", "if_icmpne");
00215   alias ("if_icmpeq_s", "if_icmpeq");
00216   alias ("if_icmpgt_s", "if_icmpgt");
00217   alias ("goto_s", "goto");
00218 
00219   bfd_set_arch_mach (stdoutput, TARGET_ARCH, 0);
00220 }
00221 
00222 /* This is the guts of the machine-dependent assembler.  STR points to
00223    a machine dependent instruction.  This function is supposed to emit
00224    the frags/bytes it assembles to.  */
00225 
00226 void
00227 md_assemble (char *str)
00228 {
00229   char *op_start;
00230   char *op_end;
00231 
00232   pj_opc_info_t *opcode;
00233   char *output;
00234   int idx = 0;
00235   char pend;
00236 
00237   int nlen = 0;
00238 
00239   /* Drop leading whitespace.  */
00240   while (*str == ' ')
00241     str++;
00242 
00243   /* Find the op code end.  */
00244   op_start = str;
00245   for (op_end = str;
00246        *op_end && !is_end_of_line[*op_end & 0xff] && *op_end != ' ';
00247        op_end++)
00248     nlen++;
00249 
00250   pend = *op_end;
00251   *op_end = 0;
00252 
00253   if (nlen == 0)
00254     as_bad (_("can't find opcode "));
00255 
00256   opcode = (pj_opc_info_t *) hash_find (opcode_hash_control, op_start);
00257   *op_end = pend;
00258 
00259   if (opcode == NULL)
00260     {
00261       as_bad (_("unknown opcode %s"), op_start);
00262       return;
00263     }
00264 
00265   if (opcode->opcode == -1)
00266     {
00267       /* It's a fake opcode.  Dig out the args and pretend that was
00268          what we were passed.  */
00269       (*opcode->u.func) (opcode, op_end);
00270     }
00271   else
00272     {
00273       int an;
00274 
00275       output = frag_more (opcode->len);
00276       output[idx++] = opcode->opcode;
00277 
00278       if (opcode->opcode_next != -1)
00279        output[idx++] = opcode->opcode_next;
00280 
00281       for (an = 0; opcode->arg[an]; an++)
00282        {
00283          expressionS arg;
00284 
00285          if (*op_end == ',' && an != 0)
00286            op_end++;
00287 
00288          if (*op_end == 0)
00289            as_bad ("expected expresssion");
00290 
00291          op_end = parse_exp_save_ilp (op_end, &arg);
00292 
00293          fix_new_exp (frag_now,
00294                      output - frag_now->fr_literal + idx,
00295                      ASIZE (opcode->arg[an]),
00296                      &arg,
00297                      PCREL (opcode->arg[an]),
00298                      pending_reloc ? pending_reloc : c_to_r (opcode->arg[an]));
00299 
00300          idx += ASIZE (opcode->arg[an]);
00301          pending_reloc = 0;
00302        }
00303 
00304       while (ISSPACE (*op_end))
00305        op_end++;
00306 
00307       if (*op_end != 0)
00308        as_warn ("extra stuff on line ignored");
00309 
00310     }
00311 
00312   if (pending_reloc)
00313     as_bad ("Something forgot to clean up\n");
00314 
00315 }
00316 
00317 /* Turn a string in input_line_pointer into a floating point constant
00318    of type type, and store the appropriate bytes in *LITP.  The number
00319    of LITTLENUMS emitted is stored in *SIZEP .  An error message is
00320    returned, or NULL on OK.  */
00321 
00322 char *
00323 md_atof (int type, char *litP, int *sizeP)
00324 {
00325   int prec;
00326   LITTLENUM_TYPE words[4];
00327   char *t;
00328   int i;
00329 
00330   switch (type)
00331     {
00332     case 'f':
00333       prec = 2;
00334       break;
00335 
00336     case 'd':
00337       prec = 4;
00338       break;
00339 
00340     default:
00341       *sizeP = 0;
00342       return _("bad call to md_atof");
00343     }
00344 
00345   t = atof_ieee (input_line_pointer, type, words);
00346   if (t)
00347     input_line_pointer = t;
00348 
00349   *sizeP = prec * 2;
00350 
00351   if (!target_big_endian)
00352     {
00353       for (i = prec - 1; i >= 0; i--)
00354        {
00355          md_number_to_chars (litP, (valueT) words[i], 2);
00356          litP += 2;
00357        }
00358     }
00359   else
00360     {
00361       for (i = 0; i < prec; i++)
00362        {
00363          md_number_to_chars (litP, (valueT) words[i], 2);
00364          litP += 2;
00365        }
00366     }
00367 
00368   return NULL;
00369 }
00370 
00371 const char *md_shortopts = "";
00372 
00373 struct option md_longopts[] =
00374 {
00375 #define OPTION_LITTLE (OPTION_MD_BASE)
00376 #define OPTION_BIG    (OPTION_LITTLE + 1)
00377 
00378   {"little", no_argument, NULL, OPTION_LITTLE},
00379   {"big", no_argument, NULL, OPTION_BIG},
00380   {NULL, no_argument, NULL, 0}
00381 };
00382 size_t md_longopts_size = sizeof (md_longopts);
00383 
00384 int
00385 md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
00386 {
00387   switch (c)
00388     {
00389     case OPTION_LITTLE:
00390       little (0);
00391       break;
00392     case OPTION_BIG:
00393       big (0);
00394       break;
00395     default:
00396       return 0;
00397     }
00398   return 1;
00399 }
00400 
00401 void
00402 md_show_usage (FILE *stream)
00403 {
00404   fprintf (stream, _("\
00405 PJ options:\n\
00406 -little                     generate little endian code\n\
00407 -big                 generate big endian code\n"));
00408 }
00409 
00410 /* Apply a fixup to the object file.  */
00411 
00412 void
00413 md_apply_fix (fixS *fixP, valueT * valP, segT seg ATTRIBUTE_UNUSED)
00414 {
00415   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
00416   long val = *valP;
00417   long max, min;
00418   int shift;
00419 
00420   max = min = 0;
00421   shift = 0;
00422   switch (fixP->fx_r_type)
00423     {
00424     case BFD_RELOC_VTABLE_INHERIT:
00425     case BFD_RELOC_VTABLE_ENTRY:
00426       fixP->fx_done = 0;
00427       return;
00428 
00429     case BFD_RELOC_PJ_CODE_REL16:
00430       if (val < -0x8000 || val >= 0x7fff)
00431        as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far"));
00432       buf[0] |= (val >> 8) & 0xff;
00433       buf[1] = val & 0xff;
00434       break;
00435 
00436     case BFD_RELOC_PJ_CODE_HI16:
00437       *buf++ = val >> 24;
00438       *buf++ = val >> 16;
00439       fixP->fx_addnumber = val & 0xffff;
00440       break;
00441 
00442     case BFD_RELOC_PJ_CODE_DIR16:
00443     case BFD_RELOC_PJ_CODE_LO16:
00444       *buf++ = val >> 8;
00445       *buf++ = val >> 0;
00446 
00447       max = 0xffff;
00448       min = -0xffff;
00449       break;
00450 
00451     case BFD_RELOC_8:
00452       max = 0xff;
00453       min = -0xff;
00454       *buf++ = val;
00455       break;
00456 
00457     case BFD_RELOC_PJ_CODE_DIR32:
00458       *buf++ = val >> 24;
00459       *buf++ = val >> 16;
00460       *buf++ = val >> 8;
00461       *buf++ = val >> 0;
00462       break;
00463 
00464     case BFD_RELOC_32:
00465       if (target_big_endian)
00466        {
00467          *buf++ = val >> 24;
00468          *buf++ = val >> 16;
00469          *buf++ = val >> 8;
00470          *buf++ = val >> 0;
00471        }
00472       else
00473        {
00474          *buf++ = val >> 0;
00475          *buf++ = val >> 8;
00476          *buf++ = val >> 16;
00477          *buf++ = val >> 24;
00478        }
00479       break;
00480 
00481     case BFD_RELOC_16:
00482       if (target_big_endian)
00483        {
00484          *buf++ = val >> 8;
00485          *buf++ = val >> 0;
00486        }
00487       else
00488        {
00489          *buf++ = val >> 0;
00490          *buf++ = val >> 8;
00491        }
00492       break;
00493 
00494     default:
00495       abort ();
00496     }
00497 
00498   if (max != 0 && (val < min || val > max))
00499     as_bad_where (fixP->fx_file, fixP->fx_line, _("offset out of range"));
00500 
00501   if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
00502     fixP->fx_done = 1;
00503 }
00504 
00505 /* Put number into target byte order.  Always put values in an
00506    executable section into big endian order.  */
00507 
00508 void
00509 md_number_to_chars (char *ptr, valueT use, int nbytes)
00510 {
00511   if (target_big_endian || now_seg->flags & SEC_CODE)
00512     number_to_chars_bigendian (ptr, use, nbytes);
00513   else
00514     number_to_chars_littleendian (ptr, use, nbytes);
00515 }
00516 
00517 /* Translate internal representation of relocation info to BFD target
00518    format.  */
00519 
00520 arelent *
00521 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
00522 {
00523   arelent *rel;
00524   bfd_reloc_code_real_type r_type;
00525 
00526   rel = xmalloc (sizeof (arelent));
00527   rel->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
00528   *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
00529   rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
00530 
00531   r_type = fixp->fx_r_type;
00532   rel->addend = fixp->fx_addnumber;
00533   rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
00534 
00535   if (rel->howto == NULL)
00536     {
00537       as_bad_where (fixp->fx_file, fixp->fx_line,
00538                   _("Cannot represent relocation type %s"),
00539                   bfd_get_reloc_code_name (r_type));
00540       /* Set howto to a garbage value so that we can keep going.  */
00541       rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
00542       assert (rel->howto != NULL);
00543     }
00544 
00545   return rel;
00546 }