1 /* tc-moxie.c -- Assemble code for moxie
2    Copyright (C) 2009-2024 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