xref: /openbsd-src/gnu/usr.bin/binutils/gas/config/tc-or32.c (revision cf2f2c5620d6d9a4fd01930983c4b9a1f76d7aa3)
1d2201f2fSdrahn /* Assembly backend for the OpenRISC 1000.
2d2201f2fSdrahn    Copyright (C) 2002 Free Software Foundation, Inc.
3d2201f2fSdrahn    Contributed by Damjan Lampret <lampret@opencores.org>.
4d2201f2fSdrahn    Modified bu Johan Rydberg, <johan.rydberg@netinsight.se>.
5d2201f2fSdrahn    Based upon a29k port.
6d2201f2fSdrahn 
7d2201f2fSdrahn    This file is part of GAS, the GNU Assembler.
8d2201f2fSdrahn 
9d2201f2fSdrahn    GAS is free software; you can redistribute it and/or modify
10d2201f2fSdrahn    it under the terms of the GNU General Public License as published by
11d2201f2fSdrahn    the Free Software Foundation; either version 2, or (at your option)
12d2201f2fSdrahn    any later version.
13d2201f2fSdrahn 
14d2201f2fSdrahn    GAS is distributed in the hope that it will be useful,
15d2201f2fSdrahn    but WITHOUT ANY WARRANTY; without even the implied warranty of
16d2201f2fSdrahn    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17d2201f2fSdrahn    GNU General Public License for more details.
18d2201f2fSdrahn 
19d2201f2fSdrahn    You should have received a copy of the GNU General Public License
20d2201f2fSdrahn    along with GAS; see the file COPYING.  If not, write to
21d2201f2fSdrahn    the Free Software Foundation, 59 Temple Place - Suite 330,
22d2201f2fSdrahn    Boston, MA 02111-1307, USA.  */
23d2201f2fSdrahn 
24d2201f2fSdrahn /* tc-a29k.c used as a template.  */
25d2201f2fSdrahn 
26d2201f2fSdrahn #include "safe-ctype.h"
27d2201f2fSdrahn #include "as.h"
28d2201f2fSdrahn #include "opcode/or32.h"
29d2201f2fSdrahn 
30d2201f2fSdrahn #ifdef BFD_ASSEMBLER
31d2201f2fSdrahn #include "elf/or32.h"
32d2201f2fSdrahn #endif
33d2201f2fSdrahn 
34d2201f2fSdrahn #define DEBUG 0
35d2201f2fSdrahn 
36d2201f2fSdrahn #ifndef REGISTER_PREFIX
37d2201f2fSdrahn #define REGISTER_PREFIX   '%'
38d2201f2fSdrahn #endif
39d2201f2fSdrahn 
40d2201f2fSdrahn /* Make it easier to clone this machine desc into another one.  */
41d2201f2fSdrahn #define machine_opcode  or32_opcode
42d2201f2fSdrahn #define machine_opcodes or32_opcodes
43d2201f2fSdrahn #define machine_ip      or32_ip
44d2201f2fSdrahn #define machine_it      or32_it
45d2201f2fSdrahn 
46d2201f2fSdrahn /* Handle of the OPCODE hash table.  */
47d2201f2fSdrahn static struct hash_control *op_hash = NULL;
48d2201f2fSdrahn 
49d2201f2fSdrahn struct machine_it
50d2201f2fSdrahn   {
51d2201f2fSdrahn     char *          error;
52d2201f2fSdrahn     unsigned long   opcode;
53d2201f2fSdrahn     struct nlist *  nlistp;
54d2201f2fSdrahn     expressionS     exp;
55d2201f2fSdrahn     int             pcrel;
56d2201f2fSdrahn     int             reloc_offset;   /* Offset of reloc within insn.  */
57d2201f2fSdrahn     int             reloc;
58d2201f2fSdrahn   }
59d2201f2fSdrahn the_insn;
60d2201f2fSdrahn 
61d2201f2fSdrahn static void machine_ip PARAMS ((char *));
62d2201f2fSdrahn 
63d2201f2fSdrahn const pseudo_typeS md_pseudo_table[] =
64d2201f2fSdrahn   {
65d2201f2fSdrahn     {"align",   s_align_bytes,  4 },
66d2201f2fSdrahn     {"space",   s_space,        0 },
67d2201f2fSdrahn     {"cputype", s_ignore,       0 },
68d2201f2fSdrahn     {"reg",     s_lsym,         0 },  /* Register equate, same as equ.  */
69d2201f2fSdrahn     {"sect",    s_ignore,       0 },  /* Creation of coff sections.  */
70d2201f2fSdrahn     {"proc",    s_ignore,       0 },  /* Start of a function.  */
71d2201f2fSdrahn     {"endproc", s_ignore,       0 },  /* Function end.  */
72d2201f2fSdrahn     {"word",    cons,           4 },
73d2201f2fSdrahn     {NULL,      0,              0 },
74d2201f2fSdrahn   };
75d2201f2fSdrahn 
76d2201f2fSdrahn int md_short_jump_size  = 4;
77d2201f2fSdrahn int md_long_jump_size   = 4;
78d2201f2fSdrahn 
79d2201f2fSdrahn #if defined(BFD_HEADERS)
80d2201f2fSdrahn #ifdef RELSZ
81d2201f2fSdrahn const int md_reloc_size = RELSZ;  /* Coff headers.  */
82d2201f2fSdrahn #else
83d2201f2fSdrahn const int md_reloc_size = 12;   /* Something else headers.  */
84d2201f2fSdrahn #endif
85d2201f2fSdrahn #else
86d2201f2fSdrahn const int md_reloc_size = 12;   /* Not bfdized.  */
87d2201f2fSdrahn #endif
88d2201f2fSdrahn 
89d2201f2fSdrahn /* This array holds the chars that always start a comment.
90d2201f2fSdrahn    If the pre-processor is disabled, these aren't very useful.  */
91d2201f2fSdrahn const char comment_chars[] = "#";
92d2201f2fSdrahn 
93d2201f2fSdrahn /* This array holds the chars that only start a comment at the beginning of
94d2201f2fSdrahn    a line.  If the line seems to have the form '# 123 filename'
95d2201f2fSdrahn    .line and .file directives will appear in the pre-processed output.  */
96d2201f2fSdrahn /* Note that input_file.c hand checks for '#' at the beginning of the
97d2201f2fSdrahn    first line of the input file.  This is because the compiler outputs
98d2201f2fSdrahn    #NO_APP at the beginning of its output.  */
99d2201f2fSdrahn /* Also note that comments like this one will always work.  */
100d2201f2fSdrahn const char line_comment_chars[] = "#";
101d2201f2fSdrahn 
102d2201f2fSdrahn /* We needed an unused char for line separation to work around the
103d2201f2fSdrahn    lack of macros, using sed and such.  */
104d2201f2fSdrahn const char line_separator_chars[] = ";";
105d2201f2fSdrahn 
106d2201f2fSdrahn /* Chars that can be used to separate mant from exp in floating point nums.  */
107d2201f2fSdrahn const char EXP_CHARS[] = "eE";
108d2201f2fSdrahn 
109d2201f2fSdrahn /* Chars that mean this number is a floating point constant.
110d2201f2fSdrahn    As in 0f12.456
111d2201f2fSdrahn    or    0d1.2345e12.  */
112d2201f2fSdrahn const char FLT_CHARS[] = "rRsSfFdDxXpP";
113d2201f2fSdrahn 
114d2201f2fSdrahn /* "l.jalr r9" precalculated opcode.  */
115d2201f2fSdrahn static unsigned long jalr_r9_opcode;
116d2201f2fSdrahn 
117d2201f2fSdrahn 
118d2201f2fSdrahn static int check_invalid_opcode PARAMS ((unsigned long));
119d2201f2fSdrahn static void encode PARAMS ((const struct machine_opcode *, unsigned long *, signed long, char));
120d2201f2fSdrahn static char *parse_operand PARAMS ((char *, expressionS *, int));
121d2201f2fSdrahn 
122d2201f2fSdrahn /* Set bits in machine opcode according to insn->encoding
123d2201f2fSdrahn    description and passed operand.  */
124d2201f2fSdrahn 
125d2201f2fSdrahn static void
encode(insn,opcode,param_val,param_ch)126d2201f2fSdrahn encode (insn, opcode, param_val, param_ch)
127d2201f2fSdrahn      const struct machine_opcode *insn;
128d2201f2fSdrahn      unsigned long *opcode;
129d2201f2fSdrahn      signed long param_val;
130d2201f2fSdrahn      char param_ch;
131d2201f2fSdrahn {
132d2201f2fSdrahn   int opc_pos = 0;
133d2201f2fSdrahn   int param_pos = 0;
134d2201f2fSdrahn   char *enc;
135d2201f2fSdrahn 
136d2201f2fSdrahn #if DEBUG
137d2201f2fSdrahn   printf ("    encode:  opcode=%.8lx  param_val=%.8lx abs=%.8lx param_ch=%c\n",
138d2201f2fSdrahn 	  *opcode, param_val, abs (param_val), param_ch);
139d2201f2fSdrahn #endif
140d2201f2fSdrahn   for (enc = insn->encoding; *enc != '\0'; enc++)
141d2201f2fSdrahn     if (*enc == param_ch)
142d2201f2fSdrahn       {
143d2201f2fSdrahn 	if (enc - 2 >= insn->encoding && (*(enc - 2) == '0') && (*(enc - 1) == 'x'))
144d2201f2fSdrahn 	  continue;
145d2201f2fSdrahn 	else
146d2201f2fSdrahn 	  param_pos ++;
147d2201f2fSdrahn       }
148d2201f2fSdrahn 
149d2201f2fSdrahn   opc_pos = 32;
150d2201f2fSdrahn 
151d2201f2fSdrahn   for (enc = insn->encoding; *enc != '\0';)
152d2201f2fSdrahn     {
153d2201f2fSdrahn       if ((*enc == '0') && (*(enc + 1) == 'x'))
154d2201f2fSdrahn 	{
155d2201f2fSdrahn 	  int tmp = strtol (enc, NULL, 16);
156d2201f2fSdrahn 
157d2201f2fSdrahn 	  opc_pos -= 4;
158d2201f2fSdrahn 	  *opcode |= tmp << opc_pos;
159d2201f2fSdrahn 	  enc += 3;
160d2201f2fSdrahn 	}
161d2201f2fSdrahn       else if ((*enc == '0') || (*enc == '-'))
162d2201f2fSdrahn 	{
163d2201f2fSdrahn 	  opc_pos--;
164d2201f2fSdrahn 	  enc++;
165d2201f2fSdrahn 	}
166d2201f2fSdrahn       else if (*enc == '1')
167d2201f2fSdrahn 	{
168d2201f2fSdrahn 	  opc_pos--;
169d2201f2fSdrahn 	  *opcode |= 1 << opc_pos;
170d2201f2fSdrahn 	  enc++;
171d2201f2fSdrahn 	}
172d2201f2fSdrahn       else if (*enc == param_ch)
173d2201f2fSdrahn 	{
174d2201f2fSdrahn 	  opc_pos--;
175d2201f2fSdrahn 	  param_pos--;
176d2201f2fSdrahn 	  *opcode |= ((param_val >> param_pos) & 0x1) << opc_pos;
177d2201f2fSdrahn 	  enc++;
178d2201f2fSdrahn 	}
179d2201f2fSdrahn       else if (ISALPHA (*enc))
180d2201f2fSdrahn 	{
181d2201f2fSdrahn 	  opc_pos--;
182d2201f2fSdrahn 	  enc++;
183d2201f2fSdrahn 	}
184d2201f2fSdrahn       else
185d2201f2fSdrahn 	enc++;
186d2201f2fSdrahn     }
187d2201f2fSdrahn 
188d2201f2fSdrahn #if DEBUG
189d2201f2fSdrahn   printf ("    opcode=%.8lx\n", *opcode);
190d2201f2fSdrahn #endif
191d2201f2fSdrahn }
192d2201f2fSdrahn 
193d2201f2fSdrahn /* This function is called once, at assembler startup time.  It should
194d2201f2fSdrahn    set up all the tables, etc., that the MD part of the assembler will
195d2201f2fSdrahn    need.  */
196d2201f2fSdrahn 
197d2201f2fSdrahn void
md_begin()198d2201f2fSdrahn md_begin ()
199d2201f2fSdrahn {
200d2201f2fSdrahn   const char *retval = NULL;
201d2201f2fSdrahn   int lose = 0;
202d2201f2fSdrahn   int skipnext = 0;
203d2201f2fSdrahn   unsigned int i;
204d2201f2fSdrahn 
205d2201f2fSdrahn   /* Hash up all the opcodes for fast use later.  */
206d2201f2fSdrahn   op_hash = hash_new ();
207d2201f2fSdrahn 
208d2201f2fSdrahn   for (i = 0; i < or32_num_opcodes; i++)
209d2201f2fSdrahn     {
210d2201f2fSdrahn       const char *name = machine_opcodes[i].name;
211d2201f2fSdrahn 
212d2201f2fSdrahn       if (skipnext)
213d2201f2fSdrahn         {
214d2201f2fSdrahn           skipnext = 0;
215d2201f2fSdrahn           continue;
216d2201f2fSdrahn         }
217d2201f2fSdrahn 
218d2201f2fSdrahn       retval = hash_insert (op_hash, name, (PTR) &machine_opcodes[i]);
219d2201f2fSdrahn       if (retval != NULL)
220d2201f2fSdrahn         {
221d2201f2fSdrahn           fprintf (stderr, "internal error: can't hash `%s': %s\n",
222d2201f2fSdrahn                    machine_opcodes[i].name, retval);
223d2201f2fSdrahn           lose = 1;
224d2201f2fSdrahn         }
225d2201f2fSdrahn     }
226d2201f2fSdrahn 
227d2201f2fSdrahn   if (lose)
228d2201f2fSdrahn     as_fatal (_("Broken assembler.  No assembly attempted."));
229d2201f2fSdrahn 
230d2201f2fSdrahn   encode (&machine_opcodes[insn_index ("l.jalr")], &jalr_r9_opcode, 9, 'B');
231d2201f2fSdrahn }
232d2201f2fSdrahn 
233*cf2f2c56Smiod /* Returns non zero if instruction is to be used.  */
234d2201f2fSdrahn 
235d2201f2fSdrahn static int
check_invalid_opcode(opcode)236d2201f2fSdrahn check_invalid_opcode (opcode)
237d2201f2fSdrahn      unsigned long opcode;
238d2201f2fSdrahn {
239d2201f2fSdrahn   return opcode == jalr_r9_opcode;
240d2201f2fSdrahn }
241d2201f2fSdrahn 
242d2201f2fSdrahn /* Assemble a single instruction.  Its label has already been handled
243d2201f2fSdrahn    by the generic front end.  We just parse opcode and operands, and
244d2201f2fSdrahn    produce the bytes of data and relocation.  */
245d2201f2fSdrahn 
246d2201f2fSdrahn void
md_assemble(str)247d2201f2fSdrahn md_assemble (str)
248d2201f2fSdrahn      char *str;
249d2201f2fSdrahn {
250d2201f2fSdrahn   char *toP;
251d2201f2fSdrahn 
252d2201f2fSdrahn #if DEBUG
253d2201f2fSdrahn   printf ("NEW INSTRUCTION\n");
254d2201f2fSdrahn #endif
255d2201f2fSdrahn 
256d2201f2fSdrahn   know (str);
257d2201f2fSdrahn   machine_ip (str);
258d2201f2fSdrahn   toP = frag_more (4);
259d2201f2fSdrahn 
260d2201f2fSdrahn   /* Put out the opcode.  */
261d2201f2fSdrahn   md_number_to_chars (toP, the_insn.opcode, 4);
262d2201f2fSdrahn 
263d2201f2fSdrahn   /* Put out the symbol-dependent stuff.  */
264d2201f2fSdrahn #ifdef BFD_ASSEMBLER
265d2201f2fSdrahn   if (the_insn.reloc != BFD_RELOC_NONE)
266d2201f2fSdrahn #else
267d2201f2fSdrahn   if (the_insn.reloc != NO_RELOC)
268d2201f2fSdrahn #endif
269d2201f2fSdrahn     {
270d2201f2fSdrahn       fix_new_exp (frag_now,
271d2201f2fSdrahn                    (toP - frag_now->fr_literal + the_insn.reloc_offset),
272d2201f2fSdrahn                    4,   /* size */
273d2201f2fSdrahn                    &the_insn.exp,
274d2201f2fSdrahn                    the_insn.pcrel,
275d2201f2fSdrahn                    the_insn.reloc);
276d2201f2fSdrahn     }
277d2201f2fSdrahn }
278d2201f2fSdrahn 
279d2201f2fSdrahn /* This is true of the we have issued a "lo(" or "hi"(.  */
280d2201f2fSdrahn static int waiting_for_shift = 0;
281d2201f2fSdrahn 
282d2201f2fSdrahn static int mask_or_shift = 0;
283d2201f2fSdrahn 
284d2201f2fSdrahn #ifdef BFD_ASSEMBLER
285d2201f2fSdrahn static char *
parse_operand(s,operandp,opt)286d2201f2fSdrahn parse_operand (s, operandp, opt)
287d2201f2fSdrahn      char *s;
288d2201f2fSdrahn      expressionS *operandp;
289d2201f2fSdrahn      int opt;
290d2201f2fSdrahn {
291d2201f2fSdrahn   char *save = input_line_pointer;
292d2201f2fSdrahn   char *new;
293d2201f2fSdrahn 
294d2201f2fSdrahn #if DEBUG
295d2201f2fSdrahn   printf ("  PROCESS NEW OPERAND(%s) == %c (%d)\n", s, opt ? opt : '!', opt);
296d2201f2fSdrahn #endif
297d2201f2fSdrahn 
298d2201f2fSdrahn   input_line_pointer = s;
299d2201f2fSdrahn 
300d2201f2fSdrahn   if (strncasecmp (s, "HI(", 3) == 0)
301d2201f2fSdrahn     {
302d2201f2fSdrahn       waiting_for_shift = 1;
303d2201f2fSdrahn       mask_or_shift = BFD_RELOC_HI16;
304d2201f2fSdrahn 
305d2201f2fSdrahn       input_line_pointer += 3;
306d2201f2fSdrahn     }
307d2201f2fSdrahn   else if (strncasecmp (s, "LO(", 3) == 0)
308d2201f2fSdrahn     {
309d2201f2fSdrahn       mask_or_shift = BFD_RELOC_LO16;
310d2201f2fSdrahn 
311d2201f2fSdrahn       input_line_pointer += 3;
312d2201f2fSdrahn     }
313d2201f2fSdrahn   else
314d2201f2fSdrahn     mask_or_shift = 0;
315d2201f2fSdrahn 
316d2201f2fSdrahn   if ((*s == '(') && (*(s+1) == 'r'))
317d2201f2fSdrahn     s++;
318d2201f2fSdrahn 
319d2201f2fSdrahn   if ((*s == 'r') && ISDIGIT (*(s + 1)))
320d2201f2fSdrahn     {
321d2201f2fSdrahn       operandp->X_add_number = strtol (s + 1, NULL, 10);
322d2201f2fSdrahn       operandp->X_op = O_register;
323d2201f2fSdrahn       for (; (*s != ',') && (*s != '\0');)
324d2201f2fSdrahn         s++;
325d2201f2fSdrahn       input_line_pointer = save;
326d2201f2fSdrahn       return s;
327d2201f2fSdrahn     }
328d2201f2fSdrahn 
329d2201f2fSdrahn   expression (operandp);
330d2201f2fSdrahn 
331d2201f2fSdrahn   if (operandp->X_op == O_absent)
332d2201f2fSdrahn     {
333d2201f2fSdrahn       if (! opt)
334d2201f2fSdrahn         as_bad (_("missing operand"));
335d2201f2fSdrahn       else
336d2201f2fSdrahn         {
337d2201f2fSdrahn           operandp->X_add_number = 0;
338d2201f2fSdrahn           operandp->X_op = O_constant;
339d2201f2fSdrahn         }
340d2201f2fSdrahn     }
341d2201f2fSdrahn 
342d2201f2fSdrahn   new = input_line_pointer;
343d2201f2fSdrahn   input_line_pointer = save;
344d2201f2fSdrahn 
345d2201f2fSdrahn #if DEBUG
346d2201f2fSdrahn   printf ("  %s=parse_operand(%s): operandp->X_op = %u\n", new, s, operandp->X_op);
347d2201f2fSdrahn #endif
348d2201f2fSdrahn 
349d2201f2fSdrahn   return new;
350d2201f2fSdrahn }
351d2201f2fSdrahn #else
352d2201f2fSdrahn 
353d2201f2fSdrahn static char *
parse_operand(s,operandp,opt)354d2201f2fSdrahn parse_operand (s, operandp, opt)
355d2201f2fSdrahn      char *s;
356d2201f2fSdrahn      expressionS *operandp;
357d2201f2fSdrahn      int opt;
358d2201f2fSdrahn {
359d2201f2fSdrahn   char *save = input_line_pointer;
360d2201f2fSdrahn   char *new;
361d2201f2fSdrahn 
362d2201f2fSdrahn #if DEBUG
363d2201f2fSdrahn   printf ("  PROCESS NEW OPERAND(%s) == %c (%d)\n", s, opt ? opt : '!', opt);
364d2201f2fSdrahn #endif
365d2201f2fSdrahn 
366d2201f2fSdrahn   input_line_pointer = s;
367d2201f2fSdrahn 
368d2201f2fSdrahn   if (strncasecmp (s, "HI(", 3) == 0)
369d2201f2fSdrahn     {
370d2201f2fSdrahn       waiting_for_shift = 1;
371d2201f2fSdrahn       mask_or_shift = RELOC_CONSTH;
372d2201f2fSdrahn 
373d2201f2fSdrahn       input_line_pointer += 3;
374d2201f2fSdrahn     }
375d2201f2fSdrahn   else if (strncasecmp (s, "LO(", 3) == 0)
376d2201f2fSdrahn     {
377d2201f2fSdrahn       mask_or_shift = RELOC_CONST;
378d2201f2fSdrahn 
379d2201f2fSdrahn       input_line_pointer += 3;
380d2201f2fSdrahn     }
381d2201f2fSdrahn   else
382d2201f2fSdrahn     mask_or_shift = 0;
383d2201f2fSdrahn 
384d2201f2fSdrahn 
385d2201f2fSdrahn   expression (operandp);
386d2201f2fSdrahn 
387d2201f2fSdrahn   if (operandp->X_op == O_absent)
388d2201f2fSdrahn     {
389d2201f2fSdrahn       if (! opt)
390d2201f2fSdrahn         as_bad (_("missing operand"));
391d2201f2fSdrahn       else
392d2201f2fSdrahn         {
393d2201f2fSdrahn           operandp->X_add_number = 0;
394d2201f2fSdrahn           operandp->X_op = O_constant;
395d2201f2fSdrahn         }
396d2201f2fSdrahn     }
397d2201f2fSdrahn 
398d2201f2fSdrahn   new = input_line_pointer;
399d2201f2fSdrahn   input_line_pointer = save;
400d2201f2fSdrahn 
401d2201f2fSdrahn   if ((operandp->X_op == O_symbol) && (*s != '_'))
402d2201f2fSdrahn     {
403d2201f2fSdrahn #if DEBUG
404d2201f2fSdrahn       printf ("symbol: '%s'\n", save);
405d2201f2fSdrahn #endif
406d2201f2fSdrahn 
407d2201f2fSdrahn       for (save = s; s < new; s++)
408d2201f2fSdrahn         if ((*s == REGISTER_PREFIX) && (*(s + 1) == 'r')) /* Register prefix.  */
409d2201f2fSdrahn           s++;
410d2201f2fSdrahn 
411d2201f2fSdrahn         if ((*s == 'r') && ISDIGIT (*(s + 1)))
412d2201f2fSdrahn           {
413d2201f2fSdrahn             operandp->X_add_number = strtol (s + 1, NULL, 10);
414d2201f2fSdrahn             operandp->X_op = O_register;
415d2201f2fSdrahn           }
416d2201f2fSdrahn       s = save;
417d2201f2fSdrahn     }
418d2201f2fSdrahn 
419d2201f2fSdrahn #if DEBUG
420d2201f2fSdrahn   printf ("  %s=parse_operand(%s): operandp->X_op = %u\n", new, s, operandp->X_op);
421d2201f2fSdrahn #endif
422d2201f2fSdrahn 
423d2201f2fSdrahn   return new;
424d2201f2fSdrahn }
425d2201f2fSdrahn #endif
426d2201f2fSdrahn 
427d2201f2fSdrahn /* Instruction parsing.  Takes a string containing the opcode.
428d2201f2fSdrahn    Operands are at input_line_pointer.  Output is in the_insn.
429d2201f2fSdrahn    Warnings or errors are generated.  */
430d2201f2fSdrahn 
431d2201f2fSdrahn #ifdef BFD_ASSEMBLER
432d2201f2fSdrahn static void
machine_ip(str)433d2201f2fSdrahn machine_ip (str)
434d2201f2fSdrahn      char *str;
435d2201f2fSdrahn {
436d2201f2fSdrahn   char *s;
437d2201f2fSdrahn   const char *args;
438d2201f2fSdrahn   const struct machine_opcode *insn;
439d2201f2fSdrahn   char *argsStart;
440d2201f2fSdrahn   unsigned long opcode;
441d2201f2fSdrahn   expressionS the_operand;
442d2201f2fSdrahn   expressionS *operand = &the_operand;
443d2201f2fSdrahn   unsigned int regno;
444d2201f2fSdrahn   int reloc = BFD_RELOC_NONE;
445d2201f2fSdrahn 
446d2201f2fSdrahn #if DEBUG
447d2201f2fSdrahn   printf ("machine_ip(%s)\n", str);
448d2201f2fSdrahn #endif
449d2201f2fSdrahn 
450d2201f2fSdrahn   s = str;
451d2201f2fSdrahn   for (; ISALNUM (*s) || *s == '.'; ++s)
452d2201f2fSdrahn     if (ISUPPER (*s))
453d2201f2fSdrahn       *s = TOLOWER (*s);
454d2201f2fSdrahn 
455d2201f2fSdrahn   switch (*s)
456d2201f2fSdrahn     {
457d2201f2fSdrahn     case '\0':
458d2201f2fSdrahn       break;
459d2201f2fSdrahn 
460d2201f2fSdrahn     case ' ':     /* FIXME-SOMEDAY more whitespace.  */
461d2201f2fSdrahn       *s++ = '\0';
462d2201f2fSdrahn       break;
463d2201f2fSdrahn 
464d2201f2fSdrahn     default:
465d2201f2fSdrahn       as_bad (_("unknown opcode1: `%s'"), str);
466d2201f2fSdrahn       return;
467d2201f2fSdrahn     }
468d2201f2fSdrahn 
469d2201f2fSdrahn   if ((insn = (struct machine_opcode *) hash_find (op_hash, str)) == NULL)
470d2201f2fSdrahn     {
471d2201f2fSdrahn       as_bad (_("unknown opcode2 `%s'."), str);
472d2201f2fSdrahn       return;
473d2201f2fSdrahn     }
474d2201f2fSdrahn 
475d2201f2fSdrahn   argsStart = s;
476d2201f2fSdrahn   opcode = 0;
477d2201f2fSdrahn   memset (&the_insn, '\0', sizeof (the_insn));
478d2201f2fSdrahn   the_insn.reloc = BFD_RELOC_NONE;
479d2201f2fSdrahn 
480d2201f2fSdrahn   reloc = BFD_RELOC_NONE;
481d2201f2fSdrahn 
482d2201f2fSdrahn   /* Build the opcode, checking as we go to make sure that the
483d2201f2fSdrahn      operands match.
484d2201f2fSdrahn 
485d2201f2fSdrahn      If an operand matches, we modify the_insn or opcode appropriately,
486d2201f2fSdrahn      and do a "continue".  If an operand fails to match, we "break".  */
487d2201f2fSdrahn   if (insn->args[0] != '\0')
488d2201f2fSdrahn     {
489d2201f2fSdrahn       /* Prime the pump.  */
490d2201f2fSdrahn       s = parse_operand (s, operand, insn->args[0] == 'I');
491d2201f2fSdrahn     }
492d2201f2fSdrahn 
493d2201f2fSdrahn   for (args = insn->args;; ++args)
494d2201f2fSdrahn     {
495d2201f2fSdrahn #if DEBUG
496d2201f2fSdrahn       printf ("  args = %s\n", args);
497d2201f2fSdrahn #endif
498d2201f2fSdrahn       switch (*args)
499d2201f2fSdrahn         {
500d2201f2fSdrahn         case '\0':    /* End of args.  */
501d2201f2fSdrahn           /* We have have 0 args, do the bazoooka!  */
502d2201f2fSdrahn           if (args == insn->args)
503d2201f2fSdrahn 	    encode (insn, &opcode, 0, 0);
504d2201f2fSdrahn 
505d2201f2fSdrahn           if (*s == '\0')
506d2201f2fSdrahn             {
507d2201f2fSdrahn               /* We are truly done.  */
508d2201f2fSdrahn               the_insn.opcode = opcode;
509d2201f2fSdrahn               if (check_invalid_opcode (opcode))
510d2201f2fSdrahn                 as_bad (_("instruction not allowed: %s"), str);
511d2201f2fSdrahn               return;
512d2201f2fSdrahn             }
513d2201f2fSdrahn           as_bad (_("too many operands: %s"), s);
514d2201f2fSdrahn           break;
515d2201f2fSdrahn 
516d2201f2fSdrahn         case ',':   /* Must match a comma.  */
517d2201f2fSdrahn           if (*s++ == ',')
518d2201f2fSdrahn             {
519d2201f2fSdrahn               reloc = BFD_RELOC_NONE;
520d2201f2fSdrahn 
521d2201f2fSdrahn               /* Parse next operand.  */
522d2201f2fSdrahn               s = parse_operand (s, operand, args[1] == 'I');
523d2201f2fSdrahn #if DEBUG
524d2201f2fSdrahn 	      printf ("    ',' case: operand->X_add_number = %d, *args = %s, *s = %s\n",
525d2201f2fSdrahn 		      operand->X_add_number, args, s);
526d2201f2fSdrahn #endif
527d2201f2fSdrahn               continue;
528d2201f2fSdrahn             }
529d2201f2fSdrahn           break;
530d2201f2fSdrahn 
531d2201f2fSdrahn         case '(':   /* Must match a (.  */
532d2201f2fSdrahn           s = parse_operand (s, operand, args[1] == 'I');
533d2201f2fSdrahn           continue;
534d2201f2fSdrahn 
535d2201f2fSdrahn         case ')':   /* Must match a ).  */
536d2201f2fSdrahn           continue;
537d2201f2fSdrahn 
538d2201f2fSdrahn         case 'r':   /* A general register.  */
539d2201f2fSdrahn           args++;
540d2201f2fSdrahn 
541d2201f2fSdrahn           if (operand->X_op != O_register)
542d2201f2fSdrahn             break;    /* Only registers.  */
543d2201f2fSdrahn 
544d2201f2fSdrahn           know (operand->X_add_symbol == 0);
545d2201f2fSdrahn           know (operand->X_op_symbol == 0);
546d2201f2fSdrahn           regno = operand->X_add_number;
547d2201f2fSdrahn           encode (insn, &opcode, regno, *args);
548d2201f2fSdrahn #if DEBUG
549d2201f2fSdrahn           printf ("    r: operand->X_op = %d\n", operand->X_op);
550d2201f2fSdrahn #endif
551d2201f2fSdrahn           continue;
552d2201f2fSdrahn 
553d2201f2fSdrahn         default:
554d2201f2fSdrahn           /* if (! ISALPHA (*args))
555d2201f2fSdrahn                break;  */   /* Only immediate values.  */
556d2201f2fSdrahn 
557d2201f2fSdrahn           if (mask_or_shift)
558d2201f2fSdrahn 	    {
559d2201f2fSdrahn #if DEBUG
560d2201f2fSdrahn 	      printf ("mask_or_shift = %d\n", mask_or_shift);
561d2201f2fSdrahn #endif
562d2201f2fSdrahn 	      reloc = mask_or_shift;
563d2201f2fSdrahn 	    }
564d2201f2fSdrahn           mask_or_shift = 0;
565d2201f2fSdrahn 
566d2201f2fSdrahn           if (strncasecmp (args, "LO(", 3) == 0)
567d2201f2fSdrahn             {
568d2201f2fSdrahn #if DEBUG
569d2201f2fSdrahn               printf ("reloc_const\n");
570d2201f2fSdrahn #endif
571d2201f2fSdrahn               reloc = BFD_RELOC_LO16;
572d2201f2fSdrahn             }
573d2201f2fSdrahn           else if (strncasecmp (args, "HI(", 3) == 0)
574d2201f2fSdrahn             {
575d2201f2fSdrahn #if DEBUG
576d2201f2fSdrahn               printf ("reloc_consth\n");
577d2201f2fSdrahn #endif
578d2201f2fSdrahn               reloc = BFD_RELOC_HI16;
579d2201f2fSdrahn             }
580d2201f2fSdrahn 
581d2201f2fSdrahn           if (*s == '(')
582d2201f2fSdrahn             {
583d2201f2fSdrahn               operand->X_op = O_constant;
584d2201f2fSdrahn #if 0
585d2201f2fSdrahn               operand->X_add_number = 0; /* ??? if enabled load/store offsets
586d2201f2fSdrahn 					    are zero.  */
587d2201f2fSdrahn #endif
588d2201f2fSdrahn             }
589d2201f2fSdrahn           else if (*s == ')')
590d2201f2fSdrahn             s += 1;
591d2201f2fSdrahn #if DEBUG
592d2201f2fSdrahn           printf ("    default case: operand->X_add_number = %d, *args = %s, *s = %s\n", operand->X_add_number, args, s);
593d2201f2fSdrahn #endif
594d2201f2fSdrahn           if (operand->X_op == O_constant)
595d2201f2fSdrahn             {
596d2201f2fSdrahn 	      if (reloc == BFD_RELOC_NONE)
597d2201f2fSdrahn 		{
598d2201f2fSdrahn 		  bfd_vma v, mask;
599d2201f2fSdrahn 
600d2201f2fSdrahn 		  mask = 0x3ffffff;
601d2201f2fSdrahn 		  v = abs (operand->X_add_number) & ~ mask;
602d2201f2fSdrahn 		  if (v)
603d2201f2fSdrahn 		    as_bad (_("call/jmp target out of range (1)"));
604d2201f2fSdrahn 		}
605d2201f2fSdrahn 
606d2201f2fSdrahn               if (reloc == BFD_RELOC_HI16)
607d2201f2fSdrahn 		operand->X_add_number = ((operand->X_add_number >> 16) & 0xffff);
608d2201f2fSdrahn 
609d2201f2fSdrahn               the_insn.pcrel = 0;
610d2201f2fSdrahn               encode (insn, &opcode, operand->X_add_number, *args);
611d2201f2fSdrahn  /*             the_insn.reloc = BFD_RELOC_NONE; */
612d2201f2fSdrahn               continue;
613d2201f2fSdrahn             }
614d2201f2fSdrahn 
615d2201f2fSdrahn           if (reloc == BFD_RELOC_NONE)
616d2201f2fSdrahn             the_insn.reloc = BFD_RELOC_32_GOT_PCREL;
617d2201f2fSdrahn           else
618d2201f2fSdrahn             the_insn.reloc = reloc;
619d2201f2fSdrahn 
620d2201f2fSdrahn           /* the_insn.reloc = insn->reloc;  */
621d2201f2fSdrahn #if DEBUG
622d2201f2fSdrahn           printf ("    reloc sym=%d\n", the_insn.reloc);
623d2201f2fSdrahn           printf ("    BFD_RELOC_NONE=%d\n", BFD_RELOC_NONE);
624d2201f2fSdrahn #endif
625d2201f2fSdrahn           the_insn.exp = *operand;
626d2201f2fSdrahn 
627d2201f2fSdrahn           /*  the_insn.reloc_offset = 1;  */
628d2201f2fSdrahn           the_insn.pcrel = 1; /* Assume PC-relative jump.  */
629d2201f2fSdrahn 
630d2201f2fSdrahn           /* FIXME-SOON, Do we figure out whether abs later, after
631d2201f2fSdrahn              know sym val?  */
632d2201f2fSdrahn           if (reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_HI16)
633d2201f2fSdrahn             the_insn.pcrel = 0;
634d2201f2fSdrahn 
635d2201f2fSdrahn           encode (insn, &opcode, operand->X_add_number, *args);
636d2201f2fSdrahn           continue;
637d2201f2fSdrahn         }
638d2201f2fSdrahn 
639d2201f2fSdrahn       /* Types or values of args don't match.  */
640d2201f2fSdrahn       as_bad (_("invalid operands"));
641d2201f2fSdrahn       return;
642d2201f2fSdrahn     }
643d2201f2fSdrahn }
644d2201f2fSdrahn 
645d2201f2fSdrahn #else
646d2201f2fSdrahn 
647d2201f2fSdrahn static void
machine_ip(str)648d2201f2fSdrahn machine_ip (str)
649d2201f2fSdrahn      char *str;
650d2201f2fSdrahn {
651d2201f2fSdrahn   char *s;
652d2201f2fSdrahn   const char *args;
653d2201f2fSdrahn   const struct machine_opcode *insn;
654d2201f2fSdrahn   char *argsStart;
655d2201f2fSdrahn   unsigned long opcode;
656d2201f2fSdrahn   expressionS the_operand;
657d2201f2fSdrahn   expressionS *operand = &the_operand;
658d2201f2fSdrahn   unsigned int regno;
659d2201f2fSdrahn   int reloc = NO_RELOC;
660d2201f2fSdrahn 
661d2201f2fSdrahn #if DEBUG
662d2201f2fSdrahn   printf ("machine_ip(%s)\n", str);
663d2201f2fSdrahn #endif
664d2201f2fSdrahn 
665d2201f2fSdrahn   s = str;
666d2201f2fSdrahn   for (; ISALNUM (*s) || *s == '.'; ++s)
667d2201f2fSdrahn     if (ISUPPER (*s))
668d2201f2fSdrahn       *s = TOLOWER (*s);
669d2201f2fSdrahn 
670d2201f2fSdrahn   switch (*s)
671d2201f2fSdrahn     {
672d2201f2fSdrahn     case '\0':
673d2201f2fSdrahn       break;
674d2201f2fSdrahn 
675d2201f2fSdrahn     case ' ':     /* FIXME-SOMEDAY more whitespace.  */
676d2201f2fSdrahn       *s++ = '\0';
677d2201f2fSdrahn       break;
678d2201f2fSdrahn 
679d2201f2fSdrahn     default:
680d2201f2fSdrahn       as_bad (_("unknown opcode1: `%s'"), str);
681d2201f2fSdrahn       return;
682d2201f2fSdrahn     }
683d2201f2fSdrahn 
684d2201f2fSdrahn   if ((insn = (struct machine_opcode *) hash_find (op_hash, str)) == NULL)
685d2201f2fSdrahn     {
686d2201f2fSdrahn       as_bad (_("unknown opcode2 `%s'."), str);
687d2201f2fSdrahn       return;
688d2201f2fSdrahn     }
689d2201f2fSdrahn 
690d2201f2fSdrahn   argsStart = s;
691d2201f2fSdrahn   opcode = 0;
692d2201f2fSdrahn   memset (&the_insn, '\0', sizeof (the_insn));
693d2201f2fSdrahn   the_insn.reloc = NO_RELOC;
694d2201f2fSdrahn 
695d2201f2fSdrahn   reloc = NO_RELOC;
696d2201f2fSdrahn 
697d2201f2fSdrahn   /* Build the opcode, checking as we go to make sure that the
698d2201f2fSdrahn      operands match.
699d2201f2fSdrahn 
700d2201f2fSdrahn      If an operand matches, we modify the_insn or opcode appropriately,
701d2201f2fSdrahn      and do a "continue".  If an operand fails to match, we "break".  */
702d2201f2fSdrahn   if (insn->args[0] != '\0')
703d2201f2fSdrahn     /* Prime the pump.  */
704d2201f2fSdrahn     s = parse_operand (s, operand,
705d2201f2fSdrahn 		       insn->args[0] == 'I'
706d2201f2fSdrahn 		       || strcmp (insn->name, "l.nop") == 0);
707d2201f2fSdrahn 
708d2201f2fSdrahn   for (args = insn->args;; ++args)
709d2201f2fSdrahn     {
710d2201f2fSdrahn #if DEBUG
711d2201f2fSdrahn       printf ("  args = %s\n", args);
712d2201f2fSdrahn #endif
713d2201f2fSdrahn       switch (*args)
714d2201f2fSdrahn         {
715d2201f2fSdrahn         case '\0':    /* End of args.  */
716d2201f2fSdrahn           /* We have have 0 args, do the bazoooka!  */
717d2201f2fSdrahn           if (args == insn->args)
718d2201f2fSdrahn 	    encode (insn, &opcode, 0, 0);
719d2201f2fSdrahn 
720d2201f2fSdrahn           if (*s == '\0')
721d2201f2fSdrahn             {
722d2201f2fSdrahn               /* We are truly done.  */
723d2201f2fSdrahn               the_insn.opcode = opcode;
724d2201f2fSdrahn               if (check_invalid_opcode (opcode))
725d2201f2fSdrahn                 as_bad (_("instruction not allowed: %s"), str);
726d2201f2fSdrahn               return;
727d2201f2fSdrahn             }
728d2201f2fSdrahn           as_bad (_("too many operands: %s"), s);
729d2201f2fSdrahn           break;
730d2201f2fSdrahn 
731d2201f2fSdrahn         case ',':   /* Must match a comma.  */
732d2201f2fSdrahn           if (*s++ == ',')
733d2201f2fSdrahn             {
734d2201f2fSdrahn               reloc = NO_RELOC;
735d2201f2fSdrahn 
736d2201f2fSdrahn               /* Parse next operand.  */
737d2201f2fSdrahn               s = parse_operand (s, operand, args[1] == 'I');
738d2201f2fSdrahn #if DEBUG
739d2201f2fSdrahn 	      printf ("    ',' case: operand->X_add_number = %d, *args = %s, *s = %s\n",
740d2201f2fSdrahn 		      operand->X_add_number, args, s);
741d2201f2fSdrahn #endif
742d2201f2fSdrahn               continue;
743d2201f2fSdrahn             }
744d2201f2fSdrahn           break;
745d2201f2fSdrahn 
746d2201f2fSdrahn         case '(':   /* Must match a (.  */
747d2201f2fSdrahn           s = parse_operand (s, operand, args[1] == 'I');
748d2201f2fSdrahn           continue;
749d2201f2fSdrahn 
750d2201f2fSdrahn         case ')':   /* Must match a ).  */
751d2201f2fSdrahn           continue;
752d2201f2fSdrahn 
753d2201f2fSdrahn         case 'r':   /* A general register.  */
754d2201f2fSdrahn           args++;
755d2201f2fSdrahn 
756d2201f2fSdrahn           if (operand->X_op != O_register)
757d2201f2fSdrahn             break;    /* Only registers.  */
758d2201f2fSdrahn 
759d2201f2fSdrahn           know (operand->X_add_symbol == 0);
760d2201f2fSdrahn           know (operand->X_op_symbol == 0);
761d2201f2fSdrahn           regno = operand->X_add_number;
762d2201f2fSdrahn           encode (insn, &opcode, regno, *args);
763d2201f2fSdrahn #if DEBUG
764d2201f2fSdrahn           printf ("    r: operand->X_op = %d\n", operand->X_op);
765d2201f2fSdrahn #endif
766d2201f2fSdrahn           continue;
767d2201f2fSdrahn 
768d2201f2fSdrahn         default:
769d2201f2fSdrahn           /* if (! ISALPHA (*args))
770d2201f2fSdrahn                break;  */   /* Only immediate values.  */
771d2201f2fSdrahn 
772d2201f2fSdrahn           if (mask_or_shift)
773d2201f2fSdrahn 	    {
774d2201f2fSdrahn #if DEBUG
775d2201f2fSdrahn 	      printf ("mask_or_shift = %d\n", mask_or_shift);
776d2201f2fSdrahn #endif
777d2201f2fSdrahn 	      reloc = mask_or_shift;
778d2201f2fSdrahn 	    }
779d2201f2fSdrahn           mask_or_shift = 0;
780d2201f2fSdrahn 
781d2201f2fSdrahn           if (strncasecmp (args, "LO(", 3) == 0)
782d2201f2fSdrahn             {
783d2201f2fSdrahn #if DEBUG
784d2201f2fSdrahn               printf ("reloc_const\n");
785d2201f2fSdrahn #endif
786d2201f2fSdrahn               reloc = RELOC_CONST;
787d2201f2fSdrahn             }
788d2201f2fSdrahn           else if (strncasecmp (args, "HI(", 3) == 0)
789d2201f2fSdrahn             {
790d2201f2fSdrahn #if DEBUG
791d2201f2fSdrahn               printf ("reloc_consth\n");
792d2201f2fSdrahn #endif
793d2201f2fSdrahn               reloc = RELOC_CONSTH;
794d2201f2fSdrahn             }
795d2201f2fSdrahn 
796d2201f2fSdrahn           if (*s == '(')
797d2201f2fSdrahn             {
798d2201f2fSdrahn               operand->X_op = O_constant;
799d2201f2fSdrahn #if 0
800d2201f2fSdrahn               operand->X_add_number = 0; /* ??? if enabled load/store offsets
801d2201f2fSdrahn 					    are zero.  */
802d2201f2fSdrahn #endif
803d2201f2fSdrahn             }
804d2201f2fSdrahn           else if (*s == ')')
805d2201f2fSdrahn             s += 1;
806d2201f2fSdrahn #if DEBUG
807d2201f2fSdrahn           printf ("    default case: operand->X_add_number = %d, *args = %s, *s = %s\n",
808d2201f2fSdrahn 		  operand->X_add_number, args, s);
809d2201f2fSdrahn #endif
810d2201f2fSdrahn           if (operand->X_op == O_constant)
811d2201f2fSdrahn             {
812d2201f2fSdrahn 	      if (reloc == NO_RELOC)
813d2201f2fSdrahn 		{
814d2201f2fSdrahn 		  unsigned long v, mask;
815d2201f2fSdrahn 
816d2201f2fSdrahn 		  mask = 0x3ffffff;
817d2201f2fSdrahn 		  v = abs (operand->X_add_number) & ~ mask;
818d2201f2fSdrahn 		  if (v)
819d2201f2fSdrahn 		    as_bad (_("call/jmp target out of range (1)"));
820d2201f2fSdrahn 		}
821d2201f2fSdrahn 
822d2201f2fSdrahn               if (reloc == RELOC_CONSTH)
823d2201f2fSdrahn 		operand->X_add_number = ((operand->X_add_number>>16) & 0xffff);
824d2201f2fSdrahn 
825d2201f2fSdrahn               the_insn.pcrel = 0;
826d2201f2fSdrahn               encode (insn, &opcode, operand->X_add_number, *args);
827d2201f2fSdrahn 	      /* the_insn.reloc = NO_RELOC; */
828d2201f2fSdrahn               continue;
829d2201f2fSdrahn             }
830d2201f2fSdrahn 
831d2201f2fSdrahn           if (reloc == NO_RELOC)
832d2201f2fSdrahn             the_insn.reloc = RELOC_JUMPTARG;
833d2201f2fSdrahn           else
834d2201f2fSdrahn             the_insn.reloc = reloc;
835d2201f2fSdrahn #if DEBUG
836d2201f2fSdrahn           printf ("    reloc sym=%d\n", the_insn.reloc);
837d2201f2fSdrahn           printf ("    NO_RELOC=%d\n", NO_RELOC);
838d2201f2fSdrahn #endif
839d2201f2fSdrahn           the_insn.exp = *operand;
840d2201f2fSdrahn 
841d2201f2fSdrahn           /*  the_insn.reloc_offset = 1;  */
842d2201f2fSdrahn           the_insn.pcrel = 1; /* Assume PC-relative jump.  */
843d2201f2fSdrahn 
844d2201f2fSdrahn           /* FIXME-SOON, Do we figure out whether abs later, after
845d2201f2fSdrahn              know sym val?  */
846d2201f2fSdrahn           if (reloc == RELOC_CONST || reloc == RELOC_CONSTH)
847d2201f2fSdrahn             the_insn.pcrel = 0;
848d2201f2fSdrahn 
849d2201f2fSdrahn           encode (insn, &opcode, operand->X_add_number, *args);
850d2201f2fSdrahn           continue;
851d2201f2fSdrahn         }
852d2201f2fSdrahn 
853d2201f2fSdrahn       /* Types or values of args don't match.  */
854d2201f2fSdrahn       as_bad (_("invalid operands"));
855d2201f2fSdrahn       return;
856d2201f2fSdrahn     }
857d2201f2fSdrahn }
858d2201f2fSdrahn #endif
859d2201f2fSdrahn 
860d2201f2fSdrahn /* This is identical to the md_atof in m68k.c.  I think this is right,
861d2201f2fSdrahn    but I'm not sure.
862d2201f2fSdrahn 
863d2201f2fSdrahn    Turn a string in input_line_pointer into a floating point constant
864d2201f2fSdrahn    of type type, and store the appropriate bytes in *litP.  The number
865d2201f2fSdrahn    of LITTLENUMS emitted is stored in *sizeP .  An error message is
866d2201f2fSdrahn    returned, or NULL on OK.  */
867d2201f2fSdrahn 
868d2201f2fSdrahn /* Equal to MAX_PRECISION in atof-ieee.c.  */
869d2201f2fSdrahn #define MAX_LITTLENUMS 6
870d2201f2fSdrahn 
871d2201f2fSdrahn char *
md_atof(type,litP,sizeP)872d2201f2fSdrahn md_atof (type, litP, sizeP)
873d2201f2fSdrahn      char   type;
874d2201f2fSdrahn      char * litP;
875d2201f2fSdrahn      int *  sizeP;
876d2201f2fSdrahn {
877d2201f2fSdrahn   int prec;
878d2201f2fSdrahn   LITTLENUM_TYPE words[MAX_LITTLENUMS];
879d2201f2fSdrahn   LITTLENUM_TYPE *wordP;
880d2201f2fSdrahn   char *t;
881d2201f2fSdrahn 
882d2201f2fSdrahn   switch (type)
883d2201f2fSdrahn     {
884d2201f2fSdrahn     case 'f':
885d2201f2fSdrahn     case 'F':
886d2201f2fSdrahn     case 's':
887d2201f2fSdrahn     case 'S':
888d2201f2fSdrahn       prec = 2;
889d2201f2fSdrahn       break;
890d2201f2fSdrahn 
891d2201f2fSdrahn     case 'd':
892d2201f2fSdrahn     case 'D':
893d2201f2fSdrahn     case 'r':
894d2201f2fSdrahn     case 'R':
895d2201f2fSdrahn       prec = 4;
896d2201f2fSdrahn       break;
897d2201f2fSdrahn 
898d2201f2fSdrahn     case 'x':
899d2201f2fSdrahn     case 'X':
900d2201f2fSdrahn       prec = 6;
901d2201f2fSdrahn       break;
902d2201f2fSdrahn 
903d2201f2fSdrahn     case 'p':
904d2201f2fSdrahn     case 'P':
905d2201f2fSdrahn       prec = 6;
906d2201f2fSdrahn       break;
907d2201f2fSdrahn 
908d2201f2fSdrahn     default:
909d2201f2fSdrahn       *sizeP = 0;
910d2201f2fSdrahn       return _("Bad call to MD_ATOF()");
911d2201f2fSdrahn     }
912d2201f2fSdrahn 
913d2201f2fSdrahn   t = atof_ieee (input_line_pointer, type, words);
914d2201f2fSdrahn   if (t)
915d2201f2fSdrahn     input_line_pointer = t;
916d2201f2fSdrahn 
917d2201f2fSdrahn   *sizeP = prec * sizeof (LITTLENUM_TYPE);
918d2201f2fSdrahn 
919d2201f2fSdrahn   for (wordP = words; prec--;)
920d2201f2fSdrahn     {
921d2201f2fSdrahn       md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE));
922d2201f2fSdrahn       litP += sizeof (LITTLENUM_TYPE);
923d2201f2fSdrahn     }
924d2201f2fSdrahn 
925d2201f2fSdrahn   return NULL;
926d2201f2fSdrahn }
927d2201f2fSdrahn 
928d2201f2fSdrahn /* Write out big-endian.  */
929d2201f2fSdrahn 
930d2201f2fSdrahn void
md_number_to_chars(buf,val,n)931d2201f2fSdrahn md_number_to_chars (buf, val, n)
932d2201f2fSdrahn      char *buf;
933d2201f2fSdrahn      valueT val;
934d2201f2fSdrahn      int n;
935d2201f2fSdrahn {
936d2201f2fSdrahn   number_to_chars_bigendian (buf, val, n);
937d2201f2fSdrahn }
938d2201f2fSdrahn 
939d2201f2fSdrahn #ifdef BFD_ASSEMBLER
940d2201f2fSdrahn void
md_apply_fix3(fixP,val,seg)941d2201f2fSdrahn md_apply_fix3 (fixP, val, seg)
942d2201f2fSdrahn      fixS *   fixP;
943d2201f2fSdrahn      valueT * val;
944d2201f2fSdrahn      segT     seg ATTRIBUTE_UNUSED;
945d2201f2fSdrahn {
946d2201f2fSdrahn   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
947d2201f2fSdrahn   long t_val;
948d2201f2fSdrahn 
949d2201f2fSdrahn   t_val = (long) *val;
950d2201f2fSdrahn 
951d2201f2fSdrahn #if DEBUG
952d2201f2fSdrahn   printf ("md_apply_fix val:%x\n", t_val);
953d2201f2fSdrahn #endif
954d2201f2fSdrahn 
955d2201f2fSdrahn   fixP->fx_addnumber = t_val; /* Remember value for emit_reloc.  */
956d2201f2fSdrahn 
957d2201f2fSdrahn   know (fixP->fx_size == 4);
958d2201f2fSdrahn   know (fixP->fx_r_type < BFD_RELOC_NONE);
959d2201f2fSdrahn 
960d2201f2fSdrahn   switch (fixP->fx_r_type)
961d2201f2fSdrahn     {
962d2201f2fSdrahn     case BFD_RELOC_32:      /* XXXXXXXX pattern in a word.  */
963d2201f2fSdrahn #if DEBUG
964d2201f2fSdrahn       printf ("reloc_const: val=%x\n", t_val);
965d2201f2fSdrahn #endif
966d2201f2fSdrahn       buf[0] = t_val >> 24;
967d2201f2fSdrahn       buf[1] = t_val >> 16;
968d2201f2fSdrahn       buf[2] = t_val >> 8;
969d2201f2fSdrahn       buf[3] = t_val;
970d2201f2fSdrahn       break;
971d2201f2fSdrahn 
972d2201f2fSdrahn     case BFD_RELOC_16:      /* XXXX0000 pattern in a word.  */
973d2201f2fSdrahn #if DEBUG
974d2201f2fSdrahn       printf ("reloc_const: val=%x\n", t_val);
975d2201f2fSdrahn #endif
976d2201f2fSdrahn       buf[0] = t_val >> 8;
977d2201f2fSdrahn       buf[1] = t_val;
978d2201f2fSdrahn       break;
979d2201f2fSdrahn 
980d2201f2fSdrahn     case BFD_RELOC_8:      /* XX000000 pattern in a word.  */
981d2201f2fSdrahn #if DEBUG
982d2201f2fSdrahn       printf ("reloc_const: val=%x\n", t_val);
983d2201f2fSdrahn #endif
984d2201f2fSdrahn       buf[0] = t_val;
985d2201f2fSdrahn       break;
986d2201f2fSdrahn 
987d2201f2fSdrahn     case BFD_RELOC_LO16:      /* 0000XXXX pattern in a word.  */
988d2201f2fSdrahn #if DEBUG
989d2201f2fSdrahn       printf ("reloc_const: val=%x\n", t_val);
990d2201f2fSdrahn #endif
991d2201f2fSdrahn       buf[2] = t_val >> 8;  /* Holds bits 0000XXXX.  */
992d2201f2fSdrahn       buf[3] = t_val;
993d2201f2fSdrahn       break;
994d2201f2fSdrahn 
995d2201f2fSdrahn     case BFD_RELOC_HI16:    /* 0000XXXX pattern in a word.  */
996d2201f2fSdrahn #if DEBUG
997d2201f2fSdrahn       printf ("reloc_consth: val=%x\n", t_val);
998d2201f2fSdrahn #endif
999d2201f2fSdrahn       buf[2] = t_val >> 24; /* Holds bits XXXX0000.  */
1000d2201f2fSdrahn       buf[3] = t_val >> 16;
1001d2201f2fSdrahn       break;
1002d2201f2fSdrahn 
1003d2201f2fSdrahn     case BFD_RELOC_32_GOT_PCREL:  /* 0000XXXX pattern in a word.  */
1004d2201f2fSdrahn       if (!fixP->fx_done)
1005d2201f2fSdrahn         {
1006d2201f2fSdrahn           /* The linker tries to support both AMD and old GNU style
1007d2201f2fSdrahn              R_IREL relocs.  That means that if the addend is exactly
1008d2201f2fSdrahn              the negative of the address within the section, the
1009d2201f2fSdrahn              linker will not handle it correctly.  */
1010d2201f2fSdrahn #if 0
1011d2201f2fSdrahn           if (fixP->fx_pcrel
1012d2201f2fSdrahn               && t_val != 0
1013d2201f2fSdrahn               && t_val == - (fixP->fx_frag->fr_address + fixP->fx_where))
1014d2201f2fSdrahn             as_bad_where
1015d2201f2fSdrahn               (fixP->fx_file, fixP->fx_line,
1016d2201f2fSdrahn                _("the linker will not handle this relocation correctly (1)"));
1017d2201f2fSdrahn #endif
1018d2201f2fSdrahn         }
1019d2201f2fSdrahn       else if (fixP->fx_pcrel)
1020d2201f2fSdrahn         {
1021d2201f2fSdrahn           long v = t_val >> 28;
1022d2201f2fSdrahn 
1023d2201f2fSdrahn           if (v != 0 && v != -1)
1024d2201f2fSdrahn             as_bad_where (fixP->fx_file, fixP->fx_line,
1025d2201f2fSdrahn                           _("call/jmp target out of range (2)"));
1026d2201f2fSdrahn         }
1027d2201f2fSdrahn       else
1028d2201f2fSdrahn         /* This case was supposed to be handled in machine_ip.  */
1029d2201f2fSdrahn         abort ();
1030d2201f2fSdrahn 
1031d2201f2fSdrahn       buf[0] |= (t_val >> 26) & 0x03; /* Holds bits 0FFFFFFC of address.  */
1032d2201f2fSdrahn       buf[1] = t_val >> 18;
1033d2201f2fSdrahn       buf[2] = t_val >> 10;
1034d2201f2fSdrahn       buf[3] = t_val >> 2;
1035d2201f2fSdrahn       break;
1036d2201f2fSdrahn 
1037d2201f2fSdrahn     case BFD_RELOC_VTABLE_INHERIT:
1038d2201f2fSdrahn     case BFD_RELOC_VTABLE_ENTRY:
1039d2201f2fSdrahn       fixP->fx_done = 0;
1040d2201f2fSdrahn       break;
1041d2201f2fSdrahn 
1042d2201f2fSdrahn     case BFD_RELOC_NONE:
1043d2201f2fSdrahn     default:
1044d2201f2fSdrahn       as_bad (_("bad relocation type: 0x%02x"), fixP->fx_r_type);
1045d2201f2fSdrahn       break;
1046d2201f2fSdrahn     }
1047d2201f2fSdrahn 
1048d2201f2fSdrahn   if (fixP->fx_addsy == (symbolS *) NULL)
1049d2201f2fSdrahn     fixP->fx_done = 1;
1050d2201f2fSdrahn }
1051d2201f2fSdrahn #else
1052d2201f2fSdrahn void
md_apply_fix3(fixP,valP,seg)1053d2201f2fSdrahn md_apply_fix3 (fixP, valP, seg)
1054d2201f2fSdrahn      fixS *fixP;
1055d2201f2fSdrahn      valueT *valP;
1056d2201f2fSdrahn      segT seg ATTRIBUTE_UNUSED;
1057d2201f2fSdrahn {
1058d2201f2fSdrahn   long val = *valP;
1059d2201f2fSdrahn   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
1060d2201f2fSdrahn 
1061d2201f2fSdrahn #if DEBUG
1062d2201f2fSdrahn   printf ("md_apply_fix val:%x\n", val);
1063d2201f2fSdrahn #endif
1064d2201f2fSdrahn 
1065d2201f2fSdrahn   fixP->fx_addnumber = val; /* Remember value for emit_reloc.  */
1066d2201f2fSdrahn 
1067d2201f2fSdrahn   know (fixP->fx_size == 4);
1068d2201f2fSdrahn   know (fixP->fx_r_type < NO_RELOC);
1069d2201f2fSdrahn 
1070d2201f2fSdrahn   /* This is a hack.  There should be a better way to handle this.  */
1071d2201f2fSdrahn   if (fixP->fx_r_type == RELOC_WDISP30 && fixP->fx_addsy)
1072d2201f2fSdrahn     val += fixP->fx_where + fixP->fx_frag->fr_address;
1073d2201f2fSdrahn 
1074d2201f2fSdrahn   switch (fixP->fx_r_type)
1075d2201f2fSdrahn     {
1076d2201f2fSdrahn     case RELOC_32:
1077d2201f2fSdrahn       buf[0] = val >> 24;
1078d2201f2fSdrahn       buf[1] = val >> 16;
1079d2201f2fSdrahn       buf[2] = val >> 8;
1080d2201f2fSdrahn       buf[3] = val;
1081d2201f2fSdrahn       break;
1082d2201f2fSdrahn 
1083d2201f2fSdrahn     case RELOC_8:
1084d2201f2fSdrahn       buf[0] = val;
1085d2201f2fSdrahn       break;
1086d2201f2fSdrahn 
1087d2201f2fSdrahn     case RELOC_WDISP30:
1088d2201f2fSdrahn       val = (val >> 2) + 1;
1089d2201f2fSdrahn       buf[0] |= (val >> 24) & 0x3f;
1090d2201f2fSdrahn       buf[1] = (val >> 16);
1091d2201f2fSdrahn       buf[2] = val >> 8;
1092d2201f2fSdrahn       buf[3] = val;
1093d2201f2fSdrahn       break;
1094d2201f2fSdrahn 
1095d2201f2fSdrahn     case RELOC_HI22:
1096d2201f2fSdrahn       buf[1] |= (val >> 26) & 0x3f;
1097d2201f2fSdrahn       buf[2] = val >> 18;
1098d2201f2fSdrahn       buf[3] = val >> 10;
1099d2201f2fSdrahn       break;
1100d2201f2fSdrahn 
1101d2201f2fSdrahn     case RELOC_LO10:
1102d2201f2fSdrahn       buf[2] |= (val >> 8) & 0x03;
1103d2201f2fSdrahn       buf[3] = val;
1104d2201f2fSdrahn       break;
1105d2201f2fSdrahn 
1106d2201f2fSdrahn     case RELOC_BASE13:
1107d2201f2fSdrahn       buf[2] |= (val >> 8) & 0x1f;
1108d2201f2fSdrahn       buf[3] = val;
1109d2201f2fSdrahn       break;
1110d2201f2fSdrahn 
1111d2201f2fSdrahn     case RELOC_WDISP22:
1112d2201f2fSdrahn       val = (val >> 2) + 1;
1113d2201f2fSdrahn       /* FALLTHROUGH */
1114d2201f2fSdrahn     case RELOC_BASE22:
1115d2201f2fSdrahn       buf[1] |= (val >> 16) & 0x3f;
1116d2201f2fSdrahn       buf[2] = val >> 8;
1117d2201f2fSdrahn       buf[3] = val;
1118d2201f2fSdrahn       break;
1119d2201f2fSdrahn 
1120d2201f2fSdrahn     case RELOC_JUMPTARG:  /* 0000XXXX pattern in a word.  */
1121d2201f2fSdrahn       if (!fixP->fx_done)
1122d2201f2fSdrahn         {
1123d2201f2fSdrahn           /* The linker tries to support both AMD and old GNU style
1124d2201f2fSdrahn              R_IREL relocs.  That means that if the addend is exactly
1125d2201f2fSdrahn              the negative of the address within the section, the
1126d2201f2fSdrahn              linker will not handle it correctly.  */
1127d2201f2fSdrahn #if 0
1128d2201f2fSdrahn           if (fixP->fx_pcrel
1129d2201f2fSdrahn               && val != 0
1130d2201f2fSdrahn               && val == - (fixP->fx_frag->fr_address + fixP->fx_where))
1131d2201f2fSdrahn             as_bad_where
1132d2201f2fSdrahn               (fixP->fx_file, fixP->fx_line,
1133d2201f2fSdrahn                _("the linker will not handle this relocation correctly (1)"));
1134d2201f2fSdrahn #endif
1135d2201f2fSdrahn         }
1136d2201f2fSdrahn       else if (fixP->fx_pcrel)
1137d2201f2fSdrahn         {
1138d2201f2fSdrahn           long v = val >> 28;
1139d2201f2fSdrahn #if 1
1140d2201f2fSdrahn           if (v != 0 && v != -1)
1141d2201f2fSdrahn             as_bad_where (fixP->fx_file, fixP->fx_line,
1142d2201f2fSdrahn                           _("call/jmp target out of range (2)"));
1143d2201f2fSdrahn #endif
1144d2201f2fSdrahn         }
1145d2201f2fSdrahn       else
1146d2201f2fSdrahn         /* This case was supposed to be handled in machine_ip.  */
1147d2201f2fSdrahn         abort ();
1148d2201f2fSdrahn 
1149d2201f2fSdrahn       buf[0] |= (val >> 26) & 0x03; /* Holds bits 0FFFFFFC of address.  */
1150d2201f2fSdrahn       buf[1] = val >> 18;
1151d2201f2fSdrahn       buf[2] = val >> 10;
1152d2201f2fSdrahn       buf[3] = val >> 2;
1153d2201f2fSdrahn       break;
1154d2201f2fSdrahn 
1155d2201f2fSdrahn     case RELOC_CONST:     /* 0000XXXX pattern in a word.  */
1156d2201f2fSdrahn #if DEBUG
1157d2201f2fSdrahn       printf ("reloc_const: val=%x\n", val);
1158d2201f2fSdrahn #endif
1159d2201f2fSdrahn       buf[2] = val >> 8;  /* Holds bits 0000XXXX.  */
1160d2201f2fSdrahn       buf[3] = val;
1161d2201f2fSdrahn       break;
1162d2201f2fSdrahn 
1163d2201f2fSdrahn     case RELOC_CONSTH:    /* 0000XXXX pattern in a word.  */
1164d2201f2fSdrahn #if DEBUG
1165d2201f2fSdrahn       printf ("reloc_consth: val=%x\n", val);
1166d2201f2fSdrahn #endif
1167d2201f2fSdrahn       buf[2] = val >> 24; /* Holds bits XXXX0000.  */
1168d2201f2fSdrahn       buf[3] = val >> 16;
1169d2201f2fSdrahn       break;
1170d2201f2fSdrahn 
1171d2201f2fSdrahn     case BFD_RELOC_VTABLE_INHERIT:
1172d2201f2fSdrahn     case BFD_RELOC_VTABLE_ENTRY:
1173d2201f2fSdrahn       fixP->fx_done = 0;
1174d2201f2fSdrahn       break;
1175d2201f2fSdrahn 
1176d2201f2fSdrahn     case NO_RELOC:
1177d2201f2fSdrahn     default:
1178d2201f2fSdrahn       as_bad (_("bad relocation type: 0x%02x"), fixP->fx_r_type);
1179d2201f2fSdrahn       break;
1180d2201f2fSdrahn     }
1181d2201f2fSdrahn 
1182d2201f2fSdrahn   if (fixP->fx_addsy == (symbolS *) NULL)
1183d2201f2fSdrahn     fixP->fx_done = 1;
1184d2201f2fSdrahn }
1185d2201f2fSdrahn #endif
1186d2201f2fSdrahn 
1187d2201f2fSdrahn #ifdef OBJ_COFF
1188d2201f2fSdrahn short
tc_coff_fix2rtype(fixP)1189d2201f2fSdrahn tc_coff_fix2rtype (fixP)
1190d2201f2fSdrahn      fixS *fixP;
1191d2201f2fSdrahn {
1192d2201f2fSdrahn #if DEBUG
1193d2201f2fSdrahn   printf ("tc_coff_fix2rtype\n");
1194d2201f2fSdrahn #endif
1195d2201f2fSdrahn 
1196d2201f2fSdrahn   switch (fixP->fx_r_type)
1197d2201f2fSdrahn     {
1198d2201f2fSdrahn     case RELOC_32:
1199d2201f2fSdrahn       return (R_WORD);
1200d2201f2fSdrahn     case RELOC_8:
1201d2201f2fSdrahn       return (R_BYTE);
1202d2201f2fSdrahn     case RELOC_CONST:
1203d2201f2fSdrahn       return (R_ILOHALF);
1204d2201f2fSdrahn     case RELOC_CONSTH:
1205d2201f2fSdrahn       return (R_IHIHALF);
1206d2201f2fSdrahn     case RELOC_JUMPTARG:
1207d2201f2fSdrahn       return (R_IREL);
1208d2201f2fSdrahn     default:
1209d2201f2fSdrahn       printf ("need %d\n", fixP->fx_r_type);
1210d2201f2fSdrahn       abort ();
1211d2201f2fSdrahn     }
1212d2201f2fSdrahn 
1213d2201f2fSdrahn   return 0;
1214d2201f2fSdrahn }
1215d2201f2fSdrahn 
1216d2201f2fSdrahn #endif /* OBJ_COFF */
1217d2201f2fSdrahn 
1218d2201f2fSdrahn /* Should never be called for or32.  */
1219d2201f2fSdrahn 
1220d2201f2fSdrahn void
md_create_short_jump(ptr,from_addr,to_addr,frag,to_symbol)1221d2201f2fSdrahn md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
1222d2201f2fSdrahn      char *    ptr       ATTRIBUTE_UNUSED;
1223d2201f2fSdrahn      addressT  from_addr ATTRIBUTE_UNUSED;
1224d2201f2fSdrahn      addressT  to_addr   ATTRIBUTE_UNUSED;
1225d2201f2fSdrahn      fragS *   frag      ATTRIBUTE_UNUSED;
1226d2201f2fSdrahn      symbolS * to_symbol ATTRIBUTE_UNUSED;
1227d2201f2fSdrahn {
1228d2201f2fSdrahn   as_fatal ("or32_create_short_jmp\n");
1229d2201f2fSdrahn }
1230d2201f2fSdrahn 
1231d2201f2fSdrahn /* Should never be called for or32.  */
1232d2201f2fSdrahn 
1233d2201f2fSdrahn #ifndef BFD_ASSEMBLER
1234d2201f2fSdrahn void
md_convert_frag(headers,seg,fragP)1235d2201f2fSdrahn md_convert_frag (headers, seg, fragP)
1236d2201f2fSdrahn      object_headers * headers ATTRIBUTE_UNUSED;
1237d2201f2fSdrahn      segT             seg     ATTRIBUTE_UNUSED;
1238d2201f2fSdrahn      register fragS * fragP   ATTRIBUTE_UNUSED;
1239d2201f2fSdrahn {
1240d2201f2fSdrahn   as_fatal ("or32_convert_frag\n");
1241d2201f2fSdrahn }
1242d2201f2fSdrahn 
1243d2201f2fSdrahn #else
1244d2201f2fSdrahn void
md_convert_frag(headers,seg,fragP)1245d2201f2fSdrahn md_convert_frag (headers, seg, fragP)
1246d2201f2fSdrahn      bfd *   headers ATTRIBUTE_UNUSED;
1247d2201f2fSdrahn      segT    seg     ATTRIBUTE_UNUSED;
1248d2201f2fSdrahn      fragS * fragP   ATTRIBUTE_UNUSED;
1249d2201f2fSdrahn {
1250d2201f2fSdrahn   as_fatal ("or32_convert_frag\n");
1251d2201f2fSdrahn }
1252d2201f2fSdrahn #endif
1253d2201f2fSdrahn 
1254d2201f2fSdrahn /* Should never be called for or32.  */
1255d2201f2fSdrahn 
1256d2201f2fSdrahn void
md_create_long_jump(ptr,from_addr,to_addr,frag,to_symbol)1257d2201f2fSdrahn md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
1258d2201f2fSdrahn      char *    ptr       ATTRIBUTE_UNUSED;
1259d2201f2fSdrahn      addressT  from_addr ATTRIBUTE_UNUSED;
1260d2201f2fSdrahn      addressT  to_addr   ATTRIBUTE_UNUSED;
1261d2201f2fSdrahn      fragS *   frag      ATTRIBUTE_UNUSED;
1262d2201f2fSdrahn      symbolS * to_symbol ATTRIBUTE_UNUSED;
1263d2201f2fSdrahn {
1264d2201f2fSdrahn   as_fatal ("or32_create_long_jump\n");
1265d2201f2fSdrahn }
1266d2201f2fSdrahn 
1267d2201f2fSdrahn /* Should never be called for or32.  */
1268d2201f2fSdrahn 
1269d2201f2fSdrahn int
md_estimate_size_before_relax(fragP,segtype)1270d2201f2fSdrahn md_estimate_size_before_relax (fragP, segtype)
1271d2201f2fSdrahn      fragS * fragP   ATTRIBUTE_UNUSED;
1272d2201f2fSdrahn      segT    segtype ATTRIBUTE_UNUSED;
1273d2201f2fSdrahn {
1274d2201f2fSdrahn   as_fatal ("or32_estimate_size_before_relax\n");
1275d2201f2fSdrahn   return 0;
1276d2201f2fSdrahn }
1277d2201f2fSdrahn 
1278d2201f2fSdrahn /* Translate internal representation of relocation info to target format.
1279d2201f2fSdrahn 
1280d2201f2fSdrahn    On sparc/29k: first 4 bytes are normal unsigned long address, next three
1281d2201f2fSdrahn    bytes are index, most sig. byte first.  Byte 7 is broken up with
1282d2201f2fSdrahn    bit 7 as external, bits 6 & 5 unused, and the lower
1283d2201f2fSdrahn    five bits as relocation type.  Next 4 bytes are long addend.  */
1284d2201f2fSdrahn /* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com.  */
1285d2201f2fSdrahn 
1286d2201f2fSdrahn #ifdef OBJ_AOUT
1287d2201f2fSdrahn void
tc_aout_fix_to_chars(where,fixP,segment_address_in_file)1288d2201f2fSdrahn tc_aout_fix_to_chars (where, fixP, segment_address_in_file)
1289d2201f2fSdrahn      char *where;
1290d2201f2fSdrahn      fixS *fixP;
1291d2201f2fSdrahn      relax_addressT segment_address_in_file;
1292d2201f2fSdrahn {
1293d2201f2fSdrahn   long r_symbolnum;
1294d2201f2fSdrahn 
1295d2201f2fSdrahn #if DEBUG
1296d2201f2fSdrahn   printf ("tc_aout_fix_to_chars\n");
1297d2201f2fSdrahn #endif
1298d2201f2fSdrahn 
1299d2201f2fSdrahn   know (fixP->fx_r_type < BFD_RELOC_NONE);
1300d2201f2fSdrahn   know (fixP->fx_addsy != NULL);
1301d2201f2fSdrahn 
1302d2201f2fSdrahn   md_number_to_chars
1303d2201f2fSdrahn     (where,
1304d2201f2fSdrahn      fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file,
1305d2201f2fSdrahn      4);
1306d2201f2fSdrahn 
1307d2201f2fSdrahn   r_symbolnum = (S_IS_DEFINED (fixP->fx_addsy)
1308d2201f2fSdrahn      ? S_GET_TYPE (fixP->fx_addsy)
1309d2201f2fSdrahn      : fixP->fx_addsy->sy_number);
1310d2201f2fSdrahn 
1311d2201f2fSdrahn   where[4] = (r_symbolnum >> 16) & 0x0ff;
1312d2201f2fSdrahn   where[5] = (r_symbolnum >> 8) & 0x0ff;
1313d2201f2fSdrahn   where[6] = r_symbolnum & 0x0ff;
1314d2201f2fSdrahn   where[7] = (((!S_IS_DEFINED (fixP->fx_addsy)) << 7) & 0x80) | (0 & 0x60) | (fixP->fx_r_type & 0x1F);
1315d2201f2fSdrahn 
1316d2201f2fSdrahn   /* Also easy.  */
1317d2201f2fSdrahn   md_number_to_chars (&where[8], fixP->fx_addnumber, 4);
1318d2201f2fSdrahn }
1319d2201f2fSdrahn 
1320d2201f2fSdrahn #endif /* OBJ_AOUT */
1321d2201f2fSdrahn 
1322d2201f2fSdrahn const char *md_shortopts = "";
1323d2201f2fSdrahn 
1324d2201f2fSdrahn struct option md_longopts[] =
1325d2201f2fSdrahn   {
1326d2201f2fSdrahn     { NULL, no_argument, NULL, 0 }
1327d2201f2fSdrahn   };
1328d2201f2fSdrahn size_t md_longopts_size = sizeof (md_longopts);
1329d2201f2fSdrahn 
1330d2201f2fSdrahn int
md_parse_option(c,arg)1331d2201f2fSdrahn md_parse_option (c, arg)
1332d2201f2fSdrahn      int    c   ATTRIBUTE_UNUSED;
1333d2201f2fSdrahn      char * arg ATTRIBUTE_UNUSED;
1334d2201f2fSdrahn {
1335d2201f2fSdrahn   return 0;
1336d2201f2fSdrahn }
1337d2201f2fSdrahn 
1338d2201f2fSdrahn void
md_show_usage(stream)1339d2201f2fSdrahn md_show_usage (stream)
1340d2201f2fSdrahn      FILE * stream ATTRIBUTE_UNUSED;
1341d2201f2fSdrahn {
1342d2201f2fSdrahn }
1343d2201f2fSdrahn 
1344d2201f2fSdrahn /* This is called when a line is unrecognized.  This is used to handle
1345d2201f2fSdrahn    definitions of or32 style local labels.  */
1346d2201f2fSdrahn 
1347d2201f2fSdrahn int
or32_unrecognized_line(c)1348d2201f2fSdrahn or32_unrecognized_line (c)
1349d2201f2fSdrahn      int c;
1350d2201f2fSdrahn {
1351d2201f2fSdrahn   int lab;
1352d2201f2fSdrahn   char *s;
1353d2201f2fSdrahn 
1354d2201f2fSdrahn   if (c != '$'
1355d2201f2fSdrahn       || ! ISDIGIT ((unsigned char) input_line_pointer[0]))
1356d2201f2fSdrahn     return 0;
1357d2201f2fSdrahn 
1358d2201f2fSdrahn   s = input_line_pointer;
1359d2201f2fSdrahn 
1360d2201f2fSdrahn   lab = 0;
1361d2201f2fSdrahn   while (ISDIGIT ((unsigned char) *s))
1362d2201f2fSdrahn     {
1363d2201f2fSdrahn       lab = lab * 10 + *s - '0';
1364d2201f2fSdrahn       ++s;
1365d2201f2fSdrahn     }
1366d2201f2fSdrahn 
1367d2201f2fSdrahn   if (*s != ':')
1368d2201f2fSdrahn     /* Not a label definition.  */
1369d2201f2fSdrahn     return 0;
1370d2201f2fSdrahn 
1371d2201f2fSdrahn   if (dollar_label_defined (lab))
1372d2201f2fSdrahn     {
1373d2201f2fSdrahn       as_bad (_("label \"$%d\" redefined"), lab);
1374d2201f2fSdrahn       return 0;
1375d2201f2fSdrahn     }
1376d2201f2fSdrahn 
1377d2201f2fSdrahn   define_dollar_label (lab);
1378d2201f2fSdrahn   colon (dollar_label_name (lab, 0));
1379d2201f2fSdrahn   input_line_pointer = s + 1;
1380d2201f2fSdrahn 
1381d2201f2fSdrahn   return 1;
1382d2201f2fSdrahn }
1383d2201f2fSdrahn 
1384d2201f2fSdrahn #ifndef BFD_ASSEMBLER
1385d2201f2fSdrahn /* Record a fixup for a cons expression.  */
1386d2201f2fSdrahn /*
1387d2201f2fSdrahn   void
1388d2201f2fSdrahn or32_cons_fix_new (frag, where, nbytes, exp)
1389d2201f2fSdrahn      fragS *frag;
1390d2201f2fSdrahn      int where;
1391d2201f2fSdrahn      int nbytes;
1392d2201f2fSdrahn      expressionS *exp;
1393d2201f2fSdrahn {
1394d2201f2fSdrahn   fix_new_exp (frag, where, nbytes, exp, 0,
1395d2201f2fSdrahn 		   nbytes == 5 ? RELOC_32
1396d2201f2fSdrahn                    : nbytes == 2 ? RELOC_16
1397d2201f2fSdrahn 		   : RELOC_8);
1398d2201f2fSdrahn }
1399d2201f2fSdrahn void
1400d2201f2fSdrahn tc_aout_pre_write_hook ()
1401d2201f2fSdrahn {
1402d2201f2fSdrahn #if DEBUG
1403d2201f2fSdrahn   printf ("In tc_aout_pre_write_hook()\n");
1404d2201f2fSdrahn #endif
1405d2201f2fSdrahn }
1406d2201f2fSdrahn */
1407d2201f2fSdrahn #endif
1408d2201f2fSdrahn 
1409d2201f2fSdrahn /* Default the values of symbols known that should be "predefined".  We
1410d2201f2fSdrahn    don't bother to predefine them unless you actually use one, since there
1411d2201f2fSdrahn    are a lot of them.  */
1412d2201f2fSdrahn 
1413d2201f2fSdrahn symbolS *
md_undefined_symbol(name)1414d2201f2fSdrahn md_undefined_symbol (name)
1415d2201f2fSdrahn      char *name ATTRIBUTE_UNUSED;
1416d2201f2fSdrahn {
1417d2201f2fSdrahn #ifndef BFD_ASSEMBLER
1418d2201f2fSdrahn   long regnum;
1419d2201f2fSdrahn   char testbuf[5 + /*SLOP*/ 5];
1420d2201f2fSdrahn 
1421d2201f2fSdrahn #if DEBUG
1422d2201f2fSdrahn   printf ("md_undefined_symbol(%s)\n", name);
1423d2201f2fSdrahn #endif
1424d2201f2fSdrahn 
1425d2201f2fSdrahn   /* Register name.  */
1426d2201f2fSdrahn   if (name[0] == 'r' || name[0] == 'R' || name[0] == 'a' || name[0] == 'b')
1427d2201f2fSdrahn     {
1428d2201f2fSdrahn       /* Parse the number, make sure it has no extra zeroes or
1429d2201f2fSdrahn          trailing chars.  */
1430d2201f2fSdrahn       regnum = atol (& name[1]);
1431d2201f2fSdrahn 
1432d2201f2fSdrahn       if (regnum > 31)
1433d2201f2fSdrahn         as_fatal (_("register out of range"));
1434d2201f2fSdrahn 
1435d2201f2fSdrahn       sprintf (testbuf, "%ld", regnum);
1436d2201f2fSdrahn 
1437d2201f2fSdrahn       if (strcmp (testbuf, &name[1]) != 0)
1438d2201f2fSdrahn         return NULL;  /* gr007 or lr7foo or whatever.  */
1439d2201f2fSdrahn 
1440d2201f2fSdrahn       /* We have a wiener!  Define and return a new symbol for it.  */
1441d2201f2fSdrahn       return (symbol_new (name, SEG_REGISTER, (valueT) regnum,
1442d2201f2fSdrahn                           &zero_address_frag));
1443d2201f2fSdrahn     }
1444d2201f2fSdrahn #endif
1445d2201f2fSdrahn   return NULL;
1446d2201f2fSdrahn }
1447d2201f2fSdrahn 
1448d2201f2fSdrahn /* Parse an operand that is machine-specific.  */
1449d2201f2fSdrahn 
1450d2201f2fSdrahn void
md_operand(expressionP)1451d2201f2fSdrahn md_operand (expressionP)
1452d2201f2fSdrahn      expressionS *expressionP;
1453d2201f2fSdrahn {
1454d2201f2fSdrahn #if DEBUG
1455d2201f2fSdrahn   printf ("  md_operand(input_line_pointer = %s)\n", input_line_pointer);
1456d2201f2fSdrahn #endif
1457d2201f2fSdrahn 
1458d2201f2fSdrahn   if (input_line_pointer[0] == REGISTER_PREFIX && input_line_pointer[1] == 'r')
1459d2201f2fSdrahn     {
1460d2201f2fSdrahn       /* We have a numeric register expression.  No biggy.  */
1461d2201f2fSdrahn       input_line_pointer += 2;  /* Skip %r */
1462d2201f2fSdrahn       (void) expression (expressionP);
1463d2201f2fSdrahn 
1464d2201f2fSdrahn       if (expressionP->X_op != O_constant
1465d2201f2fSdrahn           || expressionP->X_add_number > 255)
1466d2201f2fSdrahn         as_bad (_("Invalid expression after %%%%\n"));
1467d2201f2fSdrahn       expressionP->X_op = O_register;
1468d2201f2fSdrahn     }
1469d2201f2fSdrahn   else if (input_line_pointer[0] == '&')
1470d2201f2fSdrahn     {
1471d2201f2fSdrahn       /* We are taking the 'address' of a register...this one is not
1472d2201f2fSdrahn          in the manual, but it *is* in traps/fpsymbol.h!  What they
1473d2201f2fSdrahn          seem to want is the register number, as an absolute number.  */
1474d2201f2fSdrahn       input_line_pointer++; /* Skip & */
1475d2201f2fSdrahn       (void) expression (expressionP);
1476d2201f2fSdrahn 
1477d2201f2fSdrahn       if (expressionP->X_op != O_register)
1478d2201f2fSdrahn         as_bad (_("invalid register in & expression"));
1479d2201f2fSdrahn       else
1480d2201f2fSdrahn         expressionP->X_op = O_constant;
1481d2201f2fSdrahn     }
1482d2201f2fSdrahn   else if (input_line_pointer[0] == '$'
1483d2201f2fSdrahn            && ISDIGIT ((unsigned char) input_line_pointer[1]))
1484d2201f2fSdrahn     {
1485d2201f2fSdrahn       long lab;
1486d2201f2fSdrahn       char *name;
1487d2201f2fSdrahn       symbolS *sym;
1488d2201f2fSdrahn 
1489d2201f2fSdrahn       /* This is a local label.  */
1490d2201f2fSdrahn       ++input_line_pointer;
1491d2201f2fSdrahn       lab = (long) get_absolute_expression ();
1492d2201f2fSdrahn 
1493d2201f2fSdrahn       if (dollar_label_defined (lab))
1494d2201f2fSdrahn         {
1495d2201f2fSdrahn           name = dollar_label_name (lab, 0);
1496d2201f2fSdrahn           sym = symbol_find (name);
1497d2201f2fSdrahn         }
1498d2201f2fSdrahn       else
1499d2201f2fSdrahn         {
1500d2201f2fSdrahn           name = dollar_label_name (lab, 1);
1501d2201f2fSdrahn           sym = symbol_find_or_make (name);
1502d2201f2fSdrahn         }
1503d2201f2fSdrahn 
1504d2201f2fSdrahn       expressionP->X_op = O_symbol;
1505d2201f2fSdrahn       expressionP->X_add_symbol = sym;
1506d2201f2fSdrahn       expressionP->X_add_number = 0;
1507d2201f2fSdrahn     }
1508d2201f2fSdrahn   else if (input_line_pointer[0] == '$')
1509d2201f2fSdrahn     {
1510d2201f2fSdrahn       char *s;
1511d2201f2fSdrahn       char type;
1512d2201f2fSdrahn       int fieldnum, fieldlimit;
1513d2201f2fSdrahn       LITTLENUM_TYPE floatbuf[8];
1514d2201f2fSdrahn 
1515d2201f2fSdrahn       /* $float(), $doubleN(), or $extendN() convert floating values
1516d2201f2fSdrahn          to integers.  */
1517d2201f2fSdrahn       s = input_line_pointer;
1518d2201f2fSdrahn 
1519d2201f2fSdrahn       ++s;
1520d2201f2fSdrahn 
1521d2201f2fSdrahn       fieldnum = 0;
1522d2201f2fSdrahn       if (strncmp (s, "double", sizeof "double" - 1) == 0)
1523d2201f2fSdrahn         {
1524d2201f2fSdrahn           s += sizeof "double" - 1;
1525d2201f2fSdrahn           type = 'd';
1526d2201f2fSdrahn           fieldlimit = 2;
1527d2201f2fSdrahn         }
1528d2201f2fSdrahn       else if (strncmp (s, "float", sizeof "float" - 1) == 0)
1529d2201f2fSdrahn         {
1530d2201f2fSdrahn           s += sizeof "float" - 1;
1531d2201f2fSdrahn           type = 'f';
1532d2201f2fSdrahn           fieldlimit = 1;
1533d2201f2fSdrahn         }
1534d2201f2fSdrahn       else if (strncmp (s, "extend", sizeof "extend" - 1) == 0)
1535d2201f2fSdrahn         {
1536d2201f2fSdrahn           s += sizeof "extend" - 1;
1537d2201f2fSdrahn           type = 'x';
1538d2201f2fSdrahn           fieldlimit = 4;
1539d2201f2fSdrahn         }
1540d2201f2fSdrahn       else
1541d2201f2fSdrahn 	return;
1542d2201f2fSdrahn 
1543d2201f2fSdrahn       if (ISDIGIT (*s))
1544d2201f2fSdrahn         {
1545d2201f2fSdrahn           fieldnum = *s - '0';
1546d2201f2fSdrahn           ++s;
1547d2201f2fSdrahn         }
1548d2201f2fSdrahn       if (fieldnum >= fieldlimit)
1549d2201f2fSdrahn         return;
1550d2201f2fSdrahn 
1551d2201f2fSdrahn       SKIP_WHITESPACE ();
1552d2201f2fSdrahn       if (*s != '(')
1553d2201f2fSdrahn         return;
1554d2201f2fSdrahn       ++s;
1555d2201f2fSdrahn       SKIP_WHITESPACE ();
1556d2201f2fSdrahn 
1557d2201f2fSdrahn       s = atof_ieee (s, type, floatbuf);
1558d2201f2fSdrahn       if (s == NULL)
1559d2201f2fSdrahn         return;
1560d2201f2fSdrahn       s = s;
1561d2201f2fSdrahn 
1562d2201f2fSdrahn       SKIP_WHITESPACE ();
1563d2201f2fSdrahn       if (*s != ')')
1564d2201f2fSdrahn         return;
1565d2201f2fSdrahn       ++s;
1566d2201f2fSdrahn       SKIP_WHITESPACE ();
1567d2201f2fSdrahn 
1568d2201f2fSdrahn       input_line_pointer = s;
1569d2201f2fSdrahn       expressionP->X_op = O_constant;
1570d2201f2fSdrahn       expressionP->X_unsigned = 1;
1571d2201f2fSdrahn       expressionP->X_add_number = ((floatbuf[fieldnum * 2]
1572d2201f2fSdrahn                                     << LITTLENUM_NUMBER_OF_BITS)
1573d2201f2fSdrahn                                    + floatbuf[fieldnum * 2 + 1]);
1574d2201f2fSdrahn     }
1575d2201f2fSdrahn }
1576d2201f2fSdrahn 
1577d2201f2fSdrahn /* Round up a section size to the appropriate boundary.  */
1578d2201f2fSdrahn 
1579d2201f2fSdrahn valueT
md_section_align(segment,size)1580d2201f2fSdrahn md_section_align (segment, size)
1581d2201f2fSdrahn      segT segment ATTRIBUTE_UNUSED;
1582d2201f2fSdrahn      valueT size ATTRIBUTE_UNUSED;
1583d2201f2fSdrahn {
1584d2201f2fSdrahn   return size;      /* Byte alignment is fine.  */
1585d2201f2fSdrahn }
1586d2201f2fSdrahn 
1587d2201f2fSdrahn /* Exactly what point is a PC-relative offset relative TO?
1588d2201f2fSdrahn    On the 29000, they're relative to the address of the instruction,
1589d2201f2fSdrahn    which we have set up as the address of the fixup too.  */
1590d2201f2fSdrahn 
1591d2201f2fSdrahn long
md_pcrel_from(fixP)1592d2201f2fSdrahn md_pcrel_from (fixP)
1593d2201f2fSdrahn      fixS *fixP;
1594d2201f2fSdrahn {
1595d2201f2fSdrahn   return fixP->fx_where + fixP->fx_frag->fr_address;
1596d2201f2fSdrahn }
1597d2201f2fSdrahn 
1598d2201f2fSdrahn /* Generate a reloc for a fixup.  */
1599d2201f2fSdrahn 
1600d2201f2fSdrahn #ifdef BFD_ASSEMBLER
1601d2201f2fSdrahn arelent *
tc_gen_reloc(seg,fixp)1602d2201f2fSdrahn tc_gen_reloc (seg, fixp)
1603d2201f2fSdrahn      asection *seg ATTRIBUTE_UNUSED;
1604d2201f2fSdrahn      fixS *fixp;
1605d2201f2fSdrahn {
1606d2201f2fSdrahn   arelent *reloc;
1607d2201f2fSdrahn 
1608d2201f2fSdrahn   reloc = (arelent *) xmalloc (sizeof (arelent));
1609d2201f2fSdrahn   reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
1610d2201f2fSdrahn   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
1611d2201f2fSdrahn   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
1612d2201f2fSdrahn   /*  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where + fixp->fx_addnumber;*/
1613d2201f2fSdrahn   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
1614d2201f2fSdrahn 
1615d2201f2fSdrahn   if (reloc->howto == (reloc_howto_type *) NULL)
1616d2201f2fSdrahn     {
1617d2201f2fSdrahn       as_bad_where (fixp->fx_file, fixp->fx_line,
1618d2201f2fSdrahn 		    _("reloc %d not supported by object file format"),
1619d2201f2fSdrahn 		    (int) fixp->fx_r_type);
1620d2201f2fSdrahn       return NULL;
1621d2201f2fSdrahn     }
1622d2201f2fSdrahn 
1623d2201f2fSdrahn   if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
1624d2201f2fSdrahn     reloc->address = fixp->fx_offset;
1625d2201f2fSdrahn 
1626d2201f2fSdrahn   reloc->addend = fixp->fx_addnumber;
1627d2201f2fSdrahn   return reloc;
1628d2201f2fSdrahn }
1629d2201f2fSdrahn #endif
1630d2201f2fSdrahn 
1631