1 /* tc-moxie.c -- Assemble code for moxie 2 Copyright (C) 2009-2014 Free Software Foundation, Inc. 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 3, or (at your option) 9 any later version. 10 11 GAS is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GAS; see the file COPYING. If not, write to 18 the Free Software Foundation, 51 Franklin Street - Fifth Floor, 19 Boston, MA 02110-1301, USA. */ 20 21 /* Contributed by Anthony Green <green (at) moxielogic.com>. */ 22 23 #include "as.h" 24 #include "safe-ctype.h" 25 #include "opcode/moxie.h" 26 #include "elf/moxie.h" 27 28 extern const moxie_opc_info_t moxie_opc_info[128]; 29 30 const char comment_chars[] = "#"; 31 const char line_separator_chars[] = ";"; 32 const char line_comment_chars[] = "#"; 33 34 static int pending_reloc; 35 static struct hash_control *opcode_hash_control; 36 37 const pseudo_typeS md_pseudo_table[] = 38 { 39 {0, 0, 0} 40 }; 41 42 const char FLT_CHARS[] = "rRsSfFdDxXpP"; 43 const char EXP_CHARS[] = "eE"; 44 45 static valueT md_chars_to_number (char * buf, int n); 46 47 /* Byte order. */ 48 extern int target_big_endian; 49 50 void 51 md_operand (expressionS *op __attribute__((unused))) 52 { 53 /* Empty for now. */ 54 } 55 56 /* This function is called once, at assembler startup time. It sets 57 up the hash table with all the opcodes in it, and also initializes 58 some aliases for compatibility with other assemblers. */ 59 60 void 61 md_begin (void) 62 { 63 int count; 64 const moxie_opc_info_t *opcode; 65 opcode_hash_control = hash_new (); 66 67 /* Insert names into hash table. */ 68 for (count = 0, opcode = moxie_form1_opc_info; count++ < 64; opcode++) 69 hash_insert (opcode_hash_control, opcode->name, (char *) opcode); 70 71 for (count = 0, opcode = moxie_form2_opc_info; count++ < 4; opcode++) 72 hash_insert (opcode_hash_control, opcode->name, (char *) opcode); 73 74 for (count = 0, opcode = moxie_form3_opc_info; count++ < 10; opcode++) 75 hash_insert (opcode_hash_control, opcode->name, (char *) opcode); 76 77 target_big_endian = TARGET_BYTES_BIG_ENDIAN; 78 79 bfd_set_arch_mach (stdoutput, TARGET_ARCH, 0); 80 } 81 82 /* Parse an expression and then restore the input line pointer. */ 83 84 static char * 85 parse_exp_save_ilp (char *s, expressionS *op) 86 { 87 char *save = input_line_pointer; 88 89 input_line_pointer = s; 90 expression (op); 91 s = input_line_pointer; 92 input_line_pointer = save; 93 return s; 94 } 95 96 static int 97 parse_register_operand (char **ptr) 98 { 99 int reg; 100 char *s = *ptr; 101 102 if (*s != '$') 103 { 104 as_bad (_("expecting register")); 105 ignore_rest_of_line (); 106 return -1; 107 } 108 if (s[1] == 'f' && s[2] == 'p') 109 { 110 *ptr += 3; 111 return 0; 112 } 113 if (s[1] == 's' && s[2] == 'p') 114 { 115 *ptr += 3; 116 return 1; 117 } 118 if (s[1] == 'r') 119 { 120 reg = s[2] - '0'; 121 if ((reg < 0) || (reg > 9)) 122 { 123 as_bad (_("illegal register number")); 124 ignore_rest_of_line (); 125 return -1; 126 } 127 if (reg == 1) 128 { 129 int r2 = s[3] - '0'; 130 if ((r2 >= 0) && (r2 <= 3)) 131 { 132 reg = 10 + r2; 133 *ptr += 1; 134 } 135 } 136 } 137 else 138 { 139 as_bad (_("illegal register number")); 140 ignore_rest_of_line (); 141 return -1; 142 } 143 144 *ptr += 3; 145 146 return reg + 2; 147 } 148 149 /* This is the guts of the machine-dependent assembler. STR points to 150 a machine dependent instruction. This function is supposed to emit 151 the frags/bytes it assembles to. */ 152 153 void 154 md_assemble (char *str) 155 { 156 char *op_start; 157 char *op_end; 158 159 moxie_opc_info_t *opcode; 160 char *p; 161 char pend; 162 163 unsigned short iword = 0; 164 165 int nlen = 0; 166 167 /* Drop leading whitespace. */ 168 while (*str == ' ') 169 str++; 170 171 /* Find the op code end. */ 172 op_start = str; 173 for (op_end = str; 174 *op_end && !is_end_of_line[*op_end & 0xff] && *op_end != ' '; 175 op_end++) 176 nlen++; 177 178 pend = *op_end; 179 *op_end = 0; 180 181 if (nlen == 0) 182 as_bad (_("can't find opcode ")); 183 opcode = (moxie_opc_info_t *) hash_find (opcode_hash_control, op_start); 184 *op_end = pend; 185 186 if (opcode == NULL) 187 { 188 as_bad (_("unknown opcode %s"), op_start); 189 return; 190 } 191 192 p = frag_more (2); 193 194 switch (opcode->itype) 195 { 196 case MOXIE_F2_A8V: 197 iword = (1<<15) | (opcode->opcode << 12); 198 while (ISSPACE (*op_end)) 199 op_end++; 200 { 201 expressionS arg; 202 int reg; 203 reg = parse_register_operand (&op_end); 204 iword += (reg << 8); 205 if (*op_end != ',') 206 as_warn (_("expecting comma delimited register operands")); 207 op_end++; 208 op_end = parse_exp_save_ilp (op_end, &arg); 209 fix_new_exp (frag_now, 210 ((p + (target_big_endian ? 1 : 0)) - frag_now->fr_literal), 211 1, 212 &arg, 213 0, 214 BFD_RELOC_8); 215 } 216 break; 217 case MOXIE_F1_AB: 218 iword = opcode->opcode << 8; 219 while (ISSPACE (*op_end)) 220 op_end++; 221 { 222 int dest, src; 223 dest = parse_register_operand (&op_end); 224 if (*op_end != ',') 225 as_warn (_("expecting comma delimited register operands")); 226 op_end++; 227 src = parse_register_operand (&op_end); 228 iword += (dest << 4) + src; 229 while (ISSPACE (*op_end)) 230 op_end++; 231 if (*op_end != 0) 232 as_warn (_("extra stuff on line ignored")); 233 } 234 break; 235 case MOXIE_F1_A4: 236 iword = opcode->opcode << 8; 237 while (ISSPACE (*op_end)) 238 op_end++; 239 { 240 expressionS arg; 241 char *where; 242 int regnum; 243 244 regnum = parse_register_operand (&op_end); 245 while (ISSPACE (*op_end)) 246 op_end++; 247 248 iword += (regnum << 4); 249 250 if (*op_end != ',') 251 { 252 as_bad (_("expecting comma delimited operands")); 253 ignore_rest_of_line (); 254 return; 255 } 256 op_end++; 257 258 op_end = parse_exp_save_ilp (op_end, &arg); 259 where = frag_more (4); 260 fix_new_exp (frag_now, 261 (where - frag_now->fr_literal), 262 4, 263 &arg, 264 0, 265 BFD_RELOC_32); 266 } 267 break; 268 case MOXIE_F1_M: 269 case MOXIE_F1_4: 270 iword = opcode->opcode << 8; 271 while (ISSPACE (*op_end)) 272 op_end++; 273 { 274 expressionS arg; 275 char *where; 276 277 op_end = parse_exp_save_ilp (op_end, &arg); 278 where = frag_more (4); 279 fix_new_exp (frag_now, 280 (where - frag_now->fr_literal), 281 4, 282 &arg, 283 0, 284 BFD_RELOC_32); 285 } 286 break; 287 case MOXIE_F1_NARG: 288 iword = opcode->opcode << 8; 289 while (ISSPACE (*op_end)) 290 op_end++; 291 if (*op_end != 0) 292 as_warn (_("extra stuff on line ignored")); 293 break; 294 case MOXIE_F1_A: 295 iword = opcode->opcode << 8; 296 while (ISSPACE (*op_end)) 297 op_end++; 298 { 299 int reg; 300 reg = parse_register_operand (&op_end); 301 while (ISSPACE (*op_end)) 302 op_end++; 303 if (*op_end != 0) 304 as_warn (_("extra stuff on line ignored")); 305 iword += (reg << 4); 306 } 307 break; 308 case MOXIE_F1_ABi: 309 iword = opcode->opcode << 8; 310 while (ISSPACE (*op_end)) 311 op_end++; 312 { 313 int a, b; 314 a = parse_register_operand (&op_end); 315 if (*op_end != ',') 316 as_warn (_("expecting comma delimited register operands")); 317 op_end++; 318 if (*op_end != '(') 319 { 320 as_bad (_("expecting indirect register `($rA)'")); 321 ignore_rest_of_line (); 322 return; 323 } 324 op_end++; 325 b = parse_register_operand (&op_end); 326 if (*op_end != ')') 327 { 328 as_bad (_("missing closing parenthesis")); 329 ignore_rest_of_line (); 330 return; 331 } 332 op_end++; 333 iword += (a << 4) + b; 334 while (ISSPACE (*op_end)) 335 op_end++; 336 if (*op_end != 0) 337 as_warn (_("extra stuff on line ignored")); 338 } 339 break; 340 case MOXIE_F1_AiB: 341 iword = opcode->opcode << 8; 342 while (ISSPACE (*op_end)) 343 op_end++; 344 { 345 int a, b; 346 if (*op_end != '(') 347 { 348 as_bad (_("expecting indirect register `($rA)'")); 349 ignore_rest_of_line (); 350 return; 351 } 352 op_end++; 353 a = parse_register_operand (&op_end); 354 if (*op_end != ')') 355 { 356 as_bad (_("missing closing parenthesis")); 357 ignore_rest_of_line (); 358 return; 359 } 360 op_end++; 361 if (*op_end != ',') 362 as_warn (_("expecting comma delimited register operands")); 363 op_end++; 364 b = parse_register_operand (&op_end); 365 iword += (a << 4) + b; 366 while (ISSPACE (*op_end)) 367 op_end++; 368 if (*op_end != 0) 369 as_warn (_("extra stuff on line ignored")); 370 } 371 break; 372 case MOXIE_F1_4A: 373 iword = opcode->opcode << 8; 374 while (ISSPACE (*op_end)) 375 op_end++; 376 { 377 expressionS arg; 378 char *where; 379 int a; 380 381 op_end = parse_exp_save_ilp (op_end, &arg); 382 where = frag_more (4); 383 fix_new_exp (frag_now, 384 (where - frag_now->fr_literal), 385 4, 386 &arg, 387 0, 388 BFD_RELOC_32); 389 390 if (*op_end != ',') 391 { 392 as_bad (_("expecting comma delimited operands")); 393 ignore_rest_of_line (); 394 return; 395 } 396 op_end++; 397 398 a = parse_register_operand (&op_end); 399 while (ISSPACE (*op_end)) 400 op_end++; 401 if (*op_end != 0) 402 as_warn (_("extra stuff on line ignored")); 403 404 iword += (a << 4); 405 } 406 break; 407 case MOXIE_F1_ABi4: 408 iword = opcode->opcode << 8; 409 while (ISSPACE (*op_end)) 410 op_end++; 411 { 412 expressionS arg; 413 char *offset; 414 int a, b; 415 416 a = parse_register_operand (&op_end); 417 while (ISSPACE (*op_end)) 418 op_end++; 419 420 if (*op_end != ',') 421 { 422 as_bad (_("expecting comma delimited operands")); 423 ignore_rest_of_line (); 424 return; 425 } 426 op_end++; 427 428 op_end = parse_exp_save_ilp (op_end, &arg); 429 offset = frag_more (4); 430 fix_new_exp (frag_now, 431 (offset - frag_now->fr_literal), 432 4, 433 &arg, 434 0, 435 BFD_RELOC_32); 436 437 if (*op_end != '(') 438 { 439 as_bad (_("expecting indirect register `($rX)'")); 440 ignore_rest_of_line (); 441 return; 442 } 443 op_end++; 444 b = parse_register_operand (&op_end); 445 if (*op_end != ')') 446 { 447 as_bad (_("missing closing parenthesis")); 448 ignore_rest_of_line (); 449 return; 450 } 451 op_end++; 452 453 while (ISSPACE (*op_end)) 454 op_end++; 455 if (*op_end != 0) 456 as_warn (_("extra stuff on line ignored")); 457 458 iword += (a << 4) + b; 459 } 460 break; 461 case MOXIE_F1_AiB4: 462 iword = opcode->opcode << 8; 463 while (ISSPACE (*op_end)) 464 op_end++; 465 { 466 expressionS arg; 467 char *offset; 468 int a, b; 469 470 op_end = parse_exp_save_ilp (op_end, &arg); 471 offset = frag_more (4); 472 fix_new_exp (frag_now, 473 (offset - frag_now->fr_literal), 474 4, 475 &arg, 476 0, 477 BFD_RELOC_32); 478 479 if (*op_end != '(') 480 { 481 as_bad (_("expecting indirect register `($rX)'")); 482 ignore_rest_of_line (); 483 return; 484 } 485 op_end++; 486 a = parse_register_operand (&op_end); 487 if (*op_end != ')') 488 { 489 as_bad (_("missing closing parenthesis")); 490 ignore_rest_of_line (); 491 return; 492 } 493 op_end++; 494 495 if (*op_end != ',') 496 { 497 as_bad (_("expecting comma delimited operands")); 498 ignore_rest_of_line (); 499 return; 500 } 501 op_end++; 502 503 b = parse_register_operand (&op_end); 504 while (ISSPACE (*op_end)) 505 op_end++; 506 507 while (ISSPACE (*op_end)) 508 op_end++; 509 if (*op_end != 0) 510 as_warn (_("extra stuff on line ignored")); 511 512 iword += (a << 4) + b; 513 } 514 break; 515 case MOXIE_F2_NARG: 516 iword = opcode->opcode << 12; 517 while (ISSPACE (*op_end)) 518 op_end++; 519 if (*op_end != 0) 520 as_warn (_("extra stuff on line ignored")); 521 break; 522 case MOXIE_F3_PCREL: 523 iword = (3<<14) | (opcode->opcode << 10); 524 while (ISSPACE (*op_end)) 525 op_end++; 526 { 527 expressionS arg; 528 529 op_end = parse_exp_save_ilp (op_end, &arg); 530 fix_new_exp (frag_now, 531 (p - frag_now->fr_literal), 532 2, 533 &arg, 534 TRUE, 535 BFD_RELOC_MOXIE_10_PCREL); 536 } 537 break; 538 default: 539 abort (); 540 } 541 542 md_number_to_chars (p, iword, 2); 543 544 while (ISSPACE (*op_end)) 545 op_end++; 546 547 if (*op_end != 0) 548 as_warn (_("extra stuff on line ignored")); 549 550 if (pending_reloc) 551 as_bad (_("Something forgot to clean up\n")); 552 } 553 554 /* Turn a string in input_line_pointer into a floating point constant 555 of type type, and store the appropriate bytes in *LITP. The number 556 of LITTLENUMS emitted is stored in *SIZEP . An error message is 557 returned, or NULL on OK. */ 558 559 char * 560 md_atof (int type, char *litP, int *sizeP) 561 { 562 int prec; 563 LITTLENUM_TYPE words[4]; 564 char *t; 565 int i; 566 567 switch (type) 568 { 569 case 'f': 570 prec = 2; 571 break; 572 573 case 'd': 574 prec = 4; 575 break; 576 577 default: 578 *sizeP = 0; 579 return _("bad call to md_atof"); 580 } 581 582 t = atof_ieee (input_line_pointer, type, words); 583 if (t) 584 input_line_pointer = t; 585 586 *sizeP = prec * 2; 587 588 for (i = prec - 1; i >= 0; i--) 589 { 590 md_number_to_chars (litP, (valueT) words[i], 2); 591 litP += 2; 592 } 593 594 return NULL; 595 } 596 597 enum options 598 { 599 OPTION_EB = OPTION_MD_BASE, 600 OPTION_EL, 601 }; 602 603 struct option md_longopts[] = 604 { 605 { "EB", no_argument, NULL, OPTION_EB}, 606 { "EL", no_argument, NULL, OPTION_EL}, 607 { NULL, no_argument, NULL, 0} 608 }; 609 610 size_t md_longopts_size = sizeof (md_longopts); 611 612 const char *md_shortopts = ""; 614 615 int 616 md_parse_option (int c ATTRIBUTE_UNUSED, char *arg ATTRIBUTE_UNUSED) 617 { 618 switch (c) 619 { 620 case OPTION_EB: 621 target_big_endian = 1; 622 break; 623 case OPTION_EL: 624 target_big_endian = 0; 625 break; 626 default: 627 return 0; 628 } 629 630 return 1; 631 } 632 633 void 634 md_show_usage (FILE *stream ATTRIBUTE_UNUSED) 635 { 636 fprintf (stream, _("\ 637 -EB assemble for a big endian system (default)\n\ 638 -EL assemble for a little endian system\n")); 639 } 640 641 /* Apply a fixup to the object file. */ 642 643 void 644 md_apply_fix (fixS *fixP ATTRIBUTE_UNUSED, 645 valueT * valP ATTRIBUTE_UNUSED, segT seg ATTRIBUTE_UNUSED) 646 { 647 char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; 648 long val = *valP; 649 long newval; 650 long max, min; 651 652 max = min = 0; 653 switch (fixP->fx_r_type) 654 { 655 case BFD_RELOC_32: 656 if (target_big_endian) 657 { 658 buf[0] = val >> 24; 659 buf[1] = val >> 16; 660 buf[2] = val >> 8; 661 buf[3] = val >> 0; 662 } 663 else 664 { 665 buf[3] = val >> 24; 666 buf[2] = val >> 16; 667 buf[1] = val >> 8; 668 buf[0] = val >> 0; 669 } 670 buf += 4; 671 break; 672 673 case BFD_RELOC_16: 674 if (target_big_endian) 675 { 676 buf[0] = val >> 8; 677 buf[1] = val >> 0; 678 } 679 else 680 { 681 buf[1] = val >> 8; 682 buf[0] = val >> 0; 683 } 684 buf += 2; 685 break; 686 687 case BFD_RELOC_8: 688 *buf++ = val; 689 break; 690 691 case BFD_RELOC_MOXIE_10_PCREL: 692 if (!val) 693 break; 694 if (val < -1024 || val > 1022) 695 as_bad_where (fixP->fx_file, fixP->fx_line, 696 _("pcrel too far BFD_RELOC_MOXIE_10")); 697 /* 11 bit offset even numbered, so we remove right bit. */ 698 val >>= 1; 699 newval = md_chars_to_number (buf, 2); 700 newval |= val & 0x03ff; 701 md_number_to_chars (buf, newval, 2); 702 break; 703 704 default: 705 abort (); 706 } 707 708 if (max != 0 && (val < min || val > max)) 709 as_bad_where (fixP->fx_file, fixP->fx_line, _("offset out of range")); 710 711 if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0) 712 fixP->fx_done = 1; 713 } 714 715 /* Put number into target byte order. */ 716 717 void 718 md_number_to_chars (char * ptr, valueT use, int nbytes) 719 { 720 if (target_big_endian) 721 number_to_chars_bigendian (ptr, use, nbytes); 722 else 723 number_to_chars_littleendian (ptr, use, nbytes); 724 } 725 726 /* Convert from target byte order to host byte order. */ 727 728 static valueT 729 md_chars_to_number (char * buf, int n) 730 { 731 valueT result = 0; 732 unsigned char * where = (unsigned char *) buf; 733 734 if (target_big_endian) 735 { 736 while (n--) 737 { 738 result <<= 8; 739 result |= (*where++ & 255); 740 } 741 } 742 else 743 { 744 while (n--) 745 { 746 result <<= 8; 747 result |= (where[n] & 255); 748 } 749 } 750 751 return result; 752 } 753 754 /* Generate a machine-dependent relocation. */ 755 arelent * 756 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP) 757 { 758 arelent *relP; 759 bfd_reloc_code_real_type code; 760 761 switch (fixP->fx_r_type) 762 { 763 case BFD_RELOC_32: 764 code = fixP->fx_r_type; 765 break; 766 case BFD_RELOC_MOXIE_10_PCREL: 767 code = fixP->fx_r_type; 768 break; 769 default: 770 as_bad_where (fixP->fx_file, fixP->fx_line, 771 _("Semantics error. This type of operand can not be relocated, it must be an assembly-time constant")); 772 return 0; 773 } 774 775 relP = xmalloc (sizeof (arelent)); 776 gas_assert (relP != 0); 777 relP->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); 778 *relP->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy); 779 relP->address = fixP->fx_frag->fr_address + fixP->fx_where; 780 781 relP->addend = fixP->fx_offset; 782 783 /* This is the standard place for KLUDGEs to work around bugs in 784 bfd_install_relocation (first such note in the documentation 785 appears with binutils-2.8). 786 787 That function bfd_install_relocation does the wrong thing with 788 putting stuff into the addend of a reloc (it should stay out) for a 789 weak symbol. The really bad thing is that it adds the 790 "segment-relative offset" of the symbol into the reloc. In this 791 case, the reloc should instead be relative to the symbol with no 792 other offset than the assembly code shows; and since the symbol is 793 weak, any local definition should be ignored until link time (or 794 thereafter). 795 To wit: weaksym+42 should be weaksym+42 in the reloc, 796 not weaksym+(offset_from_segment_of_local_weaksym_definition) 797 798 To "work around" this, we subtract the segment-relative offset of 799 "known" weak symbols. This evens out the extra offset. 800 801 That happens for a.out but not for ELF, since for ELF, 802 bfd_install_relocation uses the "special function" field of the 803 howto, and does not execute the code that needs to be undone. */ 804 805 if (OUTPUT_FLAVOR == bfd_target_aout_flavour 806 && fixP->fx_addsy && S_IS_WEAK (fixP->fx_addsy) 807 && ! bfd_is_und_section (S_GET_SEGMENT (fixP->fx_addsy))) 808 { 809 relP->addend -= S_GET_VALUE (fixP->fx_addsy); 810 } 811 812 relP->howto = bfd_reloc_type_lookup (stdoutput, code); 813 if (! relP->howto) 814 { 815 const char *name; 816 817 name = S_GET_NAME (fixP->fx_addsy); 818 if (name == NULL) 819 name = _("<unknown>"); 820 as_fatal (_("Cannot generate relocation type for symbol %s, code %s"), 821 name, bfd_get_reloc_code_name (code)); 822 } 823 824 return relP; 825 } 826 827 /* Decide from what point a pc-relative relocation is relative to, 828 relative to the pc-relative fixup. Er, relatively speaking. */ 829 long 830 md_pcrel_from (fixS *fixP) 831 { 832 valueT addr = fixP->fx_where + fixP->fx_frag->fr_address; 833 834 switch (fixP->fx_r_type) 835 { 836 case BFD_RELOC_32: 837 return addr + 4; 838 case BFD_RELOC_MOXIE_10_PCREL: 839 /* Offset is from the end of the instruction. */ 840 return addr + 2; 841 default: 842 abort (); 843 return addr; 844 } 845 } 846