Home | History | Annotate | Download | only in config
      1 /* tc-pj.c -- Assemble code for Pico Java
      2    Copyright (C) 1999-2014 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 /* Contributed by Steve Chamberlain of Transmeta <sac (at) pobox.com>.  */
     22 
     23 #include "as.h"
     24 #include "safe-ctype.h"
     25 #include "opcode/pj.h"
     26 
     27 extern const pj_opc_info_t pj_opc_info[512];
     28 
     29 const char comment_chars[]        = "!/";
     30 const char line_separator_chars[] = ";";
     31 const char line_comment_chars[]   = "/!#";
     32 
     33 static int pending_reloc;
     34 static struct hash_control *opcode_hash_control;
     35 
     36 static void
     37 little (int ignore ATTRIBUTE_UNUSED)
     38 {
     39   target_big_endian = 0;
     40 }
     41 
     42 static void
     43 big (int ignore ATTRIBUTE_UNUSED)
     44 {
     45   target_big_endian = 1;
     46 }
     47 
     48 const pseudo_typeS md_pseudo_table[] =
     49 {
     50   {"ml",    little, 0},
     51   {"mb",    big,    0},
     52   {0, 0, 0}
     53 };
     54 
     55 const char FLT_CHARS[] = "rRsSfFdDxXpP";
     56 const char EXP_CHARS[] = "eE";
     57 
     58 void
     59 md_operand (expressionS *op)
     60 {
     61   if (strncmp (input_line_pointer, "%hi16", 5) == 0)
     62     {
     63       if (pending_reloc)
     64 	as_bad (_("confusing relocation expressions"));
     65       pending_reloc = BFD_RELOC_PJ_CODE_HI16;
     66       input_line_pointer += 5;
     67       expression (op);
     68     }
     69 
     70   if (strncmp (input_line_pointer, "%lo16", 5) == 0)
     71     {
     72       if (pending_reloc)
     73 	as_bad (_("confusing relocation expressions"));
     74       pending_reloc = BFD_RELOC_PJ_CODE_LO16;
     75       input_line_pointer += 5;
     76       expression (op);
     77     }
     78 }
     79 
     80 /* Parse an expression and then restore the input line pointer.  */
     81 
     82 static char *
     83 parse_exp_save_ilp (char *s, expressionS *op)
     84 {
     85   char *save = input_line_pointer;
     86 
     87   input_line_pointer = s;
     88   expression (op);
     89   s = input_line_pointer;
     90   input_line_pointer = save;
     91   return s;
     92 }
     93 
     94 /* This is called by emit_expr via TC_CONS_FIX_NEW when creating a
     95    reloc for a cons.  We could use the definition there, except that
     96    we want to handle magic pending reloc expressions specially.  */
     97 
     98 void
     99 pj_cons_fix_new_pj (fragS *frag, int where, int nbytes, expressionS *exp,
    100 		    bfd_reloc_code_real_type r ATTRIBUTE_UNUSED)
    101 {
    102   static int rv[5][2] =
    103   { { 0, 0 },
    104     { BFD_RELOC_8, BFD_RELOC_8 },
    105     { BFD_RELOC_PJ_CODE_DIR16, BFD_RELOC_16 },
    106     { 0, 0 },
    107     { BFD_RELOC_PJ_CODE_DIR32, BFD_RELOC_32 }};
    108 
    109   fix_new_exp (frag, where, nbytes, exp, 0,
    110 	       pending_reloc ? pending_reloc
    111 	       : rv[nbytes][(now_seg->flags & SEC_CODE) ? 0 : 1]);
    112 
    113   pending_reloc = 0;
    114 }
    115 
    116 /* Turn a reloc description character from the pj-opc.h table into
    117    code which BFD can handle.  */
    118 
    119 static int
    120 c_to_r (int x)
    121 {
    122   switch (x)
    123     {
    124     case O_R8:
    125       return BFD_RELOC_8_PCREL;
    126     case O_U8:
    127     case O_8:
    128       return BFD_RELOC_8;
    129     case O_R16:
    130       return BFD_RELOC_PJ_CODE_REL16;
    131     case O_U16:
    132     case O_16:
    133       return BFD_RELOC_PJ_CODE_DIR16;
    134     case O_R32:
    135       return BFD_RELOC_PJ_CODE_REL32;
    136     case O_32:
    137       return BFD_RELOC_PJ_CODE_DIR32;
    138     }
    139   abort ();
    140   return 0;
    141 }
    142 
    143 /* Handler for the ipush fake opcode,
    144    turns ipush <foo> into sipush lo16<foo>, sethi hi16<foo>.  */
    145 
    146 static void
    147 ipush_code (pj_opc_info_t *opcode ATTRIBUTE_UNUSED, char *str)
    148 {
    149   char *b = frag_more (6);
    150   expressionS arg;
    151 
    152   b[0] = 0x11;
    153   b[3] = 0xed;
    154   parse_exp_save_ilp (str + 1, &arg);
    155   if (pending_reloc)
    156     {
    157       as_bad (_("can't have relocation for ipush"));
    158       pending_reloc = 0;
    159     }
    160 
    161   fix_new_exp (frag_now, b - frag_now->fr_literal + 1, 2,
    162 	       &arg, 0, BFD_RELOC_PJ_CODE_DIR16);
    163   fix_new_exp (frag_now, b - frag_now->fr_literal + 4, 2,
    164 	       &arg, 0, BFD_RELOC_PJ_CODE_HI16);
    165 }
    166 
    167 /* Insert names into the opcode table which are really mini macros,
    168    not opcodes.  The fakeness is indicated with an opcode of -1.  */
    169 
    170 static void
    171 fake_opcode (const char *name,
    172 	     void (*func) (struct pj_opc_info_t *, char *))
    173 {
    174   pj_opc_info_t * fake = xmalloc (sizeof (pj_opc_info_t));
    175 
    176   fake->opcode = -1;
    177   fake->opcode_next = -1;
    178   fake->u.func = func;
    179   hash_insert (opcode_hash_control, name, (char *) fake);
    180 }
    181 
    182 /* Enter another entry into the opcode hash table so the same opcode
    183    can have another name.  */
    184 
    185 static void
    186 alias (const char *new_name, const char *old)
    187 {
    188   hash_insert (opcode_hash_control, new_name,
    189 	       (char *) hash_find (opcode_hash_control, old));
    190 }
    191 
    192 /* This function is called once, at assembler startup time.  It sets
    193    up the hash table with all the opcodes in it, and also initializes
    194    some aliases for compatibility with other assemblers.  */
    195 
    196 void
    197 md_begin (void)
    198 {
    199   const pj_opc_info_t *opcode;
    200   opcode_hash_control = hash_new ();
    201 
    202   /* Insert names into hash table.  */
    203   for (opcode = pj_opc_info; opcode->u.name; opcode++)
    204     hash_insert (opcode_hash_control, opcode->u.name, (char *) opcode);
    205 
    206   /* Insert the only fake opcode.  */
    207   fake_opcode ("ipush", ipush_code);
    208 
    209   /* Add some aliases for opcode names.  */
    210   alias ("ifeq_s", "ifeq");
    211   alias ("ifne_s", "ifne");
    212   alias ("if_icmpge_s", "if_icmpge");
    213   alias ("if_icmpne_s", "if_icmpne");
    214   alias ("if_icmpeq_s", "if_icmpeq");
    215   alias ("if_icmpgt_s", "if_icmpgt");
    216   alias ("goto_s", "goto");
    217 
    218   bfd_set_arch_mach (stdoutput, TARGET_ARCH, 0);
    219 }
    220 
    221 /* This is the guts of the machine-dependent assembler.  STR points to
    222    a machine dependent instruction.  This function is supposed to emit
    223    the frags/bytes it assembles to.  */
    224 
    225 void
    226 md_assemble (char *str)
    227 {
    228   char *op_start;
    229   char *op_end;
    230 
    231   pj_opc_info_t *opcode;
    232   char *output;
    233   int idx = 0;
    234   char pend;
    235 
    236   int nlen = 0;
    237 
    238   /* Drop leading whitespace.  */
    239   while (*str == ' ')
    240     str++;
    241 
    242   /* Find the op code end.  */
    243   op_start = str;
    244   for (op_end = str;
    245        *op_end && !is_end_of_line[*op_end & 0xff] && *op_end != ' ';
    246        op_end++)
    247     nlen++;
    248 
    249   pend = *op_end;
    250   *op_end = 0;
    251 
    252   if (nlen == 0)
    253     as_bad (_("can't find opcode "));
    254 
    255   opcode = (pj_opc_info_t *) hash_find (opcode_hash_control, op_start);
    256   *op_end = pend;
    257 
    258   if (opcode == NULL)
    259     {
    260       as_bad (_("unknown opcode %s"), op_start);
    261       return;
    262     }
    263 
    264   dwarf2_emit_insn (0);
    265   if (opcode->opcode == -1)
    266     {
    267       /* It's a fake opcode.  Dig out the args and pretend that was
    268          what we were passed.  */
    269       (*opcode->u.func) (opcode, op_end);
    270     }
    271   else
    272     {
    273       int an;
    274 
    275       output = frag_more (opcode->len);
    276       output[idx++] = opcode->opcode;
    277 
    278       if (opcode->opcode_next != -1)
    279 	output[idx++] = opcode->opcode_next;
    280 
    281       for (an = 0; opcode->arg[an]; an++)
    282 	{
    283 	  expressionS arg;
    284 
    285 	  if (*op_end == ',' && an != 0)
    286 	    op_end++;
    287 
    288 	  if (*op_end == 0)
    289 	    as_bad (_("expected expression"));
    290 
    291 	  op_end = parse_exp_save_ilp (op_end, &arg);
    292 
    293 	  fix_new_exp (frag_now,
    294 		       output - frag_now->fr_literal + idx,
    295 		       ASIZE (opcode->arg[an]),
    296 		       &arg,
    297 		       PCREL (opcode->arg[an]),
    298 		       pending_reloc ? pending_reloc : c_to_r (opcode->arg[an]));
    299 
    300 	  idx += ASIZE (opcode->arg[an]);
    301 	  pending_reloc = 0;
    302 	}
    303 
    304       while (ISSPACE (*op_end))
    305 	op_end++;
    306 
    307       if (*op_end != 0)
    308 	as_warn (_("extra stuff on line ignored"));
    309 
    310     }
    311 
    312   if (pending_reloc)
    313     as_bad (_("Something forgot to clean up\n"));
    314 }
    315 
    316 char *
    317 md_atof (int type, char *litP, int *sizeP)
    318 {
    319   return ieee_md_atof (type, litP, sizeP, target_big_endian);
    320 }
    321 
    322 const char *md_shortopts = "";
    324 
    325 struct option md_longopts[] =
    326 {
    327 #define OPTION_LITTLE (OPTION_MD_BASE)
    328 #define OPTION_BIG    (OPTION_LITTLE + 1)
    329 
    330   {"little", no_argument, NULL, OPTION_LITTLE},
    331   {"big", no_argument, NULL, OPTION_BIG},
    332   {NULL, no_argument, NULL, 0}
    333 };
    334 size_t md_longopts_size = sizeof (md_longopts);
    335 
    336 int
    337 md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
    338 {
    339   switch (c)
    340     {
    341     case OPTION_LITTLE:
    342       little (0);
    343       break;
    344     case OPTION_BIG:
    345       big (0);
    346       break;
    347     default:
    348       return 0;
    349     }
    350   return 1;
    351 }
    352 
    353 void
    354 md_show_usage (FILE *stream)
    355 {
    356   fprintf (stream, _("\
    357 PJ options:\n\
    358 -little			generate little endian code\n\
    359 -big			generate big endian code\n"));
    360 }
    361 
    362 /* Apply a fixup to the object file.  */
    363 
    364 void
    365 md_apply_fix (fixS *fixP, valueT * valP, segT seg ATTRIBUTE_UNUSED)
    366 {
    367   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
    368   long val = *valP;
    369   long max, min;
    370 
    371   max = min = 0;
    372   switch (fixP->fx_r_type)
    373     {
    374     case BFD_RELOC_VTABLE_INHERIT:
    375     case BFD_RELOC_VTABLE_ENTRY:
    376       fixP->fx_done = 0;
    377       return;
    378 
    379     case BFD_RELOC_PJ_CODE_REL16:
    380       if (val < -0x8000 || val >= 0x7fff)
    381 	as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far"));
    382       buf[0] |= (val >> 8) & 0xff;
    383       buf[1] = val & 0xff;
    384       break;
    385 
    386     case BFD_RELOC_PJ_CODE_HI16:
    387       *buf++ = val >> 24;
    388       *buf++ = val >> 16;
    389       fixP->fx_addnumber = val & 0xffff;
    390       break;
    391 
    392     case BFD_RELOC_PJ_CODE_DIR16:
    393     case BFD_RELOC_PJ_CODE_LO16:
    394       *buf++ = val >> 8;
    395       *buf++ = val >> 0;
    396 
    397       max = 0xffff;
    398       min = -0xffff;
    399       break;
    400 
    401     case BFD_RELOC_8:
    402       max = 0xff;
    403       min = -0xff;
    404       *buf++ = val;
    405       break;
    406 
    407     case BFD_RELOC_PJ_CODE_DIR32:
    408       *buf++ = val >> 24;
    409       *buf++ = val >> 16;
    410       *buf++ = val >> 8;
    411       *buf++ = val >> 0;
    412       break;
    413 
    414     case BFD_RELOC_32:
    415       if (target_big_endian)
    416 	{
    417 	  *buf++ = val >> 24;
    418 	  *buf++ = val >> 16;
    419 	  *buf++ = val >> 8;
    420 	  *buf++ = val >> 0;
    421 	}
    422       else
    423 	{
    424 	  *buf++ = val >> 0;
    425 	  *buf++ = val >> 8;
    426 	  *buf++ = val >> 16;
    427 	  *buf++ = val >> 24;
    428 	}
    429       break;
    430 
    431     case BFD_RELOC_16:
    432       if (target_big_endian)
    433 	{
    434 	  *buf++ = val >> 8;
    435 	  *buf++ = val >> 0;
    436 	}
    437       else
    438 	{
    439 	  *buf++ = val >> 0;
    440 	  *buf++ = val >> 8;
    441 	}
    442       break;
    443 
    444     default:
    445       abort ();
    446     }
    447 
    448   if (max != 0 && (val < min || val > max))
    449     as_bad_where (fixP->fx_file, fixP->fx_line, _("offset out of range"));
    450 
    451   if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
    452     fixP->fx_done = 1;
    453 }
    454 
    455 /* Put number into target byte order.  Always put values in an
    456    executable section into big endian order.  */
    457 
    458 void
    459 md_number_to_chars (char *ptr, valueT use, int nbytes)
    460 {
    461   if (target_big_endian || now_seg->flags & SEC_CODE)
    462     number_to_chars_bigendian (ptr, use, nbytes);
    463   else
    464     number_to_chars_littleendian (ptr, use, nbytes);
    465 }
    466 
    467 /* Translate internal representation of relocation info to BFD target
    468    format.  */
    469 
    470 arelent *
    471 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
    472 {
    473   arelent *rel;
    474   bfd_reloc_code_real_type r_type;
    475 
    476   rel = xmalloc (sizeof (arelent));
    477   rel->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
    478   *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
    479   rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
    480 
    481   r_type = fixp->fx_r_type;
    482   rel->addend = fixp->fx_addnumber;
    483   rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
    484 
    485   if (rel->howto == NULL)
    486     {
    487       as_bad_where (fixp->fx_file, fixp->fx_line,
    488 		    _("Cannot represent relocation type %s"),
    489 		    bfd_get_reloc_code_name (r_type));
    490       /* Set howto to a garbage value so that we can keep going.  */
    491       rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
    492       gas_assert (rel->howto != NULL);
    493     }
    494 
    495   return rel;
    496 }
    497