1 /* tc-frv.c -- Assembler for the Fujitsu FRV.
2 Copyright 2002, 2003 Free Software Foundation.
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 2, or (at your option)
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, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
25 #include "opcodes/frv-desc.h"
26 #include "opcodes/frv-opc.h"
29 #include "elf/common.h"
32 /* Structure to hold all of the different components describing
33 an individual instruction. */
36 const CGEN_INSN
* insn
;
37 const CGEN_INSN
* orig_insn
;
40 CGEN_INSN_INT buffer
[1];
41 #define INSN_VALUE(buf) (*(buf))
43 unsigned char buffer
[CGEN_MAX_INSN_SIZE
];
44 #define INSN_VALUE(buf) (buf)
49 fixS
* fixups
[GAS_CGEN_MAX_FIXUPS
];
50 int indices
[MAX_OPERAND_INSTANCES
];
56 VLIW_GENERIC_TYPE
, /* Don't care about this insn. */
57 VLIW_BRANCH_TYPE
, /* A Branch. */
58 VLIW_LABEL_TYPE
, /* A Label. */
59 VLIW_NOP_TYPE
, /* A NOP. */
60 VLIW_BRANCH_HAS_NOPS
/* A Branch that requires NOPS. */
63 /* We're going to use these in the fr_subtype field to mark
64 whether to keep inserted nops. */
66 #define NOP_KEEP 1 /* Keep these NOPS. */
67 #define NOP_DELETE 2 /* Delete these NOPS. */
70 #define DONT_COUNT FALSE
72 /* A list of insns within a VLIW insn. */
75 /* The type of this insn. */
76 enum vliw_insn_type type
;
78 /* The corresponding gas insn information. */
79 const CGEN_INSN
*insn
;
81 /* For branches and labels, the symbol that is referenced. */
84 /* For branches, the frag containing the single nop that was generated. */
87 /* For branches, the frag containing the double nop that was generated. */
90 /* Pointer to raw data for this insn. */
93 /* Next insn in list. */
94 struct vliw_insn_list
*next
;
97 static struct vliw_insn_list single_nop_insn
= {
98 VLIW_NOP_TYPE
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
100 static struct vliw_insn_list double_nop_insn
= {
101 VLIW_NOP_TYPE
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
107 struct vliw_insn_list
*insn_list
;
108 struct vliw_chain
*next
;
111 static struct vliw_chain
*vliw_chain_top
;
112 static struct vliw_chain
*current_vliw_chain
;
113 static struct vliw_chain
*previous_vliw_chain
;
114 static struct vliw_insn_list
*current_vliw_insn
;
116 const char comment_chars
[] = ";";
117 const char line_comment_chars
[] = "#";
118 const char line_separator_chars
[] = "!";
119 const char EXP_CHARS
[] = "eE";
120 const char FLT_CHARS
[] = "dD";
122 static FRV_VLIW vliw
;
124 /* Default machine */
126 #ifdef DEFAULT_CPU_FRV
127 #define DEFAULT_MACHINE bfd_mach_frv
128 #define DEFAULT_FLAGS EF_FRV_CPU_GENERIC
131 #ifdef DEFAULT_CPU_FR300
132 #define DEFAULT_MACHINE bfd_mach_fr300
133 #define DEFAULT_FLAGS EF_FRV_CPU_FR300
136 #ifdef DEFAULT_CPU_SIMPLE
137 #define DEFAULT_MACHINE bfd_mach_frvsimple
138 #define DEFAULT_FLAGS EF_FRV_CPU_SIMPLE
141 #ifdef DEFAULT_CPU_TOMCAT
142 #define DEFAULT_MACHINE bfd_mach_frvtomcat
143 #define DEFAULT_FLAGS EF_FRV_CPU_TOMCAT
146 #ifdef DEFAULT_CPU_FR400
147 #define DEFAULT_MACHINE bfd_mach_fr400
148 #define DEFAULT_FLAGS EF_FRV_CPU_FR400
151 #ifdef DEFAULT_CPU_FR550
152 #define DEFAULT_MACHINE bfd_mach_fr550
153 #define DEFAULT_FLAGS EF_FRV_CPU_FR550
156 #define DEFAULT_MACHINE bfd_mach_fr500
157 #define DEFAULT_FLAGS EF_FRV_CPU_FR500
166 # define DEFAULT_FDPIC EF_FRV_FDPIC
168 # define DEFAULT_FDPIC 0
171 static unsigned long frv_mach
= bfd_mach_frv
;
172 static bfd_boolean fr400_audio
;
174 /* Flags to set in the elf header */
175 static flagword frv_flags
= DEFAULT_FLAGS
| DEFAULT_FDPIC
;
177 static int frv_user_set_flags_p
= 0;
178 static int frv_pic_p
= 0;
179 static const char *frv_pic_flag
= DEFAULT_FDPIC
? "-mfdpic" : (const char *)0;
181 /* Print tomcat-specific debugging info. */
182 static int tomcat_debug
= 0;
184 /* Tomcat-specific NOP statistics. */
185 static int tomcat_stats
= 0;
186 static int tomcat_doubles
= 0;
187 static int tomcat_singles
= 0;
189 /* Forward reference to static functions */
190 static void frv_set_flags
PARAMS ((int));
191 static void frv_pic_ptr
PARAMS ((int));
192 static void frv_frob_file_section
PARAMS ((bfd
*, asection
*, PTR
));
194 /* The target specific pseudo-ops which we support. */
195 const pseudo_typeS md_pseudo_table
[] =
197 { "eflags", frv_set_flags
, 0 },
199 { "picptr", frv_pic_ptr
, 4 },
204 #define FRV_SHORTOPTS "G:"
205 const char * md_shortopts
= FRV_SHORTOPTS
;
207 #define OPTION_GPR_32 (OPTION_MD_BASE)
208 #define OPTION_GPR_64 (OPTION_MD_BASE + 1)
209 #define OPTION_FPR_32 (OPTION_MD_BASE + 2)
210 #define OPTION_FPR_64 (OPTION_MD_BASE + 3)
211 #define OPTION_SOFT_FLOAT (OPTION_MD_BASE + 4)
212 #define OPTION_DWORD_YES (OPTION_MD_BASE + 5)
213 #define OPTION_DWORD_NO (OPTION_MD_BASE + 6)
214 #define OPTION_DOUBLE (OPTION_MD_BASE + 7)
215 #define OPTION_NO_DOUBLE (OPTION_MD_BASE + 8)
216 #define OPTION_MEDIA (OPTION_MD_BASE + 9)
217 #define OPTION_NO_MEDIA (OPTION_MD_BASE + 10)
218 #define OPTION_CPU (OPTION_MD_BASE + 11)
219 #define OPTION_PIC (OPTION_MD_BASE + 12)
220 #define OPTION_BIGPIC (OPTION_MD_BASE + 13)
221 #define OPTION_LIBPIC (OPTION_MD_BASE + 14)
222 #define OPTION_MULADD (OPTION_MD_BASE + 15)
223 #define OPTION_NO_MULADD (OPTION_MD_BASE + 16)
224 #define OPTION_TOMCAT_DEBUG (OPTION_MD_BASE + 17)
225 #define OPTION_TOMCAT_STATS (OPTION_MD_BASE + 18)
226 #define OPTION_PACK (OPTION_MD_BASE + 19)
227 #define OPTION_NO_PACK (OPTION_MD_BASE + 20)
228 #define OPTION_FDPIC (OPTION_MD_BASE + 21)
229 #define OPTION_NOPIC (OPTION_MD_BASE + 22)
231 struct option md_longopts
[] =
233 { "mgpr-32", no_argument
, NULL
, OPTION_GPR_32
},
234 { "mgpr-64", no_argument
, NULL
, OPTION_GPR_64
},
235 { "mfpr-32", no_argument
, NULL
, OPTION_FPR_32
},
236 { "mfpr-64", no_argument
, NULL
, OPTION_FPR_64
},
237 { "mhard-float", no_argument
, NULL
, OPTION_FPR_64
},
238 { "msoft-float", no_argument
, NULL
, OPTION_SOFT_FLOAT
},
239 { "mdword", no_argument
, NULL
, OPTION_DWORD_YES
},
240 { "mno-dword", no_argument
, NULL
, OPTION_DWORD_NO
},
241 { "mdouble", no_argument
, NULL
, OPTION_DOUBLE
},
242 { "mno-double", no_argument
, NULL
, OPTION_NO_DOUBLE
},
243 { "mmedia", no_argument
, NULL
, OPTION_MEDIA
},
244 { "mno-media", no_argument
, NULL
, OPTION_NO_MEDIA
},
245 { "mcpu", required_argument
, NULL
, OPTION_CPU
},
246 { "mpic", no_argument
, NULL
, OPTION_PIC
},
247 { "mPIC", no_argument
, NULL
, OPTION_BIGPIC
},
248 { "mlibrary-pic", no_argument
, NULL
, OPTION_LIBPIC
},
249 { "mmuladd", no_argument
, NULL
, OPTION_MULADD
},
250 { "mno-muladd", no_argument
, NULL
, OPTION_NO_MULADD
},
251 { "mtomcat-debug", no_argument
, NULL
, OPTION_TOMCAT_DEBUG
},
252 { "mtomcat-stats", no_argument
, NULL
, OPTION_TOMCAT_STATS
},
253 { "mpack", no_argument
, NULL
, OPTION_PACK
},
254 { "mno-pack", no_argument
, NULL
, OPTION_NO_PACK
},
255 { "mfdpic", no_argument
, NULL
, OPTION_FDPIC
},
256 { "mnopic", no_argument
, NULL
, OPTION_NOPIC
},
257 { NULL
, no_argument
, NULL
, 0 },
260 size_t md_longopts_size
= sizeof (md_longopts
);
262 /* What value to give to bfd_set_gp_size. */
263 static int g_switch_value
= 8;
266 md_parse_option (c
, arg
)
276 g_switch_value
= atoi (arg
);
277 if (! g_switch_value
)
278 frv_flags
|= EF_FRV_G0
;
282 frv_flags
= (frv_flags
& ~EF_FRV_GPR_MASK
) | EF_FRV_GPR_32
;
286 frv_flags
= (frv_flags
& ~EF_FRV_GPR_MASK
) | EF_FRV_GPR_64
;
290 frv_flags
= (frv_flags
& ~EF_FRV_FPR_MASK
) | EF_FRV_FPR_32
;
294 frv_flags
= (frv_flags
& ~EF_FRV_FPR_MASK
) | EF_FRV_FPR_64
;
297 case OPTION_SOFT_FLOAT
:
298 frv_flags
= (frv_flags
& ~EF_FRV_FPR_MASK
) | EF_FRV_FPR_NONE
;
301 case OPTION_DWORD_YES
:
302 frv_flags
= (frv_flags
& ~EF_FRV_DWORD_MASK
) | EF_FRV_DWORD_YES
;
305 case OPTION_DWORD_NO
:
306 frv_flags
= (frv_flags
& ~EF_FRV_DWORD_MASK
) | EF_FRV_DWORD_NO
;
310 frv_flags
|= EF_FRV_DOUBLE
;
313 case OPTION_NO_DOUBLE
:
314 frv_flags
&= ~EF_FRV_DOUBLE
;
318 frv_flags
|= EF_FRV_MEDIA
;
321 case OPTION_NO_MEDIA
:
322 frv_flags
&= ~EF_FRV_MEDIA
;
326 frv_flags
|= EF_FRV_MULADD
;
329 case OPTION_NO_MULADD
:
330 frv_flags
&= ~EF_FRV_MULADD
;
334 frv_flags
&= ~EF_FRV_NOPACK
;
338 frv_flags
|= EF_FRV_NOPACK
;
344 int cpu_flags
= EF_FRV_CPU_GENERIC
;
346 /* Identify the processor type */
348 if (strcmp (p
, "frv") == 0)
350 cpu_flags
= EF_FRV_CPU_GENERIC
;
351 frv_mach
= bfd_mach_frv
;
354 else if (strcmp (p
, "fr500") == 0)
356 cpu_flags
= EF_FRV_CPU_FR500
;
357 frv_mach
= bfd_mach_fr500
;
360 else if (strcmp (p
, "fr550") == 0)
362 cpu_flags
= EF_FRV_CPU_FR550
;
363 frv_mach
= bfd_mach_fr550
;
366 else if (strcmp (p
, "fr450") == 0)
368 cpu_flags
= EF_FRV_CPU_FR450
;
369 frv_mach
= bfd_mach_fr450
;
372 else if (strcmp (p
, "fr405") == 0)
374 cpu_flags
= EF_FRV_CPU_FR405
;
375 frv_mach
= bfd_mach_fr400
;
379 else if (strcmp (p
, "fr400") == 0)
381 cpu_flags
= EF_FRV_CPU_FR400
;
382 frv_mach
= bfd_mach_fr400
;
386 else if (strcmp (p
, "fr300") == 0)
388 cpu_flags
= EF_FRV_CPU_FR300
;
389 frv_mach
= bfd_mach_fr300
;
392 else if (strcmp (p
, "simple") == 0)
394 cpu_flags
= EF_FRV_CPU_SIMPLE
;
395 frv_mach
= bfd_mach_frvsimple
;
396 frv_flags
|= EF_FRV_NOPACK
;
399 else if (strcmp (p
, "tomcat") == 0)
401 cpu_flags
= EF_FRV_CPU_TOMCAT
;
402 frv_mach
= bfd_mach_frvtomcat
;
407 as_fatal ("Unknown cpu -mcpu=%s", arg
);
411 frv_flags
= (frv_flags
& ~EF_FRV_CPU_MASK
) | cpu_flags
;
416 frv_flags
|= EF_FRV_PIC
;
418 frv_pic_flag
= "-fpic";
422 frv_flags
|= EF_FRV_BIGPIC
;
424 frv_pic_flag
= "-fPIC";
428 frv_flags
|= (EF_FRV_LIBPIC
| EF_FRV_G0
);
430 frv_pic_flag
= "-mlibrary-pic";
435 frv_flags
|= EF_FRV_FDPIC
;
436 frv_pic_flag
= "-mfdpic";
440 frv_flags
&= ~(EF_FRV_FDPIC
| EF_FRV_PIC
441 | EF_FRV_BIGPIC
| EF_FRV_LIBPIC
);
445 case OPTION_TOMCAT_DEBUG
:
449 case OPTION_TOMCAT_STATS
:
458 md_show_usage (stream
)
461 fprintf (stream
, _("FRV specific command line options:\n"));
462 fprintf (stream
, _("-G n Data >= n bytes is in small data area\n"));
463 fprintf (stream
, _("-mgpr-32 Note 32 gprs are used\n"));
464 fprintf (stream
, _("-mgpr-64 Note 64 gprs are used\n"));
465 fprintf (stream
, _("-mfpr-32 Note 32 fprs are used\n"));
466 fprintf (stream
, _("-mfpr-64 Note 64 fprs are used\n"));
467 fprintf (stream
, _("-msoft-float Note software fp is used\n"));
468 fprintf (stream
, _("-mdword Note stack is aligned to a 8 byte boundary\n"));
469 fprintf (stream
, _("-mno-dword Note stack is aligned to a 4 byte boundary\n"));
470 fprintf (stream
, _("-mdouble Note fp double insns are used\n"));
471 fprintf (stream
, _("-mmedia Note media insns are used\n"));
472 fprintf (stream
, _("-mmuladd Note multiply add/subtract insns are used\n"));
473 fprintf (stream
, _("-mpack Note instructions are packed\n"));
474 fprintf (stream
, _("-mno-pack Do not allow instructions to be packed\n"));
475 fprintf (stream
, _("-mpic Note small position independent code\n"));
476 fprintf (stream
, _("-mPIC Note large position independent code\n"));
477 fprintf (stream
, _("-mlibrary-pic Compile library for large position indepedent code\n"));
478 fprintf (stream
, _("-mfdpic Assemble for the FDPIC ABI\n"));
479 fprintf (stream
, _("-mnopic Disable -mpic, -mPIC, -mlibrary-pic and -mfdpic\n"));
480 fprintf (stream
, _("-mcpu={fr500|fr550|fr400|fr405|fr450|fr300|frv|simple|tomcat}\n"));
481 fprintf (stream
, _(" Record the cpu type\n"));
482 fprintf (stream
, _("-mtomcat-stats Print out stats for tomcat workarounds\n"));
483 fprintf (stream
, _("-mtomcat-debug Debug tomcat workarounds\n"));
490 /* Initialize the `cgen' interface. */
492 /* Set the machine number and endian. */
493 gas_cgen_cpu_desc
= frv_cgen_cpu_open (CGEN_CPU_OPEN_MACHS
, 0,
494 CGEN_CPU_OPEN_ENDIAN
,
497 frv_cgen_init_asm (gas_cgen_cpu_desc
);
499 /* This is a callback from cgen to gas to parse operands. */
500 cgen_set_parse_operand_fn (gas_cgen_cpu_desc
, gas_cgen_parse_operand
);
502 /* Set the ELF flags if desired. */
504 bfd_set_private_flags (stdoutput
, frv_flags
);
506 /* Set the machine type */
507 bfd_default_set_arch_mach (stdoutput
, bfd_arch_frv
, frv_mach
);
509 /* Set up gp size so we can put local common items in .sbss */
510 bfd_set_gp_size (stdoutput
, g_switch_value
);
512 frv_vliw_reset (& vliw
, frv_mach
, frv_flags
);
516 frv_md_fdpic_enabled (void)
518 return (frv_flags
& EF_FRV_FDPIC
) != 0;
523 struct vliw_insn_list
*frv_insert_vliw_insn
PARAMS ((bfd_boolean
));
525 struct vliw_insn_list
*
526 frv_insert_vliw_insn (count
)
529 struct vliw_insn_list
*vliw_insn_list_entry
;
530 struct vliw_chain
*vliw_chain_entry
;
532 if (current_vliw_chain
== NULL
)
534 vliw_chain_entry
= (struct vliw_chain
*) xmalloc (sizeof (struct vliw_chain
));
535 vliw_chain_entry
->insn_count
= 0;
536 vliw_chain_entry
->insn_list
= NULL
;
537 vliw_chain_entry
->next
= NULL
;
538 vliw_chain_entry
->num
= chain_num
++;
541 vliw_chain_top
= vliw_chain_entry
;
542 current_vliw_chain
= vliw_chain_entry
;
543 if (previous_vliw_chain
)
544 previous_vliw_chain
->next
= vliw_chain_entry
;
547 vliw_insn_list_entry
= (struct vliw_insn_list
*) xmalloc (sizeof (struct vliw_insn_list
));
548 vliw_insn_list_entry
->type
= VLIW_GENERIC_TYPE
;
549 vliw_insn_list_entry
->insn
= NULL
;
550 vliw_insn_list_entry
->sym
= NULL
;
551 vliw_insn_list_entry
->snop_frag
= NULL
;
552 vliw_insn_list_entry
->dnop_frag
= NULL
;
553 vliw_insn_list_entry
->next
= NULL
;
556 current_vliw_chain
->insn_count
++;
558 if (current_vliw_insn
)
559 current_vliw_insn
->next
= vliw_insn_list_entry
;
560 current_vliw_insn
= vliw_insn_list_entry
;
562 if (!current_vliw_chain
->insn_list
)
563 current_vliw_chain
->insn_list
= current_vliw_insn
;
565 return vliw_insn_list_entry
;
568 /* Identify the following cases:
570 1) A VLIW insn that contains both a branch and the branch destination.
571 This requires the insertion of two vliw instructions before the
572 branch. The first consists of two nops. The second consists of
575 2) A single instruction VLIW insn which is the destination of a branch
576 that is in the next VLIW insn. This requires the insertion of a vliw
577 insn containing two nops before the branch.
579 3) A double instruction VLIW insn which contains the destination of a
580 branch that is in the next VLIW insn. This requires the insertion of
581 a VLIW insn containing a single nop before the branch.
583 4) A single instruction VLIW insn which contains branch destination (x),
584 followed by a single instruction VLIW insn which does not contain
585 the branch to (x), followed by a VLIW insn which does contain the branch
586 to (x). This requires the insertion of a VLIW insn containing a single
587 nop before the VLIW instruction containing the branch.
590 #define FRV_IS_NOP(insn) (insn.buffer[0] == FRV_NOP_PACK || insn.buffer[0] == FRV_NOP_NOPACK)
591 #define FRV_NOP_PACK 0x00880000 /* ori.p gr0,0,gr0 */
592 #define FRV_NOP_NOPACK 0x80880000 /* ori gr0,0,gr0 */
594 /* Check a vliw insn for an insn of type containing the sym passed in label_sym. */
596 static struct vliw_insn_list
*frv_find_in_vliw
597 PARAMS ((enum vliw_insn_type
, struct vliw_chain
*, symbolS
*));
599 static struct vliw_insn_list
*
600 frv_find_in_vliw (vliw_insn_type
, this_chain
, label_sym
)
601 enum vliw_insn_type vliw_insn_type
;
602 struct vliw_chain
*this_chain
;
606 struct vliw_insn_list
*the_insn
;
611 for (the_insn
= this_chain
->insn_list
; the_insn
; the_insn
= the_insn
->next
)
613 if (the_insn
->type
== vliw_insn_type
614 && the_insn
->sym
== label_sym
)
623 /* A Vliw insn containing a single nop insn. */
626 /* A Vliw insn containing two nop insns. */
629 /* Two vliw insns. The first containing two nop insns.
630 The second contain a single nop insn. */
631 VLIW_DOUBLE_THEN_SINGLE_NOP
634 static void frv_debug_tomcat
PARAMS ((struct vliw_chain
*));
637 frv_debug_tomcat (start_chain
)
638 struct vliw_chain
*start_chain
;
640 struct vliw_chain
*this_chain
;
641 struct vliw_insn_list
*this_insn
;
644 for (this_chain
= start_chain
; this_chain
; this_chain
= this_chain
->next
, i
++)
646 fprintf (stderr
, "\nVliw Insn #%d, #insns: %d\n", i
, this_chain
->insn_count
);
648 for (this_insn
= this_chain
->insn_list
; this_insn
; this_insn
= this_insn
->next
)
650 if (this_insn
->type
== VLIW_LABEL_TYPE
)
651 fprintf (stderr
, "Label Value: %d\n", (int) this_insn
->sym
);
652 else if (this_insn
->type
== VLIW_BRANCH_TYPE
)
653 fprintf (stderr
, "%s to %d\n", this_insn
->insn
->base
->name
, (int) this_insn
->sym
);
654 else if (this_insn
->type
== VLIW_BRANCH_HAS_NOPS
)
655 fprintf (stderr
, "nop'd %s to %d\n", this_insn
->insn
->base
->name
, (int) this_insn
->sym
);
656 else if (this_insn
->type
== VLIW_NOP_TYPE
)
657 fprintf (stderr
, "Nop\n");
659 fprintf (stderr
, " %s\n", this_insn
->insn
->base
->name
);
664 static void frv_adjust_vliw_count
PARAMS ((struct vliw_chain
*));
667 frv_adjust_vliw_count (this_chain
)
668 struct vliw_chain
*this_chain
;
670 struct vliw_insn_list
*this_insn
;
672 this_chain
->insn_count
= 0;
674 for (this_insn
= this_chain
->insn_list
;
676 this_insn
= this_insn
->next
)
678 if (this_insn
->type
!= VLIW_LABEL_TYPE
)
679 this_chain
->insn_count
++;
684 /* Insert the desired nop combination in the vliw chain before insert_before_insn.
685 Rechain the vliw insn. */
687 static struct vliw_chain
*frv_tomcat_shuffle
688 PARAMS ((enum vliw_nop_type
, struct vliw_chain
*, struct vliw_insn_list
*));
690 static struct vliw_chain
*
691 frv_tomcat_shuffle (this_nop_type
, vliw_to_split
, insert_before_insn
)
692 enum vliw_nop_type this_nop_type
;
693 struct vliw_chain
*vliw_to_split
;
694 struct vliw_insn_list
*insert_before_insn
;
697 bfd_boolean pack_prev
= FALSE
;
698 struct vliw_chain
*return_me
= NULL
;
699 struct vliw_insn_list
*prev_insn
= NULL
;
700 struct vliw_insn_list
*curr_insn
= vliw_to_split
->insn_list
;
702 struct vliw_chain
*double_nop
= (struct vliw_chain
*) xmalloc (sizeof (struct vliw_chain
));
703 struct vliw_chain
*single_nop
= (struct vliw_chain
*) xmalloc (sizeof (struct vliw_chain
));
704 struct vliw_chain
*second_part
= (struct vliw_chain
*) xmalloc (sizeof (struct vliw_chain
));
705 struct vliw_chain
*curr_vliw
= vliw_chain_top
;
706 struct vliw_chain
*prev_vliw
= NULL
;
708 while (curr_insn
&& curr_insn
!= insert_before_insn
)
710 /* We can't set the packing bit on a label. If we have the case
714 branch that needs nops
715 Then don't set pack bit later. */
717 if (curr_insn
->type
!= VLIW_LABEL_TYPE
)
719 prev_insn
= curr_insn
;
720 curr_insn
= curr_insn
->next
;
723 while (curr_vliw
&& curr_vliw
!= vliw_to_split
)
725 prev_vliw
= curr_vliw
;
726 curr_vliw
= curr_vliw
->next
;
729 switch (this_nop_type
)
731 case VLIW_SINGLE_NOP
:
734 /* Branch is first, Insert the NOP prior to this vliw insn. */
736 prev_vliw
->next
= single_nop
;
738 vliw_chain_top
= single_nop
;
739 single_nop
->next
= vliw_to_split
;
740 vliw_to_split
->insn_list
->type
= VLIW_BRANCH_HAS_NOPS
;
741 return_me
= vliw_to_split
;
745 /* Set the packing bit on the previous insn. */
748 unsigned char *buffer
= prev_insn
->address
;
751 /* The branch is in the middle. Split this vliw insn into first
752 and second parts. Insert the NOP inbetween. */
754 second_part
->insn_list
= insert_before_insn
;
755 second_part
->insn_list
->type
= VLIW_BRANCH_HAS_NOPS
;
756 second_part
->next
= vliw_to_split
->next
;
757 frv_adjust_vliw_count (second_part
);
759 single_nop
->next
= second_part
;
761 vliw_to_split
->next
= single_nop
;
762 prev_insn
->next
= NULL
;
764 return_me
= second_part
;
765 frv_adjust_vliw_count (vliw_to_split
);
769 case VLIW_DOUBLE_NOP
:
772 /* Branch is first, Insert the NOP prior to this vliw insn. */
774 prev_vliw
->next
= double_nop
;
776 vliw_chain_top
= double_nop
;
778 double_nop
->next
= vliw_to_split
;
779 return_me
= vliw_to_split
;
780 vliw_to_split
->insn_list
->type
= VLIW_BRANCH_HAS_NOPS
;
784 /* Set the packing bit on the previous insn. */
787 unsigned char *buffer
= prev_insn
->address
;
791 /* The branch is in the middle. Split this vliw insn into first
792 and second parts. Insert the NOP inbetween. */
793 second_part
->insn_list
= insert_before_insn
;
794 second_part
->insn_list
->type
= VLIW_BRANCH_HAS_NOPS
;
795 second_part
->next
= vliw_to_split
->next
;
796 frv_adjust_vliw_count (second_part
);
798 double_nop
->next
= second_part
;
800 vliw_to_split
->next
= single_nop
;
801 prev_insn
->next
= NULL
;
802 frv_adjust_vliw_count (vliw_to_split
);
804 return_me
= second_part
;
808 case VLIW_DOUBLE_THEN_SINGLE_NOP
:
809 double_nop
->next
= single_nop
;
810 double_nop
->insn_count
= 2;
811 double_nop
->insn_list
= &double_nop_insn
;
812 single_nop
->insn_count
= 1;
813 single_nop
->insn_list
= &single_nop_insn
;
817 /* The branch is the first insn in this vliw. Don't split the vliw. Insert
818 the nops prior to this vliw. */
820 prev_vliw
->next
= double_nop
;
822 vliw_chain_top
= double_nop
;
824 single_nop
->next
= vliw_to_split
;
825 return_me
= vliw_to_split
;
826 vliw_to_split
->insn_list
->type
= VLIW_BRANCH_HAS_NOPS
;
830 /* Set the packing bit on the previous insn. */
833 unsigned char *buffer
= prev_insn
->address
;
837 /* The branch is in the middle of this vliw insn. Split into first and
838 second parts. Insert the nop vliws in between. */
839 second_part
->insn_list
= insert_before_insn
;
840 second_part
->insn_list
->type
= VLIW_BRANCH_HAS_NOPS
;
841 second_part
->next
= vliw_to_split
->next
;
842 frv_adjust_vliw_count (second_part
);
844 single_nop
->next
= second_part
;
846 vliw_to_split
->next
= double_nop
;
847 prev_insn
->next
= NULL
;
848 frv_adjust_vliw_count (vliw_to_split
);
850 return_me
= second_part
;
858 static void frv_tomcat_analyze_vliw_chains
PARAMS ((void));
861 frv_tomcat_analyze_vliw_chains ()
863 struct vliw_chain
*vliw1
= NULL
;
864 struct vliw_chain
*vliw2
= NULL
;
865 struct vliw_chain
*vliw3
= NULL
;
867 struct vliw_insn_list
*this_insn
= NULL
;
868 struct vliw_insn_list
*temp_insn
= NULL
;
870 /* We potentially need to look at three VLIW insns to determine if the
871 workaround is required. Set them up. Ignore existing nops during analysis. */
873 #define FRV_SET_VLIW_WINDOW(VLIW1, VLIW2, VLIW3) \
874 if (VLIW1 && VLIW1->next) \
875 VLIW2 = VLIW1->next; \
878 if (VLIW2 && VLIW2->next) \
879 VLIW3 = VLIW2->next; \
883 vliw1
= vliw_chain_top
;
887 FRV_SET_VLIW_WINDOW (vliw1
, vliw2
, vliw3
);
892 if (vliw1
->insn_count
== 1)
894 /* check vliw1 for a label. */
895 if (vliw1
->insn_list
->type
== VLIW_LABEL_TYPE
)
897 temp_insn
= frv_find_in_vliw (VLIW_BRANCH_TYPE
, vliw2
, vliw1
->insn_list
->sym
);
900 vliw1
= frv_tomcat_shuffle (VLIW_DOUBLE_NOP
, vliw2
, vliw1
->insn_list
);
901 temp_insn
->dnop_frag
->fr_subtype
= NOP_KEEP
;
908 && vliw2
->insn_count
== 1
909 && (temp_insn
= frv_find_in_vliw (VLIW_BRANCH_TYPE
, vliw3
, vliw1
->insn_list
->sym
)) != NULL
)
911 temp_insn
->snop_frag
->fr_subtype
= NOP_KEEP
;
912 vliw1
= frv_tomcat_shuffle (VLIW_SINGLE_NOP
, vliw3
, vliw3
->insn_list
);
920 if (vliw1
->insn_count
== 2)
922 struct vliw_insn_list
*this_insn
;
924 /* check vliw1 for a label. */
925 for (this_insn
= vliw1
->insn_list
; this_insn
; this_insn
= this_insn
->next
)
927 if (this_insn
->type
== VLIW_LABEL_TYPE
)
929 if ((temp_insn
= frv_find_in_vliw (VLIW_BRANCH_TYPE
, vliw2
, this_insn
->sym
)) != NULL
)
931 temp_insn
->snop_frag
->fr_subtype
= NOP_KEEP
;
932 vliw1
= frv_tomcat_shuffle (VLIW_SINGLE_NOP
, vliw2
, this_insn
);
942 /* Examine each insn in this VLIW. Look for the workaround criteria. */
943 for (this_insn
= vliw1
->insn_list
; this_insn
; this_insn
= this_insn
->next
)
945 /* Don't look at labels or nops. */
947 && (this_insn
->type
== VLIW_LABEL_TYPE
948 || this_insn
->type
== VLIW_NOP_TYPE
949 || this_insn
->type
== VLIW_BRANCH_HAS_NOPS
))
950 this_insn
= this_insn
->next
;
958 if (frv_is_branch_insn (this_insn
->insn
))
960 if ((temp_insn
= frv_find_in_vliw (VLIW_LABEL_TYPE
, vliw1
, this_insn
->sym
)) != NULL
)
962 /* Insert [nop/nop] [nop] before branch. */
963 this_insn
->snop_frag
->fr_subtype
= NOP_KEEP
;
964 this_insn
->dnop_frag
->fr_subtype
= NOP_KEEP
;
965 vliw1
= frv_tomcat_shuffle (VLIW_DOUBLE_THEN_SINGLE_NOP
, vliw1
, this_insn
);
972 /* This vliw insn checks out okay. Take a look at the next one. */
978 frv_tomcat_workaround ()
980 if (frv_mach
!= bfd_mach_frvtomcat
)
984 frv_debug_tomcat (vliw_chain_top
);
986 frv_tomcat_analyze_vliw_chains ();
990 fprintf (stderr
, "Inserted %d Single Nops\n", tomcat_singles
);
991 fprintf (stderr
, "Inserted %d Double Nops\n", tomcat_doubles
);
996 fr550_check_insn_acc_range (frv_insn
*insn
, int low
, int hi
)
999 switch (CGEN_INSN_NUM (insn
->insn
))
1001 case FRV_INSN_MADDACCS
:
1002 case FRV_INSN_MSUBACCS
:
1003 case FRV_INSN_MDADDACCS
:
1004 case FRV_INSN_MDSUBACCS
:
1005 case FRV_INSN_MASACCS
:
1006 case FRV_INSN_MDASACCS
:
1007 acc
= insn
->fields
.f_ACC40Si
;
1008 if (acc
< low
|| acc
> hi
)
1009 return 1; /* out of range */
1010 acc
= insn
->fields
.f_ACC40Sk
;
1011 if (acc
< low
|| acc
> hi
)
1012 return 1; /* out of range */
1014 case FRV_INSN_MMULHS
:
1015 case FRV_INSN_MMULHU
:
1016 case FRV_INSN_MMULXHS
:
1017 case FRV_INSN_MMULXHU
:
1018 case FRV_INSN_CMMULHS
:
1019 case FRV_INSN_CMMULHU
:
1020 case FRV_INSN_MQMULHS
:
1021 case FRV_INSN_MQMULHU
:
1022 case FRV_INSN_MQMULXHS
:
1023 case FRV_INSN_MQMULXHU
:
1024 case FRV_INSN_CMQMULHS
:
1025 case FRV_INSN_CMQMULHU
:
1026 case FRV_INSN_MMACHS
:
1027 case FRV_INSN_MMRDHS
:
1028 case FRV_INSN_CMMACHS
:
1029 case FRV_INSN_MQMACHS
:
1030 case FRV_INSN_CMQMACHS
:
1031 case FRV_INSN_MQXMACHS
:
1032 case FRV_INSN_MQXMACXHS
:
1033 case FRV_INSN_MQMACXHS
:
1034 case FRV_INSN_MCPXRS
:
1035 case FRV_INSN_MCPXIS
:
1036 case FRV_INSN_CMCPXRS
:
1037 case FRV_INSN_CMCPXIS
:
1038 case FRV_INSN_MQCPXRS
:
1039 case FRV_INSN_MQCPXIS
:
1040 acc
= insn
->fields
.f_ACC40Sk
;
1041 if (acc
< low
|| acc
> hi
)
1042 return 1; /* out of range */
1044 case FRV_INSN_MMACHU
:
1045 case FRV_INSN_MMRDHU
:
1046 case FRV_INSN_CMMACHU
:
1047 case FRV_INSN_MQMACHU
:
1048 case FRV_INSN_CMQMACHU
:
1049 case FRV_INSN_MCPXRU
:
1050 case FRV_INSN_MCPXIU
:
1051 case FRV_INSN_CMCPXRU
:
1052 case FRV_INSN_CMCPXIU
:
1053 case FRV_INSN_MQCPXRU
:
1054 case FRV_INSN_MQCPXIU
:
1055 acc
= insn
->fields
.f_ACC40Uk
;
1056 if (acc
< low
|| acc
> hi
)
1057 return 1; /* out of range */
1062 return 0; /* all is ok */
1066 fr550_check_acc_range (FRV_VLIW
*vliw
, frv_insn
*insn
)
1068 switch ((*vliw
->current_vliw
)[vliw
->next_slot
- 1])
1072 return fr550_check_insn_acc_range (insn
, 0, 3);
1075 return fr550_check_insn_acc_range (insn
, 4, 7);
1079 return 0; /* all is ok */
1082 /* Return true if the target implements instruction INSN. */
1085 target_implements_insn_p (const CGEN_INSN
*insn
)
1090 /* bfd_mach_frv or generic. */
1093 case bfd_mach_fr300
:
1094 case bfd_mach_frvsimple
:
1095 return CGEN_INSN_MACH_HAS_P (insn
, MACH_SIMPLE
);
1097 case bfd_mach_fr400
:
1098 return ((fr400_audio
|| !CGEN_INSN_ATTR_VALUE (insn
, CGEN_INSN_AUDIO
))
1099 && CGEN_INSN_MACH_HAS_P (insn
, MACH_FR400
));
1101 case bfd_mach_fr450
:
1102 return CGEN_INSN_MACH_HAS_P (insn
, MACH_FR450
);
1104 case bfd_mach_fr500
:
1105 return CGEN_INSN_MACH_HAS_P (insn
, MACH_FR500
);
1107 case bfd_mach_fr550
:
1108 return CGEN_INSN_MACH_HAS_P (insn
, MACH_FR550
);
1118 int packing_constraint
;
1119 finished_insnS finished_insn
;
1120 fragS
*double_nop_frag
= NULL
;
1121 fragS
*single_nop_frag
= NULL
;
1122 struct vliw_insn_list
*vliw_insn_list_entry
= NULL
;
1124 /* Initialize GAS's cgen interface for a new instruction. */
1125 gas_cgen_init_parse ();
1127 memset (&insn
, 0, sizeof (insn
));
1129 insn
.insn
= frv_cgen_assemble_insn
1130 (gas_cgen_cpu_desc
, str
, & insn
.fields
, insn
.buffer
, &errmsg
);
1138 /* If the cpu is tomcat, then we need to insert nops to workaround
1139 hardware limitations. We need to keep track of each vliw unit
1140 and examine the length of the unit and the individual insns
1141 within the unit to determine the number and location of the
1143 if (frv_mach
== bfd_mach_frvtomcat
)
1145 /* If we've just finished a VLIW insn OR this is a branch,
1146 then start up a new frag. Fill it with nops. We will get rid
1147 of those that are not required after we've seen all of the
1148 instructions but before we start resolving fixups. */
1149 if ( !FRV_IS_NOP (insn
)
1150 && (frv_is_branch_insn (insn
.insn
) || insn
.fields
.f_pack
))
1154 frag_wane (frag_now
);
1156 double_nop_frag
= frag_now
;
1157 buffer
= frag_var (rs_machine_dependent
, 8, 8, NOP_DELETE
, NULL
, 0, 0);
1158 md_number_to_chars (buffer
, FRV_NOP_PACK
, 4);
1159 md_number_to_chars (buffer
+4, FRV_NOP_NOPACK
, 4);
1161 frag_wane (frag_now
);
1163 single_nop_frag
= frag_now
;
1164 buffer
= frag_var (rs_machine_dependent
, 4, 4, NOP_DELETE
, NULL
, 0, 0);
1165 md_number_to_chars (buffer
, FRV_NOP_NOPACK
, 4);
1168 vliw_insn_list_entry
= frv_insert_vliw_insn (DO_COUNT
);
1169 vliw_insn_list_entry
->insn
= insn
.insn
;
1170 if (frv_is_branch_insn (insn
.insn
))
1171 vliw_insn_list_entry
->type
= VLIW_BRANCH_TYPE
;
1173 if ( !FRV_IS_NOP (insn
)
1174 && (frv_is_branch_insn (insn
.insn
) || insn
.fields
.f_pack
))
1176 vliw_insn_list_entry
->snop_frag
= single_nop_frag
;
1177 vliw_insn_list_entry
->dnop_frag
= double_nop_frag
;
1181 /* Make sure that this insn does not violate the VLIW packing constraints. */
1182 /* -mno-pack disallows any packing whatsoever. */
1183 if (frv_flags
& EF_FRV_NOPACK
)
1185 if (! insn
.fields
.f_pack
)
1187 as_bad (_("VLIW packing used for -mno-pack"));
1191 /* -mcpu=FRV is an idealized FR-V implementation that supports all of the
1192 instructions, don't do vliw checking. */
1193 else if (frv_mach
!= bfd_mach_frv
)
1195 if (!target_implements_insn_p (insn
.insn
))
1197 as_bad (_("Instruction not supported by this architecture"));
1200 packing_constraint
= frv_vliw_add_insn (& vliw
, insn
.insn
);
1201 if (frv_mach
== bfd_mach_fr550
&& ! packing_constraint
)
1202 packing_constraint
= fr550_check_acc_range (& vliw
, & insn
);
1203 if (insn
.fields
.f_pack
)
1204 frv_vliw_reset (& vliw
, frv_mach
, frv_flags
);
1205 if (packing_constraint
)
1207 as_bad (_("VLIW packing constraint violation"));
1212 /* Doesn't really matter what we pass for RELAX_P here. */
1213 gas_cgen_finish_insn (insn
.insn
, insn
.buffer
,
1214 CGEN_FIELDS_BITSIZE (& insn
.fields
), 1, &finished_insn
);
1217 /* If the cpu is tomcat, then we need to insert nops to workaround
1218 hardware limitations. We need to keep track of each vliw unit
1219 and examine the length of the unit and the individual insns
1220 within the unit to determine the number and location of the
1222 if (frv_mach
== bfd_mach_frvtomcat
)
1224 if (vliw_insn_list_entry
)
1225 vliw_insn_list_entry
->address
= finished_insn
.addr
;
1229 if (insn
.fields
.f_pack
)
1231 /* We've completed a VLIW insn. */
1232 previous_vliw_chain
= current_vliw_chain
;
1233 current_vliw_chain
= NULL
;
1234 current_vliw_insn
= NULL
;
1239 /* The syntax in the manual says constants begin with '#'.
1240 We just ignore it. */
1243 md_operand (expressionP
)
1244 expressionS
* expressionP
;
1246 if (* input_line_pointer
== '#')
1248 input_line_pointer
++;
1249 expression (expressionP
);
1254 md_section_align (segment
, size
)
1258 int align
= bfd_get_section_alignment (stdoutput
, segment
);
1259 return ((size
+ (1 << align
) - 1) & (-1 << align
));
1263 md_undefined_symbol (name
)
1264 char * name ATTRIBUTE_UNUSED
;
1269 /* Interface to relax_segment. */
1271 /* FIXME: Build table by hand, get it working, then machine generate. */
1272 const relax_typeS md_relax_table
[] =
1275 {511 - 2 - 2, -512 - 2 + 2, 0, 2 },
1276 {0x2000000 - 1 - 2, -0x2000000 - 2, 2, 0 },
1277 {0x2000000 - 1 - 2, -0x2000000 - 2, 4, 0 }
1281 frv_relax_frag (fragP
, stretch
)
1282 fragS
*fragP ATTRIBUTE_UNUSED
;
1283 long stretch ATTRIBUTE_UNUSED
;
1288 /* Return an initial guess of the length by which a fragment must grow to
1289 hold a branch to reach its destination.
1290 Also updates fr_type/fr_subtype as necessary.
1292 Called just before doing relaxation.
1293 Any symbol that is now undefined will not become defined.
1294 The guess for fr_var is ACTUALLY the growth beyond fr_fix.
1295 Whatever we do to grow fr_fix or fr_var contributes to our returned value.
1296 Although it may not be explicit in the frag, pretend fr_var starts with a
1300 md_estimate_size_before_relax (fragP
, segment
)
1302 segT segment ATTRIBUTE_UNUSED
;
1304 switch (fragP
->fr_subtype
)
1307 return fragP
->fr_var
;
1315 /* *fragP has been relaxed to its final size, and now needs to have
1316 the bytes inside it modified to conform to the new size.
1318 Called after relaxation is finished.
1319 fragP->fr_type == rs_machine_dependent.
1320 fragP->fr_subtype is the subtype of what the address relaxed to. */
1323 md_convert_frag (abfd
, sec
, fragP
)
1324 bfd
* abfd ATTRIBUTE_UNUSED
;
1325 segT sec ATTRIBUTE_UNUSED
;
1328 switch (fragP
->fr_subtype
)
1335 fragP
->fr_fix
= fragP
->fr_var
;
1341 /* Functions concerning relocs. */
1343 /* The location from which a PC relative jump should be calculated,
1344 given a PC relative reloc. */
1347 md_pcrel_from_section (fixP
, sec
)
1351 if (TC_FORCE_RELOCATION (fixP
)
1352 || (fixP
->fx_addsy
!= (symbolS
*) NULL
1353 && S_GET_SEGMENT (fixP
->fx_addsy
) != sec
))
1355 /* If we can't adjust this relocation, or if it references a
1356 local symbol in a different section (which
1357 TC_FORCE_RELOCATION can't check), let the linker figure it
1362 return (fixP
->fx_frag
->fr_address
+ fixP
->fx_where
) & ~1;
1365 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
1366 Returns BFD_RELOC_NONE if no reloc type can be found.
1367 *FIXP may be modified if desired. */
1369 bfd_reloc_code_real_type
1370 md_cgen_lookup_reloc (insn
, operand
, fixP
)
1371 const CGEN_INSN
* insn ATTRIBUTE_UNUSED
;
1372 const CGEN_OPERAND
* operand
;
1375 switch (operand
->type
)
1377 case FRV_OPERAND_LABEL16
:
1378 fixP
->fx_pcrel
= TRUE
;
1379 return BFD_RELOC_FRV_LABEL16
;
1381 case FRV_OPERAND_LABEL24
:
1382 fixP
->fx_pcrel
= TRUE
;
1383 return BFD_RELOC_FRV_LABEL24
;
1385 case FRV_OPERAND_UHI16
:
1386 case FRV_OPERAND_ULO16
:
1387 case FRV_OPERAND_SLO16
:
1389 /* The relocation type should be recorded in opinfo */
1390 if (fixP
->fx_cgen
.opinfo
!= 0)
1391 return fixP
->fx_cgen
.opinfo
;
1394 case FRV_OPERAND_D12
:
1395 case FRV_OPERAND_S12
:
1396 if (fixP
->fx_cgen
.opinfo
!= 0)
1397 return fixP
->fx_cgen
.opinfo
;
1399 return BFD_RELOC_FRV_GPREL12
;
1401 case FRV_OPERAND_U12
:
1402 return BFD_RELOC_FRV_GPRELU12
;
1407 return BFD_RELOC_NONE
;
1411 /* See whether we need to force a relocation into the output file.
1412 This is used to force out switch and PC relative relocations when
1416 frv_force_relocation (fix
)
1419 if (fix
->fx_r_type
== BFD_RELOC_FRV_GPREL12
1420 || fix
->fx_r_type
== BFD_RELOC_FRV_GPRELU12
)
1423 return generic_force_reloc (fix
);
1426 /* Apply a fixup that could be resolved within the assembler. */
1429 md_apply_fix3 (fixP
, valP
, seg
)
1434 if (fixP
->fx_addsy
== 0)
1435 switch (fixP
->fx_cgen
.opinfo
)
1437 case BFD_RELOC_FRV_HI16
:
1440 case BFD_RELOC_FRV_LO16
:
1445 gas_cgen_md_apply_fix3 (fixP
, valP
, seg
);
1450 /* Write a value out to the object file, using the appropriate endianness. */
1453 frv_md_number_to_chars (buf
, val
, n
)
1458 number_to_chars_bigendian (buf
, val
, n
);
1461 /* Turn a string in input_line_pointer into a floating point constant of type
1462 type, and store the appropriate bytes in *litP. The number of LITTLENUMS
1463 emitted is stored in *sizeP . An error message is returned, or NULL on OK.
1466 /* Equal to MAX_PRECISION in atof-ieee.c */
1467 #define MAX_LITTLENUMS 6
1470 md_atof (type
, litP
, sizeP
)
1477 LITTLENUM_TYPE words
[MAX_LITTLENUMS
];
1496 /* FIXME: Some targets allow other format chars for bigger sizes here. */
1500 return _("Bad call to md_atof()");
1503 t
= atof_ieee (input_line_pointer
, type
, words
);
1505 input_line_pointer
= t
;
1506 * sizeP
= prec
* sizeof (LITTLENUM_TYPE
);
1508 for (i
= 0; i
< prec
; i
++)
1510 md_number_to_chars (litP
, (valueT
) words
[i
],
1511 sizeof (LITTLENUM_TYPE
));
1512 litP
+= sizeof (LITTLENUM_TYPE
);
1519 frv_fix_adjustable (fixP
)
1522 bfd_reloc_code_real_type reloc_type
;
1524 if ((int) fixP
->fx_r_type
>= (int) BFD_RELOC_UNUSED
)
1526 const CGEN_INSN
*insn
= NULL
;
1527 int opindex
= (int) fixP
->fx_r_type
- (int) BFD_RELOC_UNUSED
;
1528 const CGEN_OPERAND
*operand
= cgen_operand_lookup_by_num(gas_cgen_cpu_desc
, opindex
);
1529 reloc_type
= md_cgen_lookup_reloc (insn
, operand
, fixP
);
1532 reloc_type
= fixP
->fx_r_type
;
1534 /* We need the symbol name for the VTABLE entries */
1535 if ( reloc_type
== BFD_RELOC_VTABLE_INHERIT
1536 || reloc_type
== BFD_RELOC_VTABLE_ENTRY
1537 || reloc_type
== BFD_RELOC_FRV_GPREL12
1538 || reloc_type
== BFD_RELOC_FRV_GPRELU12
)
1544 /* Allow user to set flags bits. */
1547 int arg ATTRIBUTE_UNUSED
;
1549 flagword new_flags
= get_absolute_expression ();
1550 flagword new_mask
= ~ (flagword
)0;
1552 frv_user_set_flags_p
= 1;
1553 if (*input_line_pointer
== ',')
1555 ++input_line_pointer
;
1556 new_mask
= get_absolute_expression ();
1559 frv_flags
= (frv_flags
& ~new_mask
) | (new_flags
& new_mask
);
1560 bfd_set_private_flags (stdoutput
, frv_flags
);
1563 /* Frv specific function to handle 4 byte initializations for pointers that are
1564 considered 'safe' for use with pic support. Until frv_frob_file{,_section}
1565 is run, we encode it a BFD_RELOC_CTOR, and it is turned back into a normal
1566 BFD_RELOC_32 at that time. */
1569 frv_pic_ptr (nbytes
)
1578 #ifdef md_flush_pending_output
1579 md_flush_pending_output ();
1582 if (is_it_end_of_statement ())
1584 demand_empty_rest_of_line ();
1588 #ifdef md_cons_align
1589 md_cons_align (nbytes
);
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;
1600 if (*input_line_pointer
== ')')
1601 input_line_pointer
++;
1603 as_bad ("missing ')'");
1604 reloc_type
= BFD_RELOC_FRV_FUNCDESC
;
1611 fix_new_exp (frag_now
, p
- frag_now
->fr_literal
, 4, &exp
, 0,
1614 while (*input_line_pointer
++ == ',');
1616 input_line_pointer
--; /* Put terminator back into stream. */
1617 demand_empty_rest_of_line ();
1623 #define DPRINTF1(A) fprintf (stderr, A)
1624 #define DPRINTF2(A,B) fprintf (stderr, A, B)
1625 #define DPRINTF3(A,B,C) fprintf (stderr, A, B, C)
1629 #define DPRINTF2(A,B)
1630 #define DPRINTF3(A,B,C)
1633 /* Go through a the sections looking for relocations that are problematical for
1634 pic. If not pic, just note that this object can't be linked with pic. If
1635 it is pic, see if it needs to be marked so that it will be fixed up, or if
1636 not possible, issue an error. */
1639 frv_frob_file_section (abfd
, sec
, ptr
)
1642 PTR ptr ATTRIBUTE_UNUSED
;
1644 segment_info_type
*seginfo
= seg_info (sec
);
1646 CGEN_CPU_DESC cd
= gas_cgen_cpu_desc
;
1647 flagword flags
= bfd_get_section_flags (abfd
, sec
);
1649 /* Skip relocations in known sections (.ctors, .dtors, and .gcc_except_table)
1650 since we can fix those up by hand. */
1651 int known_section_p
= (sec
->name
1652 && sec
->name
[0] == '.'
1653 && ((sec
->name
[1] == 'c'
1654 && strcmp (sec
->name
, ".ctor") == 0)
1655 || (sec
->name
[1] == 'd'
1656 && strcmp (sec
->name
, ".dtor") == 0)
1657 || (sec
->name
[1] == 'g'
1658 && strcmp (sec
->name
, ".gcc_except_table") == 0)));
1660 DPRINTF3 ("\nFrv section %s%s\n", sec
->name
, (known_section_p
) ? ", known section" : "");
1661 if ((flags
& SEC_ALLOC
) == 0)
1663 DPRINTF1 ("\tSkipping non-loaded section\n");
1667 for (fixp
= seginfo
->fix_root
; fixp
; fixp
= fixp
->fx_next
)
1669 symbolS
*s
= fixp
->fx_addsy
;
1670 bfd_reloc_code_real_type reloc
;
1673 const CGEN_OPERAND
*operand
;
1674 const CGEN_INSN
*insn
= fixp
->fx_cgen
.insn
;
1678 DPRINTF1 ("\tSkipping reloc that has already been done\n");
1684 DPRINTF1 ("\tSkipping reloc that is PC relative\n");
1690 DPRINTF1 ("\tSkipping reloc without symbol\n");
1694 if (fixp
->fx_r_type
< BFD_RELOC_UNUSED
)
1697 reloc
= fixp
->fx_r_type
;
1701 opindex
= (int) fixp
->fx_r_type
- (int) BFD_RELOC_UNUSED
;
1702 operand
= cgen_operand_lookup_by_num (cd
, opindex
);
1703 reloc
= md_cgen_lookup_reloc (insn
, operand
, fixp
);
1706 DPRINTF3 ("\treloc %s\t%s", bfd_get_reloc_code_name (reloc
), S_GET_NAME (s
));
1715 /* Skip relocations in known sections (.ctors, .dtors, and
1716 .gcc_except_table) since we can fix those up by hand. Also
1717 skip forward references to constants. Also skip a difference
1718 of two symbols, which still uses the BFD_RELOC_32 at this
1720 if (! known_section_p
1721 && S_GET_SEGMENT (s
) != absolute_section
1723 && (flags
& (SEC_READONLY
| SEC_CODE
)) == 0)
1729 /* FIXME -- should determine if any of the GP relocation really uses
1730 gr16 (which is not pic safe) or not. Right now, assume if we
1731 aren't being compiled with -mpic, the usage is non pic safe, but
1732 is safe with -mpic. */
1733 case BFD_RELOC_FRV_GPREL12
:
1734 case BFD_RELOC_FRV_GPRELU12
:
1735 case BFD_RELOC_FRV_GPREL32
:
1736 case BFD_RELOC_FRV_GPRELHI
:
1737 case BFD_RELOC_FRV_GPRELLO
:
1738 non_pic_p
= ! frv_pic_p
;
1741 case BFD_RELOC_FRV_LO16
:
1742 case BFD_RELOC_FRV_HI16
:
1743 if (S_GET_SEGMENT (s
) != absolute_section
)
1747 case BFD_RELOC_VTABLE_INHERIT
:
1748 case BFD_RELOC_VTABLE_ENTRY
:
1752 /* If this is a blessed BFD_RELOC_32, convert it back to the normal
1754 case BFD_RELOC_CTOR
:
1755 fixp
->fx_r_type
= BFD_RELOC_32
;
1761 DPRINTF1 (" (Non-pic relocation)\n");
1763 as_warn_where (fixp
->fx_file
, fixp
->fx_line
,
1764 _("Relocation %s is not safe for %s"),
1765 bfd_get_reloc_code_name (reloc
), frv_pic_flag
);
1767 else if ((frv_flags
& EF_FRV_NON_PIC_RELOCS
) == 0)
1769 frv_flags
|= EF_FRV_NON_PIC_RELOCS
;
1770 bfd_set_private_flags (abfd
, frv_flags
);
1780 /* After all of the symbols have been adjusted, go over the file looking
1781 for any relocations that pic won't support. */
1786 bfd_map_over_sections (stdoutput
, frv_frob_file_section
, (PTR
)0);
1790 frv_frob_label (this_label
)
1791 symbolS
*this_label
;
1793 struct vliw_insn_list
*vliw_insn_list_entry
;
1795 if (frv_mach
!= bfd_mach_frvtomcat
)
1798 if (now_seg
!= text_section
)
1801 vliw_insn_list_entry
= frv_insert_vliw_insn(DONT_COUNT
);
1802 vliw_insn_list_entry
->type
= VLIW_LABEL_TYPE
;
1803 vliw_insn_list_entry
->sym
= this_label
;
1807 frv_cgen_record_fixup_exp (frag
, where
, insn
, length
, operand
, opinfo
, exp
)
1810 const CGEN_INSN
* insn
;
1812 const CGEN_OPERAND
* operand
;
1816 fixS
* fixP
= gas_cgen_record_fixup_exp (frag
, where
, insn
, length
,
1817 operand
, opinfo
, exp
);
1819 if (frv_mach
== bfd_mach_frvtomcat
1820 && current_vliw_insn
1821 && current_vliw_insn
->type
== VLIW_BRANCH_TYPE
1823 current_vliw_insn
->sym
= exp
->X_add_symbol
;