1 /* tc-i860.c -- Assembler for the Intel i860 architecture. 2 Copyright 1989, 1992, 1993, 1994, 1995, 1998, 1999, 2000, 2001, 2002, 2003 3 Free Software Foundation, Inc. 4 5 Brought back from the dead and completely reworked 6 by Jason Eckhardt <jle@cygnus.com>. 7 8 This file is part of GAS, the GNU Assembler. 9 10 GAS is free software; you can redistribute it and/or modify 11 it under the terms of the GNU General Public License as published by 12 the Free Software Foundation; either version 2, or (at your option) 13 any later version. 14 15 GAS is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License for more details. 19 20 You should have received a copy of the GNU General Public License along 21 with GAS; see the file COPYING. If not, write to the Free Software 22 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 23 24 #include <stdio.h> 25 #include <string.h> 26 #include "as.h" 27 #include "safe-ctype.h" 28 #include "subsegs.h" 29 #include "opcode/i860.h" 30 #include "elf/i860.h" 31 32 33 /* The opcode hash table. */ 34 static struct hash_control *op_hash = NULL; 35 36 /* These characters always start a comment. */ 37 const char comment_chars[] = "#!/"; 38 39 /* These characters start a comment at the beginning of a line. */ 40 const char line_comment_chars[] = "#/"; 41 42 const char line_separator_chars[] = ";"; 43 44 /* Characters that can be used to separate the mantissa from the exponent 45 in floating point numbers. */ 46 const char EXP_CHARS[] = "eE"; 47 48 /* Characters that indicate this number is a floating point constant. 49 As in 0f12.456 or 0d1.2345e12. */ 50 const char FLT_CHARS[] = "rRsSfFdDxXpP"; 51 52 /* Register prefix (depends on syntax). */ 53 static char reg_prefix; 54 55 #define MAX_FIXUPS 2 56 57 struct i860_it 58 { 59 char *error; 60 unsigned long opcode; 61 enum expand_type expand; 62 struct i860_fi 63 { 64 expressionS exp; 65 bfd_reloc_code_real_type reloc; 66 int pcrel; 67 valueT fup; 68 } fi[MAX_FIXUPS]; 69 } the_insn; 70 71 /* The current fixup count. */ 72 static int fc; 73 74 static char *expr_end; 75 76 /* Indicates error if a pseudo operation was expanded after a branch. */ 77 static char last_expand; 78 79 /* If true, then warn if any pseudo operations were expanded. */ 80 static int target_warn_expand = 0; 81 82 /* If true, then XP support is enabled. */ 83 static int target_xp = 0; 84 85 /* If true, then Intel syntax is enabled (default to AT&T/SVR4 syntax). */ 86 static int target_intel_syntax = 0; 87 88 89 /* Prototypes. */ 90 static void i860_process_insn (char *); 91 static void s_dual (int); 92 static void s_enddual (int); 93 static void s_atmp (int); 94 static void s_align_wrapper (int); 95 static int i860_get_expression (char *); 96 static bfd_reloc_code_real_type obtain_reloc_for_imm16 (fixS *, long *); 97 #ifdef DEBUG_I860 98 static void print_insn (struct i860_it *); 99 #endif 100 101 const pseudo_typeS md_pseudo_table[] = 102 { 103 {"align", s_align_wrapper, 0}, 104 {"dual", s_dual, 0}, 105 {"enddual", s_enddual, 0}, 106 {"atmp", s_atmp, 0}, 107 {NULL, 0, 0}, 108 }; 109 110 /* Dual-instruction mode handling. */ 111 enum dual 112 { 113 DUAL_OFF = 0, DUAL_ON, DUAL_DDOT, DUAL_ONDDOT, 114 }; 115 static enum dual dual_mode = DUAL_OFF; 116 117 /* Handle ".dual" directive. */ 118 static void 119 s_dual (int ignore ATTRIBUTE_UNUSED) 120 { 121 if (target_intel_syntax) 122 dual_mode = DUAL_ON; 123 else 124 as_bad (_("Directive .dual available only with -mintel-syntax option")); 125 } 126 127 /* Handle ".enddual" directive. */ 128 static void 129 s_enddual (int ignore ATTRIBUTE_UNUSED) 130 { 131 if (target_intel_syntax) 132 dual_mode = DUAL_OFF; 133 else 134 as_bad (_("Directive .enddual available only with -mintel-syntax option")); 135 } 136 137 /* Temporary register used when expanding assembler pseudo operations. */ 138 static int atmp = 31; 139 140 static void 141 s_atmp (int ignore ATTRIBUTE_UNUSED) 142 { 143 int temp; 144 145 if (! target_intel_syntax) 146 { 147 as_bad (_("Directive .atmp available only with -mintel-syntax option")); 148 demand_empty_rest_of_line (); 149 return; 150 } 151 152 if (strncmp (input_line_pointer, "sp", 2) == 0) 153 { 154 input_line_pointer += 2; 155 atmp = 2; 156 } 157 else if (strncmp (input_line_pointer, "fp", 2) == 0) 158 { 159 input_line_pointer += 2; 160 atmp = 3; 161 } 162 else if (strncmp (input_line_pointer, "r", 1) == 0) 163 { 164 input_line_pointer += 1; 165 temp = get_absolute_expression (); 166 if (temp >= 0 && temp <= 31) 167 atmp = temp; 168 else 169 as_bad (_("Unknown temporary pseudo register")); 170 } 171 else 172 { 173 as_bad (_("Unknown temporary pseudo register")); 174 } 175 demand_empty_rest_of_line (); 176 } 177 178 /* Handle ".align" directive depending on syntax mode. 179 AT&T/SVR4 syntax uses the standard align directive. However, 180 the Intel syntax additionally allows keywords for the alignment 181 parameter: ".align type", where type is one of {.short, .long, 182 .quad, .single, .double} representing alignments of 2, 4, 183 16, 4, and 8, respectively. */ 184 static void 185 s_align_wrapper (int arg) 186 { 187 char *parm = input_line_pointer; 188 189 if (target_intel_syntax) 190 { 191 /* Replace a keyword with the equivalent integer so the 192 standard align routine can parse the directive. */ 193 if (strncmp (parm, ".short", 6) == 0) 194 strncpy (parm, " 2", 6); 195 else if (strncmp (parm, ".long", 5) == 0) 196 strncpy (parm, " 4", 5); 197 else if (strncmp (parm, ".quad", 5) == 0) 198 strncpy (parm, " 16", 5); 199 else if (strncmp (parm, ".single", 7) == 0) 200 strncpy (parm, " 4", 7); 201 else if (strncmp (parm, ".double", 7) == 0) 202 strncpy (parm, " 8", 7); 203 204 while (*input_line_pointer == ' ') 205 ++input_line_pointer; 206 } 207 208 s_align_bytes (arg); 209 } 210 211 /* This function is called once, at assembler startup time. It should 212 set up all the tables and data structures that the MD part of the 213 assembler will need. */ 214 void 215 md_begin (void) 216 { 217 const char *retval = NULL; 218 int lose = 0; 219 unsigned int i = 0; 220 221 op_hash = hash_new (); 222 223 while (i860_opcodes[i].name != NULL) 224 { 225 const char *name = i860_opcodes[i].name; 226 retval = hash_insert (op_hash, name, (PTR)&i860_opcodes[i]); 227 if (retval != NULL) 228 { 229 fprintf (stderr, _("internal error: can't hash `%s': %s\n"), 230 i860_opcodes[i].name, retval); 231 lose = 1; 232 } 233 do 234 { 235 if (i860_opcodes[i].match & i860_opcodes[i].lose) 236 { 237 fprintf (stderr, 238 _("internal error: losing opcode: `%s' \"%s\"\n"), 239 i860_opcodes[i].name, i860_opcodes[i].args); 240 lose = 1; 241 } 242 ++i; 243 } 244 while (i860_opcodes[i].name != NULL 245 && strcmp (i860_opcodes[i].name, name) == 0); 246 } 247 248 if (lose) 249 as_fatal (_("Defective assembler. No assembly attempted.")); 250 251 /* Set the register prefix for either Intel or AT&T/SVR4 syntax. */ 252 reg_prefix = target_intel_syntax ? 0 : '%'; 253 } 254 255 /* This is the core of the machine-dependent assembler. STR points to a 256 machine dependent instruction. This function emits the frags/bytes 257 it assembles to. */ 258 void 259 md_assemble (char *str) 260 { 261 char *destp; 262 int num_opcodes = 1; 263 int i; 264 struct i860_it pseudo[3]; 265 266 assert (str); 267 fc = 0; 268 269 /* Assemble the instruction. */ 270 i860_process_insn (str); 271 272 /* Check for expandable flag to produce pseudo-instructions. This 273 is an undesirable feature that should be avoided. */ 274 if (the_insn.expand != 0 && the_insn.expand != XP_ONLY 275 && ! (the_insn.fi[0].fup & (OP_SEL_HA | OP_SEL_H | OP_SEL_L | OP_SEL_GOT 276 | OP_SEL_GOTOFF | OP_SEL_PLT))) 277 { 278 for (i = 0; i < 3; i++) 279 pseudo[i] = the_insn; 280 281 fc = 1; 282 switch (the_insn.expand) 283 { 284 285 case E_DELAY: 286 num_opcodes = 1; 287 break; 288 289 case E_MOV: 290 if (the_insn.fi[0].exp.X_add_symbol == NULL 291 && the_insn.fi[0].exp.X_op_symbol == NULL 292 && (the_insn.fi[0].exp.X_add_number < (1 << 15) 293 && the_insn.fi[0].exp.X_add_number >= -(1 << 15))) 294 break; 295 296 /* Emit "or l%const,r0,ireg_dest". */ 297 pseudo[0].opcode = (the_insn.opcode & 0x001f0000) | 0xe4000000; 298 pseudo[0].fi[0].fup = (OP_IMM_S16 | OP_SEL_L); 299 300 /* Emit "orh h%const,ireg_dest,ireg_dest". */ 301 pseudo[1].opcode = (the_insn.opcode & 0x03ffffff) | 0xec000000 302 | ((the_insn.opcode & 0x001f0000) << 5); 303 pseudo[1].fi[0].fup = (OP_IMM_S16 | OP_SEL_H); 304 305 num_opcodes = 2; 306 break; 307 308 case E_ADDR: 309 if (the_insn.fi[0].exp.X_add_symbol == NULL 310 && the_insn.fi[0].exp.X_op_symbol == NULL 311 && (the_insn.fi[0].exp.X_add_number < (1 << 15) 312 && the_insn.fi[0].exp.X_add_number >= -(1 << 15))) 313 break; 314 315 /* Emit "orh ha%addr_expr,ireg_src2,r31". */ 316 pseudo[0].opcode = 0xec000000 | (the_insn.opcode & 0x03e00000) 317 | (atmp << 16); 318 pseudo[0].fi[0].fup = (OP_IMM_S16 | OP_SEL_HA); 319 320 /* Emit "l%addr_expr(r31),ireg_dest". We pick up the fixup 321 information from the original instruction. */ 322 pseudo[1].opcode = (the_insn.opcode & ~0x03e00000) | (atmp << 21); 323 pseudo[1].fi[0].fup = the_insn.fi[0].fup | OP_SEL_L; 324 325 num_opcodes = 2; 326 break; 327 328 case E_U32: 329 if (the_insn.fi[0].exp.X_add_symbol == NULL 330 && the_insn.fi[0].exp.X_op_symbol == NULL 331 && (the_insn.fi[0].exp.X_add_number < (1 << 16) 332 && the_insn.fi[0].exp.X_add_number >= 0)) 333 break; 334 335 /* Emit "$(opcode)h h%const,ireg_src2,r31". */ 336 pseudo[0].opcode = (the_insn.opcode & 0xf3e0ffff) | 0x0c000000 337 | (atmp << 16); 338 pseudo[0].fi[0].fup = (OP_IMM_S16 | OP_SEL_H); 339 340 /* Emit "$(opcode) l%const,r31,ireg_dest". */ 341 pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 342 | (atmp << 21); 343 pseudo[1].fi[0].fup = (OP_IMM_S16 | OP_SEL_L); 344 345 num_opcodes = 2; 346 break; 347 348 case E_AND: 349 if (the_insn.fi[0].exp.X_add_symbol == NULL 350 && the_insn.fi[0].exp.X_op_symbol == NULL 351 && (the_insn.fi[0].exp.X_add_number < (1 << 16) 352 && the_insn.fi[0].exp.X_add_number >= 0)) 353 break; 354 355 /* Emit "andnot h%const,ireg_src2,r31". */ 356 pseudo[0].opcode = (the_insn.opcode & 0x03e0ffff) | 0xd4000000 357 | (atmp << 16); 358 pseudo[0].fi[0].fup = (OP_IMM_S16 | OP_SEL_H); 359 pseudo[0].fi[0].exp.X_add_number = 360 -1 - the_insn.fi[0].exp.X_add_number; 361 362 /* Emit "andnot l%const,r31,ireg_dest". */ 363 pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 364 | (atmp << 21); 365 pseudo[1].fi[0].fup = (OP_IMM_S16 | OP_SEL_L); 366 pseudo[1].fi[0].exp.X_add_number = 367 -1 - the_insn.fi[0].exp.X_add_number; 368 369 num_opcodes = 2; 370 break; 371 372 case E_S32: 373 if (the_insn.fi[0].exp.X_add_symbol == NULL 374 && the_insn.fi[0].exp.X_op_symbol == NULL 375 && (the_insn.fi[0].exp.X_add_number < (1 << 15) 376 && the_insn.fi[0].exp.X_add_number >= -(1 << 15))) 377 break; 378 379 /* Emit "orh h%const,r0,r31". */ 380 pseudo[0].opcode = 0xec000000 | (atmp << 16); 381 pseudo[0].fi[0].fup = (OP_IMM_S16 | OP_SEL_H); 382 383 /* Emit "or l%const,r31,r31". */ 384 pseudo[1].opcode = 0xe4000000 | (atmp << 21) | (atmp << 16); 385 pseudo[1].fi[0].fup = (OP_IMM_S16 | OP_SEL_L); 386 387 /* Emit "r31,ireg_src2,ireg_dest". */ 388 pseudo[2].opcode = (the_insn.opcode & ~0x0400ffff) | (atmp << 11); 389 pseudo[2].fi[0].fup = OP_IMM_S16; 390 391 num_opcodes = 3; 392 break; 393 394 default: 395 as_fatal (_("failed sanity check.")); 396 } 397 398 the_insn = pseudo[0]; 399 400 /* Warn if an opcode is expanded after a delayed branch. */ 401 if (num_opcodes > 1 && last_expand == 1) 402 as_warn (_("Expanded opcode after delayed branch: `%s'"), str); 403 404 /* Warn if an opcode is expanded in dual mode. */ 405 if (num_opcodes > 1 && dual_mode != DUAL_OFF) 406 as_warn (_("Expanded opcode in dual mode: `%s'"), str); 407 408 /* Notify if any expansions happen. */ 409 if (target_warn_expand && num_opcodes > 1) 410 as_warn (_("An instruction was expanded (%s)"), str); 411 } 412 413 i = 0; 414 do 415 { 416 int tmp; 417 418 /* Output the opcode. Note that the i860 always reads instructions 419 as little-endian data. */ 420 destp = frag_more (4); 421 number_to_chars_littleendian (destp, the_insn.opcode, 4); 422 423 /* Check for expanded opcode after branch or in dual mode. */ 424 last_expand = the_insn.fi[0].pcrel; 425 426 /* Output the symbol-dependent stuff. Only btne and bte will ever 427 loop more than once here, since only they (possibly) have more 428 than one fixup. */ 429 for (tmp = 0; tmp < fc; tmp++) 430 { 431 if (the_insn.fi[tmp].fup != OP_NONE) 432 { 433 fixS *fix; 434 fix = fix_new_exp (frag_now, 435 destp - frag_now->fr_literal, 436 4, 437 &the_insn.fi[tmp].exp, 438 the_insn.fi[tmp].pcrel, 439 the_insn.fi[tmp].reloc); 440 441 /* Despite the odd name, this is a scratch field. We use 442 it to encode operand type information. */ 443 fix->fx_addnumber = the_insn.fi[tmp].fup; 444 } 445 } 446 the_insn = pseudo[++i]; 447 } 448 while (--num_opcodes > 0); 449 450 } 451 452 /* Assemble the instruction pointed to by STR. */ 453 static void 454 i860_process_insn (char *str) 455 { 456 char *s; 457 const char *args; 458 char c; 459 struct i860_opcode *insn; 460 char *args_start; 461 unsigned long opcode; 462 unsigned int mask; 463 int match = 0; 464 int comma = 0; 465 466 #if 1 /* For compiler warnings. */ 467 args = 0; 468 insn = 0; 469 args_start = 0; 470 opcode = 0; 471 #endif 472 473 for (s = str; ISLOWER (*s) || *s == '.' || *s == '3' 474 || *s == '2' || *s == '1'; ++s) 475 ; 476 477 switch (*s) 478 { 479 case '\0': 480 break; 481 482 case ',': 483 comma = 1; 484 485 /*FALLTHROUGH*/ 486 487 case ' ': 488 *s++ = '\0'; 489 break; 490 491 default: 492 as_fatal (_("Unknown opcode: `%s'"), str); 493 } 494 495 /* Check for dual mode ("d.") opcode prefix. */ 496 if (strncmp (str, "d.", 2) == 0) 497 { 498 if (dual_mode == DUAL_ON) 499 dual_mode = DUAL_ONDDOT; 500 else 501 dual_mode = DUAL_DDOT; 502 str += 2; 503 } 504 505 if ((insn = (struct i860_opcode *) hash_find (op_hash, str)) == NULL) 506 { 507 if (dual_mode == DUAL_DDOT || dual_mode == DUAL_ONDDOT) 508 str -= 2; 509 as_bad (_("Unknown opcode: `%s'"), str); 510 return; 511 } 512 513 if (comma) 514 *--s = ','; 515 516 args_start = s; 517 for (;;) 518 { 519 int t; 520 opcode = insn->match; 521 memset (&the_insn, '\0', sizeof (the_insn)); 522 fc = 0; 523 for (t = 0; t < MAX_FIXUPS; t++) 524 { 525 the_insn.fi[t].reloc = BFD_RELOC_NONE; 526 the_insn.fi[t].pcrel = 0; 527 the_insn.fi[t].fup = OP_NONE; 528 } 529 530 /* Build the opcode, checking as we go that the operands match. */ 531 for (args = insn->args; ; ++args) 532 { 533 if (fc > MAX_FIXUPS) 534 abort (); 535 536 switch (*args) 537 { 538 539 /* End of args. */ 540 case '\0': 541 if (*s == '\0') 542 match = 1; 543 break; 544 545 /* These must match exactly. */ 546 case '+': 547 case '(': 548 case ')': 549 case ',': 550 case ' ': 551 if (*s++ == *args) 552 continue; 553 break; 554 555 /* Must be at least one digit. */ 556 case '#': 557 if (ISDIGIT (*s++)) 558 { 559 while (ISDIGIT (*s)) 560 ++s; 561 continue; 562 } 563 break; 564 565 /* Next operand must be a register. */ 566 case '1': 567 case '2': 568 case 'd': 569 /* Check for register prefix if necessary. */ 570 if (reg_prefix && *s != reg_prefix) 571 goto error; 572 else if (reg_prefix) 573 s++; 574 575 switch (*s) 576 { 577 /* Frame pointer. */ 578 case 'f': 579 s++; 580 if (*s++ == 'p') 581 { 582 mask = 0x3; 583 break; 584 } 585 goto error; 586 587 /* Stack pointer. */ 588 case 's': 589 s++; 590 if (*s++ == 'p') 591 { 592 mask = 0x2; 593 break; 594 } 595 goto error; 596 597 /* Any register r0..r31. */ 598 case 'r': 599 s++; 600 if (!ISDIGIT (c = *s++)) 601 { 602 goto error; 603 } 604 if (ISDIGIT (*s)) 605 { 606 if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) 607 goto error; 608 } 609 else 610 c -= '0'; 611 mask = c; 612 break; 613 614 /* Not this opcode. */ 615 default: 616 goto error; 617 } 618 619 /* Obtained the register, now place it in the opcode. */ 620 switch (*args) 621 { 622 case '1': 623 opcode |= mask << 11; 624 continue; 625 626 case '2': 627 opcode |= mask << 21; 628 continue; 629 630 case 'd': 631 opcode |= mask << 16; 632 continue; 633 634 } 635 break; 636 637 /* Next operand is a floating point register. */ 638 case 'e': 639 case 'f': 640 case 'g': 641 /* Check for register prefix if necessary. */ 642 if (reg_prefix && *s != reg_prefix) 643 goto error; 644 else if (reg_prefix) 645 s++; 646 647 if (*s++ == 'f' && ISDIGIT (*s)) 648 { 649 mask = *s++; 650 if (ISDIGIT (*s)) 651 { 652 mask = 10 * (mask - '0') + (*s++ - '0'); 653 if (mask >= 32) 654 { 655 break; 656 } 657 } 658 else 659 mask -= '0'; 660 661 switch (*args) 662 { 663 664 case 'e': 665 opcode |= mask << 11; 666 continue; 667 668 case 'f': 669 opcode |= mask << 21; 670 continue; 671 672 case 'g': 673 opcode |= mask << 16; 674 if ((opcode & (1 << 10)) && mask != 0 675 && (mask == ((opcode >> 11) & 0x1f))) 676 as_warn (_("Pipelined instruction: fsrc1 = fdest")); 677 continue; 678 } 679 } 680 break; 681 682 /* Next operand must be a control register. */ 683 case 'c': 684 /* Check for register prefix if necessary. */ 685 if (reg_prefix && *s != reg_prefix) 686 goto error; 687 else if (reg_prefix) 688 s++; 689 690 if (strncmp (s, "fir", 3) == 0) 691 { 692 opcode |= 0x0 << 21; 693 s += 3; 694 continue; 695 } 696 if (strncmp (s, "psr", 3) == 0) 697 { 698 opcode |= 0x1 << 21; 699 s += 3; 700 continue; 701 } 702 if (strncmp (s, "dirbase", 7) == 0) 703 { 704 opcode |= 0x2 << 21; 705 s += 7; 706 continue; 707 } 708 if (strncmp (s, "db", 2) == 0) 709 { 710 opcode |= 0x3 << 21; 711 s += 2; 712 continue; 713 } 714 if (strncmp (s, "fsr", 3) == 0) 715 { 716 opcode |= 0x4 << 21; 717 s += 3; 718 continue; 719 } 720 if (strncmp (s, "epsr", 4) == 0) 721 { 722 opcode |= 0x5 << 21; 723 s += 4; 724 continue; 725 } 726 /* The remaining control registers are XP only. */ 727 if (target_xp && strncmp (s, "bear", 4) == 0) 728 { 729 opcode |= 0x6 << 21; 730 s += 4; 731 continue; 732 } 733 if (target_xp && strncmp (s, "ccr", 3) == 0) 734 { 735 opcode |= 0x7 << 21; 736 s += 3; 737 continue; 738 } 739 if (target_xp && strncmp (s, "p0", 2) == 0) 740 { 741 opcode |= 0x8 << 21; 742 s += 2; 743 continue; 744 } 745 if (target_xp && strncmp (s, "p1", 2) == 0) 746 { 747 opcode |= 0x9 << 21; 748 s += 2; 749 continue; 750 } 751 if (target_xp && strncmp (s, "p2", 2) == 0) 752 { 753 opcode |= 0xa << 21; 754 s += 2; 755 continue; 756 } 757 if (target_xp && strncmp (s, "p3", 2) == 0) 758 { 759 opcode |= 0xb << 21; 760 s += 2; 761 continue; 762 } 763 break; 764 765 /* 5-bit immediate in src1. */ 766 case '5': 767 if (! i860_get_expression (s)) 768 { 769 s = expr_end; 770 the_insn.fi[fc].fup |= OP_IMM_U5; 771 fc++; 772 continue; 773 } 774 break; 775 776 /* 26-bit immediate, relative branch (lbroff). */ 777 case 'l': 778 the_insn.fi[fc].pcrel = 1; 779 the_insn.fi[fc].fup |= OP_IMM_BR26; 780 goto immediate; 781 782 /* 16-bit split immediate, relative branch (sbroff). */ 783 case 'r': 784 the_insn.fi[fc].pcrel = 1; 785 the_insn.fi[fc].fup |= OP_IMM_BR16; 786 goto immediate; 787 788 /* 16-bit split immediate. */ 789 case 's': 790 the_insn.fi[fc].fup |= OP_IMM_SPLIT16; 791 goto immediate; 792 793 /* 16-bit split immediate, byte aligned (st.b). */ 794 case 'S': 795 the_insn.fi[fc].fup |= OP_IMM_SPLIT16; 796 goto immediate; 797 798 /* 16-bit split immediate, half-word aligned (st.s). */ 799 case 'T': 800 the_insn.fi[fc].fup |= (OP_IMM_SPLIT16 | OP_ENCODE1 | OP_ALIGN2); 801 goto immediate; 802 803 /* 16-bit split immediate, word aligned (st.l). */ 804 case 'U': 805 the_insn.fi[fc].fup |= (OP_IMM_SPLIT16 | OP_ENCODE1 | OP_ALIGN4); 806 goto immediate; 807 808 /* 16-bit immediate. */ 809 case 'i': 810 the_insn.fi[fc].fup |= OP_IMM_S16; 811 goto immediate; 812 813 /* 16-bit immediate, byte aligned (ld.b). */ 814 case 'I': 815 the_insn.fi[fc].fup |= OP_IMM_S16; 816 goto immediate; 817 818 /* 16-bit immediate, half-word aligned (ld.s). */ 819 case 'J': 820 the_insn.fi[fc].fup |= (OP_IMM_S16 | OP_ENCODE1 | OP_ALIGN2); 821 goto immediate; 822 823 /* 16-bit immediate, word aligned (ld.l, {p}fld.l, fst.l). */ 824 case 'K': 825 if (insn->name[0] == 'l') 826 the_insn.fi[fc].fup |= (OP_IMM_S16 | OP_ENCODE1 | OP_ALIGN4); 827 else 828 the_insn.fi[fc].fup |= (OP_IMM_S16 | OP_ENCODE2 | OP_ALIGN4); 829 goto immediate; 830 831 /* 16-bit immediate, double-word aligned ({p}fld.d, fst.d). */ 832 case 'L': 833 the_insn.fi[fc].fup |= (OP_IMM_S16 | OP_ENCODE3 | OP_ALIGN8); 834 goto immediate; 835 836 /* 16-bit immediate, quad-word aligned (fld.q, fst.q). */ 837 case 'M': 838 the_insn.fi[fc].fup |= (OP_IMM_S16 | OP_ENCODE3 | OP_ALIGN16); 839 840 /*FALLTHROUGH*/ 841 842 /* Handle the immediate for either the Intel syntax or 843 SVR4 syntax. The Intel syntax is "ha%immediate" 844 whereas SVR4 syntax is "[immediate]@ha". */ 845 immediate: 846 if (target_intel_syntax == 0) 847 { 848 /* AT&T/SVR4 syntax. */ 849 if (*s == ' ') 850 s++; 851 852 /* Note that if i860_get_expression() fails, we will still 853 have created U entries in the symbol table for the 854 'symbols' in the input string. Try not to create U 855 symbols for registers, etc. */ 856 if (! i860_get_expression (s)) 857 s = expr_end; 858 else 859 goto error; 860 861 if (strncmp (s, "@ha", 3) == 0) 862 { 863 the_insn.fi[fc].fup |= OP_SEL_HA; 864 s += 3; 865 } 866 else if (strncmp (s, "@h", 2) == 0) 867 { 868 the_insn.fi[fc].fup |= OP_SEL_H; 869 s += 2; 870 } 871 else if (strncmp (s, "@l", 2) == 0) 872 { 873 the_insn.fi[fc].fup |= OP_SEL_L; 874 s += 2; 875 } 876 else if (strncmp (s, "@gotoff", 7) == 0 877 || strncmp (s, "@GOTOFF", 7) == 0) 878 { 879 as_bad (_("Assembler does not yet support PIC")); 880 the_insn.fi[fc].fup |= OP_SEL_GOTOFF; 881 s += 7; 882 } 883 else if (strncmp (s, "@got", 4) == 0 884 || strncmp (s, "@GOT", 4) == 0) 885 { 886 as_bad (_("Assembler does not yet support PIC")); 887 the_insn.fi[fc].fup |= OP_SEL_GOT; 888 s += 4; 889 } 890 else if (strncmp (s, "@plt", 4) == 0 891 || strncmp (s, "@PLT", 4) == 0) 892 { 893 as_bad (_("Assembler does not yet support PIC")); 894 the_insn.fi[fc].fup |= OP_SEL_PLT; 895 s += 4; 896 } 897 898 the_insn.expand = insn->expand; 899 fc++; 900 901 continue; 902 } 903 else 904 { 905 /* Intel syntax. */ 906 if (*s == ' ') 907 s++; 908 if (strncmp (s, "ha%", 3) == 0) 909 { 910 the_insn.fi[fc].fup |= OP_SEL_HA; 911 s += 3; 912 } 913 else if (strncmp (s, "h%", 2) == 0) 914 { 915 the_insn.fi[fc].fup |= OP_SEL_H; 916 s += 2; 917 } 918 else if (strncmp (s, "l%", 2) == 0) 919 { 920 the_insn.fi[fc].fup |= OP_SEL_L; 921 s += 2; 922 } 923 the_insn.expand = insn->expand; 924 925 /* Note that if i860_get_expression() fails, we will still 926 have created U entries in the symbol table for the 927 'symbols' in the input string. Try not to create U 928 symbols for registers, etc. */ 929 if (! i860_get_expression (s)) 930 s = expr_end; 931 else 932 goto error; 933 934 fc++; 935 continue; 936 } 937 break; 938 939 default: 940 as_fatal (_("failed sanity check.")); 941 } 942 break; 943 } 944 error: 945 if (match == 0) 946 { 947 /* Args don't match. */ 948 if (insn[1].name != NULL 949 && ! strcmp (insn->name, insn[1].name)) 950 { 951 ++insn; 952 s = args_start; 953 continue; 954 } 955 else 956 { 957 as_bad (_("Illegal operands for %s"), insn->name); 958 return; 959 } 960 } 961 break; 962 } 963 964 /* Set the dual bit on this instruction if necessary. */ 965 if (dual_mode != DUAL_OFF) 966 { 967 if ((opcode & 0xfc000000) == 0x48000000 || opcode == 0xb0000000) 968 { 969 /* The instruction is a flop or a fnop, so set its dual bit 970 (but check that it is 8-byte aligned). */ 971 if (((frag_now->fr_address + frag_now_fix_octets ()) & 7) == 0) 972 opcode |= (1 << 9); 973 else 974 as_bad (_("'d.%s' must be 8-byte aligned"), insn->name); 975 976 if (dual_mode == DUAL_DDOT) 977 dual_mode = DUAL_OFF; 978 else if (dual_mode == DUAL_ONDDOT) 979 dual_mode = DUAL_ON; 980 } 981 else if (dual_mode == DUAL_DDOT || dual_mode == DUAL_ONDDOT) 982 as_bad (_("Prefix 'd.' invalid for instruction `%s'"), insn->name); 983 } 984 985 the_insn.opcode = opcode; 986 987 /* Only recognize XP instructions when the user has requested it. */ 988 if (insn->expand == XP_ONLY && ! target_xp) 989 as_bad (_("Unknown opcode: `%s'"), insn->name); 990 } 991 992 static int 993 i860_get_expression (char *str) 994 { 995 char *save_in; 996 segT seg; 997 998 save_in = input_line_pointer; 999 input_line_pointer = str; 1000 seg = expression (&the_insn.fi[fc].exp); 1001 if (seg != absolute_section 1002 && seg != undefined_section 1003 && ! SEG_NORMAL (seg)) 1004 { 1005 the_insn.error = _("bad segment"); 1006 expr_end = input_line_pointer; 1007 input_line_pointer = save_in; 1008 return 1; 1009 } 1010 expr_end = input_line_pointer; 1011 input_line_pointer = save_in; 1012 return 0; 1013 } 1014 1015 /* Turn a string in input_line_pointer into a floating point constant of 1016 type TYPE, and store the appropriate bytes in *LITP. The number of 1017 LITTLENUMS emitted is stored in *SIZEP. An error message is returned, 1018 or NULL on OK. */ 1019 1020 /* Equal to MAX_PRECISION in atof-ieee.c. */ 1021 #define MAX_LITTLENUMS 6 1022 1023 char * 1024 md_atof (int type, char *litP, int *sizeP) 1025 { 1026 int prec; 1027 LITTLENUM_TYPE words[MAX_LITTLENUMS]; 1028 LITTLENUM_TYPE *wordP; 1029 char *t; 1030 1031 switch (type) 1032 { 1033 case 'f': 1034 case 'F': 1035 case 's': 1036 case 'S': 1037 prec = 2; 1038 break; 1039 1040 case 'd': 1041 case 'D': 1042 case 'r': 1043 case 'R': 1044 prec = 4; 1045 break; 1046 1047 case 'x': 1048 case 'X': 1049 prec = 6; 1050 break; 1051 1052 case 'p': 1053 case 'P': 1054 prec = 6; 1055 break; 1056 1057 default: 1058 *sizeP = 0; 1059 return _("Bad call to MD_ATOF()"); 1060 } 1061 t = atof_ieee (input_line_pointer, type, words); 1062 if (t) 1063 input_line_pointer = t; 1064 *sizeP = prec * sizeof (LITTLENUM_TYPE); 1065 for (wordP = words; prec--;) 1066 { 1067 md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE)); 1068 litP += sizeof (LITTLENUM_TYPE); 1069 } 1070 return 0; 1071 } 1072 1073 /* Write out in current endian mode. */ 1074 void 1075 md_number_to_chars (char *buf, valueT val, int n) 1076 { 1077 if (target_big_endian) 1078 number_to_chars_bigendian (buf, val, n); 1079 else 1080 number_to_chars_littleendian (buf, val, n); 1081 } 1082 1083 /* This should never be called for i860. */ 1084 int 1085 md_estimate_size_before_relax (register fragS *fragP ATTRIBUTE_UNUSED, 1086 segT segtype ATTRIBUTE_UNUSED) 1087 { 1088 as_fatal (_("i860_estimate_size_before_relax\n")); 1089 } 1090 1091 #ifdef DEBUG_I860 1092 static void 1093 print_insn (struct i860_it *insn) 1094 { 1095 if (insn->error) 1096 fprintf (stderr, "ERROR: %s\n", insn->error); 1097 1098 fprintf (stderr, "opcode = 0x%08lx\t", insn->opcode); 1099 fprintf (stderr, "expand = 0x%x\t", insn->expand); 1100 fprintf (stderr, "reloc = %s\t\n", 1101 bfd_get_reloc_code_name (insn->reloc)); 1102 fprintf (stderr, "exp = {\n"); 1103 fprintf (stderr, "\t\tX_add_symbol = %s\n", 1104 insn->exp.X_add_symbol ? 1105 (S_GET_NAME (insn->exp.X_add_symbol) ? 1106 S_GET_NAME (insn->exp.X_add_symbol) : "???") : "0"); 1107 fprintf (stderr, "\t\tX_op_symbol = %s\n", 1108 insn->exp.X_op_symbol ? 1109 (S_GET_NAME (insn->exp.X_op_symbol) ? 1110 S_GET_NAME (insn->exp.X_op_symbol) : "???") : "0"); 1111 fprintf (stderr, "\t\tX_add_number = %lx\n", 1112 insn->exp.X_add_number); 1113 fprintf (stderr, "}\n"); 1114 } 1115 #endif /* DEBUG_I860 */ 1116 1117 1118 #ifdef OBJ_ELF 1119 const char *md_shortopts = "VQ:"; 1120 #else 1121 const char *md_shortopts = ""; 1122 #endif 1123 1124 #define OPTION_EB (OPTION_MD_BASE + 0) 1125 #define OPTION_EL (OPTION_MD_BASE + 1) 1126 #define OPTION_WARN_EXPAND (OPTION_MD_BASE + 2) 1127 #define OPTION_XP (OPTION_MD_BASE + 3) 1128 #define OPTION_INTEL_SYNTAX (OPTION_MD_BASE + 4) 1129 1130 struct option md_longopts[] = { 1131 { "EB", no_argument, NULL, OPTION_EB }, 1132 { "EL", no_argument, NULL, OPTION_EL }, 1133 { "mwarn-expand", no_argument, NULL, OPTION_WARN_EXPAND }, 1134 { "mxp", no_argument, NULL, OPTION_XP }, 1135 { "mintel-syntax",no_argument, NULL, OPTION_INTEL_SYNTAX }, 1136 { NULL, no_argument, NULL, 0 } 1137 }; 1138 size_t md_longopts_size = sizeof (md_longopts); 1139 1140 int 1141 md_parse_option (int c, char *arg ATTRIBUTE_UNUSED) 1142 { 1143 switch (c) 1144 { 1145 case OPTION_EB: 1146 target_big_endian = 1; 1147 break; 1148 1149 case OPTION_EL: 1150 target_big_endian = 0; 1151 break; 1152 1153 case OPTION_WARN_EXPAND: 1154 target_warn_expand = 1; 1155 break; 1156 1157 case OPTION_XP: 1158 target_xp = 1; 1159 break; 1160 1161 case OPTION_INTEL_SYNTAX: 1162 target_intel_syntax = 1; 1163 break; 1164 1165 #ifdef OBJ_ELF 1166 /* SVR4 argument compatibility (-V): print version ID. */ 1167 case 'V': 1168 print_version_id (); 1169 break; 1170 1171 /* SVR4 argument compatibility (-Qy, -Qn): controls whether 1172 a .comment section should be emitted or not (ignored). */ 1173 case 'Q': 1174 break; 1175 #endif 1176 1177 default: 1178 return 0; 1179 } 1180 1181 return 1; 1182 } 1183 1184 void 1185 md_show_usage (FILE *stream) 1186 { 1187 fprintf (stream, _("\ 1188 -EL generate code for little endian mode (default)\n\ 1189 -EB generate code for big endian mode\n\ 1190 -mwarn-expand warn if pseudo operations are expanded\n\ 1191 -mxp enable i860XP support (disabled by default)\n\ 1192 -mintel-syntax enable Intel syntax (default to AT&T/SVR4)\n")); 1193 #ifdef OBJ_ELF 1194 /* SVR4 compatibility flags. */ 1195 fprintf (stream, _("\ 1196 -V print assembler version number\n\ 1197 -Qy, -Qn ignored\n")); 1198 #endif 1199 } 1200 1201 1202 /* We have no need to default values of symbols. */ 1203 symbolS * 1204 md_undefined_symbol (char *name ATTRIBUTE_UNUSED) 1205 { 1206 return 0; 1207 } 1208 1209 /* The i860 denotes auto-increment with '++'. */ 1210 void 1211 md_operand (expressionS *exp) 1212 { 1213 char *s; 1214 1215 for (s = input_line_pointer; *s; s++) 1216 { 1217 if (s[0] == '+' && s[1] == '+') 1218 { 1219 input_line_pointer += 2; 1220 exp->X_op = O_register; 1221 break; 1222 } 1223 } 1224 } 1225 1226 /* Round up a section size to the appropriate boundary. */ 1227 valueT 1228 md_section_align (segT segment ATTRIBUTE_UNUSED, 1229 valueT size ATTRIBUTE_UNUSED) 1230 { 1231 /* Byte alignment is fine. */ 1232 return size; 1233 } 1234 1235 /* On the i860, a PC-relative offset is relative to the address of the 1236 offset plus its size. */ 1237 long 1238 md_pcrel_from (fixS *fixP) 1239 { 1240 return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address; 1241 } 1242 1243 /* Determine the relocation needed for non PC-relative 16-bit immediates. 1244 Also adjust the given immediate as necessary. Finally, check that 1245 all constraints (such as alignment) are satisfied. */ 1246 static bfd_reloc_code_real_type 1247 obtain_reloc_for_imm16 (fixS *fix, long *val) 1248 { 1249 valueT fup = fix->fx_addnumber; 1250 bfd_reloc_code_real_type reloc; 1251 1252 if (fix->fx_pcrel) 1253 abort (); 1254 1255 /* Check alignment restrictions. */ 1256 if ((fup & OP_ALIGN2) && (*val & 0x1)) 1257 as_bad_where (fix->fx_file, fix->fx_line, 1258 _("This immediate requires 0 MOD 2 alignment")); 1259 else if ((fup & OP_ALIGN4) && (*val & 0x3)) 1260 as_bad_where (fix->fx_file, fix->fx_line, 1261 _("This immediate requires 0 MOD 4 alignment")); 1262 else if ((fup & OP_ALIGN8) && (*val & 0x7)) 1263 as_bad_where (fix->fx_file, fix->fx_line, 1264 _("This immediate requires 0 MOD 8 alignment")); 1265 else if ((fup & OP_ALIGN16) && (*val & 0xf)) 1266 as_bad_where (fix->fx_file, fix->fx_line, 1267 _("This immediate requires 0 MOD 16 alignment")); 1268 1269 if (fup & OP_SEL_HA) 1270 { 1271 *val = (*val >> 16) + (*val & 0x8000 ? 1 : 0); 1272 reloc = BFD_RELOC_860_HIGHADJ; 1273 } 1274 else if (fup & OP_SEL_H) 1275 { 1276 *val >>= 16; 1277 reloc = BFD_RELOC_860_HIGH; 1278 } 1279 else if (fup & OP_SEL_L) 1280 { 1281 int num_encode; 1282 if (fup & OP_IMM_SPLIT16) 1283 { 1284 if (fup & OP_ENCODE1) 1285 { 1286 num_encode = 1; 1287 reloc = BFD_RELOC_860_SPLIT1; 1288 } 1289 else if (fup & OP_ENCODE2) 1290 { 1291 num_encode = 2; 1292 reloc = BFD_RELOC_860_SPLIT2; 1293 } 1294 else 1295 { 1296 num_encode = 0; 1297 reloc = BFD_RELOC_860_SPLIT0; 1298 } 1299 } 1300 else 1301 { 1302 if (fup & OP_ENCODE1) 1303 { 1304 num_encode = 1; 1305 reloc = BFD_RELOC_860_LOW1; 1306 } 1307 else if (fup & OP_ENCODE2) 1308 { 1309 num_encode = 2; 1310 reloc = BFD_RELOC_860_LOW2; 1311 } 1312 else if (fup & OP_ENCODE3) 1313 { 1314 num_encode = 3; 1315 reloc = BFD_RELOC_860_LOW3; 1316 } 1317 else 1318 { 1319 num_encode = 0; 1320 reloc = BFD_RELOC_860_LOW0; 1321 } 1322 } 1323 1324 /* Preserve size encode bits. */ 1325 *val &= ~((1 << num_encode) - 1); 1326 } 1327 else 1328 { 1329 /* No selector. What reloc do we generate (???)? */ 1330 reloc = BFD_RELOC_32; 1331 } 1332 1333 return reloc; 1334 } 1335 1336 /* Attempt to simplify or eliminate a fixup. To indicate that a fixup 1337 has been eliminated, set fix->fx_done. If fix->fx_addsy is non-NULL, 1338 we will have to generate a reloc entry. */ 1339 1340 void 1341 md_apply_fix3 (fixS *fix, valueT *valP, segT seg ATTRIBUTE_UNUSED) 1342 { 1343 char *buf; 1344 long val = *valP; 1345 unsigned long insn; 1346 valueT fup; 1347 1348 buf = fix->fx_frag->fr_literal + fix->fx_where; 1349 1350 /* Recall that earlier we stored the opcode little-endian. */ 1351 insn = bfd_getl32 (buf); 1352 1353 /* We stored a fix-up in this oddly-named scratch field. */ 1354 fup = fix->fx_addnumber; 1355 1356 /* Determine the necessary relocations as well as inserting an 1357 immediate into the instruction. */ 1358 if (fup & OP_IMM_U5) 1359 { 1360 if (val & ~0x1f) 1361 as_bad_where (fix->fx_file, fix->fx_line, 1362 _("5-bit immediate too large")); 1363 if (fix->fx_addsy) 1364 as_bad_where (fix->fx_file, fix->fx_line, 1365 _("5-bit field must be absolute")); 1366 1367 insn |= (val & 0x1f) << 11; 1368 bfd_putl32 (insn, buf); 1369 fix->fx_r_type = BFD_RELOC_NONE; 1370 fix->fx_done = 1; 1371 } 1372 else if (fup & OP_IMM_S16) 1373 { 1374 fix->fx_r_type = obtain_reloc_for_imm16 (fix, &val); 1375 1376 /* Insert the immediate. */ 1377 if (fix->fx_addsy) 1378 fix->fx_done = 0; 1379 else 1380 { 1381 insn |= val & 0xffff; 1382 bfd_putl32 (insn, buf); 1383 fix->fx_r_type = BFD_RELOC_NONE; 1384 fix->fx_done = 1; 1385 } 1386 } 1387 else if (fup & OP_IMM_U16) 1388 abort (); 1389 1390 else if (fup & OP_IMM_SPLIT16) 1391 { 1392 fix->fx_r_type = obtain_reloc_for_imm16 (fix, &val); 1393 1394 /* Insert the immediate. */ 1395 if (fix->fx_addsy) 1396 fix->fx_done = 0; 1397 else 1398 { 1399 insn |= val & 0x7ff; 1400 insn |= (val & 0xf800) << 5; 1401 bfd_putl32 (insn, buf); 1402 fix->fx_r_type = BFD_RELOC_NONE; 1403 fix->fx_done = 1; 1404 } 1405 } 1406 else if (fup & OP_IMM_BR16) 1407 { 1408 if (val & 0x3) 1409 as_bad_where (fix->fx_file, fix->fx_line, 1410 _("A branch offset requires 0 MOD 4 alignment")); 1411 1412 val = val >> 2; 1413 1414 /* Insert the immediate. */ 1415 if (fix->fx_addsy) 1416 { 1417 fix->fx_done = 0; 1418 fix->fx_r_type = BFD_RELOC_860_PC16; 1419 } 1420 else 1421 { 1422 insn |= (val & 0x7ff); 1423 insn |= ((val & 0xf800) << 5); 1424 bfd_putl32 (insn, buf); 1425 fix->fx_r_type = BFD_RELOC_NONE; 1426 fix->fx_done = 1; 1427 } 1428 } 1429 else if (fup & OP_IMM_BR26) 1430 { 1431 if (val & 0x3) 1432 as_bad_where (fix->fx_file, fix->fx_line, 1433 _("A branch offset requires 0 MOD 4 alignment")); 1434 1435 val >>= 2; 1436 1437 /* Insert the immediate. */ 1438 if (fix->fx_addsy) 1439 { 1440 fix->fx_r_type = BFD_RELOC_860_PC26; 1441 fix->fx_done = 0; 1442 } 1443 else 1444 { 1445 insn |= (val & 0x3ffffff); 1446 bfd_putl32 (insn, buf); 1447 fix->fx_r_type = BFD_RELOC_NONE; 1448 fix->fx_done = 1; 1449 } 1450 } 1451 else if (fup != OP_NONE) 1452 { 1453 as_bad_where (fix->fx_file, fix->fx_line, 1454 _("Unrecognized fix-up (0x%08lx)"), (unsigned long) fup); 1455 abort (); 1456 } 1457 else 1458 { 1459 /* I believe only fix-ups such as ".long .ep.main-main+0xc8000000" 1460 reach here (???). */ 1461 if (fix->fx_addsy) 1462 { 1463 fix->fx_r_type = BFD_RELOC_32; 1464 fix->fx_done = 0; 1465 } 1466 else 1467 { 1468 insn |= (val & 0xffffffff); 1469 bfd_putl32 (insn, buf); 1470 fix->fx_r_type = BFD_RELOC_NONE; 1471 fix->fx_done = 1; 1472 } 1473 } 1474 } 1475 1476 /* Generate a machine dependent reloc from a fixup. */ 1477 arelent* 1478 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, 1479 fixS *fixp) 1480 { 1481 arelent *reloc; 1482 1483 reloc = xmalloc (sizeof (*reloc)); 1484 reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); 1485 *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); 1486 reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; 1487 reloc->addend = fixp->fx_offset; 1488 reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); 1489 1490 if (! reloc->howto) 1491 { 1492 as_bad_where (fixp->fx_file, fixp->fx_line, 1493 "Cannot represent %s relocation in object file", 1494 bfd_get_reloc_code_name (fixp->fx_r_type)); 1495 } 1496 return reloc; 1497 } 1498 1499 /* This is called from HANDLE_ALIGN in write.c. Fill in the contents 1500 of an rs_align_code fragment. */ 1501 1502 void 1503 i860_handle_align (fragS *fragp) 1504 { 1505 /* Instructions are always stored little-endian on the i860. */ 1506 static const unsigned char le_nop[] = { 0x00, 0x00, 0x00, 0xA0 }; 1507 1508 int bytes; 1509 char *p; 1510 1511 if (fragp->fr_type != rs_align_code) 1512 return; 1513 1514 bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix; 1515 p = fragp->fr_literal + fragp->fr_fix; 1516 1517 /* Make sure we are on a 4-byte boundary, in case someone has been 1518 putting data into a text section. */ 1519 if (bytes & 3) 1520 { 1521 int fix = bytes & 3; 1522 memset (p, 0, fix); 1523 p += fix; 1524 fragp->fr_fix += fix; 1525 } 1526 1527 memcpy (p, le_nop, 4); 1528 fragp->fr_var = 4; 1529 } 1530 1531 /* This is called after a user-defined label is seen. We check 1532 if the label has a double colon (valid in Intel syntax mode only), 1533 in which case it should be externalized. */ 1534 1535 void 1536 i860_check_label (symbolS *labelsym) 1537 { 1538 /* At this point, the current line pointer is sitting on the character 1539 just after the first colon on the label. */ 1540 if (target_intel_syntax && *input_line_pointer == ':') 1541 { 1542 S_SET_EXTERNAL (labelsym); 1543 input_line_pointer++; 1544 } 1545 } 1546 1547