source: trunk/binutils/gas/config/tc-frv.c@ 2562

Last change on this file since 2562 was 607, checked in by bird, 22 years ago

Initial revision

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