Home | History | Annotate | Line # | Download | only in config
tc-moxie.c revision 1.1.1.8
      1 /* tc-moxie.c -- Assemble code for moxie
      2    Copyright (C) 2009-2025 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 (is_whitespace (*str))
    167     str++;
    168 
    169   /* Find the op code end.  */
    170   op_start = str;
    171   for (op_end = str;
    172        !is_end_of_stmt (*op_end) && !is_whitespace (*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 = 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 (is_whitespace (*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 (is_whitespace (*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 (is_whitespace (*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 (is_whitespace (*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 (is_whitespace (*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 (is_whitespace (*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 (is_whitespace (*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 (is_whitespace (*op_end))
    295 	op_end++;
    296       {
    297 	int reg;
    298 	reg = parse_register_operand (&op_end);
    299 	while (is_whitespace (*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 (is_whitespace (*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 (is_whitespace (*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 (is_whitespace (*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 (is_whitespace (*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 (is_whitespace (*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 (is_whitespace (*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 (is_whitespace (*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 (is_whitespace (*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 (is_whitespace (*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 (is_whitespace (*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 (is_whitespace (*op_end))
    503 	  op_end++;
    504 	if (*op_end != 0)
    505 	  as_warn (_("extra stuff on line ignored"));
    506 
    507 	iword += (a << 4) + b;
    508       }
    509       break;
    510     case MOXIE_F2_NARG:
    511       iword = opcode->opcode << 12;
    512       while (is_whitespace (*op_end))
    513 	op_end++;
    514       if (*op_end != 0)
    515 	as_warn (_("extra stuff on line ignored"));
    516       break;
    517     case MOXIE_F3_PCREL:
    518       iword = (3<<14) | (opcode->opcode << 10);
    519       while (is_whitespace (*op_end))
    520 	op_end++;
    521       {
    522 	expressionS arg;
    523 
    524 	op_end = parse_exp_save_ilp (op_end, &arg);
    525 	fix_new_exp (frag_now,
    526 		     (p - frag_now->fr_literal),
    527 		     2,
    528 		     &arg,
    529 		     true,
    530 		     BFD_RELOC_MOXIE_10_PCREL);
    531       }
    532       break;
    533     case MOXIE_BAD:
    534       iword = 0;
    535       while (is_whitespace (*op_end))
    536 	op_end++;
    537       if (*op_end != 0)
    538 	as_warn (_("extra stuff on line ignored"));
    539       break;
    540     default:
    541       abort ();
    542     }
    543 
    544   md_number_to_chars (p, iword, 2);
    545   dwarf2_emit_insn (2);
    546 
    547   while (is_whitespace (*op_end))
    548     op_end++;
    549 
    550   if (*op_end != 0)
    551     as_warn (_("extra stuff on line ignored"));
    552 
    553   if (pending_reloc)
    554     as_bad (_("Something forgot to clean up\n"));
    555 }
    556 
    557 /* Turn a string in input_line_pointer into a floating point constant
    558    of type type, and store the appropriate bytes in *LITP.  The number
    559    of LITTLENUMS emitted is stored in *SIZEP .  An error message is
    560    returned, or NULL on OK.  */
    561 
    562 const char *
    563 md_atof (int type, char *litP, int *sizeP)
    564 {
    565   int prec;
    566   LITTLENUM_TYPE words[4];
    567   char *t;
    568   int i;
    569 
    570   switch (type)
    571     {
    572     case 'f':
    573       prec = 2;
    574       break;
    575 
    576     case 'd':
    577       prec = 4;
    578       break;
    579 
    580     default:
    581       *sizeP = 0;
    582       return _("bad call to md_atof");
    583     }
    584 
    585   t = atof_ieee (input_line_pointer, type, words);
    586   if (t)
    587     input_line_pointer = t;
    588 
    589   *sizeP = prec * 2;
    590 
    591   for (i = prec - 1; i >= 0; i--)
    592     {
    593       md_number_to_chars (litP, words[i], 2);
    594       litP += 2;
    595     }
    596 
    597   return NULL;
    598 }
    599 
    600 enum options
    601 {
    602   OPTION_EB = OPTION_MD_BASE,
    603   OPTION_EL,
    604 };
    605 
    606 const struct option md_longopts[] =
    607 {
    608   { "EB",          no_argument, NULL, OPTION_EB},
    609   { "EL",          no_argument, NULL, OPTION_EL},
    610   { NULL,          no_argument, NULL, 0}
    611 };
    612 
    613 const size_t md_longopts_size = sizeof (md_longopts);
    614 
    615 const char md_shortopts[] = "";
    617 
    618 int
    619 md_parse_option (int c ATTRIBUTE_UNUSED, const char *arg ATTRIBUTE_UNUSED)
    620 {
    621   switch (c)
    622     {
    623     case OPTION_EB:
    624       target_big_endian = 1;
    625       break;
    626     case OPTION_EL:
    627       target_big_endian = 0;
    628       break;
    629     default:
    630       return 0;
    631     }
    632 
    633   return 1;
    634 }
    635 
    636 void
    637 md_show_usage (FILE *stream ATTRIBUTE_UNUSED)
    638 {
    639   fprintf (stream, _("\
    640   -EB                     assemble for a big endian system (default)\n\
    641   -EL                     assemble for a little endian system\n"));
    642 }
    643 
    644 /* Apply a fixup to the object file.  */
    645 
    646 void
    647 md_apply_fix (fixS *fixP ATTRIBUTE_UNUSED,
    648 	      valueT * valP ATTRIBUTE_UNUSED, segT seg ATTRIBUTE_UNUSED)
    649 {
    650   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
    651   long val = *valP;
    652   long newval;
    653   long max, min;
    654 
    655   max = min = 0;
    656   switch (fixP->fx_r_type)
    657     {
    658     case BFD_RELOC_32:
    659       if (target_big_endian)
    660 	{
    661 	  buf[0] = val >> 24;
    662 	  buf[1] = val >> 16;
    663 	  buf[2] = val >> 8;
    664 	  buf[3] = val >> 0;
    665 	}
    666       else
    667 	{
    668 	  buf[3] = val >> 24;
    669 	  buf[2] = val >> 16;
    670 	  buf[1] = val >> 8;
    671 	  buf[0] = val >> 0;
    672 	}
    673       buf += 4;
    674       break;
    675 
    676     case BFD_RELOC_16:
    677       if (target_big_endian)
    678 	{
    679 	  buf[0] = val >> 8;
    680 	  buf[1] = val >> 0;
    681 	}
    682       else
    683 	{
    684 	  buf[1] = val >> 8;
    685 	  buf[0] = val >> 0;
    686 	}
    687       buf += 2;
    688       break;
    689 
    690     case BFD_RELOC_8:
    691       *buf++ = val;
    692       break;
    693 
    694     case BFD_RELOC_MOXIE_10_PCREL:
    695       if (!val)
    696 	break;
    697       if (val < -1024 || val > 1022)
    698 	as_bad_where (fixP->fx_file, fixP->fx_line,
    699                       _("pcrel too far BFD_RELOC_MOXIE_10"));
    700       /* 11 bit offset even numbered, so we remove right bit.  */
    701       val >>= 1;
    702       newval = md_chars_to_number (buf, 2);
    703       newval |= val & 0x03ff;
    704       md_number_to_chars (buf, newval, 2);
    705       break;
    706 
    707     default:
    708       abort ();
    709     }
    710 
    711   if (max != 0 && (val < min || val > max))
    712     as_bad_where (fixP->fx_file, fixP->fx_line, _("offset out of range"));
    713 
    714   if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
    715     fixP->fx_done = 1;
    716 }
    717 
    718 /* Put number into target byte order.  */
    719 
    720 void
    721 md_number_to_chars (char * ptr, valueT use, int nbytes)
    722 {
    723   if (target_big_endian)
    724     number_to_chars_bigendian (ptr, use, nbytes);
    725   else
    726     number_to_chars_littleendian (ptr, use, nbytes);
    727 }
    728 
    729 /* Convert from target byte order to host byte order.  */
    730 
    731 static valueT
    732 md_chars_to_number (char * buf, int n)
    733 {
    734   valueT result = 0;
    735 
    736   if (target_big_endian)
    737     {
    738       while (n--)
    739 	{
    740 	  result <<= 8;
    741 	  result |= (*buf++ & 255);
    742 	}
    743     }
    744   else
    745     {
    746       while (n--)
    747 	{
    748 	  result <<= 8;
    749 	  result |= (buf[n] & 255);
    750 	}
    751     }
    752 
    753   return result;
    754 }
    755 
    756 /* Generate a machine-dependent relocation.  */
    757 arelent *
    758 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
    759 {
    760   arelent *relP;
    761   bfd_reloc_code_real_type code;
    762 
    763   switch (fixP->fx_r_type)
    764     {
    765     case BFD_RELOC_32:
    766       code = fixP->fx_r_type;
    767       break;
    768     case BFD_RELOC_MOXIE_10_PCREL:
    769       code = fixP->fx_r_type;
    770       break;
    771     default:
    772       as_bad_where (fixP->fx_file, fixP->fx_line,
    773 		    _("Semantics error.  This type of operand can not be relocated, it must be an assembly-time constant"));
    774       return 0;
    775     }
    776 
    777   relP = notes_alloc (sizeof (arelent));
    778   relP->sym_ptr_ptr = notes_alloc (sizeof (asymbol *));
    779   *relP->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
    780   relP->address = fixP->fx_frag->fr_address + fixP->fx_where;
    781 
    782   relP->addend = fixP->fx_offset;
    783 
    784   /* This is the standard place for KLUDGEs to work around bugs in
    785      bfd_install_relocation (first such note in the documentation
    786      appears with binutils-2.8).
    787 
    788      That function bfd_install_relocation does the wrong thing with
    789      putting stuff into the addend of a reloc (it should stay out) for a
    790      weak symbol.  The really bad thing is that it adds the
    791      "segment-relative offset" of the symbol into the reloc.  In this
    792      case, the reloc should instead be relative to the symbol with no
    793      other offset than the assembly code shows; and since the symbol is
    794      weak, any local definition should be ignored until link time (or
    795      thereafter).
    796      To wit:  weaksym+42  should be weaksym+42 in the reloc,
    797      not weaksym+(offset_from_segment_of_local_weaksym_definition)
    798 
    799      To "work around" this, we subtract the segment-relative offset of
    800      "known" weak symbols.  This evens out the extra offset.
    801 
    802      That happens for a.out but not for ELF, since for ELF,
    803      bfd_install_relocation uses the "special function" field of the
    804      howto, and does not execute the code that needs to be undone.  */
    805 
    806   if (OUTPUT_FLAVOR == bfd_target_aout_flavour
    807       && fixP->fx_addsy && S_IS_WEAK (fixP->fx_addsy)
    808       && ! bfd_is_und_section (S_GET_SEGMENT (fixP->fx_addsy)))
    809     {
    810       relP->addend -= S_GET_VALUE (fixP->fx_addsy);
    811     }
    812 
    813   relP->howto = bfd_reloc_type_lookup (stdoutput, code);
    814   if (! relP->howto)
    815     {
    816       const char *name;
    817 
    818       name = S_GET_NAME (fixP->fx_addsy);
    819       if (name == NULL)
    820 	name = _("<unknown>");
    821       as_fatal (_("Cannot generate relocation type for symbol %s, code %s"),
    822 		name, bfd_get_reloc_code_name (code));
    823     }
    824 
    825   return relP;
    826 }
    827 
    828 /* Decide from what point a pc-relative relocation is relative to,
    829    relative to the pc-relative fixup.  Er, relatively speaking.  */
    830 long
    831 md_pcrel_from (fixS *fixP)
    832 {
    833   valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
    834 
    835   switch (fixP->fx_r_type)
    836     {
    837     case BFD_RELOC_32:
    838       return addr + 4;
    839     case BFD_RELOC_MOXIE_10_PCREL:
    840       /* Offset is from the end of the instruction.  */
    841       return addr + 2;
    842     default:
    843       abort ();
    844       return addr;
    845     }
    846 }
    847