1 /* m88k.c -- Assembler for the Motorola 88000
2    Contributed by Devon Bowen of Buffalo University
3    and Torbjorn Granlund of the Swedish Institute of Computer Science.
4    Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1999,
5    2000, 2001, 2002
6    Free Software Foundation, Inc.
7 
8 This file is part of GAS, the GNU Assembler.
9 
10 GAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
14 
15 GAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with GAS; see the file COPYING.  If not, write to the Free
22 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 02111-1307, USA.  */
24 
25 #include "as.h"
26 #include "safe-ctype.h"
27 #include "subsegs.h"
28 #include "m88k-opcode.h"
29 
30 #if defined (OBJ_ELF)
31 #include "elf/m88k.h"
32 #endif
33 
34 #define	RELOC_LO16	BFD_RELOC_LO16
35 #define	RELOC_HI16	BFD_RELOC_HI16
36 #define	RELOC_PC16	BFD_RELOC_18_PCREL_S2
37 #define	RELOC_PC26	BFD_RELOC_28_PCREL_S2
38 #define	RELOC_32	BFD_RELOC_32
39 #define NO_RELOC	BFD_RELOC_NONE
40 
41 struct field_val_assoc
42 {
43   char *name;
44   unsigned val;
45 };
46 
47 struct field_val_assoc m88100_cr_regs[] =
48 {
49   {"PID", 0},
50   {"PSR", 1},
51   {"EPSR", 2},
52   {"SSBR", 3},
53   {"SXIP", 4},
54   {"SNIP", 5},
55   {"SFIP", 6},
56   {"VBR", 7},
57   {"DMT0", 8},
58   {"DMD0", 9},
59   {"DMA0", 10},
60   {"DMT1", 11},
61   {"DMD1", 12},
62   {"DMA1", 13},
63   {"DMT2", 14},
64   {"DMD2", 15},
65   {"DMA2", 16},
66   {"SR0", 17},
67   {"SR1", 18},
68   {"SR2", 19},
69   {"SR3", 20},
70 
71   {NULL, 0},
72 };
73 
74 struct field_val_assoc m88110_cr_regs[] =
75 {
76   {"PID", 0},
77   {"PSR", 1},
78   {"EPSR", 2},
79   {"EXIP", 4},
80   {"ENIP", 5},
81   {"VBR", 7},
82   {"SRX", 16},
83   {"SR0", 17},
84   {"SR1", 18},
85   {"SR2", 19},
86   {"SR3", 20},
87   {"ICMD", 25},
88   {"ICTL", 26},
89   {"ISAR", 27},
90   {"ISAP", 28},
91   {"IUAP", 29},
92   {"IIR", 30},
93   {"IBP", 31},
94   {"IPPU", 32},
95   {"IPPL", 33},
96   {"ISR", 34},
97   {"ILAR", 35},
98   {"IPAR", 36},
99   {"DCMD", 40},
100   {"DCTL", 41},
101   {"DSAR", 42},
102   {"DSAP", 43},
103   {"DUAP", 44},
104   {"DIR", 45},
105   {"DBP", 46},
106   {"DPPU", 47},
107   {"DPPL", 48},
108   {"DSR", 49},
109   {"DLAR", 50},
110   {"DPAR", 51},
111 
112   {NULL, 0},
113 };
114 
115 struct field_val_assoc fcr_regs[] =
116 {
117   {"FPECR", 0},
118   {"FPHS1", 1},
119   {"FPLS1", 2},
120   {"FPHS2", 3},
121   {"FPLS2", 4},
122   {"FPPT", 5},
123   {"FPRH", 6},
124   {"FPRL", 7},
125   {"FPIT", 8},
126 
127   {"FPSR", 62},
128   {"FPCR", 63},
129 
130   {NULL, 0},
131 };
132 
133 struct field_val_assoc cmpslot[] =
134 {
135 /* Integer	Floating point */
136   {"nc", 0},
137   {"cp", 1},
138   {"eq", 2},
139   {"ne", 3},
140   {"gt", 4},
141   {"le", 5},
142   {"lt", 6},
143   {"ge", 7},
144   {"hi", 8},	{"ou", 8},
145   {"ls", 9},	{"ib", 9},
146   {"lo", 10},	{"in", 10},
147   {"hs", 11},	{"ob", 11},
148   {"be", 12},	{"ue", 12},
149   {"nb", 13},	{"lg", 13},
150   {"he", 14},	{"ug", 14},
151   {"nh", 15},	{"ule", 15},
152 		{"ul", 16},
153 		{"uge", 17},
154 
155   {NULL, 0},
156 };
157 
158 struct field_val_assoc cndmsk[] =
159 {
160   {"gt0", 1},
161   {"eq0", 2},
162   {"ge0", 3},
163   {"lt0", 12},
164   {"ne0", 13},
165   {"le0", 14},
166 
167   {NULL, 0},
168 };
169 
170 struct m88k_insn
171 {
172   unsigned long opcode;
173   expressionS exp;
174   enum m88k_reloc_type reloc;
175 };
176 
177 static char *get_bf (char *param, unsigned *valp);
178 static char *get_cmp (char *param, unsigned *valp);
179 static char *get_cnd (char *param, unsigned *valp);
180 static char *get_bf2 (char *param, int bc);
181 static char *get_bf_offset_expression (char *param, unsigned *offsetp);
182 static char *get_cr (char *param, unsigned *regnop);
183 static char *get_fcr (char *param, unsigned *regnop);
184 static char *get_imm16 (char *param, struct m88k_insn *insn);
185 static char *get_o6 (char *param, unsigned *valp);
186 static char *match_name (char *, struct field_val_assoc *, unsigned *);
187 static char *get_reg (char *param, unsigned *regnop, unsigned int reg_prefix);
188 static char *get_vec9 (char *param, unsigned *valp);
189 static char *getval (char *param, unsigned int *valp);
190 static char *get_pcr (char *param, struct m88k_insn *insn,
191 		      enum m88k_reloc_type reloc);
192 
193 static int calcop (struct m88k_opcode *format,
194 			   char *param, struct m88k_insn *insn);
195 
196 static void s_m88k_88110 (int);
197 
198 static struct hash_control *op_hash = NULL;
199 
200 /* Current cpu (either 88100 or 88110, or 0 if unspecified).  Defaults to
201    zero, overriden with -m<cpu> options or assembler pseudo-ops.  */
202 static int current_cpu = 0;
203 
204 /* These chars start a comment anywhere in a source file (except inside
205    another comment.  */
206 #if defined(OBJ_ELF)
207 const char comment_chars[] = "|";
208 #elif defined(OBJ_AOUT)
209 const char comment_chars[] = "|#";
210 #else
211 const char comment_chars[] = ";";
212 #endif
213 
214 /* These chars only start a comment at the beginning of a line.  */
215 #if defined(OBJ_AOUT)
216 const char line_comment_chars[] = ";";
217 #else
218 const char line_comment_chars[] = "#";
219 #endif
220 
221 #if defined(OBJ_ELF)
222 const char line_separator_chars[] = ";";
223 #else
224 const char line_separator_chars[] = "";
225 #endif
226 
227 /* Chars that can be used to separate mant from exp in floating point nums */
228 const char EXP_CHARS[] = "eE";
229 
230 /* Chars that mean this number is a floating point constant */
231 /* as in 0f123.456 */
232 /* or    0H1.234E-12 (see exp chars above) */
233 const char FLT_CHARS[] = "dDfF";
234 
235 const pseudo_typeS md_pseudo_table[] =
236 {
237 #ifndef OBJ_ELF
238   {"align", s_align_bytes, 4},
239 #else
240   /* handled with s_align_ptwo in read.c potable[] */
241 #endif
242   {"bss", s_lcomm, 1},
243   {"def", s_set, 0},
244   {"half", cons, 2},
245   {"requires_88110", s_m88k_88110, 0},
246   {"sbss", s_lcomm, 1},
247 #if !defined(OBJ_ELF) || !defined(TE_OpenBSD) /* i.e. NO_PSEUDO_DOT == 1 */
248   /* Force set to be treated as an instruction.  */
249   {"set", NULL, 0},
250   {".set", s_set, 0},
251 #endif
252   {"uahalf", cons, 2},
253   {"uaword", cons, 4},
254   {"word", cons, 4}, /* override potable[] which has word == short */
255   {NULL, NULL, 0}
256 };
257 
258 static void
259 s_m88k_88110(int i ATTRIBUTE_UNUSED)
260 {
261   current_cpu = 88110;
262 }
263 
264 void
265 md_begin (void)
266 {
267   const char *retval = NULL;
268   unsigned int i = 0;
269 
270   /* Initialize hash table.  */
271   op_hash = hash_new ();
272 
273   while (*m88k_opcodes[i].name)
274     {
275       char *name = m88k_opcodes[i].name;
276 
277       /* Hash each mnemonic and record its position.  */
278       retval = hash_insert (op_hash, name, &m88k_opcodes[i]);
279 
280       if (retval != NULL)
281 	as_fatal (_("Can't hash instruction '%s':%s"),
282 		  m88k_opcodes[i].name, retval);
283 
284       /* Skip to next unique mnemonic or end of list.  */
285       for (i++; !strcmp (m88k_opcodes[i].name, name); i++)
286 	;
287     }
288 
289 #ifdef OBJ_ELF
290   record_alignment (text_section, 2);
291   record_alignment (data_section, 2);
292   record_alignment (bss_section, 2);
293 
294   bfd_set_private_flags (stdoutput, 0);
295 #endif
296 }
297 
298 const char *md_shortopts = "m:";
299 struct option md_longopts[] = {
300   {NULL, no_argument, NULL, 0}
301 };
302 size_t md_longopts_size = sizeof (md_longopts);
303 
304 int
305 md_parse_option (int c, char *arg)
306 {
307   switch (c)
308     {
309     case 'm':
310       if (strcmp (arg, "88100") == 0)
311 	current_cpu = 88100;
312       else if (strcmp (arg, "88110") == 0)
313 	current_cpu = 88110;
314       else
315 	as_bad (_("Option `%s' is not recognized."), arg);
316       break;
317 
318     default:
319       return 0;
320     }
321 
322   return 1;
323 }
324 
325 void
326 md_show_usage (FILE *stream)
327 {
328   fputs (_("\
329 M88k options:\n\
330   -m88100 | -m88110       select processor type\n"),
331 	 stream);
332 }
333 
334 #ifdef OBJ_ELF
335 enum m88k_pic_reloc_type {
336   pic_reloc_none,
337   pic_reloc_abdiff,
338   pic_reloc_gotrel,
339   pic_reloc_plt
340 };
341 
342 static bfd_reloc_code_real_type
343 m88k_get_reloc_code(struct m88k_insn *insn)
344 {
345   switch (insn->exp.X_md)
346     {
347     default:
348     case pic_reloc_none:
349       return insn->reloc;
350 
351     case pic_reloc_abdiff:
352       if (insn->reloc == BFD_RELOC_LO16)
353 	return BFD_RELOC_LO16_BASEREL;
354       if (insn->reloc == BFD_RELOC_HI16)
355 	return BFD_RELOC_HI16_BASEREL;
356       break;
357 
358     case pic_reloc_gotrel:
359       if (insn->reloc == BFD_RELOC_LO16)
360 	return BFD_RELOC_LO16_GOTOFF;
361       if (insn->reloc == BFD_RELOC_HI16)
362 	return BFD_RELOC_HI16_GOTOFF;
363       break;
364 
365     case pic_reloc_plt:
366       if (insn->reloc == BFD_RELOC_32)
367 	return BFD_RELOC_32_PLTOFF;
368       if (insn->reloc == BFD_RELOC_28_PCREL_S2)
369 	return BFD_RELOC_32_PLT_PCREL;
370       break;
371     }
372 
373   as_bad ("Can't process pic type %d relocation type %d",
374 	  insn->exp.X_md, insn->reloc);
375 
376   return BFD_RELOC_NONE;
377 }
378 #else
379 #define m88k_get_reloc_code(insn)	(insn).reloc
380 #endif
381 
382 void
383 md_assemble (char *op)
384 {
385   char *param, *thisfrag;
386   char c;
387   struct m88k_opcode *format;
388   struct m88k_insn insn;
389   fixS *fixP;
390 
391   assert (op);
392 
393   /* Skip over instruction to find parameters.  */
394   for (param = op; *param != 0 && !ISSPACE (*param); param++)
395     ;
396   c = *param;
397   *param++ = '\0';
398 
399   /* Try to find the instruction in the hash table.  */
400   /* XXX will not match XRF flavours of 88100 instructions on 88110 */
401   if ((format = (struct m88k_opcode *) hash_find (op_hash, op)) == NULL)
402     {
403       as_bad (_("Invalid mnemonic '%s'"), op);
404       return;
405     }
406 
407   /* Try parsing this instruction into insn.  */
408   insn.exp.X_add_symbol = 0;
409   insn.exp.X_op_symbol = 0;
410   insn.exp.X_add_number = 0;
411   insn.exp.X_op = O_illegal;
412   insn.exp.X_md = pic_reloc_none;
413   insn.reloc = NO_RELOC;
414 
415   while (!calcop (format, param, &insn))
416     {
417       /* If it doesn't parse try the next instruction.  */
418       if (!strcmp (format[0].name, format[1].name))
419 	format++;
420       else
421 	{
422 	  as_fatal (_("Parameter syntax error"));
423 	  return;
424 	}
425     }
426 
427   /* Grow the current frag and plop in the opcode.  */
428   thisfrag = frag_more (4);
429   md_number_to_chars (thisfrag, insn.opcode, 4);
430 
431   /* If this instruction requires labels mark it for later.  */
432   switch (insn.reloc)
433     {
434     case NO_RELOC:
435       break;
436 
437     case RELOC_LO16:
438     case RELOC_HI16:
439       fixP = fix_new_exp (frag_now,
440 		   thisfrag - frag_now->fr_literal + 2,
441 		   2,
442 		   &insn.exp,
443 		   0,
444 		   m88k_get_reloc_code(&insn));
445       fixP->fx_no_overflow = 1;
446       break;
447 
448 #ifdef M88KCOFF
449     case RELOC_IW16:
450       fix_new_exp (frag_now,
451 		   thisfrag - frag_now->fr_literal,
452 		   4,
453 		   &insn.exp,
454 		   0,
455 		   m88k_get_reloc_code(&insn));
456       break;
457 #endif
458 
459     case RELOC_PC16:
460 #ifdef OBJ_ELF
461       fix_new_exp (frag_now,
462 		   thisfrag - frag_now->fr_literal ,
463 		   4,
464 		   &insn.exp,
465 		   1,
466 		   m88k_get_reloc_code(&insn));
467 #else
468       fix_new_exp (frag_now,
469 		   thisfrag - frag_now->fr_literal + 2,
470 		   2,
471 		   &insn.exp,
472 		   1,
473 		   m88k_get_reloc_code(&insn));
474 #endif
475       break;
476 
477     case RELOC_PC26:
478       fix_new_exp (frag_now,
479 		   thisfrag - frag_now->fr_literal,
480 		   4,
481 		   &insn.exp,
482 		   1,
483 		   m88k_get_reloc_code(&insn));
484       break;
485 
486     case RELOC_32:
487       fix_new_exp (frag_now,
488 		   thisfrag - frag_now->fr_literal,
489 		   4,
490 		   &insn.exp,
491 		   0,
492 		   m88k_get_reloc_code(&insn));
493       break;
494 
495     default:
496       as_fatal (_("Unknown relocation type"));
497       break;
498     }
499 }
500 
501 static int
502 calcop (struct m88k_opcode *format, char *param, struct m88k_insn *insn)
503 {
504   char *fmt = format->op_spec;
505   int f;
506   unsigned val;
507   unsigned opcode;
508   unsigned int reg_prefix = 'r';
509 
510   insn->opcode = format->opcode;
511   opcode = 0;
512 
513   /*
514    * Instructions which have no arguments (such as rte) will get
515    * correctly reported only if param == "", although there could be
516    * whitespace following the instruction.
517    * Rather than eating whitespace here, let's assume everything is
518    * fine. If there were non-wanted arguments, they will be parsed as
519    * an incorrect opcode at the offending line, so that's not too bad.
520    * -- miod
521    */
522   if (*fmt == '\0')
523     return 1;
524 
525   for (;;)
526     {
527       if (param == NULL)
528 	return 0;
529 
530       f = *fmt++;
531       switch (f)
532 	{
533 	case 0:
534 	  insn->opcode |= opcode;
535 	  return (*param == 0 || *param == '\n');
536 
537 	default:
538 	  if (f != *param++)
539 	    return 0;
540 	  break;
541 
542 	case 'd':
543 	  param = get_reg (param, &val, reg_prefix);
544 	  reg_prefix = 'r';
545 	  opcode |= val << 21;
546 	  break;
547 
548 	case 'o':
549 	  param = get_o6 (param, &val);
550 	  opcode |= ((val >> 2) << 7);
551 	  break;
552 
553 	case 'x':
554 	  reg_prefix = 'x';
555 	  break;
556 
557 	case '1':
558 	  param = get_reg (param, &val, reg_prefix);
559 	  reg_prefix = 'r';
560 	  opcode |= val << 16;
561 	  break;
562 
563 	case '2':
564 	  param = get_reg (param, &val, reg_prefix);
565 	  reg_prefix = 'r';
566 	  opcode |= val;
567 	  break;
568 
569 	case '3':
570 	  param = get_reg (param, &val, 'r');
571 	  opcode |= (val << 16) | val;
572 	  break;
573 
574 	case 'I':
575 	  param = get_imm16 (param, insn);
576 	  break;
577 
578 	case 'b':
579 	  param = get_bf (param, &val);
580 	  opcode |= val;
581 	  break;
582 
583 	case 'p':
584 	  param = get_pcr (param, insn, RELOC_PC16);
585 	  break;
586 
587 	case 'P':
588 	  param = get_pcr (param, insn, RELOC_PC26);
589 	  break;
590 
591 	case 'B':
592 	  param = get_cmp (param, &val);
593 	  opcode |= val;
594 	  break;
595 
596 	case 'M':
597 	  param = get_cnd (param, &val);
598 	  opcode |= val;
599 	  break;
600 
601 	case 'c':
602 	  param = get_cr (param, &val);
603 	  opcode |= val << 5;
604 	  break;
605 
606 	case 'f':
607 	  param = get_fcr (param, &val);
608 	  opcode |= val << 5;
609 	  break;
610 
611 	case 'V':
612 	  param = get_vec9 (param, &val);
613 	  opcode |= val;
614 	  break;
615 
616 	case '?':
617 	  /* Having this here repeats the warning sometimes.
618 	   But can't we stand that?  */
619 	  as_warn (_("Use of obsolete instruction"));
620 	  break;
621 	}
622     }
623 }
624 
625 static char *
626 match_name (char *param, struct field_val_assoc *assoc_tab, unsigned *valp)
627 {
628   int i;
629   char *name;
630   int name_len;
631 
632   for (i = 0;; i++)
633     {
634       name = assoc_tab[i].name;
635       if (name == NULL)
636 	return NULL;
637       name_len = strlen (name);
638       if (!strncmp (param, name, name_len))
639 	{
640 	  *valp = assoc_tab[i].val;
641 	  return param + name_len;
642 	}
643     }
644 }
645 
646 static char *
647 get_reg (char *param, unsigned *regnop, unsigned int reg_prefix)
648 {
649   unsigned c;
650   unsigned regno;
651 
652 #ifdef REGISTER_PREFIX
653   c = *param++;
654   if (c != REGISTER_PREFIX)
655     return NULL;
656 #endif
657 
658   c = *param++;
659   if (c == reg_prefix)
660     {
661       regno = *param++ - '0';
662       if (regno < 10)
663 	{
664 	  if (regno == 0)
665 	    {
666 	      *regnop = 0;
667 	      return param;
668 	    }
669 	  c = *param - '0';
670 	  if (c < 10)
671 	    {
672 	      regno = regno * 10 + c;
673 	      if (c < 32)
674 		{
675 		  *regnop = regno;
676 		  return param + 1;
677 		}
678 	    }
679 	  else
680 	    {
681 	      *regnop = regno;
682 	      return param;
683 	    }
684 	}
685       return NULL;
686     }
687   else if (c == 's' && param[0] == 'p')
688     {
689       *regnop = 31;
690       return param + 1;
691     }
692 
693   return NULL;
694 }
695 
696 static char *
697 get_imm16 (char *param, struct m88k_insn *insn)
698 {
699   enum m88k_reloc_type reloc = NO_RELOC;
700   unsigned int val;
701   char *save_ptr;
702 #ifdef REGISTER_PREFIX
703   int found_prefix = 0;
704 #endif
705 
706 #ifdef REGISTER_PREFIX
707   if (*param == REGISTER_PREFIX)
708     {
709       param++;
710       found_prefix = 1;
711     }
712 #endif
713 
714   if (!strncmp (param, "hi16", 4) && !ISALNUM (param[4]))
715     {
716       reloc = RELOC_HI16;
717       param += 4;
718     }
719   else if (!strncmp (param, "lo16", 4) && !ISALNUM (param[4]))
720     {
721       reloc = RELOC_LO16;
722       param += 4;
723     }
724 #ifdef M88KCOFF
725   else if (!strncmp (param, "iw16", 4) && !ISALNUM (param[4]))
726     {
727       reloc = RELOC_IW16;
728       param += 4;
729     }
730 #endif
731 
732 #ifdef REGISTER_PREFIX
733   if (found_prefix && reloc == NO_RELOC)
734     return NULL;
735 #endif
736 
737   save_ptr = input_line_pointer;
738   input_line_pointer = param;
739   expression (&insn->exp);
740   param = input_line_pointer;
741   input_line_pointer = save_ptr;
742 
743   val = insn->exp.X_add_number;
744 
745   if (insn->exp.X_op == O_constant)
746     {
747       /* Insert the value now, and reset reloc to NO_RELOC.  */
748       if (reloc == NO_RELOC)
749 	{
750 	  /* Warn about too big expressions if not surrounded by xx16.  */
751 	  if (val > 0xffff)
752 	    as_warn (_("Expression truncated to 16 bits"));
753 	}
754 
755       if (reloc == RELOC_HI16)
756 	val >>= 16;
757 
758       insn->opcode |= val & 0xffff;
759       reloc = NO_RELOC;
760     }
761   else if (reloc == NO_RELOC)
762     /* We accept a symbol even without lo16, hi16, etc, and assume
763        lo16 was intended.  */
764     reloc = RELOC_LO16;
765 
766   insn->reloc = reloc;
767 
768   return param;
769 }
770 
771 static char *
772 get_pcr (char *param, struct m88k_insn *insn, enum m88k_reloc_type reloc)
773 {
774   char *saveptr, *saveparam;
775 
776   saveptr = input_line_pointer;
777   input_line_pointer = param;
778 
779   expression (&insn->exp);
780 
781   saveparam = input_line_pointer;
782   input_line_pointer = saveptr;
783 
784   /* Botch: We should relocate now if O_constant.  */
785   insn->reloc = reloc;
786 
787   return saveparam;
788 }
789 
790 static char *
791 get_cmp (char *param, unsigned *valp)
792 {
793   unsigned int val;
794   char *save_ptr;
795 
796   save_ptr = param;
797 
798 #ifdef REGISTER_PREFIX
799   /* SVR4 compiler prefixes condition codes with the register prefix */
800   if (*param == REGISTER_PREFIX)
801     param++;
802 #endif
803   param = match_name (param, cmpslot, valp);
804   val = *valp;
805 
806   if (param == NULL)
807     {
808       param = save_ptr;
809 
810       save_ptr = input_line_pointer;
811       input_line_pointer = param;
812       val = get_absolute_expression ();
813       param = input_line_pointer;
814       input_line_pointer = save_ptr;
815 
816       if (val >= 32)
817 	{
818 	  as_warn (_("Expression truncated to 5 bits"));
819 	  val %= 32;
820 	}
821     }
822 
823   *valp = val << 21;
824   return param;
825 }
826 
827 static char *
828 get_cnd (char *param, unsigned *valp)
829 {
830   unsigned int val;
831 
832   if (ISDIGIT (*param))
833     {
834       param = getval (param, &val);
835 
836       if (val >= 32)
837 	{
838 	  as_warn (_("Expression truncated to 5 bits"));
839 	  val %= 32;
840 	}
841     }
842   else
843     {
844 #ifdef REGISTER_PREFIX
845       /* SVR4 compiler prefixes condition codes with the register prefix */
846       if (*param == REGISTER_PREFIX)
847 	param++;
848 #endif
849 
850       param[0] = TOLOWER (param[0]);
851       param[1] = TOLOWER (param[1]);
852 
853       param = match_name (param, cndmsk, valp);
854 
855       if (param == NULL)
856 	return NULL;
857 
858       val = *valp;
859     }
860 
861   *valp = val << 21;
862   return param;
863 }
864 
865 static char *
866 get_bf2 (char *param, int bc)
867 {
868   int depth = 0;
869   int c;
870 
871   for (;;)
872     {
873       c = *param;
874       if (c == 0)
875 	return param;
876       else if (c == '(')
877 	depth++;
878       else if (c == ')')
879 	depth--;
880       else if (c == bc && depth <= 0)
881 	return param;
882       param++;
883     }
884 }
885 
886 static char *
887 get_bf_offset_expression (char *param, unsigned *offsetp)
888 {
889   unsigned offset;
890 
891 #ifdef REGISTER_PREFIX
892   /* SVR4 compiler prefixes condition codes with the register prefix */
893   if (*param == REGISTER_PREFIX && ISALPHA (param[1]))
894     param++;
895 #endif
896 
897   if (ISALPHA (param[0]))
898     {
899       param[0] = TOLOWER (param[0]);
900       param[1] = TOLOWER (param[1]);
901 
902       param = match_name (param, cmpslot, offsetp);
903 
904       return param;
905     }
906   else
907     {
908       input_line_pointer = param;
909       offset = get_absolute_expression ();
910       param = input_line_pointer;
911     }
912 
913   *offsetp = offset;
914   return param;
915 }
916 
917 static char *
918 get_bf (char *param, unsigned *valp)
919 {
920   unsigned offset = 0;
921   unsigned width = 0;
922   char *xp;
923   char *save_ptr;
924 
925   xp = get_bf2 (param, '<');
926 
927   save_ptr = input_line_pointer;
928   input_line_pointer = param;
929   if (*xp == 0)
930     {
931       /* We did not find '<'.  We have an offset (width implicitly 32).  */
932       param = get_bf_offset_expression (param, &offset);
933       input_line_pointer = save_ptr;
934       if (param == NULL)
935 	return NULL;
936     }
937   else
938     {
939       *xp++ = 0;		/* Overwrite the '<' */
940       param = get_bf2 (xp, '>');
941       if (*param == 0)
942 	return NULL;
943       *param++ = 0;		/* Overwrite the '>' */
944 
945       width = get_absolute_expression ();
946       xp = get_bf_offset_expression (xp, &offset);
947       input_line_pointer = save_ptr;
948 
949       if (xp + 1 != param)
950 	return NULL;
951     }
952 
953   *valp = ((width % 32) << 5) | (offset % 32);
954 
955   return param;
956 }
957 
958 static char *
959 get_cr (char *param, unsigned *regnop)
960 {
961   unsigned regno;
962   unsigned c;
963 
964 #ifdef REGISTER_PREFIX
965   if (*param++ != REGISTER_PREFIX)
966     return NULL;
967 #endif
968 
969   if (!strncmp (param, "cr", 2))
970     {
971       param += 2;
972 
973       regno = *param++ - '0';
974       if (regno < 10)
975 	{
976 	  if (regno == 0)
977 	    {
978 	      *regnop = 0;
979 	      return param;
980 	    }
981 	  c = *param - '0';
982 	  if (c < 10)
983 	    {
984 	      regno = regno * 10 + c;
985 	      if (c < 64)
986 		{
987 		  *regnop = regno;
988 		  return param + 1;
989 		}
990 	    }
991 	  else
992 	    {
993 	      *regnop = regno;
994 	      return param;
995 	    }
996 	}
997       return NULL;
998     }
999 
1000   param = match_name (param,
1001 		      current_cpu == 88110 ? m88110_cr_regs : m88100_cr_regs,
1002 		      regnop);
1003 
1004   return param;
1005 }
1006 
1007 static char *
1008 get_fcr (char *param, unsigned *regnop)
1009 {
1010   unsigned regno;
1011   unsigned c;
1012 
1013 #ifdef REGISTER_PREFIX
1014   if (*param++ != REGISTER_PREFIX)
1015     return NULL;
1016 #endif
1017 
1018   if (!strncmp (param, "fcr", 3))
1019     {
1020       param += 3;
1021 
1022       regno = *param++ - '0';
1023       if (regno < 10)
1024 	{
1025 	  if (regno == 0)
1026 	    {
1027 	      *regnop = 0;
1028 	      return param;
1029 	    }
1030 	  c = *param - '0';
1031 	  if (c < 10)
1032 	    {
1033 	      regno = regno * 10 + c;
1034 	      if (c < 64)
1035 		{
1036 		  *regnop = regno;
1037 		  return param + 1;
1038 		}
1039 	    }
1040 	  else
1041 	    {
1042 	      *regnop = regno;
1043 	      return param;
1044 	    }
1045 	}
1046       return NULL;
1047     }
1048 
1049   param = match_name (param, fcr_regs, regnop);
1050 
1051   return param;
1052 }
1053 
1054 static char *
1055 get_vec9 (char *param, unsigned *valp)
1056 {
1057   unsigned val;
1058   char *save_ptr;
1059 
1060   save_ptr = input_line_pointer;
1061   input_line_pointer = param;
1062   val = get_absolute_expression ();
1063   param = input_line_pointer;
1064   input_line_pointer = save_ptr;
1065 
1066   if (val >= 1 << 9)
1067     as_warn (_("Expression truncated to 9 bits"));
1068 
1069   *valp = val % (1 << 9);
1070 
1071   return param;
1072 }
1073 
1074 static char *
1075 get_o6 (char *param, unsigned *valp)
1076 {
1077   unsigned val;
1078   char *save_ptr;
1079 
1080   save_ptr = input_line_pointer;
1081   input_line_pointer = param;
1082   val = get_absolute_expression ();
1083   param = input_line_pointer;
1084   input_line_pointer = save_ptr;
1085 
1086   if (val & 0x3)
1087     as_warn (_("Removed lower 2 bits of expression"));
1088 
1089   *valp = val;
1090 
1091   return (param);
1092 }
1093 
1094 #define hexval(z) \
1095   (ISDIGIT (z) ? (z) - '0' :						\
1096    ISLOWER (z) ? (z) - 'a' + 10 : 					\
1097    ISUPPER (z) ? (z) - 'A' + 10 : (unsigned) -1)
1098 
1099 static char *
1100 getval (char *param, unsigned int *valp)
1101 {
1102   unsigned int val = 0;
1103   unsigned int c;
1104 
1105   c = *param++;
1106   if (c == '0')
1107     {
1108       c = *param++;
1109       if (c == 'x' || c == 'X')
1110 	{
1111 	  c = *param++;
1112 	  c = hexval (c);
1113 	  while (c < 16)
1114 	    {
1115 	      val = val * 16 + c;
1116 	      c = *param++;
1117 	      c = hexval (c);
1118 	    }
1119 	}
1120       else
1121 	{
1122 	  c -= '0';
1123 	  while (c < 8)
1124 	    {
1125 	      val = val * 8 + c;
1126 	      c = *param++ - '0';
1127 	    }
1128 	}
1129     }
1130   else
1131     {
1132       c -= '0';
1133       while (c < 10)
1134 	{
1135 	  val = val * 10 + c;
1136 	  c = *param++ - '0';
1137 	}
1138     }
1139 
1140   *valp = val;
1141   return param - 1;
1142 }
1143 
1144 void
1145 md_number_to_chars (char *buf, valueT val, int nbytes)
1146 {
1147   number_to_chars_bigendian (buf, val, nbytes);
1148 }
1149 
1150 #define MAX_LITTLENUMS 6
1151 
1152 /* Turn a string in input_line_pointer into a floating point constant of type
1153    type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
1154    emitted is stored in *sizeP .  An error message is returned, or NULL on OK.
1155  */
1156 char *
1157 md_atof (int type, char *litP, int *sizeP)
1158 {
1159   int prec;
1160   LITTLENUM_TYPE words[MAX_LITTLENUMS];
1161   LITTLENUM_TYPE *wordP;
1162   char *t;
1163 
1164   switch (type)
1165     {
1166     case 'f':
1167     case 'F':
1168     case 's':
1169     case 'S':
1170       prec = 2;
1171       break;
1172 
1173     case 'd':
1174     case 'D':
1175     case 'r':
1176     case 'R':
1177       prec = 4;
1178       break;
1179 
1180     case 'x':
1181     case 'X':
1182       prec = 6;
1183       break;
1184 
1185     case 'p':
1186     case 'P':
1187       prec = 6;
1188       break;
1189 
1190     default:
1191       *sizeP = 0;
1192       return _("Bad call to MD_ATOF()");
1193     }
1194   t = atof_ieee (input_line_pointer, type, words);
1195   if (t)
1196     input_line_pointer = t;
1197 
1198   *sizeP = prec * sizeof (LITTLENUM_TYPE);
1199   for (wordP = words; prec--;)
1200     {
1201       md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE));
1202       litP += sizeof (LITTLENUM_TYPE);
1203     }
1204   return 0;
1205 }
1206 
1207 int md_short_jump_size = 4;
1208 int md_long_jump_size = 4;
1209 
1210 void
1211 md_create_short_jump (char *ptr, addressT from_addr ATTRIBUTE_UNUSED,
1212   addressT to_addr ATTRIBUTE_UNUSED, fragS *frag, symbolS *to_symbol)
1213 {
1214   /* Since all instructions have the same width, it does not make sense to
1215      try and abuse a conditional instruction to get a short displacement
1216      (such as bb1 0, %r0, address).  */
1217   md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol);
1218 }
1219 
1220 void
1221 md_create_long_jump (char *ptr, addressT from_addr ATTRIBUTE_UNUSED,
1222   addressT to_addr ATTRIBUTE_UNUSED, fragS *frag, symbolS *to_symbol)
1223 {
1224   ptr[0] = (char) 0xc0;		/* br to_addr */
1225   ptr[1] = 0x00;
1226   ptr[2] = 0x00;
1227   ptr[3] = 0x00;
1228   fix_new (frag,
1229 	   ptr - frag->fr_literal,
1230 	   4,
1231 	   to_symbol,
1232 	   (offsetT) 0,
1233 	   0,
1234 	   RELOC_PC26);
1235 }
1236 
1237 int
1238 md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED,
1239   segT segment_type ATTRIBUTE_UNUSED)
1240 {
1241   as_fatal (_("Relaxation should never occur"));
1242   return (-1);
1243 }
1244 
1245 #ifdef M88KCOFF
1246 
1247 /* These functions are needed if we are linking with obj-coffbfd.c.
1248    That file may be replaced by a more BFD oriented version at some
1249    point.  If that happens, these functions should be reexamined.
1250 
1251    Ian Lance Taylor, Cygnus Support, 13 July 1993.  */
1252 
1253 /* Given a fixS structure (created by a call to fix_new, above),
1254    return the BFD relocation type to use for it.  */
1255 
1256 short
1257 tc_coff_fix2rtype (fixS *fixp)
1258 {
1259   switch (fixp->fx_r_type)
1260     {
1261     case RELOC_LO16:
1262       return R_LVRT16;
1263     case RELOC_HI16:
1264       return R_HVRT16;
1265     case RELOC_PC16:
1266       return R_PCR16L;
1267     case RELOC_PC26:
1268       return R_PCR26L;
1269     case RELOC_32:
1270       return R_VRT32;
1271     case RELOC_IW16:
1272       return R_VRT16;
1273     default:
1274       abort ();
1275     }
1276 }
1277 
1278 /* Apply a fixS to the object file.  Since COFF does not use addends
1279    in relocs, the addend is actually stored directly in the object
1280    file itself.  */
1281 
1282 void
1283 md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
1284 {
1285   long val = * (long *) valP;
1286   char *buf;
1287 
1288   buf = fixP->fx_frag->fr_literal + fixP->fx_where;
1289   fixP->fx_addnumber = val;
1290   fixP->fx_offset = 0;
1291 
1292   switch (fixP->fx_r_type)
1293     {
1294     case RELOC_IW16:
1295       fixP->fx_offset = val >> 16;
1296       buf[2] = val >> 8;
1297       buf[3] = val;
1298       break;
1299 
1300     case RELOC_LO16:
1301       fixP->fx_offset = val >> 16;
1302       buf[0] = val >> 8;
1303       buf[1] = val;
1304       break;
1305 
1306     case RELOC_HI16:
1307       buf[0] = val >> 24;
1308       buf[1] = val >> 16;
1309       break;
1310 
1311     case RELOC_PC16:
1312       buf[0] = val >> 10;
1313       buf[1] = val >> 2;
1314       break;
1315 
1316     case RELOC_PC26:
1317       buf[0] |= (val >> 26) & 0x03;
1318       buf[1] = val >> 18;
1319       buf[2] = val >> 10;
1320       buf[3] = val >> 2;
1321       break;
1322 
1323     case RELOC_32:
1324       buf[0] = val >> 24;
1325       buf[1] = val >> 16;
1326       buf[2] = val >> 8;
1327       buf[3] = val;
1328       break;
1329 
1330     default:
1331       abort ();
1332     }
1333 
1334   if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
1335     fixP->fx_done = 1;
1336 }
1337 
1338 #endif /* M88KCOFF */
1339 
1340 /* Fill in rs_align_code fragments.  */
1341 
1342 void
1343 m88k_handle_align (fragS *fragp)
1344 {
1345   static const unsigned char nop_pattern[] = { 0xf4, 0x00, 0x58, 0x00 };
1346 
1347   int bytes;
1348   char *p;
1349 
1350   if (fragp->fr_type != rs_align_code)
1351     return;
1352 
1353   bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
1354   p = fragp->fr_literal + fragp->fr_fix;
1355 
1356   if (bytes & 3)
1357     {
1358       int fix = bytes & 3;
1359       memset (p, 0, fix);
1360       p += fix;
1361       bytes -= fix;
1362       fragp->fr_fix += fix;
1363     }
1364 
1365   memcpy (p, nop_pattern, 4);
1366   fragp->fr_var = 4;
1367 }
1368 
1369 /* Where a PC relative offset is calculated from.  On the m88k they
1370    are calculated from just after the instruction.  */
1371 
1372 long
1373 md_pcrel_from (fixS *fixp)
1374 {
1375   switch (fixp->fx_r_type)
1376     {
1377     case RELOC_PC16:
1378 #ifdef OBJ_ELF
1379       /* FALLTHROUGH */
1380 #else
1381       return fixp->fx_frag->fr_address + fixp->fx_where - 2;
1382 #endif
1383     case RELOC_PC26:
1384 #ifdef OBJ_ELF
1385     case BFD_RELOC_32_PLT_PCREL:
1386 #endif
1387       return fixp->fx_frag->fr_address + fixp->fx_where;
1388     default:
1389       abort ();
1390     }
1391   /*NOTREACHED*/
1392 }
1393 
1394 #ifdef OBJ_ELF
1395 
1396 valueT
1397 md_section_align (segT segment ATTRIBUTE_UNUSED, valueT size)
1398 {
1399   return size;
1400 }
1401 
1402 /* Generate the BFD reloc to be stuck in the object file from the
1403    fixup used internally in the assembler.  */
1404 
1405 arelent *
1406 tc_gen_reloc (asection *sec ATTRIBUTE_UNUSED, fixS *fixp)
1407 {
1408   arelent *reloc;
1409   bfd_reloc_code_real_type code;
1410 
1411   reloc = (arelent *) xmalloc (sizeof (arelent));
1412   reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
1413   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
1414   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
1415 
1416   /* Make sure none of our internal relocations make it this far.
1417      They'd better have been fully resolved by this point.  */
1418   assert ((int) fixp->fx_r_type > 0);
1419 
1420   code = fixp->fx_r_type;
1421   reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
1422   if (reloc->howto == NULL)
1423     {
1424       as_bad_where (fixp->fx_file, fixp->fx_line,
1425 		    _("cannot represent `%s' relocation in object file"),
1426 		    bfd_get_reloc_code_name (code));
1427       return NULL;
1428     }
1429 
1430   if (!fixp->fx_pcrel != !reloc->howto->pc_relative)
1431     {
1432       as_fatal (_("internal error? cannot generate `%s' relocation"),
1433 		bfd_get_reloc_code_name (code));
1434     }
1435   assert (!fixp->fx_pcrel == !reloc->howto->pc_relative);
1436 
1437   reloc->addend = fixp->fx_offset;
1438 
1439   return reloc;
1440 }
1441 
1442 /* Apply a fixS to the object file.  This is called for all the
1443    fixups we generated by the call to fix_new_exp, above.  In the call
1444    above we used a reloc code which was the largest legal reloc code
1445    plus the operand index.  Here we undo that to recover the operand
1446    index.  At this point all symbol values should be fully resolved,
1447    and we attempt to completely resolve the reloc.  If we can not do
1448    that, we determine the correct reloc code and put it back in the
1449    fixup.
1450 
1451    This is the ELF version.
1452 */
1453 
1454 void
1455 md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
1456 {
1457   valueT val = * (valueT *) valP;
1458   char *buf;
1459   long insn;
1460 
1461   buf = fixP->fx_frag->fr_literal + fixP->fx_where;
1462 
1463   if (fixP->fx_subsy != NULL)
1464     as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
1465 
1466   if (fixP->fx_addsy)
1467     {
1468 #if 0
1469       /* can't empty 26-bit relocation values with memset() */
1470       if (fixP->fx_r_type == BFD_RELOC_28_PCREL_S2)
1471 	{
1472 	  insn = bfd_getb32 ((unsigned char *) buf);
1473 	  insn &= ~0x03ffffff;
1474 	  bfd_putb32(insn, buf);
1475 	}
1476       else
1477 	memset(buf, 0, fixP->fx_size);
1478 #endif
1479 
1480       if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
1481 	  && !S_IS_DEFINED (fixP->fx_addsy)
1482 	  && !S_IS_WEAK (fixP->fx_addsy))
1483 	S_SET_WEAK (fixP->fx_addsy);
1484 
1485       return;
1486     }
1487 
1488   switch (fixP->fx_r_type)
1489     {
1490     case BFD_RELOC_VTABLE_INHERIT:
1491     case BFD_RELOC_VTABLE_ENTRY:
1492       return;
1493 
1494     case BFD_RELOC_HI16_BASEREL:
1495     case BFD_RELOC_LO16_BASEREL:
1496     case BFD_RELOC_HI16_GOTOFF:
1497     case BFD_RELOC_LO16_GOTOFF:
1498     case BFD_RELOC_32_PLTOFF:
1499       return;
1500 
1501     case BFD_RELOC_LO16:
1502     case BFD_RELOC_HI16:
1503       if (fixP->fx_pcrel)
1504 	abort ();
1505       buf[0] = val >> 8;
1506       buf[1] = val;
1507       break;
1508 
1509     case BFD_RELOC_18_PCREL_S2:
1510       if ((val & 0x03) != 0)
1511 	as_bad_where (fixP->fx_file, fixP->fx_line,
1512 		      "Branch to unaligned address (%lx)", (long)val);
1513       buf[2] = val >> 10;
1514       buf[3] = val >> 2;
1515       break;
1516 
1517     case BFD_RELOC_32_PLT_PCREL:
1518     case BFD_RELOC_28_PCREL_S2:
1519       if ((val & 0x03) != 0)
1520 	as_bad_where (fixP->fx_file, fixP->fx_line,
1521 		      "Branch to unaligned address (%lx)", (long)val);
1522       buf[0] |= (val >> 26) & 0x03;
1523       buf[1] = val >> 18;
1524       buf[2] = val >> 10;
1525       buf[3] = val >> 2;
1526       break;
1527 
1528     case BFD_RELOC_32:
1529       insn = val;
1530       bfd_putb32(insn, buf);
1531       break;
1532 
1533     default:
1534       abort ();
1535     }
1536 
1537   if (/* fixP->fx_addsy == NULL && */ fixP->fx_pcrel == 0)
1538     fixP->fx_done = 1;
1539 }
1540 
1541 /* Set the ELF specific flags.  */
1542 void
1543 m88k_elf_final_processing (void)
1544 {
1545   if (current_cpu == 88110)
1546     elf_elfheader (stdoutput)->e_flags |= EF_M88110;
1547 }
1548 
1549 inline static char *
1550 m88k_end_of_name (char *suffix, const char *pattern, size_t patlen)
1551 {
1552   if (strncmp (suffix, pattern, patlen) == 0
1553       && ! is_part_of_name (suffix[patlen]))
1554     return suffix + patlen;
1555 
1556   return NULL;
1557 }
1558 
1559 int
1560 m88k_parse_name (const char *name, expressionS *expressionP, char *nextcharP)
1561 {
1562   char *next = input_line_pointer;
1563   char *next_end;
1564   enum m88k_pic_reloc_type reloc_type = pic_reloc_none;
1565   symbolS *symbolP;
1566   segT segment;
1567 
1568   if (*nextcharP != '#')
1569     return 0;
1570 
1571   if ((next_end = m88k_end_of_name (next + 1, "abdiff", 6)) != NULL)
1572     {
1573       reloc_type = pic_reloc_abdiff;
1574     }
1575   else if ((next_end = m88k_end_of_name (next + 1, "got_rel", 7)) != NULL)
1576     {
1577       reloc_type = pic_reloc_gotrel;
1578     }
1579   else if ((next_end = m88k_end_of_name (next + 1, "plt", 3)) != NULL)
1580     {
1581       reloc_type = pic_reloc_plt;
1582     }
1583   else
1584     return 0;
1585 
1586   symbolP = symbol_find_or_make (name);
1587   segment = S_GET_SEGMENT (symbolP);
1588   if (segment == absolute_section)
1589     {
1590       expressionP->X_op = O_constant;
1591       expressionP->X_add_number = S_GET_VALUE (symbolP);
1592     }
1593   else if (segment == reg_section)
1594     {
1595       expressionP->X_op = O_register;
1596       expressionP->X_add_number = S_GET_VALUE (symbolP);
1597     }
1598   else
1599     {
1600       expressionP->X_op = O_symbol;
1601       expressionP->X_add_symbol = symbolP;
1602       expressionP->X_add_number = 0;
1603     }
1604   expressionP->X_md = reloc_type;
1605 
1606   *input_line_pointer = *nextcharP;
1607   input_line_pointer = next_end;
1608   *nextcharP = *input_line_pointer;
1609   *input_line_pointer = '\0';
1610 
1611   return 1;
1612 }
1613 
1614 int
1615 m88k_fix_adjustable (fixS *fix)
1616 {
1617   return (fix->fx_r_type != BFD_RELOC_LO16_GOTOFF
1618 	  && fix->fx_r_type != BFD_RELOC_HI16_GOTOFF
1619 	  && fix->fx_r_type != BFD_RELOC_VTABLE_INHERIT
1620 	  && fix->fx_r_type != BFD_RELOC_VTABLE_ENTRY
1621 	  && (fix->fx_pcrel
1622 	      || (fix->fx_subsy != NULL
1623 		  && (S_GET_SEGMENT (fix->fx_subsy)
1624 		      == S_GET_SEGMENT (fix->fx_addsy)))
1625 	      || S_IS_LOCAL (fix->fx_addsy)));
1626 }
1627 #endif /* OBJ_ELF */
1628 
1629 #ifdef OBJ_AOUT
1630 
1631 /* Round up a section size to the appropriate boundary. */
1632 valueT
1633 md_section_align (segT segment ATTRIBUTE_UNUSED, valueT size)
1634 {
1635   /* For a.out, force the section size to be aligned.  If we don't do
1636      this, BFD will align it for us, but it will not write out the
1637      final bytes of the section.  This may be a bug in BFD, but it is
1638      easier to fix it here since that is how the other a.out targets
1639      work.  */
1640   int align;
1641 
1642   align = bfd_get_section_alignment (stdoutput, segment);
1643   valueT mask = ((valueT) 1 << align) - 1;
1644 
1645   return (size + mask) & ~mask;
1646 }
1647 
1648 const int md_reloc_size = 12; /* sizeof(struct relocation_info); */
1649 
1650 void
1651 tc_aout_fix_to_chars (char *where, fixS *fixP,
1652   relax_addressT segment_address_in_file)
1653 {
1654   long r_symbolnum;
1655   long r_addend = 0;
1656   long r_address;
1657 
1658   know (fixP->fx_addsy != NULL);
1659 
1660   r_address = fixP->fx_frag->fr_address + fixP->fx_where
1661 	      - segment_address_in_file;
1662   md_number_to_chars (where, r_address, 4);
1663 
1664   r_symbolnum = (S_IS_DEFINED (fixP->fx_addsy)
1665                  ? S_GET_TYPE (fixP->fx_addsy)
1666                  : fixP->fx_addsy->sy_number);
1667 
1668   where[4] = (r_symbolnum >> 16) & 0x0ff;
1669   where[5] = (r_symbolnum >> 8) & 0x0ff;
1670   where[6] = r_symbolnum & 0x0ff;
1671   where[7] = ((((!S_IS_DEFINED (fixP->fx_addsy)) << 7) & 0x80) | (0 & 0x70) |
1672 	      (fixP->fx_r_type & 0xf));
1673 
1674   if (fixP->fx_addsy->sy_frag) {
1675     r_addend = fixP->fx_addsy->sy_frag->fr_address;
1676   }
1677 
1678   if (fixP->fx_pcrel) {
1679     r_addend -= r_address;
1680   } else {
1681     r_addend = fixP->fx_addnumber;
1682   }
1683 
1684   md_number_to_chars(&where[8], r_addend, 4);
1685 }
1686 
1687 void
1688 tc_headers_hook (object_headers *headers)
1689 {
1690 #if defined(TE_NetBSD) || defined(TE_OpenBSD)
1691   N_SET_INFO(headers->header, OMAGIC, M_88K_OPENBSD, 0);
1692   headers->header.a_info = htonl(headers->header.a_info);
1693 #endif
1694 }
1695 
1696 #endif /* OBJ_AOUT */
1697