1 /* tc-microblaze.c -- Assemble code for Xilinx MicroBlaze
2 
3    Copyright (C) 2009-2024 Free Software Foundation, Inc.
4 
5    This file is part of GAS, the GNU Assembler.
6 
7    GAS is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3, or (at your option)
10    any later version.
11 
12    GAS is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with GAS; see the file COPYING.  If not, write to the Free
19    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
20    02110-1301, USA.  */
21 
22 #include "as.h"
23 #include <stdio.h>
24 #include "bfd.h"
25 #include "subsegs.h"
26 #define DEFINE_TABLE
27 #include "../opcodes/microblaze-opc.h"
28 #include "../opcodes/microblaze-opcm.h"
29 #include "safe-ctype.h"
30 #include <string.h>
31 #include <dwarf2dbg.h>
32 #include "aout/stab_gnu.h"
33 
34 #ifndef streq
35 #define streq(a,b) (strcmp (a, b) == 0)
36 #endif
37 
38 #define OPTION_EB (OPTION_MD_BASE + 0)
39 #define OPTION_EL (OPTION_MD_BASE + 1)
40 
41 void microblaze_generate_symbol (char *sym);
42 static bool check_spl_reg (unsigned *);
43 
44 /* Several places in this file insert raw instructions into the
45    object. They should generate the instruction
46    and then use these four macros to crack the instruction value into
47    the appropriate byte values.  */
48 #define   INST_BYTE0(x)  (target_big_endian ? (((x) >> 24) & 0xFF) : ((x) & 0xFF))
49 #define   INST_BYTE1(x)  (target_big_endian ? (((x) >> 16) & 0xFF) : (((x) >> 8) & 0xFF))
50 #define   INST_BYTE2(x)  (target_big_endian ? (((x) >> 8) & 0xFF) : (((x) >> 16) & 0xFF))
51 #define   INST_BYTE3(x)  (target_big_endian ? ((x) & 0xFF) : (((x) >> 24) & 0xFF))
52 
53 /* This array holds the chars that always start a comment.  If the
54    pre-processor is disabled, these aren't very useful.  */
55 const char comment_chars[] = "#";
56 
57 const char line_separator_chars[] = ";";
58 
59 /* This array holds the chars that only start a comment at the beginning of
60    a line.  */
61 const char line_comment_chars[] = "#";
62 
63 const int md_reloc_size = 8; /* Size of relocation record.  */
64 
65 /* Chars that can be used to separate mant
66    from exp in floating point numbers.  */
67 const char EXP_CHARS[] = "eE";
68 
69 /* Chars that mean this number is a floating point constant
70    As in 0f12.456
71    or    0d1.2345e12.  */
72 const char FLT_CHARS[] = "rRsSfFdDxXpP";
73 
74 /* INST_PC_OFFSET and INST_NO_OFFSET are 0 and 1.  */
75 #define UNDEFINED_PC_OFFSET  2
76 #define DEFINED_ABS_SEGMENT  3
77 #define DEFINED_PC_OFFSET    4
78 #define DEFINED_RO_SEGMENT   5
79 #define DEFINED_RW_SEGMENT   6
80 #define LARGE_DEFINED_PC_OFFSET 7
81 #define GOT_OFFSET           8
82 #define PLT_OFFSET           9
83 #define GOTOFF_OFFSET        10
84 #define TLSGD_OFFSET         11
85 #define TLSLD_OFFSET         12
86 #define TLSDTPMOD_OFFSET     13
87 #define TLSDTPREL_OFFSET     14
88 #define TLSGOTTPREL_OFFSET   15
89 #define TLSTPREL_OFFSET      16
90 #define TEXT_OFFSET      17
91 #define TEXT_PC_OFFSET       18
92 
93 /* Initialize the relax table.  */
94 const relax_typeS md_relax_table[] =
95 {
96   {          1,          1,                0, 0 },  /*  0: Unused.  */
97   {          1,          1,                0, 0 },  /*  1: Unused.  */
98   {          1,          1,                0, 0 },  /*  2: Unused.  */
99   {          1,          1,                0, 0 },  /*  3: Unused.  */
100   {      32767,   -32768, INST_WORD_SIZE, LARGE_DEFINED_PC_OFFSET }, /* 4: DEFINED_PC_OFFSET.  */
101   {    1,     1,       0, 0 },                      /*  5: Unused.  */
102   {    1,     1,       0, 0 },                      /*  6: Unused.  */
103   { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 },  /*  7: LARGE_DEFINED_PC_OFFSET.  */
104   { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 },  /*  8: GOT_OFFSET.  */
105   { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 },  /*  9: PLT_OFFSET.  */
106   { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 },  /* 10: GOTOFF_OFFSET.  */
107   { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 },  /* 11: TLSGD_OFFSET.  */
108   { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 },  /* 12: TLSLD_OFFSET.  */
109   { 0x7fffffff, 0x80000000, INST_WORD_SIZE*1, 0 },  /* 13: TLSDTPMOD_OFFSET.  */
110   { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 },  /* 14: TLSDTPREL_OFFSET.  */
111   { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 },  /* 15: TLSGOTTPREL_OFFSET.  */
112   { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 },  /* 16: TLSTPREL_OFFSET.  */
113   { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 },  /* 17: TEXT_OFFSET.  */
114   { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }   /* 18: TEXT_PC_OFFSET.  */
115 };
116 
117 static htab_t  opcode_hash_control;     /* Opcode mnemonics.  */
118 
119 static segT sbss_segment = 0;           /* Small bss section.  */
120 static segT sbss2_segment = 0;          /* Section not used.  */
121 static segT sdata_segment = 0;          /* Small data section.  */
122 static segT sdata2_segment = 0; /* Small read-only section.  */
123 static segT rodata_segment = 0; /* read-only section.  */
124 
125 /* Generate a symbol for stabs information.  */
126 
127 void
microblaze_generate_symbol(char * sym)128 microblaze_generate_symbol (char *sym)
129 {
130 #define MICROBLAZE_FAKE_LABEL_NAME "XL0\001"
131   static int microblaze_label_count;
132   sprintf (sym, "%sL%d", MICROBLAZE_FAKE_LABEL_NAME, microblaze_label_count);
133   ++microblaze_label_count;
134 }
135 
136 /* Handle the section changing pseudo-ops. */
137 
138 /* Things in the .sdata segment are always considered to be in the small data section.  */
139 
140 static void
microblaze_s_sdata(int ignore ATTRIBUTE_UNUSED)141 microblaze_s_sdata (int ignore ATTRIBUTE_UNUSED)
142 {
143 #ifdef OBJ_ELF
144   obj_elf_change_section (".sdata", SHT_PROGBITS, SHF_ALLOC+SHF_WRITE,
145                                 0, 0, false);
146 #else
147   s_data (ignore);
148 #endif
149 }
150 
151 /* Pseudo op to make file scope bss items.  */
152 
153 static void
microblaze_s_lcomm(int xxx ATTRIBUTE_UNUSED)154 microblaze_s_lcomm (int xxx ATTRIBUTE_UNUSED)
155 {
156   char *name;
157   char c;
158   char *p;
159   offsetT size;
160   symbolS *symbolP;
161   offsetT align;
162   char *pfrag;
163   int align2;
164   segT current_seg = now_seg;
165   subsegT current_subseg = now_subseg;
166 
167   c = get_symbol_name (&name);
168 
169   /* Just after name is now '\0'.  */
170   p = input_line_pointer;
171   (void) restore_line_pointer (c);
172   SKIP_WHITESPACE ();
173   if (*input_line_pointer != ',')
174     {
175       as_bad (_("Expected comma after symbol-name: rest of line ignored."));
176       ignore_rest_of_line ();
177       return;
178     }
179 
180   input_line_pointer++;                 /* skip ',' */
181   if ((size = get_absolute_expression ()) < 0)
182     {
183       as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) size);
184       ignore_rest_of_line ();
185       return;
186     }
187 
188   /* The third argument to .lcomm is the alignment.  */
189   if (*input_line_pointer != ',')
190     align = 8;
191   else
192     {
193       ++input_line_pointer;
194       align = get_absolute_expression ();
195       if (align <= 0)
196           {
197             as_warn (_("ignoring bad alignment"));
198             align = 8;
199           }
200     }
201 
202   *p = 0;
203   symbolP = symbol_find_or_make (name);
204   *p = c;
205 
206   if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP))
207     {
208       as_bad (_("Ignoring attempt to re-define symbol `%s'."),
209                 S_GET_NAME (symbolP));
210       ignore_rest_of_line ();
211       return;
212     }
213 
214   if (S_GET_VALUE (symbolP) && S_GET_VALUE (symbolP) != (valueT) size)
215     {
216       as_bad (_("Length of .lcomm \"%s\" is already %ld. Not changed to %ld."),
217                 S_GET_NAME (symbolP),
218                 (long) S_GET_VALUE (symbolP),
219                 (long) size);
220 
221       ignore_rest_of_line ();
222       return;
223     }
224 
225   /* Allocate_bss.  */
226   if (align)
227     {
228       /* Convert to a power of 2 alignment.  */
229       for (align2 = 0; (align & 1) == 0; align >>= 1, ++align2);
230       if (align != 1)
231           {
232             as_bad (_("Common alignment not a power of 2"));
233             ignore_rest_of_line ();
234             return;
235           }
236     }
237   else
238     align2 = 0;
239 
240   record_alignment (current_seg, align2);
241   subseg_set (current_seg, current_subseg);
242   if (align2)
243     frag_align (align2, 0, 0);
244   if (S_GET_SEGMENT (symbolP) == current_seg)
245     symbol_get_frag (symbolP)->fr_symbol = 0;
246   symbol_set_frag (symbolP, frag_now);
247   pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, size,
248                         (char *) 0);
249   *pfrag = 0;
250   S_SET_SIZE (symbolP, size);
251   S_SET_SEGMENT (symbolP, current_seg);
252   subseg_set (current_seg, current_subseg);
253   demand_empty_rest_of_line ();
254 }
255 
256 static void
microblaze_s_rdata(int localvar)257 microblaze_s_rdata (int localvar)
258 {
259 #ifdef OBJ_ELF
260   if (localvar == 0)
261     {
262       /* rodata.  */
263       obj_elf_change_section (".rodata", SHT_PROGBITS, SHF_ALLOC,
264                                     0, 0, false);
265       if (rodata_segment == 0)
266           rodata_segment = subseg_new (".rodata", 0);
267     }
268   else
269     {
270       /* 1 .sdata2.  */
271       obj_elf_change_section (".sdata2", SHT_PROGBITS, SHF_ALLOC,
272                                     0, 0, false);
273     }
274 #else
275   s_data (ignore);
276 #endif
277 }
278 
279 static void
microblaze_s_sbss(int ignore ATTRIBUTE_UNUSED)280 microblaze_s_sbss (int ignore ATTRIBUTE_UNUSED)
281 {
282 #ifdef OBJ_ELF
283   obj_elf_change_section (".sbss", SHT_NOBITS, SHF_ALLOC+SHF_WRITE,
284                                 0, 0, false);
285   if (sbss_segment == 0)
286     sbss_segment = subseg_new (".sbss", 0);
287 #else
288   s_data (ignore);
289 #endif
290 }
291 
292 /* endp_p is always 1 as this func is called only for .end <funcname>
293    This func consumes the <funcname> and calls regular processing
294    s_func(1) with arg 1 (1 for end). */
295 
296 static void
microblaze_s_func(int end_p ATTRIBUTE_UNUSED)297 microblaze_s_func (int end_p ATTRIBUTE_UNUSED)
298 {
299   char *name;
300   restore_line_pointer (get_symbol_name (&name));
301   s_func (1);
302 }
303 
304 /* Handle the .weakext pseudo-op as defined in Kane and Heinrich.  */
305 
306 static void
microblaze_s_weakext(int ignore ATTRIBUTE_UNUSED)307 microblaze_s_weakext (int ignore ATTRIBUTE_UNUSED)
308 {
309   char *name;
310   int c;
311   symbolS *symbolP;
312   expressionS exp;
313 
314   c = get_symbol_name (&name);
315   symbolP = symbol_find_or_make (name);
316   S_SET_WEAK (symbolP);
317   (void) restore_line_pointer (c);
318 
319   SKIP_WHITESPACE ();
320 
321   if (!is_end_of_line[(unsigned char) *input_line_pointer])
322     {
323       if (S_IS_DEFINED (symbolP))
324           {
325             as_bad ("Ignoring attempt to redefine symbol `%s'.",
326                       S_GET_NAME (symbolP));
327             ignore_rest_of_line ();
328             return;
329           }
330 
331       if (*input_line_pointer == ',')
332           {
333             ++input_line_pointer;
334             SKIP_WHITESPACE ();
335           }
336 
337       expression (&exp);
338       if (exp.X_op != O_symbol)
339           {
340             as_bad ("bad .weakext directive");
341             ignore_rest_of_line ();
342             return;
343           }
344       symbol_set_value_expression (symbolP, &exp);
345     }
346 
347   demand_empty_rest_of_line ();
348 }
349 
350 /* This table describes all the machine specific pseudo-ops the assembler
351    has to support.  The fields are:
352    Pseudo-op name without dot
353    Function to call to execute this pseudo-op
354    Integer arg to pass to the function.  */
355 /* If the pseudo-op is not found in this table, it searches in the obj-elf.c,
356    and then in the read.c table.  */
357 const pseudo_typeS md_pseudo_table[] =
358 {
359   {"lcomm", microblaze_s_lcomm, 1},
360   {"data8", cons, 1},      /* Same as byte.  */
361   {"data16", cons, 2},     /* Same as hword.  */
362   {"data32", cons, 4},     /* Same as word.  */
363   {"ent", s_func, 0}, /* Treat ent as function entry point.  */
364   {"end", microblaze_s_func, 1}, /* Treat end as function end point.  */
365   {"gpword", s_rva, 4}, /* gpword label => store resolved label address in data section.  */
366   {"weakext", microblaze_s_weakext, 0},
367   {"rodata", microblaze_s_rdata, 0},
368   {"sdata2", microblaze_s_rdata, 1},
369   {"sdata", microblaze_s_sdata, 0},
370 #ifndef OBJ_ELF
371   {"bss", s_data, 0},
372 #endif
373   {"sbss", microblaze_s_sbss, 0},
374   {"word", cons, 4},
375   {"frame", s_ignore, 0},
376   {"mask", s_ignore, 0}, /* Emitted by gcc.  */
377   {NULL, NULL, 0}
378 };
379 
380 /* This function is called once, at assembler startup time.  This should
381    set up all the tables, etc that the MD part of the assembler needs.  */
382 
383 void
md_begin(void)384 md_begin (void)
385 {
386   const struct op_code_struct * opcode;
387 
388   opcode_hash_control = str_htab_create ();
389 
390   /* Insert unique names into hash table.  */
391   for (opcode = microblaze_opcodes; opcode->name; opcode ++)
392     str_hash_insert (opcode_hash_control, opcode->name, opcode, 0);
393 }
394 
395 /* Try to parse a reg name.  */
396 
397 static char *
parse_reg(char * s,unsigned * reg)398 parse_reg (char * s, unsigned * reg)
399 {
400   unsigned tmpreg = 0;
401 
402   /* Strip leading whitespace.  */
403   while (ISSPACE (* s))
404     ++ s;
405 
406   if (strncasecmp (s, "rpc", 3) == 0)
407     {
408       *reg = REG_PC;
409       return s + 3;
410     }
411   else if (strncasecmp (s, "rmsr", 4) == 0)
412     {
413       *reg = REG_MSR;
414       return s + 4;
415     }
416   else if (strncasecmp (s, "rear", 4) == 0)
417     {
418       *reg = REG_EAR;
419       return s + 4;
420     }
421   else if (strncasecmp (s, "resr", 4) == 0)
422     {
423       *reg = REG_ESR;
424       return s + 4;
425     }
426   else if (strncasecmp (s, "rfsr", 4) == 0)
427     {
428       *reg = REG_FSR;
429       return s + 4;
430     }
431   else if (strncasecmp (s, "rbtr", 4) == 0)
432     {
433       *reg = REG_BTR;
434       return s + 4;
435     }
436   else if (strncasecmp (s, "redr", 4) == 0)
437     {
438       *reg = REG_EDR;
439       return s + 4;
440     }
441   /* MMU registers start.  */
442   else if (strncasecmp (s, "rpid", 4) == 0)
443     {
444       *reg = REG_PID;
445       return s + 4;
446     }
447   else if (strncasecmp (s, "rzpr", 4) == 0)
448     {
449       *reg = REG_ZPR;
450       return s + 4;
451     }
452   else if (strncasecmp (s, "rtlbx", 5) == 0)
453     {
454       *reg = REG_TLBX;
455       return s + 5;
456     }
457   else if (strncasecmp (s, "rtlblo", 6) == 0)
458     {
459       *reg = REG_TLBLO;
460       return s + 6;
461     }
462   else if (strncasecmp (s, "rtlbhi", 6) == 0)
463     {
464       *reg = REG_TLBHI;
465       return s + 6;
466     }
467   else if (strncasecmp (s, "rtlbsx", 6) == 0)
468     {
469       *reg = REG_TLBSX;
470       return s + 6;
471     }
472   /* MMU registers end.  */
473   else if (strncasecmp (s, "rpvr", 4) == 0)
474     {
475       if (ISDIGIT (s[4]) && ISDIGIT (s[5]))
476         {
477           tmpreg = (s[4]-'0')*10 + s[5] - '0';
478           s += 6;
479         }
480 
481       else if (ISDIGIT (s[4]))
482         {
483           tmpreg = s[4] - '0';
484           s += 5;
485         }
486       else
487         as_bad (_("register expected, but saw '%.6s'"), s);
488       if ((int) tmpreg >= MIN_PVR_REGNUM && tmpreg <= MAX_PVR_REGNUM)
489         *reg = REG_PVR + tmpreg;
490       else
491         {
492           as_bad (_("Invalid register number at '%.6s'"), s);
493           *reg = REG_PVR;
494         }
495       return s;
496     }
497   else if (strncasecmp (s, "rsp", 3) == 0)
498     {
499       *reg = REG_SP;
500       return s + 3;
501     }
502   else if (strncasecmp (s, "rfsl", 4) == 0)
503     {
504       if (ISDIGIT (s[4]) && ISDIGIT (s[5]))
505         {
506           tmpreg = (s[4] - '0') * 10 + s[5] - '0';
507           s += 6;
508         }
509       else if (ISDIGIT (s[4]))
510         {
511           tmpreg = s[4] - '0';
512           s += 5;
513         }
514       else
515           as_bad (_("register expected, but saw '%.6s'"), s);
516 
517       if ((int) tmpreg >= MIN_REGNUM && tmpreg <= MAX_REGNUM)
518         *reg = tmpreg;
519       else
520           {
521           as_bad (_("Invalid register number at '%.6s'"), s);
522           *reg = 0;
523           }
524       return s;
525     }
526   /* Stack protection registers.  */
527   else if (strncasecmp (s, "rshr", 4) == 0)
528     {
529       *reg = REG_SHR;
530       return s + 4;
531     }
532   else if (strncasecmp (s, "rslr", 4) == 0)
533     {
534       *reg = REG_SLR;
535       return s + 4;
536     }
537   else
538     {
539       if (TOLOWER (s[0]) == 'r')
540         {
541           if (ISDIGIT (s[1]) && ISDIGIT (s[2]))
542             {
543               tmpreg = (s[1] - '0') * 10 + s[2] - '0';
544               s += 3;
545             }
546           else if (ISDIGIT (s[1]))
547             {
548               tmpreg = s[1] - '0';
549               s += 2;
550             }
551           else
552             as_bad (_("register expected, but saw '%.6s'"), s);
553 
554           if ((int)tmpreg >= MIN_REGNUM && tmpreg <= MAX_REGNUM)
555             *reg = tmpreg;
556           else
557               {
558               as_bad (_("Invalid register number at '%.6s'"), s);
559               *reg = 0;
560               }
561           return s;
562         }
563     }
564   as_bad (_("register expected, but saw '%.6s'"), s);
565   *reg = 0;
566   return s;
567 }
568 
569 static char *
parse_exp(char * s,expressionS * e)570 parse_exp (char *s, expressionS *e)
571 {
572   char *save;
573   char *new_pointer;
574 
575   /* Skip whitespace.  */
576   while (ISSPACE (* s))
577     ++ s;
578 
579   save = input_line_pointer;
580   input_line_pointer = s;
581 
582   expression (e);
583 
584   if (e->X_op == O_absent)
585     as_fatal (_("missing operand"));
586 
587   new_pointer = input_line_pointer;
588   input_line_pointer = save;
589 
590   return new_pointer;
591 }
592 
593 /* Symbol modifiers (@GOT, @PLT, @GOTOFF).  */
594 #define IMM_NONE   0
595 #define IMM_GOT    1
596 #define IMM_PLT    2
597 #define IMM_GOTOFF 3
598 #define IMM_TLSGD  4
599 #define IMM_TLSLD  5
600 #define IMM_TLSDTPMOD 6
601 #define IMM_TLSDTPREL 7
602 #define IMM_TLSTPREL  8
603 #define IMM_TXTREL    9
604 #define IMM_TXTPCREL  10
605 #define IMM_MAX    11
606 
607 struct imm_type {
608           const char *isuffix;           /* Suffix String */
609           int itype;       /* Suffix Type */
610           int otype;       /* Offset Type */
611 };
612 
613 /* These are NOT in ascending order of type, GOTOFF is ahead to make
614    sure @GOTOFF does not get matched with @GOT  */
615 static struct imm_type imm_types[] = {
616           { "NONE", IMM_NONE , 0 },
617           { "GOTOFF", IMM_GOTOFF , GOTOFF_OFFSET },
618           { "GOT", IMM_GOT , GOT_OFFSET },
619           { "PLT", IMM_PLT , PLT_OFFSET },
620           { "TLSGD", IMM_TLSGD , TLSGD_OFFSET },
621           { "TLSLDM", IMM_TLSLD, TLSLD_OFFSET },
622           { "TLSDTPMOD", IMM_TLSDTPMOD, TLSDTPMOD_OFFSET },
623           { "TLSDTPREL", IMM_TLSDTPREL, TLSDTPREL_OFFSET },
624           { "TLSTPREL", IMM_TLSTPREL, TLSTPREL_OFFSET },
625           { "TXTREL", IMM_TXTREL, TEXT_OFFSET },
626           { "TXTPCREL", IMM_TXTPCREL, TEXT_PC_OFFSET }
627 };
628 
629 static int
match_imm(const char * s,int * ilen)630 match_imm (const char *s, int *ilen)
631 {
632   int i;
633   int slen;
634 
635   /* Check for matching suffix */
636   for (i = 1; i < IMM_MAX; i++)
637     {
638       slen = strlen (imm_types[i].isuffix);
639 
640       if (strncmp (imm_types[i].isuffix, s, slen) == 0)
641         {
642           *ilen = slen;
643           return imm_types[i].itype;
644         }
645     } /* for */
646   *ilen = 0;
647   return 0;
648 }
649 
650 static int
get_imm_otype(int itype)651 get_imm_otype (int itype)
652 {
653   int i, otype;
654 
655   otype = 0;
656   /* Check for matching itype */
657   for (i = 1; i < IMM_MAX; i++)
658     {
659       if (imm_types[i].itype == itype)
660         {
661           otype = imm_types[i].otype;
662           break;
663         }
664     }
665   return otype;
666 }
667 
668 static symbolS * GOT_symbol;
669 
670 #define GOT_SYMBOL_NAME "_GLOBAL_OFFSET_TABLE_"
671 
672 static char *
parse_imm(char * s,expressionS * e,offsetT min,offsetT max)673 parse_imm (char * s, expressionS * e, offsetT min, offsetT max)
674 {
675   char *new_pointer;
676   char *atp;
677   int itype, ilen;
678 
679   ilen = 0;
680 
681   /* Find the start of "@GOT" or "@PLT" suffix (if any) */
682   for (atp = s; *atp != '@'; atp++)
683     if (is_end_of_line[(unsigned char) *atp])
684       break;
685 
686   if (*atp == '@')
687     {
688       itype = match_imm (atp + 1, &ilen);
689       if (itype != 0)
690         {
691           *atp = 0;
692           e->X_md = itype;
693         }
694       else
695         {
696           atp = NULL;
697           e->X_md = 0;
698           ilen = 0;
699         }
700       *atp = 0;
701     }
702   else
703     {
704       atp = NULL;
705       e->X_md = 0;
706     }
707 
708   if (atp && !GOT_symbol)
709     {
710       GOT_symbol = symbol_find_or_make (GOT_SYMBOL_NAME);
711     }
712 
713   new_pointer = parse_exp (s, e);
714 
715   if (!GOT_symbol && startswith (s, GOT_SYMBOL_NAME))
716     {
717       GOT_symbol = symbol_find_or_make (GOT_SYMBOL_NAME);
718     }
719 
720   if (e->X_op == O_absent)
721     ; /* An error message has already been emitted.  */
722   else if ((e->X_op != O_constant && e->X_op != O_symbol) )
723     as_fatal (_("operand must be a constant or a label"));
724   else if (e->X_op == O_constant)
725     {
726       /* Special case: sign extend negative 32-bit values to offsetT size.  */
727       if ((e->X_add_number >> 31) == 1)
728           e->X_add_number |= -((addressT) (1U << 31));
729 
730       if ((int)e->X_add_number < min || (int)e->X_add_number > max)
731           {
732             as_fatal (_("operand must be absolute in range %lx..%lx, not %lx"),
733                         (long) min, (long) max, (long) e->X_add_number);
734           }
735     }
736 
737   if (atp)
738     {
739       *atp = '@'; /* restore back (needed?)  */
740       if (new_pointer >= atp)
741         new_pointer += ilen + 1; /* sizeof (imm_suffix) + 1 for '@' */
742     }
743   return new_pointer;
744 }
745 
746 static char *
check_got(int * got_type,int * got_len)747 check_got (int * got_type, int * got_len)
748 {
749   char *new_pointer;
750   char *atp;
751   char *past_got;
752   int first, second;
753   char *tmpbuf;
754 
755   /* Find the start of "@GOT" or "@PLT" suffix (if any).  */
756   for (atp = input_line_pointer; *atp != '@'; atp++)
757     if (is_end_of_line[(unsigned char) *atp])
758       return NULL;
759 
760   if (startswith (atp + 1, "GOTOFF"))
761     {
762       *got_len = 6;
763       *got_type = IMM_GOTOFF;
764     }
765   else if (startswith (atp + 1, "GOT"))
766     {
767       *got_len = 3;
768       *got_type = IMM_GOT;
769     }
770   else if (startswith (atp + 1, "PLT"))
771     {
772       *got_len = 3;
773       *got_type = IMM_PLT;
774     }
775   else
776     return NULL;
777 
778   if (!GOT_symbol)
779     GOT_symbol = symbol_find_or_make (GOT_SYMBOL_NAME);
780 
781   first = atp - input_line_pointer;
782 
783   past_got = atp + *got_len + 1;
784   for (new_pointer = past_got; !is_end_of_line[(unsigned char) *new_pointer++];)
785     ;
786   second = new_pointer - past_got;
787   /* One extra byte for ' ' and one for NUL.  */
788   tmpbuf = XNEWVEC (char, first + second + 2);
789   memcpy (tmpbuf, input_line_pointer, first);
790   tmpbuf[first] = ' '; /* @GOTOFF is replaced with a single space.  */
791   memcpy (tmpbuf + first + 1, past_got, second);
792   tmpbuf[first + second + 1] = '\0';
793 
794   return tmpbuf;
795 }
796 
797 extern bfd_reloc_code_real_type
parse_cons_expression_microblaze(expressionS * exp,int size)798 parse_cons_expression_microblaze (expressionS *exp, int size)
799 {
800   if (size == 4)
801     {
802       /* Handle @GOTOFF et.al.  */
803       char *save, *gotfree_copy;
804       int got_len, got_type;
805 
806       save = input_line_pointer;
807       gotfree_copy = check_got (& got_type, & got_len);
808       if (gotfree_copy)
809         input_line_pointer = gotfree_copy;
810 
811       expression (exp);
812 
813       if (gotfree_copy)
814           {
815           exp->X_md = got_type;
816           input_line_pointer = save + (input_line_pointer - gotfree_copy)
817               + got_len;
818           free (gotfree_copy);
819         }
820     }
821   else
822     expression (exp);
823   return BFD_RELOC_NONE;
824 }
825 
826 /* This is the guts of the machine-dependent assembler.  STR points to a
827    machine dependent instruction.  This function is supposed to emit
828    the frags/bytes it assembles to.  */
829 
830 static const char * str_microblaze_ro_anchor = "RO";
831 static const char * str_microblaze_rw_anchor = "RW";
832 
833 static bool
check_spl_reg(unsigned * reg)834 check_spl_reg (unsigned * reg)
835 {
836   if ((*reg == REG_MSR)   || (*reg == REG_PC)
837       || (*reg == REG_EAR)   || (*reg == REG_ESR)
838       || (*reg == REG_FSR)   || (*reg == REG_BTR) || (*reg == REG_EDR)
839       || (*reg == REG_PID)   || (*reg == REG_ZPR)
840       || (*reg == REG_TLBX)  || (*reg == REG_TLBLO)
841       || (*reg == REG_TLBHI) || (*reg == REG_TLBSX)
842       || (*reg == REG_SHR)   || (*reg == REG_SLR)
843       || (*reg >= REG_PVR+MIN_PVR_REGNUM && *reg <= REG_PVR+MAX_PVR_REGNUM))
844     return true;
845 
846   return false;
847 }
848 
849 /* Here we decide which fixups can be adjusted to make them relative to
850    the beginning of the section instead of the symbol.  Basically we need
851    to make sure that the dynamic relocations are done correctly, so in
852    some cases we force the original symbol to be used.  */
853 
854 int
tc_microblaze_fix_adjustable(struct fix * fixP)855 tc_microblaze_fix_adjustable (struct fix *fixP)
856 {
857   if (GOT_symbol && fixP->fx_subsy == GOT_symbol)
858     return 0;
859 
860   if (fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_GOTOFF
861       || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_32_GOTOFF
862       || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_GOT
863       || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_PLT
864       || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSGD
865       || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSLD
866       || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_32_TLSDTPMOD
867       || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_32_TLSDTPREL
868       || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSDTPREL
869       || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL
870       || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSTPREL)
871     return 0;
872 
873   return 1;
874 }
875 
876 void
md_assemble(char * str)877 md_assemble (char * str)
878 {
879   char * op_start;
880   char * op_end;
881   struct op_code_struct * opcode, *opcode1;
882   char * output = NULL;
883   int nlen = 0;
884   int i;
885   unsigned long inst, inst1;
886   unsigned reg1;
887   unsigned reg2;
888   unsigned reg3;
889   unsigned isize;
890   unsigned int immed = 0, immed2 = 0, temp;
891   expressionS exp;
892   char name[20];
893 
894   /* Drop leading whitespace.  */
895   while (ISSPACE (* str))
896     str ++;
897 
898   /* Find the op code end.  */
899   for (op_start = op_end = str;
900        *op_end && !is_end_of_line[(unsigned char) *op_end] && *op_end != ' ';
901        op_end++)
902     {
903       name[nlen] = op_start[nlen];
904       nlen++;
905       if (nlen == sizeof (name) - 1)
906           break;
907     }
908 
909   name [nlen] = 0;
910 
911   if (nlen == 0)
912     {
913       as_bad (_("can't find opcode "));
914       return;
915     }
916 
917   opcode = (struct op_code_struct *) str_hash_find (opcode_hash_control, name);
918   if (opcode == NULL)
919     {
920       as_bad (_("unknown opcode \"%s\""), name);
921       return;
922     }
923 
924   inst = opcode->bit_sequence;
925   isize = 4;
926 
927   switch (opcode->inst_type)
928     {
929     case INST_TYPE_RD_R1_R2:
930       if (strcmp (op_end, ""))
931         op_end = parse_reg (op_end + 1, &reg1);  /* Get rd.  */
932       else
933         {
934           as_fatal (_("Error in statement syntax"));
935           reg1 = 0;
936         }
937       if (strcmp (op_end, ""))
938         op_end = parse_reg (op_end + 1, &reg2);  /* Get r1.  */
939       else
940           {
941           as_fatal (_("Error in statement syntax"));
942           reg2 = 0;
943         }
944       if (strcmp (op_end, ""))
945         op_end = parse_reg (op_end + 1, &reg3);  /* Get r2.  */
946       else
947           {
948           as_fatal (_("Error in statement syntax"));
949           reg3 = 0;
950         }
951 
952       /* Check for spl registers.  */
953       if (check_spl_reg (& reg1))
954         as_fatal (_("Cannot use special register with this instruction"));
955       if (check_spl_reg (& reg2))
956         as_fatal (_("Cannot use special register with this instruction"));
957       if (check_spl_reg (& reg3))
958         as_fatal (_("Cannot use special register with this instruction"));
959 
960       if (streq (name, "sub"))
961           {
962           /* sub rd, r1, r2 becomes rsub rd, r2, r1.  */
963           inst |= (reg1 << RD_LOW) & RD_MASK;
964           inst |= (reg3 << RA_LOW) & RA_MASK;
965           inst |= (reg2 << RB_LOW) & RB_MASK;
966         }
967       else
968         {
969           inst |= (reg1 << RD_LOW) & RD_MASK;
970           inst |= (reg2 << RA_LOW) & RA_MASK;
971           inst |= (reg3 << RB_LOW) & RB_MASK;
972         }
973       output = frag_more (isize);
974       break;
975 
976     case INST_TYPE_RD_R1_IMM:
977       if (strcmp (op_end, ""))
978           op_end = parse_reg (op_end + 1, &reg1);  /* Get rd.  */
979       else
980           {
981           as_fatal (_("Error in statement syntax"));
982           reg1 = 0;
983         }
984       if (strcmp (op_end, ""))
985           op_end = parse_reg (op_end + 1, &reg2);  /* Get r1.  */
986       else
987           {
988           as_fatal (_("Error in statement syntax"));
989           reg2 = 0;
990         }
991       if (strcmp (op_end, ""))
992           op_end = parse_imm (op_end + 1, & exp, MIN_IMM, MAX_IMM);
993       else
994           as_fatal (_("Error in statement syntax"));
995 
996       /* Check for spl registers.  */
997       if (check_spl_reg (& reg1))
998           as_fatal (_("Cannot use special register with this instruction"));
999       if (check_spl_reg (& reg2))
1000           as_fatal (_("Cannot use special register with this instruction"));
1001 
1002       if (exp.X_op != O_constant || exp.X_md == IMM_TXTPCREL)
1003           {
1004           const char *opc;
1005             relax_substateT subtype;
1006 
1007           if (streq (name, "lmi"))
1008               as_fatal (_("lmi pseudo instruction should not use a label in imm field"));
1009             else if (streq (name, "smi"))
1010               as_fatal (_("smi pseudo instruction should not use a label in imm field"));
1011 
1012             if (reg2 == REG_ROSDP)
1013               opc = str_microblaze_ro_anchor;
1014             else if (reg2 == REG_RWSDP)
1015               opc = str_microblaze_rw_anchor;
1016             else
1017               opc = NULL;
1018             if (exp.X_md != 0)
1019               subtype = get_imm_otype(exp.X_md);
1020             else
1021               subtype = opcode->inst_offset_type;
1022 
1023             output = frag_var (rs_machine_dependent,
1024                                    isize * 2, /* maxm of 2 words.  */
1025                                    isize,     /* minm of 1 word.  */
1026                                    subtype,   /* PC-relative or not.  */
1027                                    exp.X_add_symbol,
1028                                    exp.X_add_number,
1029                                    (char *) opc);
1030             immed = 0;
1031         }
1032       else
1033           {
1034           output = frag_more (isize);
1035           immed = exp.X_add_number;
1036         }
1037 
1038       if (streq (name, "lmi") || streq (name, "smi"))
1039           {
1040           /* Load/store 32-d consecutive registers.  Used on exit/entry
1041              to subroutines to save and restore registers to stack.
1042              Generate 32-d insts.  */
1043           int count;
1044 
1045           count = 32 - reg1;
1046           if (streq (name, "lmi"))
1047               opcode
1048                 = (struct op_code_struct *) str_hash_find (opcode_hash_control,
1049                                                                        "lwi");
1050           else
1051               opcode
1052                 = (struct op_code_struct *) str_hash_find (opcode_hash_control,
1053                                                                        "swi");
1054           if (opcode == NULL)
1055             {
1056               as_bad (_("unknown opcode \"%s\""), "lwi");
1057               return;
1058             }
1059           inst  = opcode->bit_sequence;
1060           inst |= (reg1 << RD_LOW) & RD_MASK;
1061           inst |= (reg2 << RA_LOW) & RA_MASK;
1062           inst |= (immed << IMM_LOW) & IMM_MASK;
1063 
1064           for (i = 0; i < count - 1; i++)
1065               {
1066               output[0] = INST_BYTE0 (inst);
1067               output[1] = INST_BYTE1 (inst);
1068               output[2] = INST_BYTE2 (inst);
1069               output[3] = INST_BYTE3 (inst);
1070               output = frag_more (isize);
1071               immed = immed + 4;
1072               reg1++;
1073               inst = opcode->bit_sequence;
1074               inst |= (reg1 << RD_LOW) & RD_MASK;
1075               inst |= (reg2 << RA_LOW) & RA_MASK;
1076               inst |= (immed << IMM_LOW) & IMM_MASK;
1077             }
1078           }
1079       else
1080           {
1081           temp = immed & 0xFFFF8000;
1082           if ((temp != 0) && (temp != 0xFFFF8000))
1083               {
1084               /* Needs an immediate inst.  */
1085                 opcode1
1086                     = (struct op_code_struct *) str_hash_find (opcode_hash_control,
1087                                                                          "imm");
1088               if (opcode1 == NULL)
1089                 {
1090                   as_bad (_("unknown opcode \"%s\""), "imm");
1091                   return;
1092                 }
1093 
1094               inst1 = opcode1->bit_sequence;
1095               inst1 |= ((immed & 0xFFFF0000) >> 16) & IMM_MASK;
1096               output[0] = INST_BYTE0 (inst1);
1097               output[1] = INST_BYTE1 (inst1);
1098               output[2] = INST_BYTE2 (inst1);
1099               output[3] = INST_BYTE3 (inst1);
1100               output = frag_more (isize);
1101               }
1102             inst |= (reg1 << RD_LOW) & RD_MASK;
1103             inst |= (reg2 << RA_LOW) & RA_MASK;
1104             inst |= (immed << IMM_LOW) & IMM_MASK;
1105           }
1106       break;
1107 
1108     case INST_TYPE_RD_R1_IMM5:
1109       if (strcmp (op_end, ""))
1110         op_end = parse_reg (op_end + 1, &reg1);  /* Get rd.  */
1111       else
1112           {
1113           as_fatal (_("Error in statement syntax"));
1114           reg1 = 0;
1115         }
1116       if (strcmp (op_end, ""))
1117         op_end = parse_reg (op_end + 1, &reg2);  /* Get r1.  */
1118       else
1119           {
1120           as_fatal (_("Error in statement syntax"));
1121           reg2 = 0;
1122         }
1123       if (strcmp (op_end, ""))
1124         op_end = parse_imm (op_end + 1, & exp, MIN_IMM, MAX_IMM);
1125       else
1126         as_fatal (_("Error in statement syntax"));
1127 
1128       /* Check for spl registers.  */
1129       if (check_spl_reg (&reg1))
1130         as_fatal (_("Cannot use special register with this instruction"));
1131       if (check_spl_reg (&reg2))
1132         as_fatal (_("Cannot use special register with this instruction"));
1133 
1134       if (exp.X_op != O_constant)
1135         as_warn (_("Symbol used as immediate for shift instruction"));
1136       else
1137           {
1138           output = frag_more (isize);
1139           immed = exp.X_add_number;
1140         }
1141 
1142       if (immed != (immed % 32))
1143           {
1144           as_warn (_("Shift value > 32. using <value %% 32>"));
1145           immed = immed % 32;
1146         }
1147       inst |= (reg1 << RD_LOW) & RD_MASK;
1148       inst |= (reg2 << RA_LOW) & RA_MASK;
1149       inst |= (immed << IMM_LOW) & IMM5_MASK;
1150       break;
1151 
1152     case INST_TYPE_RD_R1_IMMW_IMMS:
1153       if (strcmp (op_end, ""))
1154           op_end = parse_reg (op_end + 1, &reg1);  /* Get rd.  */
1155       else
1156           {
1157             as_fatal (_("Error in statement syntax"));
1158             reg1 = 0;
1159           }
1160 
1161       if (strcmp (op_end, ""))
1162           op_end = parse_reg (op_end + 1, &reg2);  /* Get r1.  */
1163       else
1164           {
1165             as_fatal (_("Error in statement syntax"));
1166             reg2 = 0;
1167           }
1168 
1169       /* Check for spl registers.  */
1170       if (check_spl_reg (&reg1))
1171           as_fatal (_("Cannot use special register with this instruction"));
1172       if (check_spl_reg (&reg2))
1173           as_fatal (_("Cannot use special register with this instruction"));
1174 
1175       /* Width immediate value.  */
1176       if (strcmp (op_end, ""))
1177           op_end = parse_imm (op_end + 1, &exp, MIN_IMM_WIDTH, MAX_IMM_WIDTH);
1178       else
1179           as_fatal (_("Error in statement syntax"));
1180 
1181       if (exp.X_op != O_constant)
1182           {
1183             as_warn (_(
1184             "Symbol used as immediate width value for bit field instruction"));
1185             immed = 1;
1186           }
1187       else
1188           immed = exp.X_add_number;
1189 
1190       if (opcode->instr == bsefi && immed > 31)
1191           as_fatal (_("Width value must be less than 32"));
1192 
1193       /* Shift immediate value.  */
1194       if (strcmp (op_end, ""))
1195           op_end = parse_imm (op_end + 1, &exp, MIN_IMM, MAX_IMM);
1196       else
1197           as_fatal (_("Error in statement syntax"));
1198 
1199       if (exp.X_op != O_constant)
1200           {
1201             as_warn (_(
1202             "Symbol used as immediate shift value for bit field instruction"));
1203             immed2 = 0;
1204           }
1205       else
1206           {
1207             output = frag_more (isize);
1208             immed2 = exp.X_add_number;
1209           }
1210 
1211       if (immed2 != (immed2 % 32))
1212           {
1213             as_warn (_("Shift value greater than 32. using <value %% 32>"));
1214             immed2 = immed2 % 32;
1215           }
1216 
1217       /* Check combined value.  */
1218       if (immed + immed2 > 32)
1219           as_fatal (_("Width value + shift value must not be greater than 32"));
1220 
1221       inst |= (reg1 << RD_LOW) & RD_MASK;
1222       inst |= (reg2 << RA_LOW) & RA_MASK;
1223 
1224       if (opcode->instr == bsefi)
1225           inst |= (immed & IMM5_MASK) << IMM_WIDTH_LOW; /* bsefi */
1226       else
1227           inst |= ((immed + immed2 - 1) & IMM5_MASK)
1228                     << IMM_WIDTH_LOW; /* bsifi */
1229 
1230       inst |= (immed2 << IMM_LOW) & IMM5_MASK;
1231       break;
1232 
1233     case INST_TYPE_R1_R2:
1234       if (strcmp (op_end, ""))
1235         op_end = parse_reg (op_end + 1, &reg1);  /* Get r1.  */
1236       else
1237           {
1238           as_fatal (_("Error in statement syntax"));
1239           reg1 = 0;
1240         }
1241       if (strcmp (op_end, ""))
1242         op_end = parse_reg (op_end + 1, &reg2);  /* Get r2.  */
1243       else
1244           {
1245           as_fatal (_("Error in statement syntax"));
1246           reg2 = 0;
1247         }
1248 
1249       /* Check for spl registers.  */
1250       if (check_spl_reg (& reg1))
1251         as_fatal (_("Cannot use special register with this instruction"));
1252       if (check_spl_reg (& reg2))
1253         as_fatal (_("Cannot use special register with this instruction"));
1254 
1255       inst |= (reg1 << RA_LOW) & RA_MASK;
1256       inst |= (reg2 << RB_LOW) & RB_MASK;
1257       output = frag_more (isize);
1258       break;
1259 
1260     case INST_TYPE_RD_R1:
1261       if (strcmp (op_end, ""))
1262         op_end = parse_reg (op_end + 1, &reg1);  /* Get rd.  */
1263       else
1264           {
1265           as_fatal (_("Error in statement syntax"));
1266           reg1 = 0;
1267         }
1268       if (strcmp (op_end, ""))
1269         op_end = parse_reg (op_end + 1, &reg2);  /* Get r1.  */
1270       else
1271           {
1272           as_fatal (_("Error in statement syntax"));
1273           reg2 =0;
1274         }
1275 
1276       /* Check for spl registers.  */
1277       if (check_spl_reg (&reg1))
1278         as_fatal (_("Cannot use special register with this instruction"));
1279       if (check_spl_reg (&reg2))
1280         as_fatal (_("Cannot use special register with this instruction"));
1281 
1282       inst |= (reg1 << RD_LOW) & RD_MASK;
1283       inst |= (reg2 << RA_LOW) & RA_MASK;
1284       output = frag_more (isize);
1285       break;
1286 
1287     case INST_TYPE_RD_RFSL:
1288       if (strcmp (op_end, ""))
1289         op_end = parse_reg (op_end + 1, &reg1);  /* Get rd.  */
1290       else
1291           {
1292           as_fatal (_("Error in statement syntax"));
1293           reg1 = 0;
1294         }
1295       if (strcmp (op_end, ""))
1296         op_end = parse_reg (op_end + 1, &immed);  /* Get rfslN.  */
1297       else
1298           {
1299           as_fatal (_("Error in statement syntax"));
1300           immed = 0;
1301         }
1302 
1303       /* Check for spl registers.  */
1304       if (check_spl_reg (&reg1))
1305         as_fatal (_("Cannot use special register with this instruction"));
1306 
1307       inst |= (reg1 << RD_LOW) & RD_MASK;
1308       inst |= (immed << IMM_LOW) & RFSL_MASK;
1309       output = frag_more (isize);
1310       break;
1311 
1312     case INST_TYPE_RD_IMM15:
1313       if (strcmp (op_end, ""))
1314         op_end = parse_reg (op_end + 1, &reg1);  /* Get rd.  */
1315       else
1316           {
1317           as_fatal (_("Error in statement syntax"));
1318           reg1 = 0;
1319         }
1320 
1321       if (strcmp (op_end, ""))
1322         op_end = parse_imm (op_end + 1, & exp, MIN_IMM15, MAX_IMM15);
1323       else
1324         as_fatal (_("Error in statement syntax"));
1325 
1326       /* Check for spl registers. */
1327       if (check_spl_reg (&reg1))
1328         as_fatal (_("Cannot use special register with this instruction"));
1329 
1330       if (exp.X_op != O_constant)
1331         as_fatal (_("Symbol used as immediate value for msrset/msrclr instructions"));
1332       else
1333           {
1334           output = frag_more (isize);
1335           immed = exp.X_add_number;
1336         }
1337       inst |= (reg1 << RD_LOW) & RD_MASK;
1338       inst |= (immed << IMM_LOW) & IMM15_MASK;
1339       break;
1340 
1341     case INST_TYPE_R1_RFSL:
1342       if (strcmp (op_end, ""))
1343         op_end = parse_reg (op_end + 1, &reg1);  /* Get r1.  */
1344       else
1345           {
1346           as_fatal (_("Error in statement syntax"));
1347           reg1 = 0;
1348         }
1349       if (strcmp (op_end, ""))
1350         op_end = parse_reg (op_end + 1, &immed);  /* Get rfslN.  */
1351       else
1352           {
1353           as_fatal (_("Error in statement syntax"));
1354           immed = 0;
1355         }
1356 
1357       /* Check for spl registers.  */
1358       if (check_spl_reg (&reg1))
1359         as_fatal (_("Cannot use special register with this instruction"));
1360 
1361       inst |= (reg1 << RA_LOW) & RA_MASK;
1362       inst |= (immed << IMM_LOW) & RFSL_MASK;
1363       output = frag_more (isize);
1364       break;
1365 
1366     case INST_TYPE_RFSL:
1367       if (strcmp (op_end, ""))
1368         op_end = parse_reg (op_end + 1, &immed);  /* Get rfslN.  */
1369       else
1370           {
1371           as_fatal (_("Error in statement syntax"));
1372           immed = 0;
1373         }
1374       inst |= (immed << IMM_LOW) & RFSL_MASK;
1375       output = frag_more (isize);
1376       break;
1377 
1378     case INST_TYPE_R1:
1379       if (strcmp (op_end, ""))
1380         op_end = parse_reg (op_end + 1, &reg1);  /* Get r1.  */
1381       else
1382           {
1383           as_fatal (_("Error in statement syntax"));
1384           reg1 = 0;
1385         }
1386 
1387       /* Check for spl registers.  */
1388       if (check_spl_reg (&reg1))
1389         as_fatal (_("Cannot use special register with this instruction"));
1390 
1391       inst |= (reg1 << RA_LOW) & RA_MASK;
1392       output = frag_more (isize);
1393       break;
1394 
1395       /* For tuqula insn...:) */
1396     case INST_TYPE_RD:
1397       if (strcmp (op_end, ""))
1398         op_end = parse_reg (op_end + 1, &reg1);  /* Get rd.  */
1399       else
1400           {
1401           as_fatal (_("Error in statement syntax"));
1402           reg1 = 0;
1403         }
1404 
1405       /* Check for spl registers.  */
1406       if (check_spl_reg (&reg1))
1407         as_fatal (_("Cannot use special register with this instruction"));
1408 
1409       inst |= (reg1 << RD_LOW) & RD_MASK;
1410       output = frag_more (isize);
1411       break;
1412 
1413     case INST_TYPE_RD_SPECIAL:
1414       if (strcmp (op_end, ""))
1415         op_end = parse_reg (op_end + 1, &reg1);  /* Get rd.  */
1416       else
1417           {
1418           as_fatal (_("Error in statement syntax"));
1419           reg1 = 0;
1420         }
1421       if (strcmp (op_end, ""))
1422         op_end = parse_reg (op_end + 1, &reg2);  /* Get r1.  */
1423       else
1424           {
1425           as_fatal (_("Error in statement syntax"));
1426           reg2 = 0;
1427         }
1428 
1429       if (reg2 == REG_MSR)
1430         immed = opcode->immval_mask | REG_MSR_MASK;
1431       else if (reg2 == REG_PC)
1432         immed = opcode->immval_mask | REG_PC_MASK;
1433       else if (reg2 == REG_EAR)
1434         immed = opcode->immval_mask | REG_EAR_MASK;
1435       else if (reg2 == REG_ESR)
1436         immed = opcode->immval_mask | REG_ESR_MASK;
1437       else if (reg2 == REG_FSR)
1438         immed = opcode->immval_mask | REG_FSR_MASK;
1439       else if (reg2 == REG_BTR)
1440         immed = opcode->immval_mask | REG_BTR_MASK;
1441       else if (reg2 == REG_EDR)
1442         immed = opcode->immval_mask | REG_EDR_MASK;
1443       else if (reg2 == REG_PID)
1444         immed = opcode->immval_mask | REG_PID_MASK;
1445       else if (reg2 == REG_ZPR)
1446         immed = opcode->immval_mask | REG_ZPR_MASK;
1447       else if (reg2 == REG_TLBX)
1448         immed = opcode->immval_mask | REG_TLBX_MASK;
1449       else if (reg2 == REG_TLBLO)
1450         immed = opcode->immval_mask | REG_TLBLO_MASK;
1451       else if (reg2 == REG_TLBHI)
1452         immed = opcode->immval_mask | REG_TLBHI_MASK;
1453       else if (reg2 == REG_SHR)
1454         immed = opcode->immval_mask | REG_SHR_MASK;
1455       else if (reg2 == REG_SLR)
1456         immed = opcode->immval_mask | REG_SLR_MASK;
1457       else if (reg2 >= (REG_PVR+MIN_PVR_REGNUM) && reg2 <= (REG_PVR+MAX_PVR_REGNUM))
1458           immed = opcode->immval_mask | REG_PVR_MASK | reg2;
1459       else
1460         as_fatal (_("invalid value for special purpose register"));
1461       inst |= (reg1 << RD_LOW) & RD_MASK;
1462       inst |= (immed << IMM_LOW) & IMM_MASK;
1463       output = frag_more (isize);
1464       break;
1465 
1466     case INST_TYPE_SPECIAL_R1:
1467       if (strcmp (op_end, ""))
1468         op_end = parse_reg (op_end + 1, &reg1);  /* Get rd.  */
1469       else
1470           {
1471           as_fatal (_("Error in statement syntax"));
1472           reg1 = 0;
1473         }
1474       if (strcmp (op_end, ""))
1475         op_end = parse_reg (op_end + 1, &reg2);  /* Get r1.  */
1476       else
1477           {
1478           as_fatal (_("Error in statement syntax"));
1479           reg2 = 0;
1480         }
1481 
1482       if (reg1 == REG_MSR)
1483         immed = opcode->immval_mask | REG_MSR_MASK;
1484       else if (reg1 == REG_PC)
1485         immed = opcode->immval_mask | REG_PC_MASK;
1486       else if (reg1 == REG_EAR)
1487         immed = opcode->immval_mask | REG_EAR_MASK;
1488       else if (reg1 == REG_ESR)
1489         immed = opcode->immval_mask | REG_ESR_MASK;
1490       else if (reg1 == REG_FSR)
1491         immed = opcode->immval_mask | REG_FSR_MASK;
1492       else if (reg1 == REG_BTR)
1493         immed = opcode->immval_mask | REG_BTR_MASK;
1494       else if (reg1 == REG_EDR)
1495         immed = opcode->immval_mask | REG_EDR_MASK;
1496       else if (reg1 == REG_PID)
1497         immed = opcode->immval_mask | REG_PID_MASK;
1498       else if (reg1 == REG_ZPR)
1499         immed = opcode->immval_mask | REG_ZPR_MASK;
1500       else if (reg1 == REG_TLBX)
1501         immed = opcode->immval_mask | REG_TLBX_MASK;
1502       else if (reg1 == REG_TLBLO)
1503         immed = opcode->immval_mask | REG_TLBLO_MASK;
1504       else if (reg1 == REG_TLBHI)
1505         immed = opcode->immval_mask | REG_TLBHI_MASK;
1506       else if (reg1 == REG_TLBSX)
1507         immed = opcode->immval_mask | REG_TLBSX_MASK;
1508       else if (reg1 == REG_SHR)
1509         immed = opcode->immval_mask | REG_SHR_MASK;
1510       else if (reg1 == REG_SLR)
1511         immed = opcode->immval_mask | REG_SLR_MASK;
1512       else
1513         as_fatal (_("invalid value for special purpose register"));
1514       inst |= (reg2 << RA_LOW) & RA_MASK;
1515       inst |= (immed << IMM_LOW) & IMM_MASK;
1516       output = frag_more (isize);
1517       break;
1518 
1519     case INST_TYPE_R1_R2_SPECIAL:
1520       if (strcmp (op_end, ""))
1521         op_end = parse_reg (op_end + 1, &reg1);  /* Get r1.  */
1522       else
1523           {
1524           as_fatal (_("Error in statement syntax"));
1525           reg1 = 0;
1526         }
1527       if (strcmp (op_end, ""))
1528         op_end = parse_reg (op_end + 1, &reg2);  /* Get r2.  */
1529       else
1530           {
1531           as_fatal (_("Error in statement syntax"));
1532           reg2 =0;
1533         }
1534 
1535       /* Check for spl registers.  */
1536       if (check_spl_reg (&reg1))
1537         as_fatal (_("Cannot use special register with this instruction"));
1538       if (check_spl_reg (&reg2))
1539         as_fatal (_("Cannot use special register with this instruction"));
1540 
1541       /* insn wic ra, rb => wic ra, ra, rb.  */
1542       inst |= (reg1 << RA_LOW) & RA_MASK;
1543       inst |= (reg2 << RB_LOW) & RB_MASK;
1544 
1545       output = frag_more (isize);
1546       break;
1547 
1548     case INST_TYPE_RD_R2:
1549       if (strcmp (op_end, ""))
1550         op_end = parse_reg (op_end + 1, &reg1);  /* Get rd.  */
1551       else
1552           {
1553           as_fatal (_("Error in statement syntax"));
1554           reg1 = 0;
1555         }
1556       if (strcmp (op_end, ""))
1557         op_end = parse_reg (op_end + 1, &reg2);  /* Get r2.  */
1558       else
1559           {
1560           as_fatal (_("Error in statement syntax"));
1561           reg2 = 0;
1562         }
1563 
1564       /* Check for spl registers.  */
1565       if (check_spl_reg (&reg1))
1566         as_fatal (_("Cannot use special register with this instruction"));
1567       if (check_spl_reg (&reg2))
1568         as_fatal (_("Cannot use special register with this instruction"));
1569 
1570       inst |= (reg1 << RD_LOW) & RD_MASK;
1571       inst |= (reg2 << RB_LOW) & RB_MASK;
1572       output = frag_more (isize);
1573       break;
1574 
1575     case INST_TYPE_R1_IMM:
1576       if (strcmp (op_end, ""))
1577         op_end = parse_reg (op_end + 1, &reg1);  /* Get r1.  */
1578       else
1579           {
1580           as_fatal (_("Error in statement syntax"));
1581           reg1 = 0;
1582         }
1583       if (strcmp (op_end, ""))
1584         op_end = parse_imm (op_end + 1, & exp, MIN_IMM, MAX_IMM);
1585       else
1586         as_fatal (_("Error in statement syntax"));
1587 
1588       /* Check for spl registers.  */
1589       if (check_spl_reg (&reg1))
1590         as_fatal (_("Cannot use special register with this instruction"));
1591 
1592       if (exp.X_op != O_constant)
1593           {
1594           char *opc = NULL;
1595           relax_substateT subtype;
1596 
1597             if (exp.X_md != 0)
1598               subtype = get_imm_otype(exp.X_md);
1599             else
1600               subtype = opcode->inst_offset_type;
1601 
1602             output = frag_var (rs_machine_dependent,
1603                                    isize * 2, /* maxm of 2 words.  */
1604                                    isize,     /* minm of 1 word.  */
1605                                    subtype,   /* PC-relative or not.  */
1606                                    exp.X_add_symbol,
1607                                    exp.X_add_number,
1608                                    opc);
1609             immed = 0;
1610           }
1611       else
1612           {
1613           output = frag_more (isize);
1614           immed = exp.X_add_number;
1615         }
1616 
1617       temp = immed & 0xFFFF8000;
1618       if ((temp != 0) && (temp != 0xFFFF8000))
1619           {
1620           /* Needs an immediate inst.  */
1621             opcode1
1622               = (struct op_code_struct *) str_hash_find (opcode_hash_control,
1623                                                                    "imm");
1624           if (opcode1 == NULL)
1625             {
1626               as_bad (_("unknown opcode \"%s\""), "imm");
1627                 return;
1628             }
1629 
1630           inst1 = opcode1->bit_sequence;
1631           inst1 |= ((immed & 0xFFFF0000) >> 16) & IMM_MASK;
1632           output[0] = INST_BYTE0 (inst1);
1633           output[1] = INST_BYTE1 (inst1);
1634           output[2] = INST_BYTE2 (inst1);
1635           output[3] = INST_BYTE3 (inst1);
1636           output = frag_more (isize);
1637         }
1638 
1639       inst |= (reg1 << RA_LOW) & RA_MASK;
1640       inst |= (immed << IMM_LOW) & IMM_MASK;
1641       break;
1642 
1643     case INST_TYPE_RD_IMM:
1644       if (strcmp (op_end, ""))
1645         op_end = parse_reg (op_end + 1, &reg1);  /* Get rd.  */
1646       else
1647           {
1648           as_fatal (_("Error in statement syntax"));
1649           reg1 = 0;
1650         }
1651       if (strcmp (op_end, ""))
1652         op_end = parse_imm (op_end + 1, & exp, MIN_IMM, MAX_IMM);
1653       else
1654         as_fatal (_("Error in statement syntax"));
1655 
1656       /* Check for spl registers.  */
1657       if (check_spl_reg (&reg1))
1658         as_fatal (_("Cannot use special register with this instruction"));
1659 
1660       if (exp.X_op != O_constant)
1661           {
1662           char *opc = NULL;
1663           relax_substateT subtype;
1664 
1665             if (exp.X_md != 0)
1666               subtype = get_imm_otype(exp.X_md);
1667             else
1668               subtype = opcode->inst_offset_type;
1669 
1670           output = frag_var (rs_machine_dependent,
1671                                    isize * 2, /* maxm of 2 words.  */
1672                                    isize,     /* minm of 1 word.  */
1673                                    subtype,   /* PC-relative or not.  */
1674                                    exp.X_add_symbol,
1675                                    exp.X_add_number,
1676                                    opc);
1677           immed = 0;
1678           }
1679       else
1680           {
1681           output = frag_more (isize);
1682           immed = exp.X_add_number;
1683         }
1684 
1685       temp = immed & 0xFFFF8000;
1686       if ((temp != 0) && (temp != 0xFFFF8000))
1687           {
1688           /* Needs an immediate inst.  */
1689           opcode1
1690               = (struct op_code_struct *) str_hash_find (opcode_hash_control,
1691                                                                    "imm");
1692           if (opcode1 == NULL)
1693             {
1694               as_bad (_("unknown opcode \"%s\""), "imm");
1695               return;
1696             }
1697 
1698           inst1 = opcode1->bit_sequence;
1699           inst1 |= ((immed & 0xFFFF0000) >> 16) & IMM_MASK;
1700           output[0] = INST_BYTE0 (inst1);
1701           output[1] = INST_BYTE1 (inst1);
1702           output[2] = INST_BYTE2 (inst1);
1703           output[3] = INST_BYTE3 (inst1);
1704           output = frag_more (isize);
1705         }
1706 
1707       inst |= (reg1 << RD_LOW) & RD_MASK;
1708       inst |= (immed << IMM_LOW) & IMM_MASK;
1709       break;
1710 
1711     case INST_TYPE_R2:
1712       if (strcmp (op_end, ""))
1713         op_end = parse_reg (op_end + 1, &reg2);  /* Get r2.  */
1714       else
1715           {
1716           as_fatal (_("Error in statement syntax"));
1717           reg2 = 0;
1718         }
1719 
1720       /* Check for spl registers.  */
1721       if (check_spl_reg (&reg2))
1722         as_fatal (_("Cannot use special register with this instruction"));
1723 
1724       inst |= (reg2 << RB_LOW) & RB_MASK;
1725       output = frag_more (isize);
1726       break;
1727 
1728     case INST_TYPE_IMM:
1729       if (streq (name, "imm"))
1730         as_fatal (_("An IMM instruction should not be present in the .s file"));
1731 
1732       op_end = parse_imm (op_end + 1, & exp, MIN_IMM, MAX_IMM);
1733 
1734       if (exp.X_op != O_constant)
1735           {
1736           char *opc = NULL;
1737           relax_substateT subtype;
1738 
1739             if (exp.X_md != 0)
1740               subtype = get_imm_otype(exp.X_md);
1741             else
1742               subtype = opcode->inst_offset_type;
1743 
1744           output = frag_var (rs_machine_dependent,
1745                                    isize * 2, /* maxm of 2 words.  */
1746                                    isize,     /* minm of 1 word.  */
1747                                    subtype,   /* PC-relative or not.  */
1748                                    exp.X_add_symbol,
1749                                    exp.X_add_number,
1750                                    opc);
1751           immed = 0;
1752         }
1753       else
1754           {
1755           output = frag_more (isize);
1756           immed = exp.X_add_number;
1757         }
1758 
1759 
1760       temp = immed & 0xFFFF8000;
1761       if ((temp != 0) && (temp != 0xFFFF8000))
1762           {
1763           /* Needs an immediate inst.  */
1764           opcode1
1765               = (struct op_code_struct *) str_hash_find (opcode_hash_control,
1766                                                                    "imm");
1767           if (opcode1 == NULL)
1768             {
1769               as_bad (_("unknown opcode \"%s\""), "imm");
1770               return;
1771             }
1772 
1773           inst1 = opcode1->bit_sequence;
1774           inst1 |= ((immed & 0xFFFF0000) >> 16) & IMM_MASK;
1775           output[0] = INST_BYTE0 (inst1);
1776           output[1] = INST_BYTE1 (inst1);
1777           output[2] = INST_BYTE2 (inst1);
1778           output[3] = INST_BYTE3 (inst1);
1779           output = frag_more (isize);
1780         }
1781       inst |= (immed << IMM_LOW) & IMM_MASK;
1782       break;
1783 
1784     case INST_TYPE_NONE:
1785       output = frag_more (isize);
1786       break;
1787 
1788     case INST_TYPE_IMM5:
1789       if (strcmp(op_end, ""))
1790         op_end = parse_imm (op_end + 1, & exp, MIN_IMM5, MAX_IMM5);
1791       else
1792         as_fatal(_("Error in statement syntax"));
1793       if (exp.X_op != O_constant) {
1794         as_warn(_("Symbol used as immediate for mbar instruction"));
1795       } else {
1796         output = frag_more (isize);
1797         immed = exp.X_add_number;
1798       }
1799       if (immed != (immed % 32)) {
1800         as_warn(_("Immediate value for mbar > 32. using <value %% 32>"));
1801         immed = immed % 32;
1802       }
1803       inst |= (immed << IMM_MBAR);
1804       break;
1805 
1806     default:
1807       as_fatal (_("unimplemented opcode \"%s\""), name);
1808     }
1809 
1810   /* Drop whitespace after all the operands have been parsed.  */
1811   while (ISSPACE (* op_end))
1812     op_end ++;
1813 
1814   /* Give warning message if the insn has more operands than required.  */
1815   if (strcmp (op_end, opcode->name) && strcmp (op_end, ""))
1816     as_warn (_("ignoring operands: %s "), op_end);
1817 
1818   output[0] = INST_BYTE0 (inst);
1819   output[1] = INST_BYTE1 (inst);
1820   output[2] = INST_BYTE2 (inst);
1821   output[3] = INST_BYTE3 (inst);
1822 
1823 #ifdef OBJ_ELF
1824   dwarf2_emit_insn (4);
1825 #endif
1826 }
1827 
1828 symbolS *
md_undefined_symbol(char * name ATTRIBUTE_UNUSED)1829 md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
1830 {
1831   return NULL;
1832 }
1833 
1834 /* Turn a string in input_line_pointer into a floating point constant of type
1835    type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
1836    emitted is stored in *sizeP.  An error message is returned, or NULL on OK.*/
1837 
1838 const char *
md_atof(int type,char * litP,int * sizeP)1839 md_atof (int type, char * litP, int * sizeP)
1840 {
1841   int prec;
1842   LITTLENUM_TYPE words[MAX_LITTLENUMS];
1843   int    i;
1844   char * t;
1845 
1846   switch (type)
1847     {
1848     case 'f':
1849     case 'F':
1850     case 's':
1851     case 'S':
1852       prec = 2;
1853       break;
1854 
1855     case 'd':
1856     case 'D':
1857     case 'r':
1858     case 'R':
1859       prec = 4;
1860       break;
1861 
1862     case 'x':
1863     case 'X':
1864       prec = 6;
1865       break;
1866 
1867     case 'p':
1868     case 'P':
1869       prec = 6;
1870       break;
1871 
1872     default:
1873       *sizeP = 0;
1874       return _("Bad call to MD_NTOF()");
1875     }
1876 
1877   t = atof_ieee (input_line_pointer, type, words);
1878 
1879   if (t)
1880     input_line_pointer = t;
1881 
1882   *sizeP = prec * sizeof (LITTLENUM_TYPE);
1883 
1884   if (! target_big_endian)
1885     {
1886       for (i = prec - 1; i >= 0; i--)
1887         {
1888           md_number_to_chars (litP, (valueT) words[i],
1889                               sizeof (LITTLENUM_TYPE));
1890           litP += sizeof (LITTLENUM_TYPE);
1891         }
1892     }
1893   else
1894     for (i = 0; i < prec; i++)
1895       {
1896         md_number_to_chars (litP, (valueT) words[i],
1897                             sizeof (LITTLENUM_TYPE));
1898         litP += sizeof (LITTLENUM_TYPE);
1899       }
1900 
1901   return NULL;
1902 }
1903 
1904 const char * md_shortopts = "";
1905 
1906 struct option md_longopts[] =
1907 {
1908   {"EB", no_argument, NULL, OPTION_EB},
1909   {"EL", no_argument, NULL, OPTION_EL},
1910   {"mlittle-endian", no_argument, NULL, OPTION_EL},
1911   {"mbig-endian", no_argument, NULL, OPTION_EB},
1912   { NULL,          no_argument, NULL, 0}
1913 };
1914 
1915 size_t md_longopts_size = sizeof (md_longopts);
1916 
1917 int md_short_jump_size;
1918 
1919 void
md_create_short_jump(char * ptr ATTRIBUTE_UNUSED,addressT from_Nddr ATTRIBUTE_UNUSED,addressT to_Nddr ATTRIBUTE_UNUSED,fragS * frag ATTRIBUTE_UNUSED,symbolS * to_symbol ATTRIBUTE_UNUSED)1920 md_create_short_jump (char * ptr ATTRIBUTE_UNUSED,
1921                           addressT from_Nddr ATTRIBUTE_UNUSED,
1922                           addressT to_Nddr ATTRIBUTE_UNUSED,
1923                           fragS * frag ATTRIBUTE_UNUSED,
1924                           symbolS * to_symbol ATTRIBUTE_UNUSED)
1925 {
1926   as_fatal (_("failed sanity check: short_jump"));
1927 }
1928 
1929 void
md_create_long_jump(char * ptr ATTRIBUTE_UNUSED,addressT from_Nddr ATTRIBUTE_UNUSED,addressT to_Nddr ATTRIBUTE_UNUSED,fragS * frag ATTRIBUTE_UNUSED,symbolS * to_symbol ATTRIBUTE_UNUSED)1930 md_create_long_jump (char * ptr ATTRIBUTE_UNUSED,
1931                          addressT from_Nddr ATTRIBUTE_UNUSED,
1932                          addressT to_Nddr ATTRIBUTE_UNUSED,
1933                          fragS * frag ATTRIBUTE_UNUSED,
1934                          symbolS * to_symbol ATTRIBUTE_UNUSED)
1935 {
1936   as_fatal (_("failed sanity check: long_jump"));
1937 }
1938 
1939 /* Called after relaxing, change the frags so they know how big they are.  */
1940 
1941 void
md_convert_frag(bfd * abfd ATTRIBUTE_UNUSED,segT sec ATTRIBUTE_UNUSED,fragS * fragP)1942 md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
1943                    segT sec ATTRIBUTE_UNUSED,
1944                      fragS * fragP)
1945 {
1946   fixS *fixP;
1947 
1948   switch (fragP->fr_subtype)
1949     {
1950     case UNDEFINED_PC_OFFSET:
1951       fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
1952                  fragP->fr_offset, true, BFD_RELOC_64_PCREL);
1953       fragP->fr_fix += INST_WORD_SIZE * 2;
1954       fragP->fr_var = 0;
1955       break;
1956     case DEFINED_ABS_SEGMENT:
1957       if (fragP->fr_symbol == GOT_symbol)
1958         fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
1959                    fragP->fr_offset, true, BFD_RELOC_MICROBLAZE_64_GOTPC);
1960       else
1961         fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
1962                    fragP->fr_offset, false, BFD_RELOC_64);
1963       fragP->fr_fix += INST_WORD_SIZE * 2;
1964       fragP->fr_var = 0;
1965       break;
1966     case DEFINED_RO_SEGMENT:
1967       fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE, fragP->fr_symbol,
1968                  fragP->fr_offset, false, BFD_RELOC_MICROBLAZE_32_ROSDA);
1969       fragP->fr_fix += INST_WORD_SIZE;
1970       fragP->fr_var = 0;
1971       break;
1972     case DEFINED_RW_SEGMENT:
1973       fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE, fragP->fr_symbol,
1974                  fragP->fr_offset, false, BFD_RELOC_MICROBLAZE_32_RWSDA);
1975       fragP->fr_fix += INST_WORD_SIZE;
1976       fragP->fr_var = 0;
1977       break;
1978     case DEFINED_PC_OFFSET:
1979       fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE, fragP->fr_symbol,
1980                  fragP->fr_offset, true, BFD_RELOC_MICROBLAZE_32_LO_PCREL);
1981       fragP->fr_fix += INST_WORD_SIZE;
1982       fragP->fr_var = 0;
1983       break;
1984     case LARGE_DEFINED_PC_OFFSET:
1985       fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
1986                  fragP->fr_offset, true, BFD_RELOC_64_PCREL);
1987       fragP->fr_fix += INST_WORD_SIZE * 2;
1988       fragP->fr_var = 0;
1989       break;
1990     case GOT_OFFSET:
1991       fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
1992                  fragP->fr_offset, false, BFD_RELOC_MICROBLAZE_64_GOT);
1993       fragP->fr_fix += INST_WORD_SIZE * 2;
1994       fragP->fr_var = 0;
1995       break;
1996     case TEXT_OFFSET:
1997       fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
1998                  fragP->fr_offset, false, BFD_RELOC_MICROBLAZE_64_TEXTREL);
1999       fragP->fr_fix += INST_WORD_SIZE * 2;
2000       fragP->fr_var = 0;
2001       break;
2002     case TEXT_PC_OFFSET:
2003       fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
2004                  fragP->fr_offset, false, BFD_RELOC_MICROBLAZE_64_TEXTPCREL);
2005       fragP->fr_fix += INST_WORD_SIZE * 2;
2006       fragP->fr_var = 0;
2007       break;
2008     case PLT_OFFSET:
2009       fixP = fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
2010                         fragP->fr_offset, true, BFD_RELOC_MICROBLAZE_64_PLT);
2011       /* fixP->fx_plt = 1; */
2012       (void) fixP;
2013       fragP->fr_fix += INST_WORD_SIZE * 2;
2014       fragP->fr_var = 0;
2015       break;
2016     case GOTOFF_OFFSET:
2017       fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
2018                  fragP->fr_offset, false, BFD_RELOC_MICROBLAZE_64_GOTOFF);
2019       fragP->fr_fix += INST_WORD_SIZE * 2;
2020       fragP->fr_var = 0;
2021       break;
2022     case TLSGD_OFFSET:
2023       fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
2024                  fragP->fr_offset, false, BFD_RELOC_MICROBLAZE_64_TLSGD);
2025       fragP->fr_fix += INST_WORD_SIZE * 2;
2026       fragP->fr_var = 0;
2027       break;
2028     case TLSLD_OFFSET:
2029       fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
2030                  fragP->fr_offset, false, BFD_RELOC_MICROBLAZE_64_TLSLD);
2031       fragP->fr_fix += INST_WORD_SIZE * 2;
2032       fragP->fr_var = 0;
2033       break;
2034     case TLSDTPREL_OFFSET:
2035       fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
2036                  fragP->fr_offset, false, BFD_RELOC_MICROBLAZE_64_TLSDTPREL);
2037       fragP->fr_fix += INST_WORD_SIZE * 2;
2038       fragP->fr_var = 0;
2039       break;
2040 
2041     default:
2042       abort ();
2043     }
2044 }
2045 
2046 /* Applies the desired value to the specified location.
2047    Also sets up addends for 'rela' type relocations.  */
2048 void
md_apply_fix(fixS * fixP,valueT * valp,segT segment)2049 md_apply_fix (fixS *   fixP,
2050                 valueT * valp,
2051                 segT     segment)
2052 {
2053   char *       buf  = fixP->fx_where + &fixP->fx_frag->fr_literal[0];
2054   const char *       file = fixP->fx_file ? fixP->fx_file : _("unknown");
2055   const char * symname;
2056   /* Note: use offsetT because it is signed, valueT is unsigned.  */
2057   offsetT      val  = (offsetT) * valp;
2058   int          i;
2059   struct op_code_struct * opcode1;
2060   unsigned long inst1;
2061 
2062   symname = fixP->fx_addsy ? S_GET_NAME (fixP->fx_addsy) : _("<unknown>");
2063 
2064   /* fixP->fx_offset is supposed to be set up correctly for all
2065      symbol relocations.  */
2066   if (fixP->fx_addsy == NULL)
2067     {
2068       if (!fixP->fx_pcrel)
2069         fixP->fx_offset = val; /* Absolute relocation.  */
2070       else
2071         fprintf (stderr, "NULL symbol PC-relative relocation? offset = %08x, val = %08x\n",
2072                  (unsigned int) fixP->fx_offset, (unsigned int) val);
2073     }
2074 
2075   /* If we aren't adjusting this fixup to be against the section
2076      symbol, we need to adjust the value.  */
2077   if (fixP->fx_addsy != NULL)
2078     {
2079       if (S_IS_WEAK (fixP->fx_addsy)
2080             || (symbol_used_in_reloc_p (fixP->fx_addsy)
2081                 && (((bfd_section_flags (S_GET_SEGMENT (fixP->fx_addsy))
2082                         & SEC_LINK_ONCE) != 0)
2083                       || startswith (segment_name (S_GET_SEGMENT (fixP->fx_addsy)),
2084                                          ".gnu.linkonce"))))
2085           {
2086             val -= S_GET_VALUE (fixP->fx_addsy);
2087             if (val != 0 && ! fixP->fx_pcrel)
2088             {
2089               /* In this case, the bfd_install_relocation routine will
2090                  incorrectly add the symbol value back in.  We just want
2091                  the addend to appear in the object file.
2092                    FIXME: If this makes VALUE zero, we're toast.  */
2093               val -= S_GET_VALUE (fixP->fx_addsy);
2094             }
2095           }
2096     }
2097 
2098   /* If the fix is relative to a symbol which is not defined, or not
2099      in the same segment as the fix, we cannot resolve it here.  */
2100   /* fixP->fx_addsy is NULL if valp contains the entire relocation.  */
2101   if (fixP->fx_addsy != NULL
2102       && (!S_IS_DEFINED (fixP->fx_addsy)
2103           || (S_GET_SEGMENT (fixP->fx_addsy) != segment)))
2104     {
2105       fixP->fx_done = 0;
2106 #ifdef OBJ_ELF
2107       /* For ELF we can just return and let the reloc that will be generated
2108          take care of everything.  For COFF we still have to insert 'val'
2109          into the insn since the addend field will be ignored.  */
2110       /* return; */
2111 #endif
2112     }
2113   /* All fixups in the text section must be handled in the linker.  */
2114   else if (segment->flags & SEC_CODE)
2115     fixP->fx_done = 0;
2116   else if (!fixP->fx_pcrel && fixP->fx_addsy != NULL)
2117     fixP->fx_done = 0;
2118   else
2119     fixP->fx_done = 1;
2120 
2121   switch (fixP->fx_r_type)
2122     {
2123     case BFD_RELOC_MICROBLAZE_32_LO:
2124     case BFD_RELOC_MICROBLAZE_32_LO_PCREL:
2125       if (target_big_endian)
2126           {
2127             buf[2] |= ((val >> 8) & 0xff);
2128             buf[3] |= (val & 0xff);
2129           }
2130       else
2131           {
2132             buf[1] |= ((val >> 8) & 0xff);
2133             buf[0] |= (val & 0xff);
2134           }
2135       break;
2136     case BFD_RELOC_MICROBLAZE_32_ROSDA:
2137     case BFD_RELOC_MICROBLAZE_32_RWSDA:
2138       /* Don't do anything if the symbol is not defined.  */
2139       if (fixP->fx_addsy == NULL || S_IS_DEFINED (fixP->fx_addsy))
2140           {
2141             if (((val & 0xFFFF8000) != 0) && ((val & 0xFFFF8000) != 0xFFFF8000))
2142               as_bad_where (file, fixP->fx_line,
2143                                 _("pcrel for branch to %s too far (0x%x)"),
2144                                 symname, (int) val);
2145             if (target_big_endian)
2146               {
2147                 buf[2] |= ((val >> 8) & 0xff);
2148                 buf[3] |= (val & 0xff);
2149               }
2150             else
2151               {
2152                 buf[1] |= ((val >> 8) & 0xff);
2153                 buf[0] |= (val & 0xff);
2154               }
2155           }
2156       break;
2157     case BFD_RELOC_32:
2158     case BFD_RELOC_RVA:
2159     case BFD_RELOC_32_PCREL:
2160     case BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM:
2161       /* Don't do anything if the symbol is not defined.  */
2162       if (fixP->fx_addsy == NULL || S_IS_DEFINED (fixP->fx_addsy))
2163           {
2164             if (target_big_endian)
2165               {
2166                 buf[0] |= ((val >> 24) & 0xff);
2167                 buf[1] |= ((val >> 16) & 0xff);
2168                 buf[2] |= ((val >> 8) & 0xff);
2169                 buf[3] |= (val & 0xff);
2170               }
2171             else
2172               {
2173                 buf[3] |= ((val >> 24) & 0xff);
2174                 buf[2] |= ((val >> 16) & 0xff);
2175                 buf[1] |= ((val >> 8) & 0xff);
2176                 buf[0] |= (val & 0xff);
2177               }
2178           }
2179       break;
2180     case BFD_RELOC_64_PCREL:
2181     case BFD_RELOC_64:
2182     case BFD_RELOC_MICROBLAZE_64_TEXTREL:
2183       /* Add an imm instruction.  First save the current instruction.  */
2184       for (i = 0; i < INST_WORD_SIZE; i++)
2185           buf[i + INST_WORD_SIZE] = buf[i];
2186 
2187       /* Generate the imm instruction.  */
2188       opcode1
2189           = (struct op_code_struct *) str_hash_find (opcode_hash_control, "imm");
2190       if (opcode1 == NULL)
2191           {
2192             as_bad (_("unknown opcode \"%s\""), "imm");
2193             return;
2194           }
2195 
2196       inst1 = opcode1->bit_sequence;
2197       if (fixP->fx_addsy == NULL || S_IS_DEFINED (fixP->fx_addsy))
2198           inst1 |= ((val & 0xFFFF0000) >> 16) & IMM_MASK;
2199 
2200       buf[0] = INST_BYTE0 (inst1);
2201       buf[1] = INST_BYTE1 (inst1);
2202       buf[2] = INST_BYTE2 (inst1);
2203       buf[3] = INST_BYTE3 (inst1);
2204 
2205       /* Add the value only if the symbol is defined.  */
2206       if (fixP->fx_addsy == NULL || S_IS_DEFINED (fixP->fx_addsy))
2207           {
2208             if (target_big_endian)
2209               {
2210                 buf[6] |= ((val >> 8) & 0xff);
2211                 buf[7] |= (val & 0xff);
2212               }
2213             else
2214               {
2215                 buf[5] |= ((val >> 8) & 0xff);
2216                 buf[4] |= (val & 0xff);
2217               }
2218           }
2219       break;
2220 
2221     case BFD_RELOC_MICROBLAZE_64_TLSDTPREL:
2222     case BFD_RELOC_MICROBLAZE_64_TLSGD:
2223     case BFD_RELOC_MICROBLAZE_64_TLSLD:
2224       S_SET_THREAD_LOCAL (fixP->fx_addsy);
2225       /* Fall through.  */
2226 
2227     case BFD_RELOC_MICROBLAZE_64_GOTPC:
2228     case BFD_RELOC_MICROBLAZE_64_GOT:
2229     case BFD_RELOC_MICROBLAZE_64_PLT:
2230     case BFD_RELOC_MICROBLAZE_64_GOTOFF:
2231     case BFD_RELOC_MICROBLAZE_64_TEXTPCREL:
2232       /* Add an imm instruction.  First save the current instruction.  */
2233       for (i = 0; i < INST_WORD_SIZE; i++)
2234           buf[i + INST_WORD_SIZE] = buf[i];
2235 
2236       /* Generate the imm instruction.  */
2237       opcode1
2238           = (struct op_code_struct *) str_hash_find (opcode_hash_control, "imm");
2239       if (opcode1 == NULL)
2240           {
2241             as_bad (_("unknown opcode \"%s\""), "imm");
2242             return;
2243           }
2244 
2245       inst1 = opcode1->bit_sequence;
2246 
2247       /* We can fixup call to a defined non-global address
2248            within the same section only.  */
2249       buf[0] = INST_BYTE0 (inst1);
2250       buf[1] = INST_BYTE1 (inst1);
2251       buf[2] = INST_BYTE2 (inst1);
2252       buf[3] = INST_BYTE3 (inst1);
2253       return;
2254 
2255     default:
2256       break;
2257     }
2258 
2259   if (fixP->fx_addsy == NULL)
2260     {
2261       /* This fixup has been resolved.  Create a reloc in case the linker
2262            moves code around due to relaxing.  */
2263       if (fixP->fx_r_type == BFD_RELOC_64_PCREL)
2264           fixP->fx_r_type = BFD_RELOC_MICROBLAZE_64_NONE;
2265       else if (fixP->fx_r_type == BFD_RELOC_32)
2266           fixP->fx_r_type = BFD_RELOC_MICROBLAZE_32_NONE;
2267       else
2268           fixP->fx_r_type = BFD_RELOC_NONE;
2269       fixP->fx_addsy = section_symbol (absolute_section);
2270     }
2271   return;
2272 }
2273 
2274 void
md_operand(expressionS * expressionP)2275 md_operand (expressionS * expressionP)
2276 {
2277   /* Ignore leading hash symbol, if present.  */
2278   if (*input_line_pointer == '#')
2279     {
2280       input_line_pointer ++;
2281       expression (expressionP);
2282     }
2283 }
2284 
2285 /* Called just before address relaxation, return the length
2286    by which a fragment must grow to reach it's destination.  */
2287 
2288 int
md_estimate_size_before_relax(fragS * fragP,segT segment_type)2289 md_estimate_size_before_relax (fragS * fragP,
2290                                      segT segment_type)
2291 {
2292   sbss_segment = bfd_get_section_by_name (stdoutput, ".sbss");
2293   sbss2_segment = bfd_get_section_by_name (stdoutput, ".sbss2");
2294   sdata_segment = bfd_get_section_by_name (stdoutput, ".sdata");
2295   sdata2_segment = bfd_get_section_by_name (stdoutput, ".sdata2");
2296 
2297   switch (fragP->fr_subtype)
2298     {
2299     case INST_PC_OFFSET:
2300       /* Used to be a PC-relative branch.  */
2301       if (!fragP->fr_symbol)
2302         {
2303           /* We know the abs value: Should never happen.  */
2304           as_bad (_("Absolute PC-relative value in relaxation code.  Assembler error....."));
2305           abort ();
2306         }
2307       else if (S_GET_SEGMENT (fragP->fr_symbol) == segment_type &&
2308                !S_IS_WEAK (fragP->fr_symbol))
2309         {
2310           fragP->fr_subtype = DEFINED_PC_OFFSET;
2311           /* Don't know now whether we need an imm instruction.  */
2312           fragP->fr_var = INST_WORD_SIZE;
2313         }
2314       else if (S_IS_DEFINED (fragP->fr_symbol)
2315                  && (((S_GET_SEGMENT (fragP->fr_symbol))->flags & SEC_CODE) == 0))
2316         {
2317           /* Cannot have a PC-relative branch to a diff segment.  */
2318           as_bad (_("PC relative branch to label %s which is not in the instruction space"),
2319                       S_GET_NAME (fragP->fr_symbol));
2320           fragP->fr_subtype = UNDEFINED_PC_OFFSET;
2321           fragP->fr_var = INST_WORD_SIZE*2;
2322         }
2323       else
2324           {
2325             fragP->fr_subtype = UNDEFINED_PC_OFFSET;
2326             fragP->fr_var = INST_WORD_SIZE*2;
2327           }
2328       break;
2329 
2330     case INST_NO_OFFSET:
2331     case TEXT_OFFSET:
2332       /* Used to be a reference to somewhere which was unknown.  */
2333       if (fragP->fr_symbol)
2334         {
2335             if (fragP->fr_opcode == NULL)
2336               {
2337                 /* Used as an absolute value.  */
2338                 if (fragP->fr_subtype == INST_NO_OFFSET)
2339                   fragP->fr_subtype = DEFINED_ABS_SEGMENT;
2340                 /* Variable part does not change.  */
2341                 fragP->fr_var = INST_WORD_SIZE*2;
2342               }
2343             else if (streq (fragP->fr_opcode, str_microblaze_ro_anchor))
2344               {
2345               /* It is accessed using the small data read only anchor.  */
2346               if ((S_GET_SEGMENT (fragP->fr_symbol) == bfd_com_section_ptr)
2347                       || (S_GET_SEGMENT (fragP->fr_symbol) == sdata2_segment)
2348                       || (S_GET_SEGMENT (fragP->fr_symbol) == sbss2_segment)
2349                       || (! S_IS_DEFINED (fragP->fr_symbol)))
2350                     {
2351                   fragP->fr_subtype = DEFINED_RO_SEGMENT;
2352                   fragP->fr_var = INST_WORD_SIZE;
2353                 }
2354                 else
2355                     {
2356                   /* Variable not in small data read only segment accessed
2357                          using small data read only anchor.  */
2358                   const char *file = fragP->fr_file ? fragP->fr_file : _("unknown");
2359 
2360                   as_bad_where (file, fragP->fr_line,
2361                                 _("Variable is accessed using small data read "
2362                                           "only anchor, but it is not in the small data "
2363                                         "read only section"));
2364                   fragP->fr_subtype = DEFINED_RO_SEGMENT;
2365                   fragP->fr_var = INST_WORD_SIZE;
2366                 }
2367             }
2368             else if (streq (fragP->fr_opcode, str_microblaze_rw_anchor))
2369               {
2370               if ((S_GET_SEGMENT (fragP->fr_symbol) == bfd_com_section_ptr)
2371                       || (S_GET_SEGMENT (fragP->fr_symbol) == sdata_segment)
2372                       || (S_GET_SEGMENT (fragP->fr_symbol) == sbss_segment)
2373                       || (!S_IS_DEFINED (fragP->fr_symbol)))
2374                   {
2375                   /* It is accessed using the small data read write anchor.  */
2376                   fragP->fr_subtype = DEFINED_RW_SEGMENT;
2377                   fragP->fr_var = INST_WORD_SIZE;
2378                 }
2379                 else
2380                     {
2381                   const char *file = fragP->fr_file ? fragP->fr_file : _("unknown");
2382 
2383                   as_bad_where (file, fragP->fr_line,
2384                                 _("Variable is accessed using small data read "
2385                                           "write anchor, but it is not in the small data "
2386                                           "read write section"));
2387                   fragP->fr_subtype = DEFINED_RW_SEGMENT;
2388                   fragP->fr_var = INST_WORD_SIZE;
2389                 }
2390             }
2391           else
2392               {
2393               as_bad (_("Incorrect fr_opcode value in frag.  Internal error....."));
2394               abort ();
2395             }
2396           }
2397       else
2398           {
2399             /* We know the abs value: Should never happen.  */
2400             as_bad (_("Absolute value in relaxation code.  Assembler error....."));
2401             abort ();
2402           }
2403       break;
2404 
2405     case UNDEFINED_PC_OFFSET:
2406     case LARGE_DEFINED_PC_OFFSET:
2407     case DEFINED_ABS_SEGMENT:
2408     case GOT_OFFSET:
2409     case PLT_OFFSET:
2410     case GOTOFF_OFFSET:
2411     case TEXT_PC_OFFSET:
2412     case TLSGD_OFFSET:
2413     case TLSLD_OFFSET:
2414     case TLSTPREL_OFFSET:
2415     case TLSDTPREL_OFFSET:
2416       fragP->fr_var = INST_WORD_SIZE*2;
2417       break;
2418     case DEFINED_RO_SEGMENT:
2419     case DEFINED_RW_SEGMENT:
2420     case DEFINED_PC_OFFSET:
2421     case TLSDTPMOD_OFFSET:
2422       fragP->fr_var = INST_WORD_SIZE;
2423       break;
2424     default:
2425       abort ();
2426     }
2427 
2428   return fragP->fr_var;
2429 }
2430 
2431 /* Put number into target byte order.  */
2432 
2433 void
md_number_to_chars(char * ptr,valueT use,int nbytes)2434 md_number_to_chars (char * ptr, valueT use, int nbytes)
2435 {
2436   if (target_big_endian)
2437     number_to_chars_bigendian (ptr, use, nbytes);
2438   else
2439     number_to_chars_littleendian (ptr, use, nbytes);
2440 }
2441 
2442 /* Round up a section size to the appropriate boundary.  */
2443 
2444 valueT
md_section_align(segT segment ATTRIBUTE_UNUSED,valueT size)2445 md_section_align (segT segment ATTRIBUTE_UNUSED, valueT size)
2446 {
2447   return size;                          /* Byte alignment is fine.  */
2448 }
2449 
2450 
2451 /* The location from which a PC relative jump should be calculated,
2452    given a PC relative reloc.  */
2453 
2454 long
md_pcrel_from_section(fixS * fixp,segT sec ATTRIBUTE_UNUSED)2455 md_pcrel_from_section (fixS * fixp, segT sec ATTRIBUTE_UNUSED)
2456 {
2457 #ifdef OBJ_ELF
2458   /* If the symbol is undefined or defined in another section
2459      we leave the add number alone for the linker to fix it later.
2460      Only account for the PC pre-bump (No PC-pre-bump on the Microblaze). */
2461 
2462   if (fixp->fx_addsy != (symbolS *) NULL
2463       && (!S_IS_DEFINED (fixp->fx_addsy)
2464           || (S_GET_SEGMENT (fixp->fx_addsy) != sec)))
2465     return 0;
2466   else
2467     {
2468       /* The case where we are going to resolve things... */
2469       if (fixp->fx_r_type == BFD_RELOC_64_PCREL)
2470         return  fixp->fx_where + fixp->fx_frag->fr_address + INST_WORD_SIZE;
2471       else
2472         return  fixp->fx_where + fixp->fx_frag->fr_address;
2473     }
2474 #endif
2475 }
2476 
2477 
2478 #define F(SZ,PCREL)           (((SZ) << 1) + (PCREL))
2479 #define MAP(SZ,PCREL,TYPE)    case F (SZ, PCREL): code = (TYPE); break
2480 
2481 arelent *
tc_gen_reloc(asection * section ATTRIBUTE_UNUSED,fixS * fixp)2482 tc_gen_reloc (asection * section ATTRIBUTE_UNUSED, fixS * fixp)
2483 {
2484   arelent * rel;
2485   bfd_reloc_code_real_type code;
2486 
2487   switch (fixp->fx_r_type)
2488     {
2489     case BFD_RELOC_NONE:
2490     case BFD_RELOC_MICROBLAZE_32_NONE:
2491     case BFD_RELOC_MICROBLAZE_64_NONE:
2492     case BFD_RELOC_32:
2493     case BFD_RELOC_MICROBLAZE_32_LO:
2494     case BFD_RELOC_MICROBLAZE_32_LO_PCREL:
2495     case BFD_RELOC_RVA:
2496     case BFD_RELOC_64:
2497     case BFD_RELOC_64_PCREL:
2498     case BFD_RELOC_MICROBLAZE_32_ROSDA:
2499     case BFD_RELOC_MICROBLAZE_32_RWSDA:
2500     case BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM:
2501     case BFD_RELOC_MICROBLAZE_64_GOTPC:
2502     case BFD_RELOC_MICROBLAZE_64_GOT:
2503     case BFD_RELOC_MICROBLAZE_64_PLT:
2504     case BFD_RELOC_MICROBLAZE_64_GOTOFF:
2505     case BFD_RELOC_MICROBLAZE_32_GOTOFF:
2506     case BFD_RELOC_MICROBLAZE_64_TLSGD:
2507     case BFD_RELOC_MICROBLAZE_64_TLSLD:
2508     case BFD_RELOC_MICROBLAZE_32_TLSDTPMOD:
2509     case BFD_RELOC_MICROBLAZE_32_TLSDTPREL:
2510     case BFD_RELOC_MICROBLAZE_64_TLSDTPREL:
2511     case BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL:
2512     case BFD_RELOC_MICROBLAZE_64_TLSTPREL:
2513     case BFD_RELOC_MICROBLAZE_64_TEXTPCREL:
2514     case BFD_RELOC_MICROBLAZE_64_TEXTREL:
2515       code = fixp->fx_r_type;
2516       break;
2517 
2518     default:
2519       switch (F (fixp->fx_size, fixp->fx_pcrel))
2520         {
2521           MAP (1, 0, BFD_RELOC_8);
2522           MAP (2, 0, BFD_RELOC_16);
2523           MAP (4, 0, BFD_RELOC_32);
2524           MAP (1, 1, BFD_RELOC_8_PCREL);
2525           MAP (2, 1, BFD_RELOC_16_PCREL);
2526           MAP (4, 1, BFD_RELOC_32_PCREL);
2527         default:
2528           code = fixp->fx_r_type;
2529           as_bad (_("Can not do %d byte %srelocation"),
2530                   fixp->fx_size,
2531                   fixp->fx_pcrel ? _("pc-relative ") : "");
2532         }
2533       break;
2534     }
2535 
2536   rel = XNEW (arelent);
2537   rel->sym_ptr_ptr = XNEW (asymbol *);
2538 
2539   if (code == BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM)
2540     *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
2541   else
2542     *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
2543 
2544   rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
2545   /* Always pass the addend along!  */
2546   rel->addend = fixp->fx_offset;
2547   rel->howto = bfd_reloc_type_lookup (stdoutput, code);
2548 
2549   if (rel->howto == NULL)
2550     {
2551       as_bad_where (fixp->fx_file, fixp->fx_line,
2552                     _("Cannot represent relocation type %s"),
2553                     bfd_get_reloc_code_name (code));
2554 
2555       /* Set howto to a garbage value so that we can keep going.  */
2556       rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
2557       gas_assert (rel->howto != NULL);
2558     }
2559   return rel;
2560 }
2561 
2562 int
md_parse_option(int c,const char * arg ATTRIBUTE_UNUSED)2563 md_parse_option (int c, const char * arg ATTRIBUTE_UNUSED)
2564 {
2565   switch (c)
2566     {
2567     case OPTION_EB:
2568       target_big_endian = 1;
2569       break;
2570     case OPTION_EL:
2571       target_big_endian = 0;
2572       break;
2573     default:
2574       return 0;
2575     }
2576   return 1;
2577 }
2578 
2579 void
md_show_usage(FILE * stream ATTRIBUTE_UNUSED)2580 md_show_usage (FILE * stream ATTRIBUTE_UNUSED)
2581 {
2582   /*  fprintf(stream, _("\
2583       MicroBlaze options:\n\
2584       -noSmall         Data in the comm and data sections do not go into the small data section\n")); */
2585   fprintf (stream, _(" MicroBlaze specific assembler options:\n"));
2586   fprintf (stream, "  -%-23s%s\n", "mbig-endian", N_("assemble for a big endian cpu"));
2587   fprintf (stream, "  -%-23s%s\n", "mlittle-endian", N_("assemble for a little endian cpu"));
2588 }
2589 
2590 
2591 /* Create a fixup for a cons expression.  If parse_cons_expression_microblaze
2592    found a machine specific op in an expression,
2593    then we create relocs accordingly.  */
2594 
2595 void
cons_fix_new_microblaze(fragS * frag,int where,int size,expressionS * exp,bfd_reloc_code_real_type r)2596 cons_fix_new_microblaze (fragS * frag,
2597                                int where,
2598                                int size,
2599                                expressionS *exp,
2600                                bfd_reloc_code_real_type r)
2601 {
2602   if ((exp->X_op == O_subtract) && (exp->X_add_symbol) &&
2603       (exp->X_op_symbol) && (now_seg != absolute_section) && (size == 4)
2604       && (!S_IS_LOCAL (exp->X_op_symbol)))
2605     r = BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM;
2606   else if (exp->X_md == IMM_GOTOFF && exp->X_op == O_symbol_rva)
2607     {
2608       exp->X_op = O_symbol;
2609       r = BFD_RELOC_MICROBLAZE_32_GOTOFF;
2610     }
2611   else
2612     {
2613       switch (size)
2614         {
2615         case 1:
2616           r = BFD_RELOC_8;
2617           break;
2618         case 2:
2619           r = BFD_RELOC_16;
2620           break;
2621         case 4:
2622           r = BFD_RELOC_32;
2623           break;
2624         case 8:
2625           r = BFD_RELOC_64;
2626           break;
2627         default:
2628           as_bad (_("unsupported BFD relocation size %u"), size);
2629           r = BFD_RELOC_32;
2630           break;
2631         }
2632     }
2633   fix_new_exp (frag, where, size, exp, 0, r);
2634 }
2635