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