Home | History | Annotate | Line # | Download | only in config
tc-moxie.c revision 1.1.1.1
      1 /* tc-moxie.c -- Assemble code for moxie
      2    Copyright 2009
      3    Free Software Foundation, Inc.
      4 
      5    This file is part of GAS, the GNU Assembler.
      6 
      7    GAS is free software; you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3, or (at your option)
     10    any later version.
     11 
     12    GAS is distributed in the hope that it will be useful,
     13    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15    GNU General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with GAS; see the file COPYING.  If not, write to
     19    the Free Software Foundation, 51 Franklin Street - Fifth Floor,
     20    Boston, MA 02110-1301, USA.  */
     21 
     22 /* Contributed by Anthony Green <green (at) moxielogic.com>.  */
     23 
     24 #include "as.h"
     25 #include "safe-ctype.h"
     26 #include "opcode/moxie.h"
     27 #include "elf/moxie.h"
     28 
     29 extern const moxie_opc_info_t moxie_opc_info[128];
     30 
     31 const char comment_chars[]        = "#";
     32 const char line_separator_chars[] = ";";
     33 const char line_comment_chars[]   = "#";
     34 
     35 static int pending_reloc;
     36 static struct hash_control *opcode_hash_control;
     37 
     38 const pseudo_typeS md_pseudo_table[] =
     39 {
     40   {0, 0, 0}
     41 };
     42 
     43 const char FLT_CHARS[] = "rRsSfFdDxXpP";
     44 const char EXP_CHARS[] = "eE";
     45 
     46 static int md_chars_to_number (char *val, int n);
     47 
     48 void
     49 md_operand (expressionS *op __attribute__((unused)))
     50 {
     51   /* Empty for now. */
     52 }
     53 
     54 /* This function is called once, at assembler startup time.  It sets
     55    up the hash table with all the opcodes in it, and also initializes
     56    some aliases for compatibility with other assemblers.  */
     57 
     58 void
     59 md_begin (void)
     60 {
     61   int count;
     62   const moxie_opc_info_t *opcode;
     63   opcode_hash_control = hash_new ();
     64 
     65   /* Insert names into hash table.  */
     66   for (count = 0, opcode = moxie_form1_opc_info; count++ < 64; opcode++)
     67     hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
     68 
     69   for (count = 0, opcode = moxie_form2_opc_info; count++ < 4; opcode++)
     70     hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
     71 
     72   for (count = 0, opcode = moxie_form3_opc_info; count++ < 10; opcode++)
     73     hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
     74 
     75   bfd_set_arch_mach (stdoutput, TARGET_ARCH, 0);
     76 }
     77 
     78 /* Parse an expression and then restore the input line pointer.  */
     79 
     80 static char *
     81 parse_exp_save_ilp (char *s, expressionS *op)
     82 {
     83   char *save = input_line_pointer;
     84 
     85   input_line_pointer = s;
     86   expression (op);
     87   s = input_line_pointer;
     88   input_line_pointer = save;
     89   return s;
     90 }
     91 
     92 static int
     93 parse_register_operand (char **ptr)
     94 {
     95   int reg;
     96   char *s = *ptr;
     97 
     98   if (*s != '$')
     99     {
    100       as_bad (_("expecting register"));
    101       ignore_rest_of_line ();
    102       return -1;
    103     }
    104   if (s[1] == 'f' && s[2] == 'p')
    105     {
    106       *ptr += 3;
    107       return 0;
    108     }
    109   if (s[1] == 's' && s[2] == 'p')
    110     {
    111       *ptr += 3;
    112       return 1;
    113     }
    114   if (s[1] == 'r')
    115     {
    116       reg = s[2] - '0';
    117       if ((reg < 0) || (reg > 9))
    118 	{
    119 	  as_bad (_("illegal register number"));
    120 	  ignore_rest_of_line ();
    121 	  return -1;
    122 	}
    123       if (reg == 1)
    124 	{
    125 	  int r2 = s[3] - '0';
    126 	  if ((r2 >= 0) && (r2 <= 3))
    127 	    {
    128 	      reg = 10 + r2;
    129 	      *ptr += 1;
    130 	    }
    131 	}
    132     }
    133   else
    134     {
    135       as_bad (_("illegal register number"));
    136       ignore_rest_of_line ();
    137       return -1;
    138     }
    139 
    140   *ptr += 3;
    141 
    142   return reg + 2;
    143 }
    144 
    145 /* This is the guts of the machine-dependent assembler.  STR points to
    146    a machine dependent instruction.  This function is supposed to emit
    147    the frags/bytes it assembles to.  */
    148 
    149 void
    150 md_assemble (char *str)
    151 {
    152   char *op_start;
    153   char *op_end;
    154 
    155   moxie_opc_info_t *opcode;
    156   char *p;
    157   char pend;
    158 
    159   unsigned short iword = 0;
    160 
    161   int nlen = 0;
    162 
    163   /* Drop leading whitespace.  */
    164   while (*str == ' ')
    165     str++;
    166 
    167   /* Find the op code end.  */
    168   op_start = str;
    169   for (op_end = str;
    170        *op_end && !is_end_of_line[*op_end & 0xff] && *op_end != ' ';
    171        op_end++)
    172     nlen++;
    173 
    174   pend = *op_end;
    175   *op_end = 0;
    176 
    177   if (nlen == 0)
    178     as_bad (_("can't find opcode "));
    179   opcode = (moxie_opc_info_t *) hash_find (opcode_hash_control, op_start);
    180   *op_end = pend;
    181 
    182   if (opcode == NULL)
    183     {
    184       as_bad (_("unknown opcode %s"), op_start);
    185       return;
    186     }
    187 
    188   p = frag_more (2);
    189 
    190   switch (opcode->itype)
    191     {
    192     case MOXIE_F2_A8V:
    193       iword = (1<<15) | (opcode->opcode << 12);
    194       while (ISSPACE (*op_end))
    195 	op_end++;
    196       {
    197 	expressionS arg;
    198 	int reg;
    199 	reg = parse_register_operand (&op_end);
    200 	iword += (reg << 8);
    201 	if (*op_end != ',')
    202 	  as_warn (_("expecting comma delimited register operands"));
    203 	op_end++;
    204 	op_end = parse_exp_save_ilp (op_end, &arg);
    205 	fix_new_exp (frag_now,
    206 		     ((p+1) - frag_now->fr_literal),
    207 		     1,
    208 		     &arg,
    209 		     0,
    210 		     BFD_RELOC_8);
    211       }
    212       break;
    213     case MOXIE_F1_AB:
    214       iword = opcode->opcode << 8;
    215       while (ISSPACE (*op_end))
    216 	op_end++;
    217       {
    218 	int dest, src;
    219 	dest = parse_register_operand (&op_end);
    220 	if (*op_end != ',')
    221 	  as_warn (_("expecting comma delimited register operands"));
    222 	op_end++;
    223 	src  = parse_register_operand (&op_end);
    224 	iword += (dest << 4) + src;
    225 	while (ISSPACE (*op_end))
    226 	  op_end++;
    227 	if (*op_end != 0)
    228 	  as_warn (_("extra stuff on line ignored"));
    229       }
    230       break;
    231     case MOXIE_F1_A4:
    232       iword = opcode->opcode << 8;
    233       while (ISSPACE (*op_end))
    234 	op_end++;
    235       {
    236 	expressionS arg;
    237 	char *where;
    238 	int regnum;
    239 
    240  	regnum = parse_register_operand (&op_end);
    241 	while (ISSPACE (*op_end))
    242 	  op_end++;
    243 
    244 	iword += (regnum << 4);
    245 
    246 	if (*op_end != ',')
    247 	  {
    248 	    as_bad (_("expecting comma delimited operands"));
    249 	    ignore_rest_of_line ();
    250 	    return;
    251 	  }
    252 	op_end++;
    253 
    254 	op_end = parse_exp_save_ilp (op_end, &arg);
    255 	where = frag_more (4);
    256 	fix_new_exp (frag_now,
    257 		     (where - frag_now->fr_literal),
    258 		     4,
    259 		     &arg,
    260 		     0,
    261 		     BFD_RELOC_32);
    262       }
    263       break;
    264     case MOXIE_F1_M:
    265     case MOXIE_F1_4:
    266       iword = opcode->opcode << 8;
    267       while (ISSPACE (*op_end))
    268 	op_end++;
    269       {
    270 	expressionS arg;
    271 	char *where;
    272 
    273 	op_end = parse_exp_save_ilp (op_end, &arg);
    274 	where = frag_more (4);
    275 	fix_new_exp (frag_now,
    276 		     (where - frag_now->fr_literal),
    277 		     4,
    278 		     &arg,
    279 		     0,
    280 		     BFD_RELOC_32);
    281       }
    282       break;
    283     case MOXIE_F1_NARG:
    284       iword = opcode->opcode << 8;
    285       while (ISSPACE (*op_end))
    286 	op_end++;
    287       if (*op_end != 0)
    288 	as_warn (_("extra stuff on line ignored"));
    289       break;
    290     case MOXIE_F1_A:
    291       iword = opcode->opcode << 8;
    292       while (ISSPACE (*op_end))
    293 	op_end++;
    294       {
    295 	int reg;
    296 	reg = parse_register_operand (&op_end);
    297 	while (ISSPACE (*op_end))
    298 	  op_end++;
    299 	if (*op_end != 0)
    300 	  as_warn (_("extra stuff on line ignored"));
    301 	iword += (reg << 4);
    302       }
    303       break;
    304     case MOXIE_F1_ABi:
    305       iword = opcode->opcode << 8;
    306       while (ISSPACE (*op_end))
    307 	op_end++;
    308       {
    309 	int a, b;
    310 	a = parse_register_operand (&op_end);
    311 	if (*op_end != ',')
    312 	  as_warn (_("expecting comma delimited register operands"));
    313 	op_end++;
    314 	if (*op_end != '(')
    315 	  {
    316 	    as_bad (_("expecting indirect register `($rA)'"));
    317 	    ignore_rest_of_line ();
    318 	    return;
    319 	  }
    320 	op_end++;
    321 	b = parse_register_operand (&op_end);
    322 	if (*op_end != ')')
    323 	  {
    324 	    as_bad (_("missing closing parenthesis"));
    325 	    ignore_rest_of_line ();
    326 	    return;
    327 	  }
    328 	op_end++;
    329 	iword += (a << 4) + b;
    330 	while (ISSPACE (*op_end))
    331 	  op_end++;
    332 	if (*op_end != 0)
    333 	  as_warn (_("extra stuff on line ignored"));
    334       }
    335       break;
    336     case MOXIE_F1_AiB:
    337       iword = opcode->opcode << 8;
    338       while (ISSPACE (*op_end))
    339 	op_end++;
    340       {
    341 	int a, b;
    342 	if (*op_end != '(')
    343 	  {
    344 	    as_bad (_("expecting indirect register `($rA)'"));
    345 	    ignore_rest_of_line ();
    346 	    return;
    347 	  }
    348 	op_end++;
    349 	a = parse_register_operand (&op_end);
    350 	if (*op_end != ')')
    351 	  {
    352 	    as_bad (_("missing closing parenthesis"));
    353 	    ignore_rest_of_line ();
    354 	    return;
    355 	  }
    356 	op_end++;
    357 	if (*op_end != ',')
    358 	  as_warn (_("expecting comma delimited register operands"));
    359 	op_end++;
    360 	b = parse_register_operand (&op_end);
    361 	iword += (a << 4) + b;
    362 	while (ISSPACE (*op_end))
    363 	  op_end++;
    364 	if (*op_end != 0)
    365 	  as_warn (_("extra stuff on line ignored"));
    366       }
    367       break;
    368     case MOXIE_F1_4A:
    369       iword = opcode->opcode << 8;
    370       while (ISSPACE (*op_end))
    371 	op_end++;
    372       {
    373 	expressionS arg;
    374 	char *where;
    375 	int a;
    376 
    377 	op_end = parse_exp_save_ilp (op_end, &arg);
    378 	where = frag_more (4);
    379 	fix_new_exp (frag_now,
    380 		     (where - frag_now->fr_literal),
    381 		     4,
    382 		     &arg,
    383 		     0,
    384 		     BFD_RELOC_32);
    385 
    386 	if (*op_end != ',')
    387 	  {
    388 	    as_bad (_("expecting comma delimited operands"));
    389 	    ignore_rest_of_line ();
    390 	    return;
    391 	  }
    392 	op_end++;
    393 
    394  	a = parse_register_operand (&op_end);
    395 	while (ISSPACE (*op_end))
    396 	  op_end++;
    397 	if (*op_end != 0)
    398 	  as_warn (_("extra stuff on line ignored"));
    399 
    400 	iword += (a << 4);
    401       }
    402       break;
    403     case MOXIE_F1_ABi4:
    404       iword = opcode->opcode << 8;
    405       while (ISSPACE (*op_end))
    406 	op_end++;
    407       {
    408 	expressionS arg;
    409 	char *offset;
    410 	int a, b;
    411 
    412  	a = parse_register_operand (&op_end);
    413 	while (ISSPACE (*op_end))
    414 	  op_end++;
    415 
    416 	if (*op_end != ',')
    417 	  {
    418 	    as_bad (_("expecting comma delimited operands"));
    419 	    ignore_rest_of_line ();
    420 	    return;
    421 	  }
    422 	op_end++;
    423 
    424 	op_end = parse_exp_save_ilp (op_end, &arg);
    425 	offset = frag_more (4);
    426 	fix_new_exp (frag_now,
    427 		     (offset - frag_now->fr_literal),
    428 		     4,
    429 		     &arg,
    430 		     0,
    431 		     BFD_RELOC_32);
    432 
    433 	if (*op_end != '(')
    434 	  {
    435 	    as_bad (_("expecting indirect register `($rX)'"));
    436 	    ignore_rest_of_line ();
    437 	    return;
    438 	  }
    439 	op_end++;
    440 	b = parse_register_operand (&op_end);
    441 	if (*op_end != ')')
    442 	  {
    443 	    as_bad (_("missing closing parenthesis"));
    444 	    ignore_rest_of_line ();
    445 	    return;
    446 	  }
    447 	op_end++;
    448 
    449 	while (ISSPACE (*op_end))
    450 	  op_end++;
    451 	if (*op_end != 0)
    452 	  as_warn (_("extra stuff on line ignored"));
    453 
    454 	iword += (a << 4) + b;
    455       }
    456       break;
    457     case MOXIE_F1_AiB4:
    458       iword = opcode->opcode << 8;
    459       while (ISSPACE (*op_end))
    460 	op_end++;
    461       {
    462 	expressionS arg;
    463 	char *offset;
    464 	int a, b;
    465 
    466 	op_end = parse_exp_save_ilp (op_end, &arg);
    467 	offset = frag_more (4);
    468 	fix_new_exp (frag_now,
    469 		     (offset - frag_now->fr_literal),
    470 		     4,
    471 		     &arg,
    472 		     0,
    473 		     BFD_RELOC_32);
    474 
    475 	if (*op_end != '(')
    476 	  {
    477 	    as_bad (_("expecting indirect register `($rX)'"));
    478 	    ignore_rest_of_line ();
    479 	    return;
    480 	  }
    481 	op_end++;
    482 	a = parse_register_operand (&op_end);
    483 	if (*op_end != ')')
    484 	  {
    485 	    as_bad (_("missing closing parenthesis"));
    486 	    ignore_rest_of_line ();
    487 	    return;
    488 	  }
    489 	op_end++;
    490 
    491 	if (*op_end != ',')
    492 	  {
    493 	    as_bad (_("expecting comma delimited operands"));
    494 	    ignore_rest_of_line ();
    495 	    return;
    496 	  }
    497 	op_end++;
    498 
    499  	b = parse_register_operand (&op_end);
    500 	while (ISSPACE (*op_end))
    501 	  op_end++;
    502 
    503 	while (ISSPACE (*op_end))
    504 	  op_end++;
    505 	if (*op_end != 0)
    506 	  as_warn (_("extra stuff on line ignored"));
    507 
    508 	iword += (a << 4) + b;
    509       }
    510       break;
    511     case MOXIE_F2_NARG:
    512       iword = opcode->opcode << 12;
    513       while (ISSPACE (*op_end))
    514 	op_end++;
    515       if (*op_end != 0)
    516 	as_warn (_("extra stuff on line ignored"));
    517       break;
    518     case MOXIE_F3_PCREL:
    519       iword = (3<<14) | (opcode->opcode << 10);
    520       while (ISSPACE (*op_end))
    521 	op_end++;
    522       {
    523 	expressionS arg;
    524 
    525 	op_end = parse_exp_save_ilp (op_end, &arg);
    526 	fix_new_exp (frag_now,
    527 		     (p - frag_now->fr_literal),
    528 		     2,
    529 		     &arg,
    530 		     TRUE,
    531 		     BFD_RELOC_MOXIE_10_PCREL);
    532       }
    533       break;
    534     default:
    535       abort ();
    536     }
    537 
    538   md_number_to_chars (p, iword, 2);
    539 
    540   while (ISSPACE (*op_end))
    541     op_end++;
    542 
    543   if (*op_end != 0)
    544     as_warn (_("extra stuff on line ignored"));
    545 
    546   if (pending_reloc)
    547     as_bad (_("Something forgot to clean up\n"));
    548 }
    549 
    550 /* Turn a string in input_line_pointer into a floating point constant
    551    of type type, and store the appropriate bytes in *LITP.  The number
    552    of LITTLENUMS emitted is stored in *SIZEP .  An error message is
    553    returned, or NULL on OK.  */
    554 
    555 char *
    556 md_atof (int type, char *litP, int *sizeP)
    557 {
    558   int prec;
    559   LITTLENUM_TYPE words[4];
    560   char *t;
    561   int i;
    562 
    563   switch (type)
    564     {
    565     case 'f':
    566       prec = 2;
    567       break;
    568 
    569     case 'd':
    570       prec = 4;
    571       break;
    572 
    573     default:
    574       *sizeP = 0;
    575       return _("bad call to md_atof");
    576     }
    577 
    578   t = atof_ieee (input_line_pointer, type, words);
    579   if (t)
    580     input_line_pointer = t;
    581 
    582   *sizeP = prec * 2;
    583 
    584   for (i = prec - 1; i >= 0; i--)
    585     {
    586       md_number_to_chars (litP, (valueT) words[i], 2);
    587       litP += 2;
    588     }
    589 
    590   return NULL;
    591 }
    592 
    593 const char *md_shortopts = "";
    595 
    596 struct option md_longopts[] =
    597 {
    598   {NULL, no_argument, NULL, 0}
    599 };
    600 size_t md_longopts_size = sizeof (md_longopts);
    601 
    602 /* We have no target specific options yet, so these next
    603    two functions are empty.  */
    604 int
    605 md_parse_option (int c ATTRIBUTE_UNUSED, char *arg ATTRIBUTE_UNUSED)
    606 {
    607   return 0;
    608 }
    609 
    610 void
    611 md_show_usage (FILE *stream ATTRIBUTE_UNUSED)
    612 {
    613 }
    614 
    615 /* Apply a fixup to the object file.  */
    616 
    617 void
    618 md_apply_fix (fixS *fixP ATTRIBUTE_UNUSED,
    619 	      valueT * valP ATTRIBUTE_UNUSED, segT seg ATTRIBUTE_UNUSED)
    620 {
    621   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
    622   long val = *valP;
    623   long newval;
    624   long max, min;
    625 
    626   max = min = 0;
    627   switch (fixP->fx_r_type)
    628     {
    629     case BFD_RELOC_32:
    630       *buf++ = val >> 24;
    631       *buf++ = val >> 16;
    632       *buf++ = val >> 8;
    633       *buf++ = val >> 0;
    634       break;
    635 
    636     case BFD_RELOC_16:
    637       *buf++ = val >> 8;
    638       *buf++ = val >> 0;
    639       break;
    640 
    641     case BFD_RELOC_8:
    642       *buf++ = val;
    643       break;
    644 
    645     case BFD_RELOC_MOXIE_10_PCREL:
    646       if (!val)
    647 	break;
    648       if (val < -1024 || val > 1022)
    649 	as_bad_where (fixP->fx_file, fixP->fx_line,
    650                       _("pcrel too far BFD_RELOC_MOXIE_10"));
    651       /* 11 bit offset even numbered, so we remove right bit.  */
    652       val >>= 1;
    653       newval = md_chars_to_number (buf, 2);
    654       newval |= val & 0x03ff;
    655       md_number_to_chars (buf, newval, 2);
    656       break;
    657 
    658     default:
    659       abort ();
    660     }
    661 
    662   if (max != 0 && (val < min || val > max))
    663     as_bad_where (fixP->fx_file, fixP->fx_line, _("offset out of range"));
    664 
    665   if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
    666     fixP->fx_done = 1;
    667 }
    668 
    669 /* Put number into target byte order (big endian).  */
    670 
    671 void
    672 md_number_to_chars (char *ptr, valueT use, int nbytes)
    673 {
    674   number_to_chars_bigendian (ptr, use, nbytes);
    675 }
    676 
    677 /* Convert from target byte order to host byte order.  */
    678 
    679 static int
    680 md_chars_to_number (char *val, int n)
    681 {
    682   int retval = 0;
    683 
    684   while (n--)
    685     {
    686       retval <<= 8;
    687       retval |= (*val++ & 255);
    688     }
    689 
    690   return retval;
    691 }
    692 
    693 /* Generate a machine-dependent relocation.  */
    694 arelent *
    695 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
    696 {
    697   arelent *relP;
    698   bfd_reloc_code_real_type code;
    699 
    700   switch (fixP->fx_r_type)
    701     {
    702     case BFD_RELOC_32:
    703       code = fixP->fx_r_type;
    704       break;
    705     case BFD_RELOC_MOXIE_10_PCREL:
    706       code = fixP->fx_r_type;
    707       break;
    708     default:
    709       as_bad_where (fixP->fx_file, fixP->fx_line,
    710 		    _("Semantics error.  This type of operand can not be relocated, it must be an assembly-time constant"));
    711       return 0;
    712     }
    713 
    714   relP = xmalloc (sizeof (arelent));
    715   gas_assert (relP != 0);
    716   relP->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
    717   *relP->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
    718   relP->address = fixP->fx_frag->fr_address + fixP->fx_where;
    719 
    720   relP->addend = fixP->fx_offset;
    721 
    722   /* This is the standard place for KLUDGEs to work around bugs in
    723      bfd_install_relocation (first such note in the documentation
    724      appears with binutils-2.8).
    725 
    726      That function bfd_install_relocation does the wrong thing with
    727      putting stuff into the addend of a reloc (it should stay out) for a
    728      weak symbol.  The really bad thing is that it adds the
    729      "segment-relative offset" of the symbol into the reloc.  In this
    730      case, the reloc should instead be relative to the symbol with no
    731      other offset than the assembly code shows; and since the symbol is
    732      weak, any local definition should be ignored until link time (or
    733      thereafter).
    734      To wit:  weaksym+42  should be weaksym+42 in the reloc,
    735      not weaksym+(offset_from_segment_of_local_weaksym_definition)
    736 
    737      To "work around" this, we subtract the segment-relative offset of
    738      "known" weak symbols.  This evens out the extra offset.
    739 
    740      That happens for a.out but not for ELF, since for ELF,
    741      bfd_install_relocation uses the "special function" field of the
    742      howto, and does not execute the code that needs to be undone.  */
    743 
    744   if (OUTPUT_FLAVOR == bfd_target_aout_flavour
    745       && fixP->fx_addsy && S_IS_WEAK (fixP->fx_addsy)
    746       && ! bfd_is_und_section (S_GET_SEGMENT (fixP->fx_addsy)))
    747     {
    748       relP->addend -= S_GET_VALUE (fixP->fx_addsy);
    749     }
    750 
    751   relP->howto = bfd_reloc_type_lookup (stdoutput, code);
    752   if (! relP->howto)
    753     {
    754       const char *name;
    755 
    756       name = S_GET_NAME (fixP->fx_addsy);
    757       if (name == NULL)
    758 	name = _("<unknown>");
    759       as_fatal (_("Cannot generate relocation type for symbol %s, code %s"),
    760 		name, bfd_get_reloc_code_name (code));
    761     }
    762 
    763   return relP;
    764 }
    765 
    766 /* Decide from what point a pc-relative relocation is relative to,
    767    relative to the pc-relative fixup.  Er, relatively speaking.  */
    768 long
    769 md_pcrel_from (fixS *fixP)
    770 {
    771   valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
    772 
    773   switch (fixP->fx_r_type)
    774     {
    775     case BFD_RELOC_32:
    776       return addr + 4;
    777     case BFD_RELOC_MOXIE_10_PCREL:
    778       return addr;
    779     default:
    780       abort ();
    781       return addr;
    782     }
    783 }
    784