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