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