xref: /netbsd-src/external/gpl3/binutils.old/dist/gas/config/tc-moxie.c (revision e992f068c547fd6e84b3f104dc2340adcc955732)
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@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
md_operand(expressionS * op)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
md_begin(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 *
parse_exp_save_ilp(char * s,expressionS * op)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
parse_register_operand(char ** ptr)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
md_assemble(char * str)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 *
md_atof(int type,char * litP,int * sizeP)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 = "";
619 
620 int
md_parse_option(int c ATTRIBUTE_UNUSED,const char * arg ATTRIBUTE_UNUSED)621 md_parse_option (int c ATTRIBUTE_UNUSED, const char *arg ATTRIBUTE_UNUSED)
622 {
623   switch (c)
624     {
625     case OPTION_EB:
626       target_big_endian = 1;
627       break;
628     case OPTION_EL:
629       target_big_endian = 0;
630       break;
631     default:
632       return 0;
633     }
634 
635   return 1;
636 }
637 
638 void
md_show_usage(FILE * stream ATTRIBUTE_UNUSED)639 md_show_usage (FILE *stream ATTRIBUTE_UNUSED)
640 {
641   fprintf (stream, _("\
642   -EB                     assemble for a big endian system (default)\n\
643   -EL                     assemble for a little endian system\n"));
644 }
645 
646 /* Apply a fixup to the object file.  */
647 
648 void
md_apply_fix(fixS * fixP ATTRIBUTE_UNUSED,valueT * valP ATTRIBUTE_UNUSED,segT seg ATTRIBUTE_UNUSED)649 md_apply_fix (fixS *fixP ATTRIBUTE_UNUSED,
650 	      valueT * valP ATTRIBUTE_UNUSED, segT seg ATTRIBUTE_UNUSED)
651 {
652   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
653   long val = *valP;
654   long newval;
655   long max, min;
656 
657   max = min = 0;
658   switch (fixP->fx_r_type)
659     {
660     case BFD_RELOC_32:
661       if (target_big_endian)
662 	{
663 	  buf[0] = val >> 24;
664 	  buf[1] = val >> 16;
665 	  buf[2] = val >> 8;
666 	  buf[3] = val >> 0;
667 	}
668       else
669 	{
670 	  buf[3] = val >> 24;
671 	  buf[2] = val >> 16;
672 	  buf[1] = val >> 8;
673 	  buf[0] = val >> 0;
674 	}
675       buf += 4;
676       break;
677 
678     case BFD_RELOC_16:
679       if (target_big_endian)
680 	{
681 	  buf[0] = val >> 8;
682 	  buf[1] = val >> 0;
683 	}
684       else
685 	{
686 	  buf[1] = val >> 8;
687 	  buf[0] = val >> 0;
688 	}
689       buf += 2;
690       break;
691 
692     case BFD_RELOC_8:
693       *buf++ = val;
694       break;
695 
696     case BFD_RELOC_MOXIE_10_PCREL:
697       if (!val)
698 	break;
699       if (val < -1024 || val > 1022)
700 	as_bad_where (fixP->fx_file, fixP->fx_line,
701                       _("pcrel too far BFD_RELOC_MOXIE_10"));
702       /* 11 bit offset even numbered, so we remove right bit.  */
703       val >>= 1;
704       newval = md_chars_to_number (buf, 2);
705       newval |= val & 0x03ff;
706       md_number_to_chars (buf, newval, 2);
707       break;
708 
709     default:
710       abort ();
711     }
712 
713   if (max != 0 && (val < min || val > max))
714     as_bad_where (fixP->fx_file, fixP->fx_line, _("offset out of range"));
715 
716   if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
717     fixP->fx_done = 1;
718 }
719 
720 /* Put number into target byte order.  */
721 
722 void
md_number_to_chars(char * ptr,valueT use,int nbytes)723 md_number_to_chars (char * ptr, valueT use, int nbytes)
724 {
725   if (target_big_endian)
726     number_to_chars_bigendian (ptr, use, nbytes);
727   else
728     number_to_chars_littleendian (ptr, use, nbytes);
729 }
730 
731 /* Convert from target byte order to host byte order.  */
732 
733 static valueT
md_chars_to_number(char * buf,int n)734 md_chars_to_number (char * buf, int n)
735 {
736   valueT result = 0;
737   unsigned char * where = (unsigned char *) buf;
738 
739   if (target_big_endian)
740     {
741       while (n--)
742 	{
743 	  result <<= 8;
744 	  result |= (*where++ & 255);
745 	}
746     }
747   else
748     {
749       while (n--)
750 	{
751 	  result <<= 8;
752 	  result |= (where[n] & 255);
753 	}
754     }
755 
756   return result;
757 }
758 
759 /* Generate a machine-dependent relocation.  */
760 arelent *
tc_gen_reloc(asection * section ATTRIBUTE_UNUSED,fixS * fixP)761 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
762 {
763   arelent *relP;
764   bfd_reloc_code_real_type code;
765 
766   switch (fixP->fx_r_type)
767     {
768     case BFD_RELOC_32:
769       code = fixP->fx_r_type;
770       break;
771     case BFD_RELOC_MOXIE_10_PCREL:
772       code = fixP->fx_r_type;
773       break;
774     default:
775       as_bad_where (fixP->fx_file, fixP->fx_line,
776 		    _("Semantics error.  This type of operand can not be relocated, it must be an assembly-time constant"));
777       return 0;
778     }
779 
780   relP = XNEW (arelent);
781   relP->sym_ptr_ptr = XNEW (asymbol *);
782   *relP->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
783   relP->address = fixP->fx_frag->fr_address + fixP->fx_where;
784 
785   relP->addend = fixP->fx_offset;
786 
787   /* This is the standard place for KLUDGEs to work around bugs in
788      bfd_install_relocation (first such note in the documentation
789      appears with binutils-2.8).
790 
791      That function bfd_install_relocation does the wrong thing with
792      putting stuff into the addend of a reloc (it should stay out) for a
793      weak symbol.  The really bad thing is that it adds the
794      "segment-relative offset" of the symbol into the reloc.  In this
795      case, the reloc should instead be relative to the symbol with no
796      other offset than the assembly code shows; and since the symbol is
797      weak, any local definition should be ignored until link time (or
798      thereafter).
799      To wit:  weaksym+42  should be weaksym+42 in the reloc,
800      not weaksym+(offset_from_segment_of_local_weaksym_definition)
801 
802      To "work around" this, we subtract the segment-relative offset of
803      "known" weak symbols.  This evens out the extra offset.
804 
805      That happens for a.out but not for ELF, since for ELF,
806      bfd_install_relocation uses the "special function" field of the
807      howto, and does not execute the code that needs to be undone.  */
808 
809   if (OUTPUT_FLAVOR == bfd_target_aout_flavour
810       && fixP->fx_addsy && S_IS_WEAK (fixP->fx_addsy)
811       && ! bfd_is_und_section (S_GET_SEGMENT (fixP->fx_addsy)))
812     {
813       relP->addend -= S_GET_VALUE (fixP->fx_addsy);
814     }
815 
816   relP->howto = bfd_reloc_type_lookup (stdoutput, code);
817   if (! relP->howto)
818     {
819       const char *name;
820 
821       name = S_GET_NAME (fixP->fx_addsy);
822       if (name == NULL)
823 	name = _("<unknown>");
824       as_fatal (_("Cannot generate relocation type for symbol %s, code %s"),
825 		name, bfd_get_reloc_code_name (code));
826     }
827 
828   return relP;
829 }
830 
831 /* Decide from what point a pc-relative relocation is relative to,
832    relative to the pc-relative fixup.  Er, relatively speaking.  */
833 long
md_pcrel_from(fixS * fixP)834 md_pcrel_from (fixS *fixP)
835 {
836   valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
837 
838   switch (fixP->fx_r_type)
839     {
840     case BFD_RELOC_32:
841       return addr + 4;
842     case BFD_RELOC_MOXIE_10_PCREL:
843       /* Offset is from the end of the instruction.  */
844       return addr + 2;
845     default:
846       abort ();
847       return addr;
848     }
849 }
850