2003-09-26 Matt Thomas <matt@3am-software.com>
[deliverable/binutils-gdb.git] / gas / config / tc-frv.c
CommitLineData
0ebb9a87 1/* tc-frv.c -- Assembler for the Fujitsu FRV.
ae6063d4 2 Copyright 2002, 2003 Free Software Foundation.
0ebb9a87
DB
3
4 This file is part of GAS, the GNU Assembler.
5
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)
9 any later version.
10
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.
15
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. */
20
21#include <stdio.h>
22#include "as.h"
0ebb9a87
DB
23#include "subsegs.h"
24#include "symcat.h"
25#include "opcodes/frv-desc.h"
26#include "opcodes/frv-opc.h"
27#include "cgen.h"
28#include "libbfd.h"
29#include "elf/common.h"
30#include "elf/frv.h"
31
32/* Structure to hold all of the different components describing
33 an individual instruction. */
34typedef struct
35{
36 const CGEN_INSN * insn;
37 const CGEN_INSN * orig_insn;
38 CGEN_FIELDS fields;
39#if CGEN_INT_INSN_P
40 CGEN_INSN_INT buffer [1];
41#define INSN_VALUE(buf) (*(buf))
42#else
43 unsigned char buffer [CGEN_MAX_INSN_SIZE];
44#define INSN_VALUE(buf) (buf)
45#endif
46 char * addr;
47 fragS * frag;
48 int num_fixups;
49 fixS * fixups [GAS_CGEN_MAX_FIXUPS];
50 int indices [MAX_OPERAND_INSTANCES];
51}
52frv_insn;
53
54enum vliw_insn_type
55{
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. */
61};
62
63/* We're going to use these in the fr_subtype field to mark
64 whether to keep inserted nops. */
65
66#define NOP_KEEP 1 /* Keep these NOPS. */
67#define NOP_DELETE 2 /* Delete these NOPS. */
68
b34976b6
AM
69#define DO_COUNT TRUE
70#define DONT_COUNT FALSE
0ebb9a87
DB
71
72/* A list of insns within a VLIW insn. */
73struct vliw_insn_list
74{
75 /* The type of this insn. */
76 enum vliw_insn_type type;
77
78 /* The corresponding gas insn information. */
79 const CGEN_INSN *insn;
80
81 /* For branches and labels, the symbol that is referenced. */
82 symbolS *sym;
83
84 /* For branches, the frag containing the single nop that was generated. */
85 fragS *snop_frag;
86
87 /* For branches, the frag containing the double nop that was generated. */
88 fragS *dnop_frag;
89
90 /* Pointer to raw data for this insn. */
91 char *address;
92
93 /* Next insn in list. */
94 struct vliw_insn_list *next;
95};
96
97static struct vliw_insn_list single_nop_insn = {
98 VLIW_NOP_TYPE, NULL, NULL, NULL, NULL, NULL, NULL };
99
100static struct vliw_insn_list double_nop_insn = {
101 VLIW_NOP_TYPE, NULL, NULL, NULL, NULL, NULL, NULL };
102
103struct vliw_chain
104{
105 int num;
106 int insn_count;
107 struct vliw_insn_list *insn_list;
108 struct vliw_chain *next;
109};
110
111static struct vliw_chain *vliw_chain_top;
112static struct vliw_chain *current_vliw_chain;
113static struct vliw_chain *previous_vliw_chain;
114static struct vliw_insn_list *current_vliw_insn;
115
116const char comment_chars[] = ";";
117const char line_comment_chars[] = "#";
118const char line_separator_chars[] = "";
119const char EXP_CHARS[] = "eE";
120const char FLT_CHARS[] = "dD";
121
122static FRV_VLIW vliw;
123
124/* Default machine */
125
126#ifdef DEFAULT_CPU_FRV
127#define DEFAULT_MACHINE bfd_mach_frv
128#define DEFAULT_FLAGS EF_FRV_CPU_GENERIC
129
130#else
131#ifdef DEFAULT_CPU_FR300
132#define DEFAULT_MACHINE bfd_mach_fr300
133#define DEFAULT_FLAGS EF_FRV_CPU_FR300
134
135#else
136#ifdef DEFAULT_CPU_SIMPLE
137#define DEFAULT_MACHINE bfd_mach_frvsimple
138#define DEFAULT_FLAGS EF_FRV_CPU_SIMPLE
139
140#else
141#ifdef DEFAULT_CPU_TOMCAT
142#define DEFAULT_MACHINE bfd_mach_frvtomcat
143#define DEFAULT_FLAGS EF_FRV_CPU_TOMCAT
144
145#else
146#ifdef DEFAULT_CPU_FR400
147#define DEFAULT_MACHINE bfd_mach_fr400
148#define DEFAULT_FLAGS EF_FRV_CPU_FR400
149
150#else
151#define DEFAULT_MACHINE bfd_mach_fr500
152#define DEFAULT_FLAGS EF_FRV_CPU_FR500
153#endif
154#endif
155#endif
156#endif
157#endif
158
159static unsigned long frv_mach = bfd_mach_frv;
160
161/* Flags to set in the elf header */
162static flagword frv_flags = DEFAULT_FLAGS;
163
164static int frv_user_set_flags_p = 0;
165static int frv_pic_p = 0;
166static const char *frv_pic_flag = (const char *)0;
167
168/* Print tomcat-specific debugging info. */
169static int tomcat_debug = 0;
170
171/* Tomcat-specific NOP statistics. */
172static int tomcat_stats = 0;
173static int tomcat_doubles = 0;
174static int tomcat_singles = 0;
175
176/* Forward reference to static functions */
177static void frv_set_flags PARAMS ((int));
178static void frv_pic_ptr PARAMS ((int));
179static void frv_frob_file_section PARAMS ((bfd *, asection *, PTR));
180
181/* The target specific pseudo-ops which we support. */
182const pseudo_typeS md_pseudo_table[] =
183{
184 { "eflags", frv_set_flags, 0 },
185 { "word", cons, 4 },
186 { "picptr", frv_pic_ptr, 4 },
0ebb9a87
DB
187 { NULL, NULL, 0 }
188};
189
190\f
191#define FRV_SHORTOPTS "G:"
192const char * md_shortopts = FRV_SHORTOPTS;
193
194#define OPTION_GPR_32 (OPTION_MD_BASE)
195#define OPTION_GPR_64 (OPTION_MD_BASE + 1)
196#define OPTION_FPR_32 (OPTION_MD_BASE + 2)
197#define OPTION_FPR_64 (OPTION_MD_BASE + 3)
198#define OPTION_SOFT_FLOAT (OPTION_MD_BASE + 4)
199#define OPTION_DWORD_YES (OPTION_MD_BASE + 5)
200#define OPTION_DWORD_NO (OPTION_MD_BASE + 6)
201#define OPTION_DOUBLE (OPTION_MD_BASE + 7)
202#define OPTION_NO_DOUBLE (OPTION_MD_BASE + 8)
203#define OPTION_MEDIA (OPTION_MD_BASE + 9)
204#define OPTION_NO_MEDIA (OPTION_MD_BASE + 10)
205#define OPTION_CPU (OPTION_MD_BASE + 11)
206#define OPTION_PIC (OPTION_MD_BASE + 12)
207#define OPTION_BIGPIC (OPTION_MD_BASE + 13)
208#define OPTION_LIBPIC (OPTION_MD_BASE + 14)
209#define OPTION_MULADD (OPTION_MD_BASE + 15)
210#define OPTION_NO_MULADD (OPTION_MD_BASE + 16)
211#define OPTION_TOMCAT_DEBUG (OPTION_MD_BASE + 17)
212#define OPTION_TOMCAT_STATS (OPTION_MD_BASE + 18)
213#define OPTION_PACK (OPTION_MD_BASE + 19)
214#define OPTION_NO_PACK (OPTION_MD_BASE + 20)
215
216struct option md_longopts[] =
217{
218 { "mgpr-32", no_argument, NULL, OPTION_GPR_32 },
219 { "mgpr-64", no_argument, NULL, OPTION_GPR_64 },
220 { "mfpr-32", no_argument, NULL, OPTION_FPR_32 },
221 { "mfpr-64", no_argument, NULL, OPTION_FPR_64 },
222 { "mhard-float", no_argument, NULL, OPTION_FPR_64 },
223 { "msoft-float", no_argument, NULL, OPTION_SOFT_FLOAT },
224 { "mdword", no_argument, NULL, OPTION_DWORD_YES },
225 { "mno-dword", no_argument, NULL, OPTION_DWORD_NO },
226 { "mdouble", no_argument, NULL, OPTION_DOUBLE },
227 { "mno-double", no_argument, NULL, OPTION_NO_DOUBLE },
228 { "mmedia", no_argument, NULL, OPTION_MEDIA },
229 { "mno-media", no_argument, NULL, OPTION_NO_MEDIA },
230 { "mcpu", required_argument, NULL, OPTION_CPU },
231 { "mpic", no_argument, NULL, OPTION_PIC },
232 { "mPIC", no_argument, NULL, OPTION_BIGPIC },
233 { "mlibrary-pic", no_argument, NULL, OPTION_LIBPIC },
234 { "mmuladd", no_argument, NULL, OPTION_MULADD },
235 { "mno-muladd", no_argument, NULL, OPTION_NO_MULADD },
236 { "mtomcat-debug", no_argument, NULL, OPTION_TOMCAT_DEBUG },
237 { "mtomcat-stats", no_argument, NULL, OPTION_TOMCAT_STATS },
238 { "mpack", no_argument, NULL, OPTION_PACK },
239 { "mno-pack", no_argument, NULL, OPTION_NO_PACK },
240 { NULL, no_argument, NULL, 0 },
241};
242
243size_t md_longopts_size = sizeof (md_longopts);
244
245/* What value to give to bfd_set_gp_size. */
246static int g_switch_value = 8;
247
248int
249md_parse_option (c, arg)
250 int c;
251 char * arg;
252{
253 switch (c)
254 {
255 default:
256 return 0;
257
258 case 'G':
259 g_switch_value = atoi (arg);
260 if (! g_switch_value)
261 frv_flags |= EF_FRV_G0;
262 break;
263
264 case OPTION_GPR_32:
265 frv_flags = (frv_flags & ~EF_FRV_GPR_MASK) | EF_FRV_GPR_32;
266 break;
267
268 case OPTION_GPR_64:
269 frv_flags = (frv_flags & ~EF_FRV_GPR_MASK) | EF_FRV_GPR_64;
270 break;
271
272 case OPTION_FPR_32:
273 frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_32;
274 break;
275
276 case OPTION_FPR_64:
277 frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_64;
278 break;
279
280 case OPTION_SOFT_FLOAT:
281 frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_NONE;
282 break;
283
284 case OPTION_DWORD_YES:
285 frv_flags = (frv_flags & ~EF_FRV_DWORD_MASK) | EF_FRV_DWORD_YES;
286 break;
287
288 case OPTION_DWORD_NO:
289 frv_flags = (frv_flags & ~EF_FRV_DWORD_MASK) | EF_FRV_DWORD_NO;
290 break;
291
292 case OPTION_DOUBLE:
293 frv_flags |= EF_FRV_DOUBLE;
294 break;
295
296 case OPTION_NO_DOUBLE:
297 frv_flags &= ~EF_FRV_DOUBLE;
298 break;
299
300 case OPTION_MEDIA:
301 frv_flags |= EF_FRV_MEDIA;
302 break;
303
304 case OPTION_NO_MEDIA:
305 frv_flags &= ~EF_FRV_MEDIA;
306 break;
307
308 case OPTION_MULADD:
309 frv_flags |= EF_FRV_MULADD;
310 break;
311
312 case OPTION_NO_MULADD:
313 frv_flags &= ~EF_FRV_MULADD;
314 break;
315
316 case OPTION_PACK:
317 frv_flags &= ~EF_FRV_NOPACK;
318 break;
319
320 case OPTION_NO_PACK:
321 frv_flags |= EF_FRV_NOPACK;
322 break;
323
324 case OPTION_CPU:
325 {
326 char *p;
327 int cpu_flags = EF_FRV_CPU_GENERIC;
328
329 /* Identify the processor type */
330 p = arg;
331 if (strcmp (p, "frv") == 0)
332 {
333 cpu_flags = EF_FRV_CPU_GENERIC;
334 frv_mach = bfd_mach_frv;
335 }
336
337 else if (strcmp (p, "fr500") == 0)
338 {
339 cpu_flags = EF_FRV_CPU_FR500;
340 frv_mach = bfd_mach_fr500;
341 }
342
343 else if (strcmp (p, "fr400") == 0)
344 {
345 cpu_flags = EF_FRV_CPU_FR400;
346 frv_mach = bfd_mach_fr400;
347 }
348
349 else if (strcmp (p, "fr300") == 0)
350 {
351 cpu_flags = EF_FRV_CPU_FR300;
352 frv_mach = bfd_mach_fr300;
353 }
354
355 else if (strcmp (p, "simple") == 0)
356 {
357 cpu_flags = EF_FRV_CPU_SIMPLE;
358 frv_mach = bfd_mach_frvsimple;
359 frv_flags |= EF_FRV_NOPACK;
360 }
361
362 else if (strcmp (p, "tomcat") == 0)
363 {
364 cpu_flags = EF_FRV_CPU_TOMCAT;
365 frv_mach = bfd_mach_frvtomcat;
366 }
367
368 else
369 {
370 as_fatal ("Unknown cpu -mcpu=%s", arg);
371 return 0;
372 }
373
374 frv_flags = (frv_flags & ~EF_FRV_CPU_MASK) | cpu_flags;
375 }
376 break;
377
378 case OPTION_PIC:
379 frv_flags |= EF_FRV_PIC;
380 frv_pic_p = 1;
381 frv_pic_flag = "-fpic";
382 break;
383
384 case OPTION_BIGPIC:
385 frv_flags |= EF_FRV_BIGPIC;
386 frv_pic_p = 1;
387 frv_pic_flag = "-fPIC";
388 break;
389
390 case OPTION_LIBPIC:
391 frv_flags |= (EF_FRV_LIBPIC | EF_FRV_G0);
392 frv_pic_p = 1;
393 frv_pic_flag = "-mlibrary-pic";
394 g_switch_value = 0;
395 break;
396
397 case OPTION_TOMCAT_DEBUG:
398 tomcat_debug = 1;
399 break;
400
401 case OPTION_TOMCAT_STATS:
402 tomcat_stats = 1;
403 break;
404 }
405
406 return 1;
407}
408
409void
410md_show_usage (stream)
411 FILE * stream;
412{
413 fprintf (stream, _("FRV specific command line options:\n"));
414 fprintf (stream, _("-G n Data >= n bytes is in small data area\n"));
415 fprintf (stream, _("-mgpr-32 Note 32 gprs are used\n"));
416 fprintf (stream, _("-mgpr-64 Note 64 gprs are used\n"));
417 fprintf (stream, _("-mfpr-32 Note 32 fprs are used\n"));
418 fprintf (stream, _("-mfpr-64 Note 64 fprs are used\n"));
419 fprintf (stream, _("-msoft-float Note software fp is used\n"));
420 fprintf (stream, _("-mdword Note stack is aligned to a 8 byte boundary\n"));
421 fprintf (stream, _("-mno-dword Note stack is aligned to a 4 byte boundary\n"));
422 fprintf (stream, _("-mdouble Note fp double insns are used\n"));
423 fprintf (stream, _("-mmedia Note media insns are used\n"));
424 fprintf (stream, _("-mmuladd Note multiply add/subtract insns are used\n"));
425 fprintf (stream, _("-mpack Note instructions are packed\n"));
426 fprintf (stream, _("-mno-pack Do not allow instructions to be packed\n"));
427 fprintf (stream, _("-mpic Note small position independent code\n"));
428 fprintf (stream, _("-mPIC Note large position independent code\n"));
429 fprintf (stream, _("-mlibrary-pic Compile library for large position indepedent code\n"));
430 fprintf (stream, _("-mcpu={fr500|fr400|fr300|frv|simple|tomcat}\n"));
431 fprintf (stream, _(" Record the cpu type\n"));
432 fprintf (stream, _("-mtomcat-stats Print out stats for tomcat workarounds\n"));
433 fprintf (stream, _("-mtomcat-debug Debug tomcat workarounds\n"));
434}
435
436\f
437void
438md_begin ()
439{
440 /* Initialize the `cgen' interface. */
441
442 /* Set the machine number and endian. */
443 gas_cgen_cpu_desc = frv_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
444 CGEN_CPU_OPEN_ENDIAN,
445 CGEN_ENDIAN_BIG,
446 CGEN_CPU_OPEN_END);
447 frv_cgen_init_asm (gas_cgen_cpu_desc);
448
449 /* This is a callback from cgen to gas to parse operands. */
450 cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
451
452 /* Set the ELF flags if desired. */
453 if (frv_flags)
454 bfd_set_private_flags (stdoutput, frv_flags);
455
456 /* Set the machine type */
457 bfd_default_set_arch_mach (stdoutput, bfd_arch_frv, frv_mach);
458
459 /* Set up gp size so we can put local common items in .sbss */
460 bfd_set_gp_size (stdoutput, g_switch_value);
461
462 frv_vliw_reset (& vliw, frv_mach, frv_flags);
463}
464
465int chain_num = 0;
466
a08333bb
AM
467struct vliw_insn_list *frv_insert_vliw_insn PARAMS ((bfd_boolean));
468
0ebb9a87
DB
469struct vliw_insn_list *
470frv_insert_vliw_insn (count)
b34976b6 471 bfd_boolean count;
0ebb9a87
DB
472{
473 struct vliw_insn_list *vliw_insn_list_entry;
474 struct vliw_chain *vliw_chain_entry;
475
476 if (current_vliw_chain == NULL)
477 {
478 vliw_chain_entry = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
479 vliw_chain_entry->insn_count = 0;
480 vliw_chain_entry->insn_list = NULL;
481 vliw_chain_entry->next = NULL;
482 vliw_chain_entry->num = chain_num++;
483
484 if (!vliw_chain_top)
485 vliw_chain_top = vliw_chain_entry;
486 current_vliw_chain = vliw_chain_entry;
487 if (previous_vliw_chain)
488 previous_vliw_chain->next = vliw_chain_entry;
489 }
490
491 vliw_insn_list_entry = (struct vliw_insn_list *) xmalloc (sizeof (struct vliw_insn_list));
492 vliw_insn_list_entry->type = VLIW_GENERIC_TYPE;
493 vliw_insn_list_entry->insn = NULL;
494 vliw_insn_list_entry->sym = NULL;
495 vliw_insn_list_entry->snop_frag = NULL;
496 vliw_insn_list_entry->dnop_frag = NULL;
497 vliw_insn_list_entry->next = NULL;
498
499 if (count)
500 current_vliw_chain->insn_count++;
501
502 if (current_vliw_insn)
503 current_vliw_insn->next = vliw_insn_list_entry;
504 current_vliw_insn = vliw_insn_list_entry;
505
506 if (!current_vliw_chain->insn_list)
507 current_vliw_chain->insn_list = current_vliw_insn;
508
509 return vliw_insn_list_entry;
510}
511
512 /* Identify the following cases:
513
514 1) A VLIW insn that contains both a branch and the branch destination.
515 This requires the insertion of two vliw instructions before the
516 branch. The first consists of two nops. The second consists of
517 a single nop.
518
519 2) A single instruction VLIW insn which is the destination of a branch
520 that is in the next VLIW insn. This requires the insertion of a vliw
521 insn containing two nops before the branch.
522
523 3) A double instruction VLIW insn which contains the destination of a
524 branch that is in the next VLIW insn. This requires the insertion of
525 a VLIW insn containing a single nop before the branch.
526
527 4) A single instruction VLIW insn which contains branch destination (x),
528 followed by a single instruction VLIW insn which does not contain
529 the branch to (x), followed by a VLIW insn which does contain the branch
530 to (x). This requires the insertion of a VLIW insn containing a single
531 nop before the VLIW instruction containing the branch.
532
533 */
534#define FRV_IS_NOP(insn) (insn.buffer[0] == FRV_NOP_PACK || insn.buffer[0] == FRV_NOP_NOPACK)
535#define FRV_NOP_PACK 0x00880000 /* ori.p gr0,0,gr0 */
536#define FRV_NOP_NOPACK 0x80880000 /* ori gr0,0,gr0 */
537
538/* Check a vliw insn for an insn of type containing the sym passed in label_sym. */
539
a08333bb
AM
540static struct vliw_insn_list *frv_find_in_vliw
541 PARAMS ((enum vliw_insn_type, struct vliw_chain *, symbolS *));
542
0ebb9a87
DB
543static struct vliw_insn_list *
544frv_find_in_vliw (vliw_insn_type, this_chain, label_sym)
545 enum vliw_insn_type vliw_insn_type;
546 struct vliw_chain *this_chain;
547 symbolS *label_sym;
548{
549
550 struct vliw_insn_list *the_insn;
551
552 if (!this_chain)
553 return NULL;
554
555 for (the_insn = this_chain->insn_list; the_insn; the_insn = the_insn->next)
556 {
557 if (the_insn->type == vliw_insn_type
558 && the_insn->sym == label_sym)
559 return the_insn;
560 }
561
562 return NULL;
563}
564
565enum vliw_nop_type
566{
567 /* A Vliw insn containing a single nop insn. */
568 VLIW_SINGLE_NOP,
569
570 /* A Vliw insn containing two nop insns. */
571 VLIW_DOUBLE_NOP,
572
573 /* Two vliw insns. The first containing two nop insns.
574 The second contain a single nop insn. */
575 VLIW_DOUBLE_THEN_SINGLE_NOP
576};
577
a08333bb
AM
578static void frv_debug_tomcat PARAMS ((struct vliw_chain *));
579
0ebb9a87
DB
580static void
581frv_debug_tomcat (start_chain)
582 struct vliw_chain *start_chain;
583{
584 struct vliw_chain *this_chain;
585 struct vliw_insn_list *this_insn;
586 int i = 1;
587
588 for (this_chain = start_chain; this_chain; this_chain = this_chain->next, i++)
589 {
590 fprintf (stderr, "\nVliw Insn #%d, #insns: %d\n", i, this_chain->insn_count);
591
592 for (this_insn = this_chain->insn_list; this_insn; this_insn = this_insn->next)
593 {
594 if (this_insn->type == VLIW_LABEL_TYPE)
595 fprintf (stderr, "Label Value: %d\n", (int) this_insn->sym);
596 else if (this_insn->type == VLIW_BRANCH_TYPE)
597 fprintf (stderr, "%s to %d\n", this_insn->insn->base->name, (int) this_insn->sym);
598 else if (this_insn->type == VLIW_BRANCH_HAS_NOPS)
599 fprintf (stderr, "nop'd %s to %d\n", this_insn->insn->base->name, (int) this_insn->sym);
600 else if (this_insn->type == VLIW_NOP_TYPE)
601 fprintf (stderr, "Nop\n");
602 else
603 fprintf (stderr, " %s\n", this_insn->insn->base->name);
604 }
605 }
606}
607
a08333bb 608static void frv_adjust_vliw_count PARAMS ((struct vliw_chain *));
0ebb9a87
DB
609
610static void
611frv_adjust_vliw_count (this_chain)
612 struct vliw_chain *this_chain;
613{
614 struct vliw_insn_list *this_insn;
615
616 this_chain->insn_count = 0;
617
618 for (this_insn = this_chain->insn_list;
619 this_insn;
620 this_insn = this_insn->next)
621 {
622 if (this_insn->type != VLIW_LABEL_TYPE)
623 this_chain->insn_count++;
624 }
625
626}
627
628/* Insert the desired nop combination in the vliw chain before insert_before_insn.
629 Rechain the vliw insn. */
630
a08333bb
AM
631static struct vliw_chain *frv_tomcat_shuffle
632 PARAMS ((enum vliw_nop_type, struct vliw_chain *, struct vliw_insn_list *));
0ebb9a87
DB
633
634static struct vliw_chain *
635frv_tomcat_shuffle (this_nop_type, vliw_to_split, insert_before_insn)
636 enum vliw_nop_type this_nop_type;
637 struct vliw_chain *vliw_to_split;
638 struct vliw_insn_list *insert_before_insn;
639{
640
b34976b6 641 bfd_boolean pack_prev = FALSE;
0ebb9a87
DB
642 struct vliw_chain *return_me = NULL;
643 struct vliw_insn_list *prev_insn = NULL;
644 struct vliw_insn_list *curr_insn = vliw_to_split->insn_list;
645
646 struct vliw_chain *double_nop = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
647 struct vliw_chain *single_nop = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
648 struct vliw_chain *second_part = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
649 struct vliw_chain *curr_vliw = vliw_chain_top;
650 struct vliw_chain *prev_vliw = NULL;
651
652 while (curr_insn && curr_insn != insert_before_insn)
653 {
654 /* We can't set the packing bit on a label. If we have the case
655 label 1:
656 label 2:
657 label 3:
658 branch that needs nops
659 Then don't set pack bit later. */
660
661 if (curr_insn->type != VLIW_LABEL_TYPE)
b34976b6 662 pack_prev = TRUE;
0ebb9a87
DB
663 prev_insn = curr_insn;
664 curr_insn = curr_insn->next;
665 }
666
667 while (curr_vliw && curr_vliw != vliw_to_split)
668 {
669 prev_vliw = curr_vliw;
670 curr_vliw = curr_vliw->next;
671 }
672
673 switch (this_nop_type)
674 {
675 case VLIW_SINGLE_NOP:
676 if (!prev_insn)
677 {
678 /* Branch is first, Insert the NOP prior to this vliw insn. */
679 if (prev_vliw)
680 prev_vliw->next = single_nop;
681 else
682 vliw_chain_top = single_nop;
683 single_nop->next = vliw_to_split;
684 vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
685 return_me = vliw_to_split;
686 }
687 else
688 {
689 /* Set the packing bit on the previous insn. */
690 if (pack_prev)
691 {
692 unsigned char *buffer = prev_insn->address;
693 buffer[0] |= 0x80;
694 }
695 /* The branch is in the middle. Split this vliw insn into first
696 and second parts. Insert the NOP inbetween. */
697
698 second_part->insn_list = insert_before_insn;
699 second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
700 second_part->next = vliw_to_split->next;
701 frv_adjust_vliw_count (second_part);
702
703 single_nop->next = second_part;
704
705 vliw_to_split->next = single_nop;
706 prev_insn->next = NULL;
707
708 return_me = second_part;
709 frv_adjust_vliw_count (vliw_to_split);
710 }
711 break;
712
713 case VLIW_DOUBLE_NOP:
714 if (!prev_insn)
715 {
716 /* Branch is first, Insert the NOP prior to this vliw insn. */
717 if (prev_vliw)
718 prev_vliw->next = double_nop;
719 else
720 vliw_chain_top = double_nop;
721
722 double_nop->next = vliw_to_split;
723 return_me = vliw_to_split;
724 vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
725 }
726 else
727 {
728 /* Set the packing bit on the previous insn. */
729 if (pack_prev)
730 {
731 unsigned char *buffer = prev_insn->address;
732 buffer[0] |= 0x80;
733 }
734
735 /* The branch is in the middle. Split this vliw insn into first
736 and second parts. Insert the NOP inbetween. */
737 second_part->insn_list = insert_before_insn;
738 second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
739 second_part->next = vliw_to_split->next;
740 frv_adjust_vliw_count (second_part);
741
742 double_nop->next = second_part;
743
744 vliw_to_split->next = single_nop;
745 prev_insn->next = NULL;
746 frv_adjust_vliw_count (vliw_to_split);
747
748 return_me = second_part;
749 }
750 break;
751
752 case VLIW_DOUBLE_THEN_SINGLE_NOP:
753 double_nop->next = single_nop;
754 double_nop->insn_count = 2;
755 double_nop->insn_list = &double_nop_insn;
756 single_nop->insn_count = 1;
757 single_nop->insn_list = &single_nop_insn;
758
759 if (!prev_insn)
760 {
761 /* The branch is the first insn in this vliw. Don't split the vliw. Insert
762 the nops prior to this vliw. */
763 if (prev_vliw)
764 prev_vliw->next = double_nop;
765 else
766 vliw_chain_top = double_nop;
767
768 single_nop->next = vliw_to_split;
769 return_me = vliw_to_split;
770 vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
771 }
772 else
773 {
774 /* Set the packing bit on the previous insn. */
775 if (pack_prev)
776 {
777 unsigned char *buffer = prev_insn->address;
778 buffer[0] |= 0x80;
779 }
780
781 /* The branch is in the middle of this vliw insn. Split into first and
782 second parts. Insert the nop vliws in between. */
783 second_part->insn_list = insert_before_insn;
784 second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
785 second_part->next = vliw_to_split->next;
786 frv_adjust_vliw_count (second_part);
787
788 single_nop->next = second_part;
789
790 vliw_to_split->next = double_nop;
791 prev_insn->next = NULL;
792 frv_adjust_vliw_count (vliw_to_split);
793
794 return_me = second_part;
795 }
796 break;
797 }
798
799 return return_me;
800}
801
a08333bb
AM
802static void frv_tomcat_analyze_vliw_chains PARAMS ((void));
803
0ebb9a87
DB
804static void
805frv_tomcat_analyze_vliw_chains ()
806{
807 struct vliw_chain *vliw1 = NULL;
808 struct vliw_chain *vliw2 = NULL;
809 struct vliw_chain *vliw3 = NULL;
810
811 struct vliw_insn_list *this_insn = NULL;
812 struct vliw_insn_list *temp_insn = NULL;
813
814 /* We potentially need to look at three VLIW insns to determine if the
815 workaround is required. Set them up. Ignore existing nops during analysis. */
816
817#define FRV_SET_VLIW_WINDOW(VLIW1, VLIW2, VLIW3) \
818 if (VLIW1 && VLIW1->next) \
819 VLIW2 = VLIW1->next; \
820 else \
821 VLIW2 = NULL; \
822 if (VLIW2 && VLIW2->next) \
823 VLIW3 = VLIW2->next; \
824 else \
825 VLIW3 = NULL
826
827 vliw1 = vliw_chain_top;
828
829workaround_top:
830
831 FRV_SET_VLIW_WINDOW (vliw1, vliw2, vliw3);
832
833 if (!vliw1)
834 return;
835
836 if (vliw1->insn_count == 1)
837 {
838 /* check vliw1 for a label. */
839 if (vliw1->insn_list->type == VLIW_LABEL_TYPE)
840 {
841 temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, vliw1->insn_list->sym);
842 if (temp_insn)
843 {
844 vliw1 = frv_tomcat_shuffle (VLIW_DOUBLE_NOP, vliw2, vliw1->insn_list);
845 temp_insn->dnop_frag->fr_subtype = NOP_KEEP;
846 vliw1 = vliw1->next;
847 if (tomcat_stats)
848 tomcat_doubles++;
849 goto workaround_top;
850 }
851 else if (vliw2
852 && vliw2->insn_count == 1
853 && (temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw3, vliw1->insn_list->sym)) != NULL)
854 {
855 temp_insn->snop_frag->fr_subtype = NOP_KEEP;
856 vliw1 = frv_tomcat_shuffle (VLIW_SINGLE_NOP, vliw3, vliw3->insn_list);
857 if (tomcat_stats)
858 tomcat_singles++;
859 goto workaround_top;
860 }
861 }
862 }
863
864 if (vliw1->insn_count == 2)
865 {
866 struct vliw_insn_list *this_insn;
867
868 /* check vliw1 for a label. */
869 for (this_insn = vliw1->insn_list; this_insn; this_insn = this_insn->next)
870 {
871 if (this_insn->type == VLIW_LABEL_TYPE)
872 {
a08333bb 873 if ((temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, this_insn->sym)) != NULL)
0ebb9a87
DB
874 {
875 temp_insn->snop_frag->fr_subtype = NOP_KEEP;
876 vliw1 = frv_tomcat_shuffle (VLIW_SINGLE_NOP, vliw2, this_insn);
877 if (tomcat_stats)
878 tomcat_singles++;
879 }
880 else
881 vliw1 = vliw1->next;
882 goto workaround_top;
883 }
884 }
885 }
886 /* Examine each insn in this VLIW. Look for the workaround criteria. */
887 for (this_insn = vliw1->insn_list; this_insn; this_insn = this_insn->next)
888 {
889 /* Don't look at labels or nops. */
890 while (this_insn
891 && (this_insn->type == VLIW_LABEL_TYPE
892 || this_insn->type == VLIW_NOP_TYPE
893 || this_insn->type == VLIW_BRANCH_HAS_NOPS))
894 this_insn = this_insn->next;
895
896 if (!this_insn)
897 {
898 vliw1 = vliw2;
899 goto workaround_top;
900 }
901
902 if (frv_is_branch_insn (this_insn->insn))
903 {
a08333bb 904 if ((temp_insn = frv_find_in_vliw (VLIW_LABEL_TYPE, vliw1, this_insn->sym)) != NULL)
0ebb9a87
DB
905 {
906 /* Insert [nop/nop] [nop] before branch. */
907 this_insn->snop_frag->fr_subtype = NOP_KEEP;
908 this_insn->dnop_frag->fr_subtype = NOP_KEEP;
909 vliw1 = frv_tomcat_shuffle (VLIW_DOUBLE_THEN_SINGLE_NOP, vliw1, this_insn);
910 goto workaround_top;
911 }
912 }
913
914
915 }
916 /* This vliw insn checks out okay. Take a look at the next one. */
917 vliw1 = vliw1->next;
918 goto workaround_top;
919}
920
921void
922frv_tomcat_workaround ()
923{
924 if (frv_mach != bfd_mach_frvtomcat)
925 return;
926
927 if (tomcat_debug)
928 frv_debug_tomcat (vliw_chain_top);
929
930 frv_tomcat_analyze_vliw_chains ();
931
932 if (tomcat_stats)
933 {
934 fprintf (stderr, "Inserted %d Single Nops\n", tomcat_singles);
935 fprintf (stderr, "Inserted %d Double Nops\n", tomcat_doubles);
936 }
937}
938
939void
940md_assemble (str)
941 char * str;
942{
943 frv_insn insn;
944 char *errmsg;
945 int packing_constraint;
946 finished_insnS finished_insn;
947 fragS *double_nop_frag = NULL;
948 fragS *single_nop_frag = NULL;
949 struct vliw_insn_list *vliw_insn_list_entry = NULL;
950
951 /* Initialize GAS's cgen interface for a new instruction. */
952 gas_cgen_init_parse ();
953
954 insn.insn = frv_cgen_assemble_insn
955 (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, &errmsg);
956
957 if (!insn.insn)
958 {
959 as_bad (errmsg);
960 return;
961 }
962
963 /* If the cpu is tomcat, then we need to insert nops to workaround
964 hardware limitations. We need to keep track of each vliw unit
965 and examine the length of the unit and the individual insns
966 within the unit to determine the number and location of the
967 required nops. */
968 if (frv_mach == bfd_mach_frvtomcat)
969 {
970 /* If we've just finished a VLIW insn OR this is a branch,
971 then start up a new frag. Fill it with nops. We will get rid
972 of those that are not required after we've seen all of the
973 instructions but before we start resolving fixups. */
974 if ( !FRV_IS_NOP (insn)
975 && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
976 {
977 char *buffer;
978
979 frag_wane (frag_now);
980 frag_new (0);
981 double_nop_frag = frag_now;
982 buffer = frag_var (rs_machine_dependent, 8, 8, NOP_DELETE, NULL, 0, 0);
983 md_number_to_chars (buffer, FRV_NOP_PACK, 4);
984 md_number_to_chars (buffer+4, FRV_NOP_NOPACK, 4);
985
986 frag_wane (frag_now);
987 frag_new (0);
988 single_nop_frag = frag_now;
989 buffer = frag_var (rs_machine_dependent, 4, 4, NOP_DELETE, NULL, 0, 0);
990 md_number_to_chars (buffer, FRV_NOP_NOPACK, 4);
991 }
992
993 vliw_insn_list_entry = frv_insert_vliw_insn (DO_COUNT);
994 vliw_insn_list_entry->insn = insn.insn;
995 if (frv_is_branch_insn (insn.insn))
996 vliw_insn_list_entry->type = VLIW_BRANCH_TYPE;
997
998 if ( !FRV_IS_NOP (insn)
999 && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
1000 {
1001 vliw_insn_list_entry->snop_frag = single_nop_frag;
1002 vliw_insn_list_entry->dnop_frag = double_nop_frag;
1003 }
1004 }
1005
1006 /* Make sure that this insn does not violate the VLIW packing constraints. */
1007 /* -mno-pack disallows any packing whatsoever. */
1008 if (frv_flags & EF_FRV_NOPACK)
1009 {
1010 if (! insn.fields.f_pack)
1011 {
1012 as_bad (_("VLIW packing used for -mno-pack"));
1013 return;
1014 }
1015 }
1016 /* -mcpu=FRV is an idealized FR-V implementation that supports all of the
1017 instructions, don't do vliw checking. */
1018 else if (frv_mach != bfd_mach_frv)
1019 {
1020 packing_constraint = frv_vliw_add_insn (& vliw, insn.insn);
1021 if (insn.fields.f_pack)
1022 frv_vliw_reset (& vliw, frv_mach, frv_flags);
1023 if (packing_constraint)
1024 {
1025 as_bad (_("VLIW packing constraint violation"));
1026 return;
1027 }
1028 }
1029
1030 /* Doesn't really matter what we pass for RELAX_P here. */
1031 gas_cgen_finish_insn (insn.insn, insn.buffer,
1032 CGEN_FIELDS_BITSIZE (& insn.fields), 1, &finished_insn);
1033
1034
1035 /* If the cpu is tomcat, then we need to insert nops to workaround
1036 hardware limitations. We need to keep track of each vliw unit
1037 and examine the length of the unit and the individual insns
1038 within the unit to determine the number and location of the
1039 required nops. */
1040 if (frv_mach == bfd_mach_frvtomcat)
1041 {
1042 if (vliw_insn_list_entry)
1043 vliw_insn_list_entry->address = finished_insn.addr;
1044 else
1045 abort();
1046
1047 if (insn.fields.f_pack)
1048 {
1049 /* We've completed a VLIW insn. */
1050 previous_vliw_chain = current_vliw_chain;
1051 current_vliw_chain = NULL;
1052 current_vliw_insn = NULL;
1053 }
1054 }
1055}
1056
1057/* The syntax in the manual says constants begin with '#'.
1058 We just ignore it. */
1059
1060void
1061md_operand (expressionP)
1062 expressionS * expressionP;
1063{
1064 if (* input_line_pointer == '#')
1065 {
1066 input_line_pointer ++;
1067 expression (expressionP);
1068 }
1069}
1070
1071valueT
1072md_section_align (segment, size)
1073 segT segment;
1074 valueT size;
1075{
1076 int align = bfd_get_section_alignment (stdoutput, segment);
1077 return ((size + (1 << align) - 1) & (-1 << align));
1078}
1079
1080symbolS *
1081md_undefined_symbol (name)
1082 char * name ATTRIBUTE_UNUSED;
1083{
1084 return 0;
1085}
1086\f
1087/* Interface to relax_segment. */
1088
1089/* FIXME: Build table by hand, get it working, then machine generate. */
1090const relax_typeS md_relax_table[] =
1091{
1092 {1, 1, 0, 0},
1093 {511 - 2 - 2, -512 - 2 + 2, 0, 2 },
1094 {0x2000000 - 1 - 2, -0x2000000 - 2, 2, 0 },
1095 {0x2000000 - 1 - 2, -0x2000000 - 2, 4, 0 }
1096};
1097
1098long
1099frv_relax_frag (fragP, stretch)
1100 fragS *fragP ATTRIBUTE_UNUSED;
1101 long stretch ATTRIBUTE_UNUSED;
1102{
1103 return 0;
1104}
1105
1106/* Return an initial guess of the length by which a fragment must grow to
1107 hold a branch to reach its destination.
1108 Also updates fr_type/fr_subtype as necessary.
1109
1110 Called just before doing relaxation.
1111 Any symbol that is now undefined will not become defined.
1112 The guess for fr_var is ACTUALLY the growth beyond fr_fix.
1113 Whatever we do to grow fr_fix or fr_var contributes to our returned value.
1114 Although it may not be explicit in the frag, pretend fr_var starts with a
1115 0 value. */
1116
1117int
1118md_estimate_size_before_relax (fragP, segment)
1119 fragS * fragP;
1120 segT segment ATTRIBUTE_UNUSED;
1121{
1122 switch (fragP->fr_subtype)
1123 {
1124 case NOP_KEEP:
1125 return fragP->fr_var;
1126
1127 default:
1128 case NOP_DELETE:
1129 return 0;
1130 }
1131}
1132
1133/* *fragP has been relaxed to its final size, and now needs to have
1134 the bytes inside it modified to conform to the new size.
1135
1136 Called after relaxation is finished.
1137 fragP->fr_type == rs_machine_dependent.
1138 fragP->fr_subtype is the subtype of what the address relaxed to. */
1139
1140void
1141md_convert_frag (abfd, sec, fragP)
1142 bfd * abfd ATTRIBUTE_UNUSED;
1143 segT sec ATTRIBUTE_UNUSED;
1144 fragS * fragP;
1145{
1146 switch (fragP->fr_subtype)
1147 {
1148 default:
1149 case NOP_DELETE:
1150 return;
1151
1152 case NOP_KEEP:
1153 fragP->fr_fix = fragP->fr_var;
1154 fragP->fr_var = 0;
1155 return;
1156 }
1157}
1158\f
1159/* Functions concerning relocs. */
1160
1161/* The location from which a PC relative jump should be calculated,
1162 given a PC relative reloc. */
1163
1164long
1165md_pcrel_from_section (fixP, sec)
1166 fixS * fixP;
d5087907 1167 segT sec ATTRIBUTE_UNUSED;
0ebb9a87 1168{
d5087907
RS
1169 /* Make no adjustment for relocations that will be written out. */
1170 if (TC_FORCE_RELOCATION (fixP))
1171 return 0;
0ebb9a87
DB
1172
1173 return (fixP->fx_frag->fr_address + fixP->fx_where) & ~1;
1174}
1175
1176/* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
1177 Returns BFD_RELOC_NONE if no reloc type can be found.
1178 *FIXP may be modified if desired. */
1179
1180bfd_reloc_code_real_type
1181md_cgen_lookup_reloc (insn, operand, fixP)
1182 const CGEN_INSN * insn ATTRIBUTE_UNUSED;
1183 const CGEN_OPERAND * operand;
1184 fixS * fixP;
1185{
1186 switch (operand->type)
1187 {
1188 case FRV_OPERAND_LABEL16:
b34976b6 1189 fixP->fx_pcrel = TRUE;
0ebb9a87
DB
1190 return BFD_RELOC_FRV_LABEL16;
1191
1192 case FRV_OPERAND_LABEL24:
b34976b6 1193 fixP->fx_pcrel = TRUE;
0ebb9a87
DB
1194 return BFD_RELOC_FRV_LABEL24;
1195
1196 case FRV_OPERAND_UHI16:
1197 case FRV_OPERAND_ULO16:
1198 case FRV_OPERAND_SLO16:
1199
1200 /* The relocation type should be recorded in opinfo */
1201 if (fixP->fx_cgen.opinfo != 0)
1202 return fixP->fx_cgen.opinfo;
1203 break;
1204
1205 case FRV_OPERAND_D12:
1206 case FRV_OPERAND_S12:
1207 return BFD_RELOC_FRV_GPREL12;
1208
1209 case FRV_OPERAND_U12:
1210 return BFD_RELOC_FRV_GPRELU12;
1211
1212 default:
1213 break;
1214 }
1215 return BFD_RELOC_NONE;
1216}
1217
1218
1219/* See whether we need to force a relocation into the output file.
1220 This is used to force out switch and PC relative relocations when
1221 relaxing. */
1222
1223int
1224frv_force_relocation (fix)
1225 fixS * fix;
1226{
ae6063d4 1227 if (fix->fx_r_type == BFD_RELOC_FRV_GPREL12
0ebb9a87
DB
1228 || fix->fx_r_type == BFD_RELOC_FRV_GPRELU12)
1229 return 1;
1230
ae6063d4 1231 return generic_force_reloc (fix);
0ebb9a87
DB
1232}
1233\f
1234/* Write a value out to the object file, using the appropriate endianness. */
1235
1236void
1237frv_md_number_to_chars (buf, val, n)
1238 char * buf;
1239 valueT val;
1240 int n;
1241{
1242 number_to_chars_bigendian (buf, val, n);
1243}
1244
1245/* Turn a string in input_line_pointer into a floating point constant of type
1246 type, and store the appropriate bytes in *litP. The number of LITTLENUMS
1247 emitted is stored in *sizeP . An error message is returned, or NULL on OK.
1248*/
1249
1250/* Equal to MAX_PRECISION in atof-ieee.c */
1251#define MAX_LITTLENUMS 6
1252
1253char *
1254md_atof (type, litP, sizeP)
1255 char type;
1256 char * litP;
1257 int * sizeP;
1258{
1259 int i;
1260 int prec;
1261 LITTLENUM_TYPE words [MAX_LITTLENUMS];
1262 char * t;
0ebb9a87
DB
1263
1264 switch (type)
1265 {
1266 case 'f':
1267 case 'F':
1268 case 's':
1269 case 'S':
1270 prec = 2;
1271 break;
1272
1273 case 'd':
1274 case 'D':
1275 case 'r':
1276 case 'R':
1277 prec = 4;
1278 break;
1279
1280 /* FIXME: Some targets allow other format chars for bigger sizes here. */
1281
1282 default:
1283 * sizeP = 0;
1284 return _("Bad call to md_atof()");
1285 }
1286
1287 t = atof_ieee (input_line_pointer, type, words);
1288 if (t)
1289 input_line_pointer = t;
1290 * sizeP = prec * sizeof (LITTLENUM_TYPE);
1291
1292 for (i = 0; i < prec; i++)
1293 {
1294 md_number_to_chars (litP, (valueT) words[i],
1295 sizeof (LITTLENUM_TYPE));
1296 litP += sizeof (LITTLENUM_TYPE);
1297 }
1298
1299 return 0;
1300}
1301
b34976b6 1302bfd_boolean
0ebb9a87
DB
1303frv_fix_adjustable (fixP)
1304 fixS * fixP;
1305{
1306 bfd_reloc_code_real_type reloc_type;
1307
1308 if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
1309 {
1310 const CGEN_INSN *insn = NULL;
1311 int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
1312 const CGEN_OPERAND *operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
1313 reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
1314 }
1315 else
1316 reloc_type = fixP->fx_r_type;
1317
0ebb9a87
DB
1318 /* We need the symbol name for the VTABLE entries */
1319 if ( reloc_type == BFD_RELOC_VTABLE_INHERIT
1320 || reloc_type == BFD_RELOC_VTABLE_ENTRY
1321 || reloc_type == BFD_RELOC_FRV_GPREL12
1322 || reloc_type == BFD_RELOC_FRV_GPRELU12)
1323 return 0;
1324
1325 return 1;
1326}
1327
1328/* Allow user to set flags bits. */
1329void
1330frv_set_flags (arg)
1331 int arg ATTRIBUTE_UNUSED;
1332{
1333 flagword new_flags = get_absolute_expression ();
1334 flagword new_mask = ~ (flagword)0;
1335
1336 frv_user_set_flags_p = 1;
1337 if (*input_line_pointer == ',')
1338 {
1339 ++input_line_pointer;
1340 new_mask = get_absolute_expression ();
1341 }
1342
1343 frv_flags = (frv_flags & ~new_mask) | (new_flags & new_mask);
1344 bfd_set_private_flags (stdoutput, frv_flags);
1345}
1346
1347/* Frv specific function to handle 4 byte initializations for pointers that are
1348 considered 'safe' for use with pic support. Until frv_frob_file{,_section}
1349 is run, we encode it a BFD_RELOC_CTOR, and it is turned back into a normal
1350 BFD_RELOC_32 at that time. */
1351
1352void
1353frv_pic_ptr (nbytes)
1354 int nbytes;
1355{
1356 expressionS exp;
1357 char *p;
1358
1359 if (nbytes != 4)
1360 abort ();
1361
1362#ifdef md_flush_pending_output
1363 md_flush_pending_output ();
1364#endif
1365
1366 if (is_it_end_of_statement ())
1367 {
1368 demand_empty_rest_of_line ();
1369 return;
1370 }
1371
1372#ifdef md_cons_align
1373 md_cons_align (nbytes);
1374#endif
1375
1376 do
1377 {
1378 expression (&exp);
1379
1380 p = frag_more (4);
1381 memset (p, 0, 4);
1382 fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &exp, 0,
1383 BFD_RELOC_CTOR);
1384 }
1385 while (*input_line_pointer++ == ',');
1386
1387 input_line_pointer--; /* Put terminator back into stream. */
1388 demand_empty_rest_of_line ();
1389}
1390
1391\f
1392
1393#ifdef DEBUG
1394#define DPRINTF1(A) fprintf (stderr, A)
1395#define DPRINTF2(A,B) fprintf (stderr, A, B)
1396#define DPRINTF3(A,B,C) fprintf (stderr, A, B, C)
1397
1398#else
1399#define DPRINTF1(A)
1400#define DPRINTF2(A,B)
1401#define DPRINTF3(A,B,C)
1402#endif
1403
1404/* Go through a the sections looking for relocations that are problematical for
1405 pic. If not pic, just note that this object can't be linked with pic. If
1406 it is pic, see if it needs to be marked so that it will be fixed up, or if
1407 not possible, issue an error. */
1408
1409static void
1410frv_frob_file_section (abfd, sec, ptr)
1411 bfd *abfd;
1412 asection *sec;
1413 PTR ptr ATTRIBUTE_UNUSED;
1414{
1415 segment_info_type *seginfo = seg_info (sec);
1416 fixS *fixp;
1417 CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
1418 flagword flags = bfd_get_section_flags (abfd, sec);
1419
1420 /* Skip relocations in known sections (.ctors, .dtors, and .gcc_except_table)
1421 since we can fix those up by hand. */
1422 int known_section_p = (sec->name
1423 && sec->name[0] == '.'
1424 && ((sec->name[1] == 'c'
1425 && strcmp (sec->name, ".ctor") == 0)
1426 || (sec->name[1] == 'd'
1427 && strcmp (sec->name, ".dtor") == 0)
1428 || (sec->name[1] == 'g'
1429 && strcmp (sec->name, ".gcc_except_table") == 0)));
1430
1431 DPRINTF3 ("\nFrv section %s%s\n", sec->name, (known_section_p) ? ", known section" : "");
1432 if ((flags & SEC_ALLOC) == 0)
1433 {
1434 DPRINTF1 ("\tSkipping non-loaded section\n");
1435 return;
1436 }
1437
1438 for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
1439 {
1440 symbolS *s = fixp->fx_addsy;
1441 bfd_reloc_code_real_type reloc;
1442 int non_pic_p;
1443 int opindex;
1444 const CGEN_OPERAND *operand;
1445 const CGEN_INSN *insn = fixp->fx_cgen.insn;
1446
1447 if (fixp->fx_done)
1448 {
1449 DPRINTF1 ("\tSkipping reloc that has already been done\n");
1450 continue;
1451 }
1452
1453 if (fixp->fx_pcrel)
1454 {
1455 DPRINTF1 ("\tSkipping reloc that is PC relative\n");
1456 continue;
1457 }
1458
1459 if (! s)
1460 {
1461 DPRINTF1 ("\tSkipping reloc without symbol\n");
1462 continue;
1463 }
1464
1465 if (fixp->fx_r_type < BFD_RELOC_UNUSED)
1466 {
1467 opindex = -1;
1468 reloc = fixp->fx_r_type;
1469 }
1470 else
1471 {
1472 opindex = (int) fixp->fx_r_type - (int) BFD_RELOC_UNUSED;
1473 operand = cgen_operand_lookup_by_num (cd, opindex);
1474 reloc = md_cgen_lookup_reloc (insn, operand, fixp);
1475 }
1476
1477 DPRINTF3 ("\treloc %s\t%s", bfd_get_reloc_code_name (reloc), S_GET_NAME (s));
1478
1479 non_pic_p = 0;
1480 switch (reloc)
1481 {
1482 default:
1483 break;
1484
1485 case BFD_RELOC_32:
1486 /* Skip relocations in known sections (.ctors, .dtors, and
1487 .gcc_except_table) since we can fix those up by hand. Also
1488 skip forward references to constants. Also skip a difference
1489 of two symbols, which still uses the BFD_RELOC_32 at this
1490 point. */
1491 if (! known_section_p
1492 && S_GET_SEGMENT (s) != absolute_section
1493 && !fixp->fx_subsy
1494 && (flags & (SEC_READONLY | SEC_CODE)) == 0)
1495 {
1496 non_pic_p = 1;
1497 }
1498 break;
1499
1500 /* FIXME -- should determine if any of the GP relocation really uses
1501 gr16 (which is not pic safe) or not. Right now, assume if we
1502 aren't being compiled with -mpic, the usage is non pic safe, but
1503 is safe with -mpic. */
1504 case BFD_RELOC_FRV_GPREL12:
1505 case BFD_RELOC_FRV_GPRELU12:
1506 case BFD_RELOC_FRV_GPREL32:
1507 case BFD_RELOC_FRV_GPRELHI:
1508 case BFD_RELOC_FRV_GPRELLO:
1509 non_pic_p = ! frv_pic_p;
1510 break;
1511
1512 case BFD_RELOC_FRV_LO16:
1513 case BFD_RELOC_FRV_HI16:
1514 if (S_GET_SEGMENT (s) != absolute_section)
1515 non_pic_p = 1;
1516 break;
1517
1518 case BFD_RELOC_VTABLE_INHERIT:
1519 case BFD_RELOC_VTABLE_ENTRY:
1520 non_pic_p = 1;
1521 break;
1522
1523 /* If this is a blessed BFD_RELOC_32, convert it back to the normal
1524 relocation. */
1525 case BFD_RELOC_CTOR:
1526 fixp->fx_r_type = BFD_RELOC_32;
1527 break;
1528 }
1529
1530 if (non_pic_p)
1531 {
1532 DPRINTF1 (" (Non-pic relocation)\n");
1533 if (frv_pic_p)
1534 as_warn_where (fixp->fx_file, fixp->fx_line,
1535 _("Relocation %s is not safe for %s"),
1536 bfd_get_reloc_code_name (reloc), frv_pic_flag);
1537
1538 else if ((frv_flags & EF_FRV_NON_PIC_RELOCS) == 0)
1539 {
1540 frv_flags |= EF_FRV_NON_PIC_RELOCS;
1541 bfd_set_private_flags (abfd, frv_flags);
1542 }
1543 }
1544#ifdef DEBUG
1545 else
1546 DPRINTF1 ("\n");
1547#endif
1548 }
1549}
1550
1551/* After all of the symbols have been adjusted, go over the file looking
1552 for any relocations that pic won't support. */
1553
1554void
1555frv_frob_file ()
1556{
1557 bfd_map_over_sections (stdoutput, frv_frob_file_section, (PTR)0);
1558}
1559
1560void
1561frv_frob_label (this_label)
1562 symbolS *this_label;
1563{
1564 struct vliw_insn_list *vliw_insn_list_entry;
1565
1566 if (frv_mach != bfd_mach_frvtomcat)
1567 return;
1568
1569 if (now_seg != text_section)
1570 return;
1571
1572 vliw_insn_list_entry = frv_insert_vliw_insn(DONT_COUNT);
1573 vliw_insn_list_entry->type = VLIW_LABEL_TYPE;
1574 vliw_insn_list_entry->sym = this_label;
1575}
1576
1577fixS *
1578frv_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
1579 fragS * frag;
1580 int where;
1581 const CGEN_INSN * insn;
1582 int length;
1583 const CGEN_OPERAND * operand;
1584 int opinfo;
1585 expressionS * exp;
1586{
1587 fixS * fixP = gas_cgen_record_fixup_exp (frag, where, insn, length,
1588 operand, opinfo, exp);
1589
1590 if (frv_mach == bfd_mach_frvtomcat
1591 && current_vliw_insn
1592 && current_vliw_insn->type == VLIW_BRANCH_TYPE
1593 && exp != NULL)
1594 current_vliw_insn->sym = exp->X_add_symbol;
1595
1596 return fixP;
1597}
This page took 0.139033 seconds and 4 git commands to generate.