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