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