Fix: nm: SEGV at bfd/elf.c:2267 in _bfd_elf_get_dynamic_symbols
[binutils-gdb.git] / gas / config / tc-frv.c
blob43783b8004bbd513286d1008e8c4e14af2cc5d84
1 /* tc-frv.c -- Assembler for the Fujitsu FRV.
2 Copyright (C) 2002-2023 Free Software Foundation, Inc.
4 This file is part of GAS, the GNU Assembler.
6 GAS is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
11 GAS is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GAS; see the file COPYING. If not, write to
18 the Free Software Foundation, 51 Franklin Street - Fifth Floor,
19 Boston, MA 02110-1301, USA. */
21 #include "as.h"
22 #include "subsegs.h"
23 #include "symcat.h"
24 #include "opcodes/frv-desc.h"
25 #include "opcodes/frv-opc.h"
26 #include "cgen.h"
27 #include "elf/common.h"
28 #include "elf/frv.h"
29 #include "dwarf2dbg.h"
31 /* Structure to hold all of the different components describing
32 an individual instruction. */
33 typedef struct
35 const CGEN_INSN * insn;
36 const CGEN_INSN * orig_insn;
37 CGEN_FIELDS fields;
38 #if CGEN_INT_INSN_P
39 CGEN_INSN_INT buffer [1];
40 #define INSN_VALUE(buf) (*(buf))
41 #else
42 unsigned char buffer [CGEN_MAX_INSN_SIZE];
43 #define INSN_VALUE(buf) (buf)
44 #endif
45 char * addr;
46 fragS * frag;
47 int num_fixups;
48 fixS * fixups [GAS_CGEN_MAX_FIXUPS];
49 int indices [MAX_OPERAND_INSTANCES];
51 frv_insn;
53 enum vliw_insn_type
55 VLIW_GENERIC_TYPE, /* Don't care about this insn. */
56 VLIW_BRANCH_TYPE, /* A Branch. */
57 VLIW_LABEL_TYPE, /* A Label. */
58 VLIW_NOP_TYPE, /* A NOP. */
59 VLIW_BRANCH_HAS_NOPS /* A Branch that requires NOPS. */
62 /* We're going to use these in the fr_subtype field to mark
63 whether to keep inserted nops. */
65 #define NOP_KEEP 1 /* Keep these NOPS. */
66 #define NOP_DELETE 2 /* Delete these NOPS. */
68 #define DO_COUNT true
69 #define DONT_COUNT false
71 /* A list of insns within a VLIW insn. */
72 struct vliw_insn_list
74 /* The type of this insn. */
75 enum vliw_insn_type type;
77 /* The corresponding gas insn information. */
78 const CGEN_INSN *insn;
80 /* For branches and labels, the symbol that is referenced. */
81 symbolS *sym;
83 /* For branches, the frag containing the single nop that was generated. */
84 fragS *snop_frag;
86 /* For branches, the frag containing the double nop that was generated. */
87 fragS *dnop_frag;
89 /* Pointer to raw data for this insn. */
90 char *address;
92 /* Next insn in list. */
93 struct vliw_insn_list *next;
96 static struct vliw_insn_list single_nop_insn = {
97 VLIW_NOP_TYPE, NULL, NULL, NULL, NULL, NULL, NULL };
99 static struct vliw_insn_list double_nop_insn = {
100 VLIW_NOP_TYPE, NULL, NULL, NULL, NULL, NULL, NULL };
102 struct vliw_chain
104 int num;
105 int insn_count;
106 struct vliw_insn_list *insn_list;
107 struct vliw_chain *next;
110 static struct vliw_chain *vliw_chain_top;
111 static struct vliw_chain *current_vliw_chain;
112 static struct vliw_chain *previous_vliw_chain;
113 static struct vliw_insn_list *current_vliw_insn;
115 const char comment_chars[] = ";";
116 const char line_comment_chars[] = "#";
117 const char line_separator_chars[] = "!";
118 const char EXP_CHARS[] = "eE";
119 const char FLT_CHARS[] = "dD";
121 static FRV_VLIW vliw;
123 /* Default machine */
125 #ifdef DEFAULT_CPU_FRV
126 #define DEFAULT_MACHINE bfd_mach_frv
127 #define DEFAULT_FLAGS EF_FRV_CPU_GENERIC
129 #else
130 #ifdef DEFAULT_CPU_FR300
131 #define DEFAULT_MACHINE bfd_mach_fr300
132 #define DEFAULT_FLAGS EF_FRV_CPU_FR300
134 #else
135 #ifdef DEFAULT_CPU_SIMPLE
136 #define DEFAULT_MACHINE bfd_mach_frvsimple
137 #define DEFAULT_FLAGS EF_FRV_CPU_SIMPLE
139 #else
140 #ifdef DEFAULT_CPU_TOMCAT
141 #define DEFAULT_MACHINE bfd_mach_frvtomcat
142 #define DEFAULT_FLAGS EF_FRV_CPU_TOMCAT
144 #else
145 #ifdef DEFAULT_CPU_FR400
146 #define DEFAULT_MACHINE bfd_mach_fr400
147 #define DEFAULT_FLAGS EF_FRV_CPU_FR400
149 #else
150 #ifdef DEFAULT_CPU_FR550
151 #define DEFAULT_MACHINE bfd_mach_fr550
152 #define DEFAULT_FLAGS EF_FRV_CPU_FR550
154 #else
155 #define DEFAULT_MACHINE bfd_mach_fr500
156 #define DEFAULT_FLAGS EF_FRV_CPU_FR500
157 #endif
158 #endif
159 #endif
160 #endif
161 #endif
162 #endif
164 #ifdef TE_LINUX
165 # define DEFAULT_FDPIC EF_FRV_FDPIC
166 #else
167 # define DEFAULT_FDPIC 0
168 #endif
170 static unsigned long frv_mach = bfd_mach_frv;
171 static bool fr400_audio;
173 /* Flags to set in the elf header */
174 static flagword frv_flags = DEFAULT_FLAGS | DEFAULT_FDPIC;
176 static int frv_user_set_flags_p = 0;
177 static int frv_pic_p = 0;
178 static const char *frv_pic_flag = DEFAULT_FDPIC ? "-mfdpic" : (const char *)0;
180 /* Print tomcat-specific debugging info. */
181 static int tomcat_debug = 0;
183 /* Tomcat-specific NOP statistics. */
184 static int tomcat_stats = 0;
185 static int tomcat_doubles = 0;
186 static int tomcat_singles = 0;
188 /* Forward reference to static functions */
189 static void frv_set_flags (int);
190 static void frv_pic_ptr (int);
192 /* The target specific pseudo-ops which we support. */
193 const pseudo_typeS md_pseudo_table[] =
195 { "eflags", frv_set_flags, 0 },
196 { "word", cons, 4 },
197 { "picptr", frv_pic_ptr, 4 },
198 { NULL, NULL, 0 }
202 #define FRV_SHORTOPTS "G:"
203 const char * md_shortopts = FRV_SHORTOPTS;
205 #define OPTION_GPR_32 (OPTION_MD_BASE)
206 #define OPTION_GPR_64 (OPTION_MD_BASE + 1)
207 #define OPTION_FPR_32 (OPTION_MD_BASE + 2)
208 #define OPTION_FPR_64 (OPTION_MD_BASE + 3)
209 #define OPTION_SOFT_FLOAT (OPTION_MD_BASE + 4)
210 #define OPTION_DWORD_YES (OPTION_MD_BASE + 5)
211 #define OPTION_DWORD_NO (OPTION_MD_BASE + 6)
212 #define OPTION_DOUBLE (OPTION_MD_BASE + 7)
213 #define OPTION_NO_DOUBLE (OPTION_MD_BASE + 8)
214 #define OPTION_MEDIA (OPTION_MD_BASE + 9)
215 #define OPTION_NO_MEDIA (OPTION_MD_BASE + 10)
216 #define OPTION_CPU (OPTION_MD_BASE + 11)
217 #define OPTION_PIC (OPTION_MD_BASE + 12)
218 #define OPTION_BIGPIC (OPTION_MD_BASE + 13)
219 #define OPTION_LIBPIC (OPTION_MD_BASE + 14)
220 #define OPTION_MULADD (OPTION_MD_BASE + 15)
221 #define OPTION_NO_MULADD (OPTION_MD_BASE + 16)
222 #define OPTION_TOMCAT_DEBUG (OPTION_MD_BASE + 17)
223 #define OPTION_TOMCAT_STATS (OPTION_MD_BASE + 18)
224 #define OPTION_PACK (OPTION_MD_BASE + 19)
225 #define OPTION_NO_PACK (OPTION_MD_BASE + 20)
226 #define OPTION_FDPIC (OPTION_MD_BASE + 21)
227 #define OPTION_NOPIC (OPTION_MD_BASE + 22)
229 struct option md_longopts[] =
231 { "mgpr-32", no_argument, NULL, OPTION_GPR_32 },
232 { "mgpr-64", no_argument, NULL, OPTION_GPR_64 },
233 { "mfpr-32", no_argument, NULL, OPTION_FPR_32 },
234 { "mfpr-64", no_argument, NULL, OPTION_FPR_64 },
235 { "mhard-float", no_argument, NULL, OPTION_FPR_64 },
236 { "msoft-float", no_argument, NULL, OPTION_SOFT_FLOAT },
237 { "mdword", no_argument, NULL, OPTION_DWORD_YES },
238 { "mno-dword", no_argument, NULL, OPTION_DWORD_NO },
239 { "mdouble", no_argument, NULL, OPTION_DOUBLE },
240 { "mno-double", no_argument, NULL, OPTION_NO_DOUBLE },
241 { "mmedia", no_argument, NULL, OPTION_MEDIA },
242 { "mno-media", no_argument, NULL, OPTION_NO_MEDIA },
243 { "mcpu", required_argument, NULL, OPTION_CPU },
244 { "mpic", no_argument, NULL, OPTION_PIC },
245 { "mPIC", no_argument, NULL, OPTION_BIGPIC },
246 { "mlibrary-pic", no_argument, NULL, OPTION_LIBPIC },
247 { "mmuladd", no_argument, NULL, OPTION_MULADD },
248 { "mno-muladd", no_argument, NULL, OPTION_NO_MULADD },
249 { "mtomcat-debug", no_argument, NULL, OPTION_TOMCAT_DEBUG },
250 { "mtomcat-stats", no_argument, NULL, OPTION_TOMCAT_STATS },
251 { "mpack", no_argument, NULL, OPTION_PACK },
252 { "mno-pack", no_argument, NULL, OPTION_NO_PACK },
253 { "mfdpic", no_argument, NULL, OPTION_FDPIC },
254 { "mnopic", no_argument, NULL, OPTION_NOPIC },
255 { NULL, no_argument, NULL, 0 },
258 size_t md_longopts_size = sizeof (md_longopts);
260 /* What value to give to bfd_set_gp_size. */
261 static int g_switch_value = 8;
264 md_parse_option (int c, const char *arg)
266 switch (c)
268 default:
269 return 0;
271 case 'G':
272 g_switch_value = atoi (arg);
273 if (! g_switch_value)
274 frv_flags |= EF_FRV_G0;
275 break;
277 case OPTION_GPR_32:
278 frv_flags = (frv_flags & ~EF_FRV_GPR_MASK) | EF_FRV_GPR_32;
279 break;
281 case OPTION_GPR_64:
282 frv_flags = (frv_flags & ~EF_FRV_GPR_MASK) | EF_FRV_GPR_64;
283 break;
285 case OPTION_FPR_32:
286 frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_32;
287 break;
289 case OPTION_FPR_64:
290 frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_64;
291 break;
293 case OPTION_SOFT_FLOAT:
294 frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_NONE;
295 break;
297 case OPTION_DWORD_YES:
298 frv_flags = (frv_flags & ~EF_FRV_DWORD_MASK) | EF_FRV_DWORD_YES;
299 break;
301 case OPTION_DWORD_NO:
302 frv_flags = (frv_flags & ~EF_FRV_DWORD_MASK) | EF_FRV_DWORD_NO;
303 break;
305 case OPTION_DOUBLE:
306 frv_flags |= EF_FRV_DOUBLE;
307 break;
309 case OPTION_NO_DOUBLE:
310 frv_flags &= ~EF_FRV_DOUBLE;
311 break;
313 case OPTION_MEDIA:
314 frv_flags |= EF_FRV_MEDIA;
315 break;
317 case OPTION_NO_MEDIA:
318 frv_flags &= ~EF_FRV_MEDIA;
319 break;
321 case OPTION_MULADD:
322 frv_flags |= EF_FRV_MULADD;
323 break;
325 case OPTION_NO_MULADD:
326 frv_flags &= ~EF_FRV_MULADD;
327 break;
329 case OPTION_PACK:
330 frv_flags &= ~EF_FRV_NOPACK;
331 break;
333 case OPTION_NO_PACK:
334 frv_flags |= EF_FRV_NOPACK;
335 break;
337 case OPTION_CPU:
339 const char *p;
340 int cpu_flags = EF_FRV_CPU_GENERIC;
342 /* Identify the processor type */
343 p = arg;
344 if (strcmp (p, "frv") == 0)
346 cpu_flags = EF_FRV_CPU_GENERIC;
347 frv_mach = bfd_mach_frv;
350 else if (strcmp (p, "fr500") == 0)
352 cpu_flags = EF_FRV_CPU_FR500;
353 frv_mach = bfd_mach_fr500;
356 else if (strcmp (p, "fr550") == 0)
358 cpu_flags = EF_FRV_CPU_FR550;
359 frv_mach = bfd_mach_fr550;
362 else if (strcmp (p, "fr450") == 0)
364 cpu_flags = EF_FRV_CPU_FR450;
365 frv_mach = bfd_mach_fr450;
368 else if (strcmp (p, "fr405") == 0)
370 cpu_flags = EF_FRV_CPU_FR405;
371 frv_mach = bfd_mach_fr400;
372 fr400_audio = true;
375 else if (strcmp (p, "fr400") == 0)
377 cpu_flags = EF_FRV_CPU_FR400;
378 frv_mach = bfd_mach_fr400;
379 fr400_audio = false;
382 else if (strcmp (p, "fr300") == 0)
384 cpu_flags = EF_FRV_CPU_FR300;
385 frv_mach = bfd_mach_fr300;
388 else if (strcmp (p, "simple") == 0)
390 cpu_flags = EF_FRV_CPU_SIMPLE;
391 frv_mach = bfd_mach_frvsimple;
392 frv_flags |= EF_FRV_NOPACK;
395 else if (strcmp (p, "tomcat") == 0)
397 cpu_flags = EF_FRV_CPU_TOMCAT;
398 frv_mach = bfd_mach_frvtomcat;
401 else
403 as_fatal (_("Unknown cpu -mcpu=%s"), arg);
404 return 0;
407 frv_flags = (frv_flags & ~EF_FRV_CPU_MASK) | cpu_flags;
409 break;
411 case OPTION_PIC:
412 frv_flags |= EF_FRV_PIC;
413 frv_pic_p = 1;
414 frv_pic_flag = "-fpic";
415 break;
417 case OPTION_BIGPIC:
418 frv_flags |= EF_FRV_BIGPIC;
419 frv_pic_p = 1;
420 frv_pic_flag = "-fPIC";
421 break;
423 case OPTION_LIBPIC:
424 frv_flags |= (EF_FRV_LIBPIC | EF_FRV_G0);
425 frv_pic_p = 1;
426 frv_pic_flag = "-mlibrary-pic";
427 g_switch_value = 0;
428 break;
430 case OPTION_FDPIC:
431 frv_flags |= EF_FRV_FDPIC;
432 frv_pic_flag = "-mfdpic";
433 break;
435 case OPTION_NOPIC:
436 frv_flags &= ~(EF_FRV_FDPIC | EF_FRV_PIC
437 | EF_FRV_BIGPIC | EF_FRV_LIBPIC);
438 frv_pic_flag = 0;
439 break;
441 case OPTION_TOMCAT_DEBUG:
442 tomcat_debug = 1;
443 break;
445 case OPTION_TOMCAT_STATS:
446 tomcat_stats = 1;
447 break;
450 return 1;
453 void
454 md_show_usage (FILE * stream)
456 fprintf (stream, _("FRV specific command line options:\n"));
457 fprintf (stream, _("-G n Put data <= n bytes in the small data area\n"));
458 fprintf (stream, _("-mgpr-32 Mark generated file as only using 32 GPRs\n"));
459 fprintf (stream, _("-mgpr-64 Mark generated file as using all 64 GPRs\n"));
460 fprintf (stream, _("-mfpr-32 Mark generated file as only using 32 FPRs\n"));
461 fprintf (stream, _("-mfpr-64 Mark generated file as using all 64 FPRs\n"));
462 fprintf (stream, _("-msoft-float Mark generated file as using software FP\n"));
463 fprintf (stream, _("-mdword Mark generated file as using a 8-byte stack alignment\n"));
464 fprintf (stream, _("-mno-dword Mark generated file as using a 4-byte stack alignment\n"));
465 fprintf (stream, _("-mdouble Mark generated file as using double precision FP insns\n"));
466 fprintf (stream, _("-mmedia Mark generated file as using media insns\n"));
467 fprintf (stream, _("-mmuladd Mark generated file as using multiply add/subtract insns\n"));
468 fprintf (stream, _("-mpack Allow instructions to be packed\n"));
469 fprintf (stream, _("-mno-pack Do not allow instructions to be packed\n"));
470 fprintf (stream, _("-mpic Mark generated file as using small position independent code\n"));
471 fprintf (stream, _("-mPIC Mark generated file as using large position independent code\n"));
472 fprintf (stream, _("-mlibrary-pic Mark generated file as using position independent code for libraries\n"));
473 fprintf (stream, _("-mfdpic Assemble for the FDPIC ABI\n"));
474 fprintf (stream, _("-mnopic Disable -mpic, -mPIC, -mlibrary-pic and -mfdpic\n"));
475 fprintf (stream, _("-mcpu={fr500|fr550|fr400|fr405|fr450|fr300|frv|simple|tomcat}\n"));
476 fprintf (stream, _(" Record the cpu type\n"));
477 fprintf (stream, _("-mtomcat-stats Print out stats for tomcat workarounds\n"));
478 fprintf (stream, _("-mtomcat-debug Debug tomcat workarounds\n"));
482 void
483 md_begin (void)
485 /* Initialize the `cgen' interface. */
487 /* Set the machine number and endian. */
488 gas_cgen_cpu_desc = frv_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
489 CGEN_CPU_OPEN_ENDIAN,
490 CGEN_ENDIAN_BIG,
491 CGEN_CPU_OPEN_END);
492 frv_cgen_init_asm (gas_cgen_cpu_desc);
494 /* This is a callback from cgen to gas to parse operands. */
495 cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
497 /* Set the ELF flags if desired. */
498 if (frv_flags)
499 bfd_set_private_flags (stdoutput, frv_flags);
501 /* Set the machine type */
502 bfd_default_set_arch_mach (stdoutput, bfd_arch_frv, frv_mach);
504 /* Set up gp size so we can put local common items in .sbss */
505 bfd_set_gp_size (stdoutput, g_switch_value);
507 frv_vliw_reset (& vliw, frv_mach, frv_flags);
510 bool
511 frv_md_fdpic_enabled (void)
513 return (frv_flags & EF_FRV_FDPIC) != 0;
516 int chain_num = 0;
518 static struct vliw_insn_list *
519 frv_insert_vliw_insn (bool count)
521 struct vliw_insn_list *vliw_insn_list_entry;
522 struct vliw_chain *vliw_chain_entry;
524 if (current_vliw_chain == NULL)
526 vliw_chain_entry = XNEW (struct vliw_chain);
527 vliw_chain_entry->insn_count = 0;
528 vliw_chain_entry->insn_list = NULL;
529 vliw_chain_entry->next = NULL;
530 vliw_chain_entry->num = chain_num++;
532 if (!vliw_chain_top)
533 vliw_chain_top = vliw_chain_entry;
534 current_vliw_chain = vliw_chain_entry;
535 if (previous_vliw_chain)
536 previous_vliw_chain->next = vliw_chain_entry;
539 vliw_insn_list_entry = XNEW (struct vliw_insn_list);
540 vliw_insn_list_entry->type = VLIW_GENERIC_TYPE;
541 vliw_insn_list_entry->insn = NULL;
542 vliw_insn_list_entry->sym = NULL;
543 vliw_insn_list_entry->snop_frag = NULL;
544 vliw_insn_list_entry->dnop_frag = NULL;
545 vliw_insn_list_entry->next = NULL;
547 if (count)
548 current_vliw_chain->insn_count++;
550 if (current_vliw_insn)
551 current_vliw_insn->next = vliw_insn_list_entry;
552 current_vliw_insn = vliw_insn_list_entry;
554 if (!current_vliw_chain->insn_list)
555 current_vliw_chain->insn_list = current_vliw_insn;
557 return vliw_insn_list_entry;
560 /* Identify the following cases:
562 1) A VLIW insn that contains both a branch and the branch destination.
563 This requires the insertion of two vliw instructions before the
564 branch. The first consists of two nops. The second consists of
565 a single nop.
567 2) A single instruction VLIW insn which is the destination of a branch
568 that is in the next VLIW insn. This requires the insertion of a vliw
569 insn containing two nops before the branch.
571 3) A double instruction VLIW insn which contains the destination of a
572 branch that is in the next VLIW insn. This requires the insertion of
573 a VLIW insn containing a single nop before the branch.
575 4) A single instruction VLIW insn which contains branch destination (x),
576 followed by a single instruction VLIW insn which does not contain
577 the branch to (x), followed by a VLIW insn which does contain the branch
578 to (x). This requires the insertion of a VLIW insn containing a single
579 nop before the VLIW instruction containing the branch.
582 #define FRV_IS_NOP(insn) (insn.buffer[0] == FRV_NOP_PACK || insn.buffer[0] == FRV_NOP_NOPACK)
583 #define FRV_NOP_PACK 0x00880000 /* ori.p gr0,0,gr0 */
584 #define FRV_NOP_NOPACK 0x80880000 /* ori gr0,0,gr0 */
586 /* Check a vliw insn for an insn of type containing the sym passed in label_sym. */
588 static struct vliw_insn_list *
589 frv_find_in_vliw (enum vliw_insn_type vliw_insn_type,
590 struct vliw_chain *this_chain,
591 symbolS *label_sym)
594 struct vliw_insn_list *the_insn;
596 if (!this_chain)
597 return NULL;
599 for (the_insn = this_chain->insn_list; the_insn; the_insn = the_insn->next)
601 if (the_insn->type == vliw_insn_type
602 && the_insn->sym == label_sym)
603 return the_insn;
606 return NULL;
609 enum vliw_nop_type
611 /* A Vliw insn containing a single nop insn. */
612 VLIW_SINGLE_NOP,
614 /* A Vliw insn containing two nop insns. */
615 VLIW_DOUBLE_NOP,
617 /* Two vliw insns. The first containing two nop insns.
618 The second contain a single nop insn. */
619 VLIW_DOUBLE_THEN_SINGLE_NOP
622 static void
623 frv_debug_tomcat (struct vliw_chain *start_chain)
625 struct vliw_chain *this_chain;
626 struct vliw_insn_list *this_insn;
627 int i = 1;
629 for (this_chain = start_chain; this_chain; this_chain = this_chain->next, i++)
631 fprintf (stderr, "\nVliw Insn #%d, #insns: %d\n", i, this_chain->insn_count);
633 for (this_insn = this_chain->insn_list; this_insn; this_insn = this_insn->next)
635 if (this_insn->type == VLIW_LABEL_TYPE)
636 fprintf (stderr, "Label Value: %p\n", this_insn->sym);
637 else if (this_insn->type == VLIW_BRANCH_TYPE)
638 fprintf (stderr, "%s to %p\n", this_insn->insn->base->name, this_insn->sym);
639 else if (this_insn->type == VLIW_BRANCH_HAS_NOPS)
640 fprintf (stderr, "nop'd %s to %p\n", this_insn->insn->base->name, this_insn->sym);
641 else if (this_insn->type == VLIW_NOP_TYPE)
642 fprintf (stderr, "Nop\n");
643 else
644 fprintf (stderr, " %s\n", this_insn->insn->base->name);
649 static void
650 frv_adjust_vliw_count (struct vliw_chain *this_chain)
652 struct vliw_insn_list *this_insn;
654 this_chain->insn_count = 0;
656 for (this_insn = this_chain->insn_list;
657 this_insn;
658 this_insn = this_insn->next)
660 if (this_insn->type != VLIW_LABEL_TYPE)
661 this_chain->insn_count++;
666 /* Insert the desired nop combination in the vliw chain before insert_before_insn.
667 Rechain the vliw insn. */
669 static struct vliw_chain *
670 frv_tomcat_shuffle (enum vliw_nop_type this_nop_type,
671 struct vliw_chain *vliw_to_split,
672 struct vliw_insn_list *insert_before_insn)
675 bool pack_prev = false;
676 struct vliw_chain *return_me = NULL;
677 struct vliw_insn_list *prev_insn = NULL;
678 struct vliw_insn_list *curr_insn = vliw_to_split->insn_list;
680 struct vliw_chain *double_nop = XNEW (struct vliw_chain);
681 struct vliw_chain *single_nop = XNEW (struct vliw_chain);
682 struct vliw_chain *second_part = XNEW (struct vliw_chain);
683 struct vliw_chain *curr_vliw = vliw_chain_top;
684 struct vliw_chain *prev_vliw = NULL;
686 while (curr_insn && curr_insn != insert_before_insn)
688 /* We can't set the packing bit on a label. If we have the case
689 label 1:
690 label 2:
691 label 3:
692 branch that needs nops
693 Then don't set pack bit later. */
695 if (curr_insn->type != VLIW_LABEL_TYPE)
696 pack_prev = true;
697 prev_insn = curr_insn;
698 curr_insn = curr_insn->next;
701 while (curr_vliw && curr_vliw != vliw_to_split)
703 prev_vliw = curr_vliw;
704 curr_vliw = curr_vliw->next;
707 switch (this_nop_type)
709 case VLIW_SINGLE_NOP:
710 if (!prev_insn)
712 /* Branch is first, Insert the NOP prior to this vliw insn. */
713 if (prev_vliw)
714 prev_vliw->next = single_nop;
715 else
716 vliw_chain_top = single_nop;
717 single_nop->next = vliw_to_split;
718 vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
719 return_me = vliw_to_split;
721 else
723 /* Set the packing bit on the previous insn. */
724 if (pack_prev)
726 char *buffer = prev_insn->address;
727 buffer[0] |= 0x80;
729 /* The branch is in the middle. Split this vliw insn into first
730 and second parts. Insert the NOP between. */
732 second_part->insn_list = insert_before_insn;
733 second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
734 second_part->next = vliw_to_split->next;
735 frv_adjust_vliw_count (second_part);
737 single_nop->next = second_part;
739 vliw_to_split->next = single_nop;
740 prev_insn->next = NULL;
742 return_me = second_part;
743 frv_adjust_vliw_count (vliw_to_split);
745 break;
747 case VLIW_DOUBLE_NOP:
748 if (!prev_insn)
750 /* Branch is first, Insert the NOP prior to this vliw insn. */
751 if (prev_vliw)
752 prev_vliw->next = double_nop;
753 else
754 vliw_chain_top = double_nop;
756 double_nop->next = vliw_to_split;
757 return_me = vliw_to_split;
758 vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
760 else
762 /* Set the packing bit on the previous insn. */
763 if (pack_prev)
765 char *buffer = prev_insn->address;
766 buffer[0] |= 0x80;
769 /* The branch is in the middle. Split this vliw insn into first
770 and second parts. Insert the NOP in between. */
771 second_part->insn_list = insert_before_insn;
772 second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
773 second_part->next = vliw_to_split->next;
774 frv_adjust_vliw_count (second_part);
776 double_nop->next = second_part;
778 vliw_to_split->next = single_nop;
779 prev_insn->next = NULL;
780 frv_adjust_vliw_count (vliw_to_split);
782 return_me = second_part;
784 break;
786 case VLIW_DOUBLE_THEN_SINGLE_NOP:
787 double_nop->next = single_nop;
788 double_nop->insn_count = 2;
789 double_nop->insn_list = &double_nop_insn;
790 single_nop->insn_count = 1;
791 single_nop->insn_list = &single_nop_insn;
793 if (!prev_insn)
795 /* The branch is the first insn in this vliw. Don't split the vliw. Insert
796 the nops prior to this vliw. */
797 if (prev_vliw)
798 prev_vliw->next = double_nop;
799 else
800 vliw_chain_top = double_nop;
802 single_nop->next = vliw_to_split;
803 return_me = vliw_to_split;
804 vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
806 else
808 /* Set the packing bit on the previous insn. */
809 if (pack_prev)
811 char *buffer = prev_insn->address;
812 buffer[0] |= 0x80;
815 /* The branch is in the middle of this vliw insn. Split into first and
816 second parts. Insert the nop vliws in between. */
817 second_part->insn_list = insert_before_insn;
818 second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
819 second_part->next = vliw_to_split->next;
820 frv_adjust_vliw_count (second_part);
822 single_nop->next = second_part;
824 vliw_to_split->next = double_nop;
825 prev_insn->next = NULL;
826 frv_adjust_vliw_count (vliw_to_split);
828 return_me = second_part;
830 break;
833 return return_me;
836 static void
837 frv_tomcat_analyze_vliw_chains (void)
839 struct vliw_chain *vliw1 = NULL;
840 struct vliw_chain *vliw2 = NULL;
841 struct vliw_chain *vliw3 = NULL;
843 struct vliw_insn_list *this_insn = NULL;
844 struct vliw_insn_list *temp_insn = NULL;
846 /* We potentially need to look at three VLIW insns to determine if the
847 workaround is required. Set them up. Ignore existing nops during analysis. */
849 #define FRV_SET_VLIW_WINDOW(VLIW1, VLIW2, VLIW3) \
850 if (VLIW1 && VLIW1->next) \
851 VLIW2 = VLIW1->next; \
852 else \
853 VLIW2 = NULL; \
854 if (VLIW2 && VLIW2->next) \
855 VLIW3 = VLIW2->next; \
856 else \
857 VLIW3 = NULL
859 vliw1 = vliw_chain_top;
861 workaround_top:
863 FRV_SET_VLIW_WINDOW (vliw1, vliw2, vliw3);
865 if (!vliw1)
866 return;
868 if (vliw1->insn_count == 1)
870 /* check vliw1 for a label. */
871 if (vliw1->insn_list->type == VLIW_LABEL_TYPE)
873 temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, vliw1->insn_list->sym);
874 if (temp_insn)
876 vliw1 = frv_tomcat_shuffle (VLIW_DOUBLE_NOP, vliw2, vliw1->insn_list);
877 temp_insn->dnop_frag->fr_subtype = NOP_KEEP;
878 vliw1 = vliw1->next;
879 if (tomcat_stats)
880 tomcat_doubles++;
881 goto workaround_top;
883 else if (vliw2
884 && vliw2->insn_count == 1
885 && (temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw3, vliw1->insn_list->sym)) != NULL)
887 temp_insn->snop_frag->fr_subtype = NOP_KEEP;
888 vliw1 = frv_tomcat_shuffle (VLIW_SINGLE_NOP, vliw3, vliw3->insn_list);
889 if (tomcat_stats)
890 tomcat_singles++;
891 goto workaround_top;
896 if (vliw1->insn_count == 2)
898 /* Check vliw1 for a label. */
899 for (this_insn = vliw1->insn_list; this_insn; this_insn = this_insn->next)
901 if (this_insn->type == VLIW_LABEL_TYPE)
903 if ((temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, this_insn->sym)) != NULL)
905 temp_insn->snop_frag->fr_subtype = NOP_KEEP;
906 vliw1 = frv_tomcat_shuffle (VLIW_SINGLE_NOP, vliw2, this_insn);
907 if (tomcat_stats)
908 tomcat_singles++;
910 else
911 vliw1 = vliw1->next;
912 goto workaround_top;
916 /* Examine each insn in this VLIW. Look for the workaround criteria. */
917 for (this_insn = vliw1->insn_list; this_insn; this_insn = this_insn->next)
919 /* Don't look at labels or nops. */
920 while (this_insn
921 && (this_insn->type == VLIW_LABEL_TYPE
922 || this_insn->type == VLIW_NOP_TYPE
923 || this_insn->type == VLIW_BRANCH_HAS_NOPS))
924 this_insn = this_insn->next;
926 if (!this_insn)
928 vliw1 = vliw2;
929 goto workaround_top;
932 if (frv_is_branch_insn (this_insn->insn))
934 if ((temp_insn = frv_find_in_vliw (VLIW_LABEL_TYPE, vliw1, this_insn->sym)) != NULL)
936 /* Insert [nop/nop] [nop] before branch. */
937 this_insn->snop_frag->fr_subtype = NOP_KEEP;
938 this_insn->dnop_frag->fr_subtype = NOP_KEEP;
939 vliw1 = frv_tomcat_shuffle (VLIW_DOUBLE_THEN_SINGLE_NOP, vliw1, this_insn);
940 goto workaround_top;
946 /* This vliw insn checks out okay. Take a look at the next one. */
947 vliw1 = vliw1->next;
948 goto workaround_top;
951 void
952 frv_tomcat_workaround (void)
954 if (frv_mach != bfd_mach_frvtomcat)
955 return;
957 if (tomcat_debug)
958 frv_debug_tomcat (vliw_chain_top);
960 frv_tomcat_analyze_vliw_chains ();
962 if (tomcat_stats)
964 fprintf (stderr, "Inserted %d Single Nops\n", tomcat_singles);
965 fprintf (stderr, "Inserted %d Double Nops\n", tomcat_doubles);
969 static int
970 fr550_check_insn_acc_range (frv_insn *insn, int low, int hi)
972 int acc;
973 switch (CGEN_INSN_NUM (insn->insn))
975 case FRV_INSN_MADDACCS:
976 case FRV_INSN_MSUBACCS:
977 case FRV_INSN_MDADDACCS:
978 case FRV_INSN_MDSUBACCS:
979 case FRV_INSN_MASACCS:
980 case FRV_INSN_MDASACCS:
981 acc = insn->fields.f_ACC40Si;
982 if (acc < low || acc > hi)
983 return 1; /* out of range */
984 acc = insn->fields.f_ACC40Sk;
985 if (acc < low || acc > hi)
986 return 1; /* out of range */
987 break;
988 case FRV_INSN_MMULHS:
989 case FRV_INSN_MMULHU:
990 case FRV_INSN_MMULXHS:
991 case FRV_INSN_MMULXHU:
992 case FRV_INSN_CMMULHS:
993 case FRV_INSN_CMMULHU:
994 case FRV_INSN_MQMULHS:
995 case FRV_INSN_MQMULHU:
996 case FRV_INSN_MQMULXHS:
997 case FRV_INSN_MQMULXHU:
998 case FRV_INSN_CMQMULHS:
999 case FRV_INSN_CMQMULHU:
1000 case FRV_INSN_MMACHS:
1001 case FRV_INSN_MMRDHS:
1002 case FRV_INSN_CMMACHS:
1003 case FRV_INSN_MQMACHS:
1004 case FRV_INSN_CMQMACHS:
1005 case FRV_INSN_MQXMACHS:
1006 case FRV_INSN_MQXMACXHS:
1007 case FRV_INSN_MQMACXHS:
1008 case FRV_INSN_MCPXRS:
1009 case FRV_INSN_MCPXIS:
1010 case FRV_INSN_CMCPXRS:
1011 case FRV_INSN_CMCPXIS:
1012 case FRV_INSN_MQCPXRS:
1013 case FRV_INSN_MQCPXIS:
1014 acc = insn->fields.f_ACC40Sk;
1015 if (acc < low || acc > hi)
1016 return 1; /* out of range */
1017 break;
1018 case FRV_INSN_MMACHU:
1019 case FRV_INSN_MMRDHU:
1020 case FRV_INSN_CMMACHU:
1021 case FRV_INSN_MQMACHU:
1022 case FRV_INSN_CMQMACHU:
1023 case FRV_INSN_MCPXRU:
1024 case FRV_INSN_MCPXIU:
1025 case FRV_INSN_CMCPXRU:
1026 case FRV_INSN_CMCPXIU:
1027 case FRV_INSN_MQCPXRU:
1028 case FRV_INSN_MQCPXIU:
1029 acc = insn->fields.f_ACC40Uk;
1030 if (acc < low || acc > hi)
1031 return 1; /* out of range */
1032 break;
1033 default:
1034 break;
1036 return 0; /* all is ok */
1039 static int
1040 fr550_check_acc_range (FRV_VLIW *vlw, frv_insn *insn)
1042 switch ((*vlw->current_vliw)[vlw->next_slot - 1])
1044 case UNIT_FM0:
1045 case UNIT_FM2:
1046 return fr550_check_insn_acc_range (insn, 0, 3);
1047 case UNIT_FM1:
1048 case UNIT_FM3:
1049 return fr550_check_insn_acc_range (insn, 4, 7);
1050 default:
1051 break;
1053 return 0; /* all is ok */
1056 /* Return true if the target implements instruction INSN. */
1058 static bool
1059 target_implements_insn_p (const CGEN_INSN *insn)
1061 switch (frv_mach)
1063 default:
1064 /* bfd_mach_frv or generic. */
1065 return true;
1067 case bfd_mach_fr300:
1068 case bfd_mach_frvsimple:
1069 return CGEN_INSN_MACH_HAS_P (insn, MACH_SIMPLE);
1071 case bfd_mach_fr400:
1072 return ((fr400_audio || !CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_AUDIO))
1073 && CGEN_INSN_MACH_HAS_P (insn, MACH_FR400));
1075 case bfd_mach_fr450:
1076 return CGEN_INSN_MACH_HAS_P (insn, MACH_FR450);
1078 case bfd_mach_fr500:
1079 return CGEN_INSN_MACH_HAS_P (insn, MACH_FR500);
1081 case bfd_mach_fr550:
1082 return CGEN_INSN_MACH_HAS_P (insn, MACH_FR550);
1086 void
1087 md_assemble (char *str)
1089 frv_insn insn;
1090 char *errmsg;
1091 int packing_constraint;
1092 finished_insnS finished_insn;
1093 fragS *double_nop_frag = NULL;
1094 fragS *single_nop_frag = NULL;
1095 struct vliw_insn_list *vliw_insn_list_entry = NULL;
1097 /* Initialize GAS's cgen interface for a new instruction. */
1098 gas_cgen_init_parse ();
1100 memset (&insn, 0, sizeof (insn));
1102 insn.insn = frv_cgen_assemble_insn
1103 (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, &errmsg);
1105 if (!insn.insn)
1107 as_bad ("%s", errmsg);
1108 return;
1111 /* If the cpu is tomcat, then we need to insert nops to workaround
1112 hardware limitations. We need to keep track of each vliw unit
1113 and examine the length of the unit and the individual insns
1114 within the unit to determine the number and location of the
1115 required nops. */
1116 if (frv_mach == bfd_mach_frvtomcat)
1118 /* If we've just finished a VLIW insn OR this is a branch,
1119 then start up a new frag. Fill it with nops. We will get rid
1120 of those that are not required after we've seen all of the
1121 instructions but before we start resolving fixups. */
1122 if ( !FRV_IS_NOP (insn)
1123 && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
1125 char *buffer;
1127 frag_wane (frag_now);
1128 frag_new (0);
1129 double_nop_frag = frag_now;
1130 buffer = frag_var (rs_machine_dependent, 8, 8, NOP_DELETE, NULL, 0, 0);
1131 md_number_to_chars (buffer, FRV_NOP_PACK, 4);
1132 md_number_to_chars (buffer+4, FRV_NOP_NOPACK, 4);
1134 frag_wane (frag_now);
1135 frag_new (0);
1136 single_nop_frag = frag_now;
1137 buffer = frag_var (rs_machine_dependent, 4, 4, NOP_DELETE, NULL, 0, 0);
1138 md_number_to_chars (buffer, FRV_NOP_NOPACK, 4);
1141 vliw_insn_list_entry = frv_insert_vliw_insn (DO_COUNT);
1142 vliw_insn_list_entry->insn = insn.insn;
1143 if (frv_is_branch_insn (insn.insn))
1144 vliw_insn_list_entry->type = VLIW_BRANCH_TYPE;
1146 if ( !FRV_IS_NOP (insn)
1147 && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
1149 vliw_insn_list_entry->snop_frag = single_nop_frag;
1150 vliw_insn_list_entry->dnop_frag = double_nop_frag;
1154 /* Make sure that this insn does not violate the VLIW packing constraints. */
1155 /* -mno-pack disallows any packing whatsoever. */
1156 if (frv_flags & EF_FRV_NOPACK)
1158 if (! insn.fields.f_pack)
1160 as_bad (_("VLIW packing used for -mno-pack"));
1161 return;
1164 /* -mcpu=FRV is an idealized FR-V implementation that supports all of the
1165 instructions, don't do vliw checking. */
1166 else if (frv_mach != bfd_mach_frv)
1168 if (!target_implements_insn_p (insn.insn))
1170 as_bad (_("Instruction not supported by this architecture"));
1171 return;
1173 packing_constraint = frv_vliw_add_insn (& vliw, insn.insn);
1174 if (frv_mach == bfd_mach_fr550 && ! packing_constraint)
1175 packing_constraint = fr550_check_acc_range (& vliw, & insn);
1176 if (insn.fields.f_pack)
1177 frv_vliw_reset (& vliw, frv_mach, frv_flags);
1178 if (packing_constraint)
1180 as_bad (_("VLIW packing constraint violation"));
1181 return;
1185 /* Doesn't really matter what we pass for RELAX_P here. */
1186 gas_cgen_finish_insn (insn.insn, insn.buffer,
1187 CGEN_FIELDS_BITSIZE (& insn.fields), 1, &finished_insn);
1190 /* If the cpu is tomcat, then we need to insert nops to workaround
1191 hardware limitations. We need to keep track of each vliw unit
1192 and examine the length of the unit and the individual insns
1193 within the unit to determine the number and location of the
1194 required nops. */
1195 if (frv_mach == bfd_mach_frvtomcat)
1197 if (vliw_insn_list_entry)
1198 vliw_insn_list_entry->address = finished_insn.addr;
1199 else
1200 abort();
1202 if (insn.fields.f_pack)
1204 /* We've completed a VLIW insn. */
1205 previous_vliw_chain = current_vliw_chain;
1206 current_vliw_chain = NULL;
1207 current_vliw_insn = NULL;
1212 /* The syntax in the manual says constants begin with '#'.
1213 We just ignore it. */
1215 void
1216 md_operand (expressionS *expressionP)
1218 if (* input_line_pointer == '#')
1220 input_line_pointer ++;
1221 expression (expressionP);
1225 valueT
1226 md_section_align (segT segment, valueT size)
1228 int align = bfd_section_alignment (segment);
1229 return ((size + (1 << align) - 1) & -(1 << align));
1232 symbolS *
1233 md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
1235 return 0;
1238 /* Interface to relax_segment. */
1240 /* FIXME: Build table by hand, get it working, then machine generate. */
1241 const relax_typeS md_relax_table[] =
1243 {1, 1, 0, 0},
1244 {511 - 2 - 2, -512 - 2 + 2, 0, 2 },
1245 {0x2000000 - 1 - 2, -0x2000000 - 2, 2, 0 },
1246 {0x2000000 - 1 - 2, -0x2000000 - 2, 4, 0 }
1249 long
1250 frv_relax_frag (fragS *fragP ATTRIBUTE_UNUSED, long stretch ATTRIBUTE_UNUSED)
1252 return 0;
1255 /* Return an initial guess of the length by which a fragment must grow to
1256 hold a branch to reach its destination.
1257 Also updates fr_type/fr_subtype as necessary.
1259 Called just before doing relaxation.
1260 Any symbol that is now undefined will not become defined.
1261 The guess for fr_var is ACTUALLY the growth beyond fr_fix.
1262 Whatever we do to grow fr_fix or fr_var contributes to our returned value.
1263 Although it may not be explicit in the frag, pretend fr_var starts with a
1264 0 value. */
1267 md_estimate_size_before_relax (fragS *fragP, segT segment ATTRIBUTE_UNUSED)
1269 switch (fragP->fr_subtype)
1271 case NOP_KEEP:
1272 return fragP->fr_var;
1274 default:
1275 case NOP_DELETE:
1276 return 0;
1280 /* *fragP has been relaxed to its final size, and now needs to have
1281 the bytes inside it modified to conform to the new size.
1283 Called after relaxation is finished.
1284 fragP->fr_type == rs_machine_dependent.
1285 fragP->fr_subtype is the subtype of what the address relaxed to. */
1287 void
1288 md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
1289 segT sec ATTRIBUTE_UNUSED,
1290 fragS *fragP)
1292 switch (fragP->fr_subtype)
1294 default:
1295 case NOP_DELETE:
1296 return;
1298 case NOP_KEEP:
1299 fragP->fr_fix = fragP->fr_var;
1300 fragP->fr_var = 0;
1301 return;
1305 /* Functions concerning relocs. */
1307 /* The location from which a PC relative jump should be calculated,
1308 given a PC relative reloc. */
1310 long
1311 md_pcrel_from_section (fixS *fixP, segT sec)
1313 if (TC_FORCE_RELOCATION (fixP)
1314 || (fixP->fx_addsy != (symbolS *) NULL
1315 && S_GET_SEGMENT (fixP->fx_addsy) != sec))
1317 /* If we can't adjust this relocation, or if it references a
1318 local symbol in a different section (which
1319 TC_FORCE_RELOCATION can't check), let the linker figure it
1320 out. */
1321 return 0;
1324 return (fixP->fx_frag->fr_address + fixP->fx_where) & ~1;
1327 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
1328 Returns BFD_RELOC_NONE if no reloc type can be found.
1329 *FIXP may be modified if desired. */
1331 bfd_reloc_code_real_type
1332 md_cgen_lookup_reloc (const CGEN_INSN *insn ATTRIBUTE_UNUSED,
1333 const CGEN_OPERAND *operand,
1334 fixS *fixP)
1336 switch (operand->type)
1338 case FRV_OPERAND_LABEL16:
1339 fixP->fx_pcrel = true;
1340 return BFD_RELOC_FRV_LABEL16;
1342 case FRV_OPERAND_LABEL24:
1343 fixP->fx_pcrel = true;
1345 if (fixP->fx_cgen.opinfo != 0)
1346 return fixP->fx_cgen.opinfo;
1348 return BFD_RELOC_FRV_LABEL24;
1350 case FRV_OPERAND_UHI16:
1351 case FRV_OPERAND_ULO16:
1352 case FRV_OPERAND_SLO16:
1353 case FRV_OPERAND_CALLANN:
1354 case FRV_OPERAND_LDANN:
1355 case FRV_OPERAND_LDDANN:
1356 /* The relocation type should be recorded in opinfo */
1357 if (fixP->fx_cgen.opinfo != 0)
1358 return fixP->fx_cgen.opinfo;
1359 break;
1361 case FRV_OPERAND_D12:
1362 case FRV_OPERAND_S12:
1363 if (fixP->fx_cgen.opinfo != 0)
1364 return fixP->fx_cgen.opinfo;
1366 return BFD_RELOC_FRV_GPREL12;
1368 case FRV_OPERAND_U12:
1369 return BFD_RELOC_FRV_GPRELU12;
1371 default:
1372 break;
1374 return BFD_RELOC_NONE;
1378 /* See whether we need to force a relocation into the output file.
1379 This is used to force out switch and PC relative relocations when
1380 relaxing. */
1383 frv_force_relocation (fixS *fix)
1385 switch (fix->fx_r_type < BFD_RELOC_UNUSED
1386 ? (int) fix->fx_r_type
1387 : fix->fx_cgen.opinfo)
1389 case BFD_RELOC_FRV_GPREL12:
1390 case BFD_RELOC_FRV_GPRELU12:
1391 case BFD_RELOC_FRV_GPREL32:
1392 case BFD_RELOC_FRV_GPRELHI:
1393 case BFD_RELOC_FRV_GPRELLO:
1394 case BFD_RELOC_FRV_GOT12:
1395 case BFD_RELOC_FRV_GOTHI:
1396 case BFD_RELOC_FRV_GOTLO:
1397 case BFD_RELOC_FRV_FUNCDESC_VALUE:
1398 case BFD_RELOC_FRV_FUNCDESC_GOTOFF12:
1399 case BFD_RELOC_FRV_FUNCDESC_GOTOFFHI:
1400 case BFD_RELOC_FRV_FUNCDESC_GOTOFFLO:
1401 case BFD_RELOC_FRV_GOTOFF12:
1402 case BFD_RELOC_FRV_GOTOFFHI:
1403 case BFD_RELOC_FRV_GOTOFFLO:
1404 case BFD_RELOC_FRV_GETTLSOFF:
1405 case BFD_RELOC_FRV_TLSDESC_VALUE:
1406 case BFD_RELOC_FRV_GOTTLSDESC12:
1407 case BFD_RELOC_FRV_GOTTLSDESCHI:
1408 case BFD_RELOC_FRV_GOTTLSDESCLO:
1409 case BFD_RELOC_FRV_TLSMOFF12:
1410 case BFD_RELOC_FRV_TLSMOFFHI:
1411 case BFD_RELOC_FRV_TLSMOFFLO:
1412 case BFD_RELOC_FRV_GOTTLSOFF12:
1413 case BFD_RELOC_FRV_GOTTLSOFFHI:
1414 case BFD_RELOC_FRV_GOTTLSOFFLO:
1415 case BFD_RELOC_FRV_TLSOFF:
1416 case BFD_RELOC_FRV_TLSDESC_RELAX:
1417 case BFD_RELOC_FRV_GETTLSOFF_RELAX:
1418 case BFD_RELOC_FRV_TLSOFF_RELAX:
1419 return 1;
1421 default:
1422 break;
1425 return generic_force_reloc (fix);
1428 /* Apply a fixup that could be resolved within the assembler. */
1430 void
1431 md_apply_fix (fixS *fixP, valueT *valP, segT seg)
1433 if (fixP->fx_addsy == 0)
1434 switch (fixP->fx_cgen.opinfo)
1436 case BFD_RELOC_FRV_HI16:
1437 *valP >>= 16;
1438 /* Fall through. */
1439 case BFD_RELOC_FRV_LO16:
1440 *valP &= 0xffff;
1441 break;
1443 /* We need relocations for these, even if their symbols reduce
1444 to constants. */
1445 case BFD_RELOC_FRV_GPREL12:
1446 case BFD_RELOC_FRV_GPRELU12:
1447 case BFD_RELOC_FRV_GPREL32:
1448 case BFD_RELOC_FRV_GPRELHI:
1449 case BFD_RELOC_FRV_GPRELLO:
1450 case BFD_RELOC_FRV_GOT12:
1451 case BFD_RELOC_FRV_GOTHI:
1452 case BFD_RELOC_FRV_GOTLO:
1453 case BFD_RELOC_FRV_FUNCDESC_VALUE:
1454 case BFD_RELOC_FRV_FUNCDESC_GOTOFF12:
1455 case BFD_RELOC_FRV_FUNCDESC_GOTOFFHI:
1456 case BFD_RELOC_FRV_FUNCDESC_GOTOFFLO:
1457 case BFD_RELOC_FRV_GOTOFF12:
1458 case BFD_RELOC_FRV_GOTOFFHI:
1459 case BFD_RELOC_FRV_GOTOFFLO:
1460 case BFD_RELOC_FRV_GETTLSOFF:
1461 case BFD_RELOC_FRV_TLSDESC_VALUE:
1462 case BFD_RELOC_FRV_GOTTLSDESC12:
1463 case BFD_RELOC_FRV_GOTTLSDESCHI:
1464 case BFD_RELOC_FRV_GOTTLSDESCLO:
1465 case BFD_RELOC_FRV_TLSMOFF12:
1466 case BFD_RELOC_FRV_TLSMOFFHI:
1467 case BFD_RELOC_FRV_TLSMOFFLO:
1468 case BFD_RELOC_FRV_GOTTLSOFF12:
1469 case BFD_RELOC_FRV_GOTTLSOFFHI:
1470 case BFD_RELOC_FRV_GOTTLSOFFLO:
1471 case BFD_RELOC_FRV_TLSOFF:
1472 case BFD_RELOC_FRV_TLSDESC_RELAX:
1473 case BFD_RELOC_FRV_GETTLSOFF_RELAX:
1474 case BFD_RELOC_FRV_TLSOFF_RELAX:
1475 fixP->fx_addsy = abs_section_sym;
1476 break;
1478 else
1479 switch (fixP->fx_cgen.opinfo)
1481 case BFD_RELOC_FRV_GETTLSOFF:
1482 case BFD_RELOC_FRV_TLSDESC_VALUE:
1483 case BFD_RELOC_FRV_GOTTLSDESC12:
1484 case BFD_RELOC_FRV_GOTTLSDESCHI:
1485 case BFD_RELOC_FRV_GOTTLSDESCLO:
1486 case BFD_RELOC_FRV_TLSMOFF12:
1487 case BFD_RELOC_FRV_TLSMOFFHI:
1488 case BFD_RELOC_FRV_TLSMOFFLO:
1489 case BFD_RELOC_FRV_GOTTLSOFF12:
1490 case BFD_RELOC_FRV_GOTTLSOFFHI:
1491 case BFD_RELOC_FRV_GOTTLSOFFLO:
1492 case BFD_RELOC_FRV_TLSOFF:
1493 case BFD_RELOC_FRV_TLSDESC_RELAX:
1494 case BFD_RELOC_FRV_GETTLSOFF_RELAX:
1495 case BFD_RELOC_FRV_TLSOFF_RELAX:
1496 /* Mark TLS symbols as such. */
1497 if (S_GET_SEGMENT (fixP->fx_addsy) != absolute_section)
1498 S_SET_THREAD_LOCAL (fixP->fx_addsy);
1499 break;
1502 gas_cgen_md_apply_fix (fixP, valP, seg);
1503 return;
1507 /* Write a value out to the object file, using the appropriate endianness. */
1509 void
1510 frv_md_number_to_chars (char *buf, valueT val, int n)
1512 number_to_chars_bigendian (buf, val, n);
1515 const char *
1516 md_atof (int type, char *litP, int *sizeP)
1518 return ieee_md_atof (type, litP, sizeP, true);
1521 bool
1522 frv_fix_adjustable (fixS *fixP)
1524 bfd_reloc_code_real_type reloc_type;
1526 if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
1528 const CGEN_INSN *insn = NULL;
1529 int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
1530 const CGEN_OPERAND *operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
1531 reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
1533 else
1534 reloc_type = fixP->fx_r_type;
1536 /* We need the symbol name for the VTABLE entries */
1537 if ( reloc_type == BFD_RELOC_VTABLE_INHERIT
1538 || reloc_type == BFD_RELOC_VTABLE_ENTRY
1539 || reloc_type == BFD_RELOC_FRV_GPREL12
1540 || reloc_type == BFD_RELOC_FRV_GPRELU12)
1541 return 0;
1543 return 1;
1546 /* Allow user to set flags bits. */
1547 void
1548 frv_set_flags (int arg ATTRIBUTE_UNUSED)
1550 flagword new_flags = get_absolute_expression ();
1551 flagword new_mask = ~ (flagword)0;
1553 frv_user_set_flags_p = 1;
1554 if (*input_line_pointer == ',')
1556 ++input_line_pointer;
1557 new_mask = get_absolute_expression ();
1560 frv_flags = (frv_flags & ~new_mask) | (new_flags & new_mask);
1561 bfd_set_private_flags (stdoutput, frv_flags);
1564 /* Frv specific function to handle 4 byte initializations for pointers that are
1565 considered 'safe' for use with pic support. Until frv_frob_file{,_section}
1566 is run, we encode it a BFD_RELOC_CTOR, and it is turned back into a normal
1567 BFD_RELOC_32 at that time. */
1569 void
1570 frv_pic_ptr (int nbytes)
1572 expressionS exp;
1573 char *p;
1575 if (nbytes != 4)
1576 abort ();
1578 #ifdef md_flush_pending_output
1579 md_flush_pending_output ();
1580 #endif
1582 if (is_it_end_of_statement ())
1584 demand_empty_rest_of_line ();
1585 return;
1588 #ifdef md_cons_align
1589 md_cons_align (nbytes);
1590 #endif
1594 bfd_reloc_code_real_type reloc_type = BFD_RELOC_CTOR;
1596 if (strncasecmp (input_line_pointer, "funcdesc(", 9) == 0)
1598 input_line_pointer += 9;
1599 expression (&exp);
1600 if (*input_line_pointer == ')')
1601 input_line_pointer++;
1602 else
1603 as_bad (_("missing ')'"));
1604 reloc_type = BFD_RELOC_FRV_FUNCDESC;
1606 else if (strncasecmp (input_line_pointer, "tlsmoff(", 8) == 0)
1608 input_line_pointer += 8;
1609 expression (&exp);
1610 if (*input_line_pointer == ')')
1611 input_line_pointer++;
1612 else
1613 as_bad (_("missing ')'"));
1614 reloc_type = BFD_RELOC_FRV_TLSMOFF;
1616 else
1617 expression (&exp);
1619 p = frag_more (4);
1620 memset (p, 0, 4);
1621 fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &exp, 0,
1622 reloc_type);
1624 while (*input_line_pointer++ == ',');
1626 input_line_pointer--; /* Put terminator back into stream. */
1627 demand_empty_rest_of_line ();
1632 #ifdef DEBUG
1633 #define DPRINTF1(A) fprintf (stderr, A)
1634 #define DPRINTF2(A,B) fprintf (stderr, A, B)
1635 #define DPRINTF3(A,B,C) fprintf (stderr, A, B, C)
1637 #else
1638 #define DPRINTF1(A)
1639 #define DPRINTF2(A,B)
1640 #define DPRINTF3(A,B,C)
1641 #endif
1643 /* Go through a the sections looking for relocations that are problematical for
1644 pic. If not pic, just note that this object can't be linked with pic. If
1645 it is pic, see if it needs to be marked so that it will be fixed up, or if
1646 not possible, issue an error. */
1648 static void
1649 frv_frob_file_section (bfd *abfd, asection *sec, void *ptr ATTRIBUTE_UNUSED)
1651 segment_info_type *seginfo = seg_info (sec);
1652 fixS *fixp;
1653 CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
1654 flagword flags = bfd_section_flags (sec);
1656 /* Skip relocations in known sections (.ctors, .dtors, and .gcc_except_table)
1657 since we can fix those up by hand. */
1658 int known_section_p = (sec->name
1659 && sec->name[0] == '.'
1660 && ((sec->name[1] == 'c'
1661 && strcmp (sec->name, ".ctor") == 0)
1662 || (sec->name[1] == 'd'
1663 && strcmp (sec->name, ".dtor") == 0)
1664 || (sec->name[1] == 'g'
1665 && strcmp (sec->name, ".gcc_except_table") == 0)));
1667 DPRINTF3 ("\nFrv section %s%s\n", sec->name, (known_section_p) ? ", known section" : "");
1668 if ((flags & SEC_ALLOC) == 0)
1670 DPRINTF1 ("\tSkipping non-loaded section\n");
1671 return;
1674 for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
1676 symbolS *s = fixp->fx_addsy;
1677 bfd_reloc_code_real_type reloc;
1678 int non_pic_p;
1679 int opindex;
1680 const CGEN_OPERAND *operand;
1681 const CGEN_INSN *insn = fixp->fx_cgen.insn;
1683 if (fixp->fx_done)
1685 DPRINTF1 ("\tSkipping reloc that has already been done\n");
1686 continue;
1689 if (fixp->fx_pcrel)
1691 DPRINTF1 ("\tSkipping reloc that is PC relative\n");
1692 continue;
1695 if (! s)
1697 DPRINTF1 ("\tSkipping reloc without symbol\n");
1698 continue;
1701 if (fixp->fx_r_type < BFD_RELOC_UNUSED)
1703 opindex = -1;
1704 reloc = fixp->fx_r_type;
1706 else
1708 opindex = (int) fixp->fx_r_type - (int) BFD_RELOC_UNUSED;
1709 operand = cgen_operand_lookup_by_num (cd, opindex);
1710 reloc = md_cgen_lookup_reloc (insn, operand, fixp);
1713 DPRINTF3 ("\treloc %s\t%s", bfd_get_reloc_code_name (reloc), S_GET_NAME (s));
1715 non_pic_p = 0;
1716 switch (reloc)
1718 default:
1719 break;
1721 case BFD_RELOC_32:
1722 /* Skip relocations in known sections (.ctors, .dtors, and
1723 .gcc_except_table) since we can fix those up by hand. Also
1724 skip forward references to constants. Also skip a difference
1725 of two symbols, which still uses the BFD_RELOC_32 at this
1726 point. */
1727 if (! known_section_p
1728 && S_GET_SEGMENT (s) != absolute_section
1729 && !fixp->fx_subsy
1730 && (flags & (SEC_READONLY | SEC_CODE)) == 0)
1732 non_pic_p = 1;
1734 break;
1736 /* FIXME -- should determine if any of the GP relocation really uses
1737 gr16 (which is not pic safe) or not. Right now, assume if we
1738 aren't being compiled with -mpic, the usage is non pic safe, but
1739 is safe with -mpic. */
1740 case BFD_RELOC_FRV_GPREL12:
1741 case BFD_RELOC_FRV_GPRELU12:
1742 case BFD_RELOC_FRV_GPREL32:
1743 case BFD_RELOC_FRV_GPRELHI:
1744 case BFD_RELOC_FRV_GPRELLO:
1745 non_pic_p = ! frv_pic_p;
1746 break;
1748 case BFD_RELOC_FRV_LO16:
1749 case BFD_RELOC_FRV_HI16:
1750 if (S_GET_SEGMENT (s) != absolute_section)
1751 non_pic_p = 1;
1752 break;
1754 case BFD_RELOC_VTABLE_INHERIT:
1755 case BFD_RELOC_VTABLE_ENTRY:
1756 non_pic_p = 1;
1757 break;
1759 /* If this is a blessed BFD_RELOC_32, convert it back to the normal
1760 relocation. */
1761 case BFD_RELOC_CTOR:
1762 fixp->fx_r_type = BFD_RELOC_32;
1763 break;
1766 if (non_pic_p)
1768 DPRINTF1 (" (Non-pic relocation)\n");
1769 if (frv_pic_p)
1770 as_warn_where (fixp->fx_file, fixp->fx_line,
1771 _("Relocation %s is not safe for %s"),
1772 bfd_get_reloc_code_name (reloc), frv_pic_flag);
1774 else if ((frv_flags & EF_FRV_NON_PIC_RELOCS) == 0)
1776 frv_flags |= EF_FRV_NON_PIC_RELOCS;
1777 bfd_set_private_flags (abfd, frv_flags);
1780 #ifdef DEBUG
1781 else
1782 DPRINTF1 ("\n");
1783 #endif
1787 /* After all of the symbols have been adjusted, go over the file looking
1788 for any relocations that pic won't support. */
1790 void
1791 frv_frob_file (void)
1793 bfd_map_over_sections (stdoutput, frv_frob_file_section, (void *) 0);
1796 void
1797 frv_frob_label (symbolS *this_label)
1799 struct vliw_insn_list *vliw_insn_list_entry;
1801 dwarf2_emit_label (this_label);
1802 if (frv_mach != bfd_mach_frvtomcat)
1803 return;
1805 if (now_seg != text_section)
1806 return;
1808 vliw_insn_list_entry = frv_insert_vliw_insn(DONT_COUNT);
1809 vliw_insn_list_entry->type = VLIW_LABEL_TYPE;
1810 vliw_insn_list_entry->sym = this_label;
1813 fixS *
1814 frv_cgen_record_fixup_exp (fragS *frag,
1815 int where,
1816 const CGEN_INSN *insn,
1817 int length,
1818 const CGEN_OPERAND *operand,
1819 int opinfo,
1820 expressionS *exp)
1822 fixS * fixP = gas_cgen_record_fixup_exp (frag, where, insn, length,
1823 operand, opinfo, exp);
1825 if (frv_mach == bfd_mach_frvtomcat
1826 && current_vliw_insn
1827 && current_vliw_insn->type == VLIW_BRANCH_TYPE
1828 && exp != NULL)
1829 current_vliw_insn->sym = exp->X_add_symbol;
1831 return fixP;