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