138889Sjdp/* tc-arc.c -- Assembler for the ARC 2218822Sdim Copyright 1994, 1995, 1997, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 3218822Sdim 2006 Free Software Foundation, Inc. 438889Sjdp Contributed by Doug Evans (dje@cygnus.com). 538889Sjdp 638889Sjdp This file is part of GAS, the GNU Assembler. 738889Sjdp 838889Sjdp GAS is free software; you can redistribute it and/or modify 938889Sjdp it under the terms of the GNU General Public License as published by 1038889Sjdp the Free Software Foundation; either version 2, or (at your option) 1138889Sjdp any later version. 1238889Sjdp 1338889Sjdp GAS is distributed in the hope that it will be useful, 1438889Sjdp but WITHOUT ANY WARRANTY; without even the implied warranty of 1538889Sjdp MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1638889Sjdp GNU General Public License for more details. 1738889Sjdp 1838889Sjdp You should have received a copy of the GNU General Public License 1960484Sobrien along with GAS; see the file COPYING. If not, write to the Free 20218822Sdim Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 21218822Sdim 02110-1301, USA. */ 2238889Sjdp 2338889Sjdp#include "as.h" 24130561Sobrien#include "struc-symbol.h" 2589857Sobrien#include "safe-ctype.h" 2638889Sjdp#include "subsegs.h" 2738889Sjdp#include "opcode/arc.h" 2885815Sobrien#include "../opcodes/arc-ext.h" 2938889Sjdp#include "elf/arc.h" 3085815Sobrien#include "dwarf2dbg.h" 3138889Sjdp 32218822Sdimconst struct suffix_classes 33218822Sdim{ 3485815Sobrien char *name; 3585815Sobrien int len; 36218822Sdim} suffixclass[] = 37218822Sdim{ 3885815Sobrien { "SUFFIX_COND|SUFFIX_FLAG",23 }, 3985815Sobrien { "SUFFIX_FLAG", 11 }, 4085815Sobrien { "SUFFIX_COND", 11 }, 4185815Sobrien { "SUFFIX_NONE", 11 } 4285815Sobrien}; 4385815Sobrien 4485815Sobrien#define MAXSUFFIXCLASS (sizeof (suffixclass) / sizeof (struct suffix_classes)) 4585815Sobrien 46218822Sdimconst struct syntax_classes 47218822Sdim{ 4885815Sobrien char *name; 4985815Sobrien int len; 5085815Sobrien int class; 51218822Sdim} syntaxclass[] = 52218822Sdim{ 5385815Sobrien { "SYNTAX_3OP|OP1_MUST_BE_IMM", 26, SYNTAX_3OP|OP1_MUST_BE_IMM|SYNTAX_VALID }, 5485815Sobrien { "OP1_MUST_BE_IMM|SYNTAX_3OP", 26, OP1_MUST_BE_IMM|SYNTAX_3OP|SYNTAX_VALID }, 5585815Sobrien { "SYNTAX_2OP|OP1_IMM_IMPLIED", 26, SYNTAX_2OP|OP1_IMM_IMPLIED|SYNTAX_VALID }, 5685815Sobrien { "OP1_IMM_IMPLIED|SYNTAX_2OP", 26, OP1_IMM_IMPLIED|SYNTAX_2OP|SYNTAX_VALID }, 5785815Sobrien { "SYNTAX_3OP", 10, SYNTAX_3OP|SYNTAX_VALID }, 5885815Sobrien { "SYNTAX_2OP", 10, SYNTAX_2OP|SYNTAX_VALID } 5985815Sobrien}; 6085815Sobrien 6185815Sobrien#define MAXSYNTAXCLASS (sizeof (syntaxclass) / sizeof (struct syntax_classes)) 6285815Sobrien 6338889Sjdp/* This array holds the chars that always start a comment. If the 6485815Sobrien pre-processor is disabled, these aren't very useful. */ 6538889Sjdpconst char comment_chars[] = "#;"; 6638889Sjdp 6738889Sjdp/* This array holds the chars that only start a comment at the beginning of 6838889Sjdp a line. If the line seems to have the form '# 123 filename' 6938889Sjdp .line and .file directives will appear in the pre-processed output */ 7038889Sjdp/* Note that input_file.c hand checks for '#' at the beginning of the 7138889Sjdp first line of the input file. This is because the compiler outputs 7285815Sobrien #NO_APP at the beginning of its output. */ 7338889Sjdp/* Also note that comments started like this one will always 7485815Sobrien work if '/' isn't otherwise defined. */ 7538889Sjdpconst char line_comment_chars[] = "#"; 7638889Sjdp 7738889Sjdpconst char line_separator_chars[] = ""; 7838889Sjdp 7985815Sobrien/* Chars that can be used to separate mant from exp in floating point nums. */ 8038889Sjdpconst char EXP_CHARS[] = "eE"; 8138889Sjdp 8285815Sobrien/* Chars that mean this number is a floating point constant 8385815Sobrien As in 0f12.456 or 0d1.2345e12. */ 8438889Sjdpconst char FLT_CHARS[] = "rRsSfFdD"; 8538889Sjdp 8638889Sjdp/* Byte order. */ 8738889Sjdpextern int target_big_endian; 8838889Sjdpconst char *arc_target_format = DEFAULT_TARGET_FORMAT; 8938889Sjdpstatic int byte_order = DEFAULT_BYTE_ORDER; 9038889Sjdp 9185815Sobrienstatic segT arcext_section; 9238889Sjdp 9385815Sobrien/* One of bfd_mach_arc_n. */ 9485815Sobrienstatic int arc_mach_type = bfd_mach_arc_6; 9585815Sobrien 9638889Sjdp/* Non-zero if the cpu type has been explicitly specified. */ 9738889Sjdpstatic int mach_type_specified_p = 0; 9838889Sjdp 9938889Sjdp/* Non-zero if opcode tables have been initialized. 10085815Sobrien A .option command must appear before any instructions. */ 10138889Sjdpstatic int cpu_tables_init_p = 0; 10238889Sjdp 10338889Sjdpstatic struct hash_control *arc_suffix_hash = NULL; 10438889Sjdp 10538889Sjdpconst char *md_shortopts = ""; 106218822Sdim 107218822Sdimenum options 108218822Sdim{ 109218822Sdim OPTION_EB = OPTION_MD_BASE, 110218822Sdim OPTION_EL, 111218822Sdim OPTION_ARC5, 112218822Sdim OPTION_ARC6, 113218822Sdim OPTION_ARC7, 114218822Sdim OPTION_ARC8, 115218822Sdim OPTION_ARC 116218822Sdim}; 117218822Sdim 118218822Sdimstruct option md_longopts[] = 119218822Sdim{ 12085815Sobrien { "EB", no_argument, NULL, OPTION_EB }, 12185815Sobrien { "EL", no_argument, NULL, OPTION_EL }, 12285815Sobrien { "marc5", no_argument, NULL, OPTION_ARC5 }, 12385815Sobrien { "pre-v6", no_argument, NULL, OPTION_ARC5 }, 12485815Sobrien { "marc6", no_argument, NULL, OPTION_ARC6 }, 12585815Sobrien { "marc7", no_argument, NULL, OPTION_ARC7 }, 12685815Sobrien { "marc8", no_argument, NULL, OPTION_ARC8 }, 12785815Sobrien { "marc", no_argument, NULL, OPTION_ARC }, 12838889Sjdp { NULL, no_argument, NULL, 0 } 12938889Sjdp}; 13038889Sjdpsize_t md_longopts_size = sizeof (md_longopts); 13138889Sjdp 13285815Sobrien#define IS_SYMBOL_OPERAND(o) \ 13385815Sobrien ((o) == 'b' || (o) == 'c' || (o) == 's' || (o) == 'o' || (o) == 'O') 13438889Sjdp 13585815Sobrienstruct arc_operand_value *get_ext_suffix (char *s); 13685815Sobrien 13785815Sobrien/* Invocation line includes a switch not recognized by the base assembler. 13885815Sobrien See if it's a processor-specific option. */ 13985815Sobrien 14038889Sjdpint 141218822Sdimmd_parse_option (int c, char *arg ATTRIBUTE_UNUSED) 14238889Sjdp{ 14338889Sjdp switch (c) 14438889Sjdp { 14585815Sobrien case OPTION_ARC5: 14685815Sobrien arc_mach_type = bfd_mach_arc_5; 14785815Sobrien break; 14885815Sobrien case OPTION_ARC: 14985815Sobrien case OPTION_ARC6: 15085815Sobrien arc_mach_type = bfd_mach_arc_6; 15185815Sobrien break; 15285815Sobrien case OPTION_ARC7: 15385815Sobrien arc_mach_type = bfd_mach_arc_7; 15485815Sobrien break; 15585815Sobrien case OPTION_ARC8: 15685815Sobrien arc_mach_type = bfd_mach_arc_8; 15785815Sobrien break; 15838889Sjdp case OPTION_EB: 15938889Sjdp byte_order = BIG_ENDIAN; 16038889Sjdp arc_target_format = "elf32-bigarc"; 16138889Sjdp break; 16238889Sjdp case OPTION_EL: 16338889Sjdp byte_order = LITTLE_ENDIAN; 16438889Sjdp arc_target_format = "elf32-littlearc"; 16538889Sjdp break; 16638889Sjdp default: 16738889Sjdp return 0; 16838889Sjdp } 16938889Sjdp return 1; 17038889Sjdp} 17138889Sjdp 17238889Sjdpvoid 173218822Sdimmd_show_usage (FILE *stream) 17438889Sjdp{ 17585815Sobrien fprintf (stream, "\ 17685815SobrienARC Options:\n\ 17785815Sobrien -marc[5|6|7|8] select processor variant (default arc%d)\n\ 17885815Sobrien -EB assemble code for a big endian cpu\n\ 17985815Sobrien -EL assemble code for a little endian cpu\n", arc_mach_type + 5); 18038889Sjdp} 18138889Sjdp 18238889Sjdp/* This function is called once, at assembler startup time. It should 18338889Sjdp set up all the tables, etc. that the MD part of the assembler will need. 18485815Sobrien Opcode selection is deferred until later because we might see a .option 18538889Sjdp command. */ 18638889Sjdp 18738889Sjdpvoid 188218822Sdimmd_begin (void) 18938889Sjdp{ 19038889Sjdp /* The endianness can be chosen "at the factory". */ 19138889Sjdp target_big_endian = byte_order == BIG_ENDIAN; 19238889Sjdp 19338889Sjdp if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, arc_mach_type)) 19485815Sobrien as_warn ("could not set architecture and machine"); 19538889Sjdp 19685815Sobrien /* This call is necessary because we need to initialize `arc_operand_map' 19785815Sobrien which may be needed before we see the first insn. */ 19885815Sobrien arc_opcode_init_tables (arc_get_opcode_mach (arc_mach_type, 19938889Sjdp target_big_endian)); 20038889Sjdp} 20138889Sjdp 20238889Sjdp/* Initialize the various opcode and operand tables. 20338889Sjdp MACH is one of bfd_mach_arc_xxx. */ 204218822Sdim 20538889Sjdpstatic void 206218822Sdiminit_opcode_tables (int mach) 20738889Sjdp{ 20885815Sobrien int i; 20938889Sjdp char *last; 21038889Sjdp 21138889Sjdp if ((arc_suffix_hash = hash_new ()) == NULL) 21285815Sobrien as_fatal ("virtual memory exhausted"); 21338889Sjdp 21438889Sjdp if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, mach)) 21585815Sobrien as_warn ("could not set architecture and machine"); 21638889Sjdp 21738889Sjdp /* This initializes a few things in arc-opc.c that we need. 21838889Sjdp This must be called before the various arc_xxx_supported fns. */ 21938889Sjdp arc_opcode_init_tables (arc_get_opcode_mach (mach, target_big_endian)); 22038889Sjdp 22138889Sjdp /* Only put the first entry of each equivalently named suffix in the 22238889Sjdp table. */ 22338889Sjdp last = ""; 22438889Sjdp for (i = 0; i < arc_suffixes_count; i++) 22538889Sjdp { 22638889Sjdp if (strcmp (arc_suffixes[i].name, last) != 0) 227218822Sdim hash_insert (arc_suffix_hash, arc_suffixes[i].name, (void *) (arc_suffixes + i)); 22838889Sjdp last = arc_suffixes[i].name; 22938889Sjdp } 23038889Sjdp 23138889Sjdp /* Since registers don't have a prefix, we put them in the symbol table so 23238889Sjdp they can't be used as symbols. This also simplifies argument parsing as 23338889Sjdp we can let gas parse registers for us. The recorded register number is 23485815Sobrien the address of the register's entry in arc_reg_names. 23585815Sobrien 23685815Sobrien If the register name is already in the table, then the existing 23785815Sobrien definition is assumed to be from an .ExtCoreRegister pseudo-op. */ 23885815Sobrien 23938889Sjdp for (i = 0; i < arc_reg_names_count; i++) 24038889Sjdp { 24185815Sobrien if (symbol_find (arc_reg_names[i].name)) 24238889Sjdp continue; 24338889Sjdp /* Use symbol_create here instead of symbol_new so we don't try to 24438889Sjdp output registers into the object file's symbol table. */ 24585815Sobrien symbol_table_insert (symbol_create (arc_reg_names[i].name, 24685815Sobrien reg_section, 247218822Sdim (valueT) &arc_reg_names[i], 24885815Sobrien &zero_address_frag)); 24938889Sjdp } 25038889Sjdp 25185815Sobrien /* Tell `.option' it's too late. */ 25238889Sjdp cpu_tables_init_p = 1; 25338889Sjdp} 25438889Sjdp 25538889Sjdp/* Insert an operand value into an instruction. 25638889Sjdp If REG is non-NULL, it is a register number and ignore VAL. */ 25738889Sjdp 25838889Sjdpstatic arc_insn 259218822Sdimarc_insert_operand (arc_insn insn, 260218822Sdim const struct arc_operand *operand, 261218822Sdim int mods, 262218822Sdim const struct arc_operand_value *reg, 263218822Sdim offsetT val, 264218822Sdim char *file, 265218822Sdim unsigned int line) 26638889Sjdp{ 26738889Sjdp if (operand->bits != 32) 26838889Sjdp { 26938889Sjdp long min, max; 27038889Sjdp offsetT test; 27138889Sjdp 27238889Sjdp if ((operand->flags & ARC_OPERAND_SIGNED) != 0) 27338889Sjdp { 27438889Sjdp if ((operand->flags & ARC_OPERAND_SIGNOPT) != 0) 27538889Sjdp max = (1 << operand->bits) - 1; 27638889Sjdp else 27738889Sjdp max = (1 << (operand->bits - 1)) - 1; 27838889Sjdp min = - (1 << (operand->bits - 1)); 27938889Sjdp } 28038889Sjdp else 28138889Sjdp { 28238889Sjdp max = (1 << operand->bits) - 1; 28338889Sjdp min = 0; 28438889Sjdp } 28538889Sjdp 28638889Sjdp if ((operand->flags & ARC_OPERAND_NEGATIVE) != 0) 28738889Sjdp test = - val; 28838889Sjdp else 28938889Sjdp test = val; 29038889Sjdp 29138889Sjdp if (test < (offsetT) min || test > (offsetT) max) 292218822Sdim as_warn_value_out_of_range (_("operand"), test, (offsetT) min, (offsetT) max, file, line); 29338889Sjdp } 29438889Sjdp 29538889Sjdp if (operand->insert) 29638889Sjdp { 29738889Sjdp const char *errmsg; 29838889Sjdp 29938889Sjdp errmsg = NULL; 30038889Sjdp insn = (*operand->insert) (insn, operand, mods, reg, (long) val, &errmsg); 30138889Sjdp if (errmsg != (const char *) NULL) 30238889Sjdp as_warn (errmsg); 30338889Sjdp } 30438889Sjdp else 30538889Sjdp insn |= (((long) val & ((1 << operand->bits) - 1)) 30638889Sjdp << operand->shift); 30738889Sjdp 30838889Sjdp return insn; 30938889Sjdp} 31038889Sjdp 31138889Sjdp/* We need to keep a list of fixups. We can't simply generate them as 31238889Sjdp we go, because that would require us to first create the frag, and 31338889Sjdp that would screw up references to ``.''. */ 31438889Sjdp 315218822Sdimstruct arc_fixup 316218822Sdim{ 31785815Sobrien /* index into `arc_operands' */ 31838889Sjdp int opindex; 31938889Sjdp expressionS exp; 32038889Sjdp}; 32138889Sjdp 32238889Sjdp#define MAX_FIXUPS 5 32338889Sjdp 32438889Sjdp#define MAX_SUFFIXES 5 32538889Sjdp 326218822Sdim/* Compute the reloc type of an expression. 327218822Sdim The possibly modified expression is stored in EXPNEW. 32838889Sjdp 329218822Sdim This is used to convert the expressions generated by the %-op's into 330218822Sdim the appropriate operand type. It is called for both data in instructions 331218822Sdim (operands) and data outside instructions (variables, debugging info, etc.). 33238889Sjdp 333218822Sdim Currently supported %-ops: 33438889Sjdp 335218822Sdim %st(symbol): represented as "symbol >> 2" 336218822Sdim "st" is short for STatus as in the status register (pc) 33738889Sjdp 338218822Sdim DEFAULT_TYPE is the type to use if no special processing is required. 33938889Sjdp 340218822Sdim DATA_P is non-zero for data or limm values, zero for insn operands. 341218822Sdim Remember that the opcode "insertion fns" cannot be used on data, they're 342218822Sdim only for inserting operands into insns. They also can't be used for limm 343218822Sdim values as the insertion routines don't handle limm values. When called for 344218822Sdim insns we return fudged reloc types (real_value - BFD_RELOC_UNUSED). When 345218822Sdim called for data or limm values we use real reloc types. */ 34638889Sjdp 347218822Sdimstatic int 348218822Sdimget_arc_exp_reloc_type (int data_p, 349218822Sdim int default_type, 350218822Sdim expressionS *exp, 351218822Sdim expressionS *expnew) 352218822Sdim{ 353218822Sdim /* If the expression is "symbol >> 2" we must change it to just "symbol", 354218822Sdim as fix_new_exp can't handle it. Similarly for (symbol - symbol) >> 2. 355218822Sdim That's ok though. What's really going on here is that we're using 356218822Sdim ">> 2" as a special syntax for specifying BFD_RELOC_ARC_B26. */ 35738889Sjdp 358218822Sdim if (exp->X_op == O_right_shift 359218822Sdim && exp->X_op_symbol != NULL 360218822Sdim && exp->X_op_symbol->sy_value.X_op == O_constant 361218822Sdim && exp->X_op_symbol->sy_value.X_add_number == 2 362218822Sdim && exp->X_add_number == 0) 36338889Sjdp { 364218822Sdim if (exp->X_add_symbol != NULL 365218822Sdim && (exp->X_add_symbol->sy_value.X_op == O_constant 366218822Sdim || exp->X_add_symbol->sy_value.X_op == O_symbol)) 36738889Sjdp { 368218822Sdim *expnew = *exp; 369218822Sdim expnew->X_op = O_symbol; 370218822Sdim expnew->X_op_symbol = NULL; 371218822Sdim return data_p ? BFD_RELOC_ARC_B26 : arc_operand_map['J']; 37238889Sjdp } 373218822Sdim else if (exp->X_add_symbol != NULL 374218822Sdim && exp->X_add_symbol->sy_value.X_op == O_subtract) 37538889Sjdp { 376218822Sdim *expnew = exp->X_add_symbol->sy_value; 377218822Sdim return data_p ? BFD_RELOC_ARC_B26 : arc_operand_map['J']; 37838889Sjdp } 379218822Sdim } 38038889Sjdp 381218822Sdim *expnew = *exp; 382218822Sdim return default_type; 383218822Sdim} 384218822Sdim 385218822Sdimstatic int 386218822Sdimarc_set_ext_seg (void) 387218822Sdim{ 388218822Sdim if (!arcext_section) 389218822Sdim { 390218822Sdim arcext_section = subseg_new (".arcextmap", 0); 391218822Sdim bfd_set_section_flags (stdoutput, arcext_section, 392218822Sdim SEC_READONLY | SEC_HAS_CONTENTS); 39338889Sjdp } 39485815Sobrien else 395218822Sdim subseg_set (arcext_section, 0); 396218822Sdim return 1; 39738889Sjdp} 398218822Sdim 39938889Sjdpstatic void 400218822Sdimarc_extoper (int opertype) 40138889Sjdp{ 40238889Sjdp char *name; 40385815Sobrien char *mode; 40438889Sjdp char c; 40538889Sjdp char *p; 40685815Sobrien int imode = 0; 40785815Sobrien int number; 40885815Sobrien struct arc_ext_operand_value *ext_oper; 40938889Sjdp symbolS *symbolP; 41038889Sjdp 41185815Sobrien segT old_sec; 41285815Sobrien int old_subsec; 41385815Sobrien 41438889Sjdp name = input_line_pointer; 41538889Sjdp c = get_symbol_end (); 41685815Sobrien name = xstrdup (name); 41785815Sobrien 41885815Sobrien p = name; 41985815Sobrien while (*p) 42085815Sobrien { 42189857Sobrien *p = TOLOWER (*p); 42285815Sobrien p++; 42385815Sobrien } 42485815Sobrien 42585815Sobrien /* just after name is now '\0' */ 42638889Sjdp p = input_line_pointer; 42738889Sjdp *p = c; 42838889Sjdp SKIP_WHITESPACE (); 42985815Sobrien 43038889Sjdp if (*input_line_pointer != ',') 43138889Sjdp { 43285815Sobrien as_bad ("expected comma after operand name"); 43338889Sjdp ignore_rest_of_line (); 43485815Sobrien free (name); 43538889Sjdp return; 43638889Sjdp } 43785815Sobrien 43885815Sobrien input_line_pointer++; /* skip ',' */ 43985815Sobrien number = get_absolute_expression (); 44085815Sobrien 44185815Sobrien if (number < 0) 44238889Sjdp { 44385815Sobrien as_bad ("negative operand number %d", number); 44438889Sjdp ignore_rest_of_line (); 44585815Sobrien free (name); 44638889Sjdp return; 44738889Sjdp } 44885815Sobrien 44985815Sobrien if (opertype) 45038889Sjdp { 45185815Sobrien SKIP_WHITESPACE (); 45285815Sobrien 45385815Sobrien if (*input_line_pointer != ',') 45485815Sobrien { 45585815Sobrien as_bad ("expected comma after register-number"); 45685815Sobrien ignore_rest_of_line (); 45785815Sobrien free (name); 45885815Sobrien return; 45985815Sobrien } 46085815Sobrien 46185815Sobrien input_line_pointer++; /* skip ',' */ 46285815Sobrien mode = input_line_pointer; 46385815Sobrien 46485815Sobrien if (!strncmp (mode, "r|w", 3)) 46585815Sobrien { 46685815Sobrien imode = 0; 46785815Sobrien input_line_pointer += 3; 46885815Sobrien } 46985815Sobrien else 47085815Sobrien { 47185815Sobrien if (!strncmp (mode, "r", 1)) 47285815Sobrien { 47385815Sobrien imode = ARC_REGISTER_READONLY; 47485815Sobrien input_line_pointer += 1; 47585815Sobrien } 47685815Sobrien else 47785815Sobrien { 47885815Sobrien if (strncmp (mode, "w", 1)) 47985815Sobrien { 48085815Sobrien as_bad ("invalid mode"); 48185815Sobrien ignore_rest_of_line (); 48285815Sobrien free (name); 48385815Sobrien return; 48485815Sobrien } 48585815Sobrien else 48685815Sobrien { 48785815Sobrien imode = ARC_REGISTER_WRITEONLY; 48885815Sobrien input_line_pointer += 1; 48985815Sobrien } 49085815Sobrien } 49185815Sobrien } 49285815Sobrien SKIP_WHITESPACE (); 49385815Sobrien if (1 == opertype) 49485815Sobrien { 49585815Sobrien if (*input_line_pointer != ',') 49685815Sobrien { 49785815Sobrien as_bad ("expected comma after register-mode"); 49885815Sobrien ignore_rest_of_line (); 49985815Sobrien free (name); 50085815Sobrien return; 50185815Sobrien } 50285815Sobrien 50385815Sobrien input_line_pointer++; /* skip ',' */ 50485815Sobrien 50585815Sobrien if (!strncmp (input_line_pointer, "cannot_shortcut", 15)) 50685815Sobrien { 50785815Sobrien imode |= arc_get_noshortcut_flag (); 50885815Sobrien input_line_pointer += 15; 50985815Sobrien } 51085815Sobrien else 51185815Sobrien { 51285815Sobrien if (strncmp (input_line_pointer, "can_shortcut", 12)) 51385815Sobrien { 51485815Sobrien as_bad ("shortcut designator invalid"); 51585815Sobrien ignore_rest_of_line (); 51685815Sobrien free (name); 51785815Sobrien return; 51885815Sobrien } 51985815Sobrien else 52085815Sobrien { 52185815Sobrien input_line_pointer += 12; 52285815Sobrien } 52385815Sobrien } 52485815Sobrien } 52585815Sobrien } 52685815Sobrien 52785815Sobrien if ((opertype == 1) && number > 60) 52885815Sobrien { 52985815Sobrien as_bad ("core register value (%d) too large", number); 53038889Sjdp ignore_rest_of_line (); 53185815Sobrien free (name); 53238889Sjdp return; 53338889Sjdp } 53485815Sobrien 53585815Sobrien if ((opertype == 0) && number > 31) 53638889Sjdp { 53785815Sobrien as_bad ("condition code value (%d) too large", number); 53885815Sobrien ignore_rest_of_line (); 53985815Sobrien free (name); 54085815Sobrien return; 54185815Sobrien } 54285815Sobrien 543218822Sdim ext_oper = xmalloc (sizeof (struct arc_ext_operand_value)); 54485815Sobrien 54585815Sobrien if (opertype) 54685815Sobrien { 54785815Sobrien /* If the symbol already exists, point it at the new definition. */ 54885815Sobrien if ((symbolP = symbol_find (name))) 54938889Sjdp { 55085815Sobrien if (S_GET_SEGMENT (symbolP) == reg_section) 551218822Sdim S_SET_VALUE (symbolP, (valueT) &ext_oper->operand); 55285815Sobrien else 55385815Sobrien { 55485815Sobrien as_bad ("attempt to override symbol: %s", name); 55585815Sobrien ignore_rest_of_line (); 55685815Sobrien free (name); 55785815Sobrien free (ext_oper); 55885815Sobrien return; 55985815Sobrien } 56038889Sjdp } 56185815Sobrien else 56285815Sobrien { 56385815Sobrien /* If its not there, add it. */ 56485815Sobrien symbol_table_insert (symbol_create (name, reg_section, 565218822Sdim (valueT) &ext_oper->operand, 566218822Sdim &zero_address_frag)); 56785815Sobrien } 56838889Sjdp } 56985815Sobrien 57085815Sobrien ext_oper->operand.name = name; 57185815Sobrien ext_oper->operand.value = number; 57285815Sobrien ext_oper->operand.type = arc_operand_type (opertype); 57385815Sobrien ext_oper->operand.flags = imode; 57485815Sobrien 57585815Sobrien ext_oper->next = arc_ext_operands; 57685815Sobrien arc_ext_operands = ext_oper; 57785815Sobrien 57885815Sobrien /* OK, now that we know what this operand is, put a description in 57985815Sobrien the arc extension section of the output file. */ 58085815Sobrien 58185815Sobrien old_sec = now_seg; 58285815Sobrien old_subsec = now_subseg; 58385815Sobrien 58485815Sobrien arc_set_ext_seg (); 58585815Sobrien 58685815Sobrien switch (opertype) 58785815Sobrien { 58885815Sobrien case 0: 58985815Sobrien p = frag_more (1); 59085815Sobrien *p = 3 + strlen (name) + 1; 59185815Sobrien p = frag_more (1); 59285815Sobrien *p = EXT_COND_CODE; 59385815Sobrien p = frag_more (1); 59485815Sobrien *p = number; 59585815Sobrien p = frag_more (strlen (name) + 1); 59685815Sobrien strcpy (p, name); 59785815Sobrien break; 59885815Sobrien case 1: 59985815Sobrien p = frag_more (1); 60085815Sobrien *p = 3 + strlen (name) + 1; 60185815Sobrien p = frag_more (1); 60285815Sobrien *p = EXT_CORE_REGISTER; 60385815Sobrien p = frag_more (1); 60485815Sobrien *p = number; 60585815Sobrien p = frag_more (strlen (name) + 1); 60685815Sobrien strcpy (p, name); 60785815Sobrien break; 60885815Sobrien case 2: 60985815Sobrien p = frag_more (1); 61085815Sobrien *p = 6 + strlen (name) + 1; 61185815Sobrien p = frag_more (1); 61285815Sobrien *p = EXT_AUX_REGISTER; 61385815Sobrien p = frag_more (1); 61485815Sobrien *p = number >> 24 & 0xff; 61585815Sobrien p = frag_more (1); 61685815Sobrien *p = number >> 16 & 0xff; 61785815Sobrien p = frag_more (1); 61885815Sobrien *p = number >> 8 & 0xff; 61985815Sobrien p = frag_more (1); 62085815Sobrien *p = number & 0xff; 62185815Sobrien p = frag_more (strlen (name) + 1); 62285815Sobrien strcpy (p, name); 62385815Sobrien break; 62485815Sobrien default: 62585815Sobrien as_bad ("invalid opertype"); 62685815Sobrien ignore_rest_of_line (); 62785815Sobrien free (name); 62885815Sobrien return; 62985815Sobrien break; 63085815Sobrien } 63185815Sobrien 63285815Sobrien subseg_set (old_sec, old_subsec); 63385815Sobrien 63485815Sobrien /* Enter all registers into the symbol table. */ 63585815Sobrien 63685815Sobrien demand_empty_rest_of_line (); 63785815Sobrien} 63885815Sobrien 63985815Sobrienstatic void 640218822Sdimarc_extinst (int ignore ATTRIBUTE_UNUSED) 64185815Sobrien{ 642218822Sdim char syntax[129]; 64385815Sobrien char *name; 64485815Sobrien char *p; 64585815Sobrien char c; 64685815Sobrien int suffixcode = -1; 64785815Sobrien int opcode, subopcode; 64885815Sobrien int i; 64985815Sobrien int class = 0; 65085815Sobrien int name_len; 65185815Sobrien struct arc_opcode *ext_op; 65285815Sobrien 65385815Sobrien segT old_sec; 65485815Sobrien int old_subsec; 65585815Sobrien 65685815Sobrien name = input_line_pointer; 65785815Sobrien c = get_symbol_end (); 65885815Sobrien name = xstrdup (name); 65985815Sobrien strcpy (syntax, name); 66085815Sobrien name_len = strlen (name); 66185815Sobrien 66285815Sobrien /* just after name is now '\0' */ 66385815Sobrien p = input_line_pointer; 66485815Sobrien *p = c; 66585815Sobrien 66685815Sobrien SKIP_WHITESPACE (); 66785815Sobrien 66838889Sjdp if (*input_line_pointer != ',') 66938889Sjdp { 67085815Sobrien as_bad ("expected comma after operand name"); 67138889Sjdp ignore_rest_of_line (); 67238889Sjdp return; 67338889Sjdp } 67485815Sobrien 67585815Sobrien input_line_pointer++; /* skip ',' */ 67685815Sobrien opcode = get_absolute_expression (); 67785815Sobrien 67838889Sjdp SKIP_WHITESPACE (); 67985815Sobrien 68085815Sobrien if (*input_line_pointer != ',') 68138889Sjdp { 68285815Sobrien as_bad ("expected comma after opcode"); 68385815Sobrien ignore_rest_of_line (); 68485815Sobrien return; 68585815Sobrien } 68685815Sobrien 68785815Sobrien input_line_pointer++; /* skip ',' */ 68885815Sobrien subopcode = get_absolute_expression (); 68985815Sobrien 69085815Sobrien if (subopcode < 0) 69185815Sobrien { 69285815Sobrien as_bad ("negative subopcode %d", subopcode); 69385815Sobrien ignore_rest_of_line (); 69485815Sobrien return; 69585815Sobrien } 69685815Sobrien 69785815Sobrien if (subopcode) 69885815Sobrien { 69985815Sobrien if (3 != opcode) 70038889Sjdp { 70185815Sobrien as_bad ("subcode value found when opcode not equal 0x03"); 70285815Sobrien ignore_rest_of_line (); 70385815Sobrien return; 70438889Sjdp } 70585815Sobrien else 70638889Sjdp { 70785815Sobrien if (subopcode < 0x09 || subopcode == 0x3f) 70885815Sobrien { 70985815Sobrien as_bad ("invalid subopcode %d", subopcode); 71085815Sobrien ignore_rest_of_line (); 71185815Sobrien return; 71285815Sobrien } 71385815Sobrien } 71485815Sobrien } 71538889Sjdp 71685815Sobrien SKIP_WHITESPACE (); 71785815Sobrien 71885815Sobrien if (*input_line_pointer != ',') 71985815Sobrien { 72085815Sobrien as_bad ("expected comma after subopcode"); 72185815Sobrien ignore_rest_of_line (); 72285815Sobrien return; 72385815Sobrien } 72485815Sobrien 72585815Sobrien input_line_pointer++; /* skip ',' */ 72685815Sobrien 72785815Sobrien for (i = 0; i < (int) MAXSUFFIXCLASS; i++) 72885815Sobrien { 72985815Sobrien if (!strncmp (suffixclass[i].name,input_line_pointer, suffixclass[i].len)) 73038889Sjdp { 73185815Sobrien suffixcode = i; 73285815Sobrien input_line_pointer += suffixclass[i].len; 73385815Sobrien break; 73438889Sjdp } 73538889Sjdp } 73685815Sobrien 73785815Sobrien if (-1 == suffixcode) 73838889Sjdp { 73985815Sobrien as_bad ("invalid suffix class"); 74085815Sobrien ignore_rest_of_line (); 74185815Sobrien return; 74285815Sobrien } 74385815Sobrien 74485815Sobrien SKIP_WHITESPACE (); 74585815Sobrien 74685815Sobrien if (*input_line_pointer != ',') 74785815Sobrien { 74885815Sobrien as_bad ("expected comma after suffix class"); 74985815Sobrien ignore_rest_of_line (); 75085815Sobrien return; 75185815Sobrien } 75285815Sobrien 75385815Sobrien input_line_pointer++; /* skip ',' */ 75485815Sobrien 75585815Sobrien for (i = 0; i < (int) MAXSYNTAXCLASS; i++) 75685815Sobrien { 75785815Sobrien if (!strncmp (syntaxclass[i].name,input_line_pointer, syntaxclass[i].len)) 75838889Sjdp { 75985815Sobrien class = syntaxclass[i].class; 76085815Sobrien input_line_pointer += syntaxclass[i].len; 76185815Sobrien break; 76238889Sjdp } 76338889Sjdp } 76485815Sobrien 76585815Sobrien if (0 == (SYNTAX_VALID & class)) 76685815Sobrien { 76785815Sobrien as_bad ("invalid syntax class"); 76885815Sobrien ignore_rest_of_line (); 76985815Sobrien return; 77085815Sobrien } 77185815Sobrien 77285815Sobrien if ((0x3 == opcode) & (class & SYNTAX_3OP)) 77385815Sobrien { 77485815Sobrien as_bad ("opcode 0x3 and SYNTAX_3OP invalid"); 77585815Sobrien ignore_rest_of_line (); 77685815Sobrien return; 77785815Sobrien } 77885815Sobrien 77985815Sobrien switch (suffixcode) 78085815Sobrien { 78185815Sobrien case 0: 78285815Sobrien strcat (syntax, "%.q%.f "); 78385815Sobrien break; 78485815Sobrien case 1: 78585815Sobrien strcat (syntax, "%.f "); 78685815Sobrien break; 78785815Sobrien case 2: 78885815Sobrien strcat (syntax, "%.q "); 78985815Sobrien break; 79085815Sobrien case 3: 79185815Sobrien strcat (syntax, " "); 79285815Sobrien break; 79385815Sobrien default: 79485815Sobrien as_bad ("unknown suffix class"); 79585815Sobrien ignore_rest_of_line (); 79685815Sobrien return; 79785815Sobrien break; 79885815Sobrien }; 79985815Sobrien 80085815Sobrien strcat (syntax, ((opcode == 0x3) ? "%a,%b" : ((class & SYNTAX_3OP) ? "%a,%b,%c" : "%b,%c"))); 80185815Sobrien if (suffixcode < 2) 80285815Sobrien strcat (syntax, "%F"); 80385815Sobrien strcat (syntax, "%S%L"); 80485815Sobrien 805218822Sdim ext_op = xmalloc (sizeof (struct arc_opcode)); 80685815Sobrien ext_op->syntax = xstrdup (syntax); 80785815Sobrien 80885815Sobrien ext_op->mask = I (-1) | ((0x3 == opcode) ? C (-1) : 0); 80985815Sobrien ext_op->value = I (opcode) | ((0x3 == opcode) ? C (subopcode) : 0); 81085815Sobrien ext_op->flags = class; 81185815Sobrien ext_op->next_asm = arc_ext_opcodes; 81285815Sobrien ext_op->next_dis = arc_ext_opcodes; 81385815Sobrien arc_ext_opcodes = ext_op; 81485815Sobrien 81585815Sobrien /* OK, now that we know what this inst is, put a description in the 81685815Sobrien arc extension section of the output file. */ 81785815Sobrien 81885815Sobrien old_sec = now_seg; 81985815Sobrien old_subsec = now_subseg; 82085815Sobrien 82185815Sobrien arc_set_ext_seg (); 82285815Sobrien 82385815Sobrien p = frag_more (1); 82485815Sobrien *p = 5 + name_len + 1; 82585815Sobrien p = frag_more (1); 82685815Sobrien *p = EXT_INSTRUCTION; 82785815Sobrien p = frag_more (1); 82885815Sobrien *p = opcode; 82985815Sobrien p = frag_more (1); 83085815Sobrien *p = subopcode; 83185815Sobrien p = frag_more (1); 83285815Sobrien *p = (class & (OP1_MUST_BE_IMM | OP1_IMM_IMPLIED) ? IGNORE_FIRST_OPD : 0); 83385815Sobrien p = frag_more (name_len); 83485815Sobrien strncpy (p, syntax, name_len); 83585815Sobrien p = frag_more (1); 83685815Sobrien *p = '\0'; 83785815Sobrien 83885815Sobrien subseg_set (old_sec, old_subsec); 83985815Sobrien 84038889Sjdp demand_empty_rest_of_line (); 84185815Sobrien} 84238889Sjdp 84338889Sjdpstatic void 844218822Sdimarc_common (int localScope) 84538889Sjdp{ 84685815Sobrien char *name; 84738889Sjdp char c; 84885815Sobrien char *p; 84985815Sobrien int align, size; 85085815Sobrien symbolS *symbolP; 85138889Sjdp 85285815Sobrien name = input_line_pointer; 85385815Sobrien c = get_symbol_end (); 85485815Sobrien /* just after name is now '\0' */ 85585815Sobrien p = input_line_pointer; 85685815Sobrien *p = c; 85785815Sobrien SKIP_WHITESPACE (); 85885815Sobrien 85985815Sobrien if (*input_line_pointer != ',') 86038889Sjdp { 86185815Sobrien as_bad ("expected comma after symbol name"); 86238889Sjdp ignore_rest_of_line (); 86338889Sjdp return; 86438889Sjdp } 86538889Sjdp 86685815Sobrien input_line_pointer++; /* skip ',' */ 86785815Sobrien size = get_absolute_expression (); 86838889Sjdp 86985815Sobrien if (size < 0) 87085815Sobrien { 87185815Sobrien as_bad ("negative symbol length"); 87285815Sobrien ignore_rest_of_line (); 87385815Sobrien return; 87485815Sobrien } 87538889Sjdp 87685815Sobrien *p = 0; 87785815Sobrien symbolP = symbol_find_or_make (name); 87885815Sobrien *p = c; 87985815Sobrien 88085815Sobrien if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) 88185815Sobrien { 88285815Sobrien as_bad ("ignoring attempt to re-define symbol"); 88385815Sobrien ignore_rest_of_line (); 88485815Sobrien return; 88585815Sobrien } 88685815Sobrien if (((int) S_GET_VALUE (symbolP) != 0) \ 88785815Sobrien && ((int) S_GET_VALUE (symbolP) != size)) 88885815Sobrien { 88985815Sobrien as_warn ("length of symbol \"%s\" already %ld, ignoring %d", 89085815Sobrien S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), size); 89185815Sobrien } 89285815Sobrien assert (symbolP->sy_frag == &zero_address_frag); 89385815Sobrien 89485815Sobrien /* Now parse the alignment field. This field is optional for 89585815Sobrien local and global symbols. Default alignment is zero. */ 89685815Sobrien if (*input_line_pointer == ',') 89785815Sobrien { 89885815Sobrien input_line_pointer++; 89985815Sobrien align = get_absolute_expression (); 90085815Sobrien if (align < 0) 90185815Sobrien { 90285815Sobrien align = 0; 90385815Sobrien as_warn ("assuming symbol alignment of zero"); 90485815Sobrien } 90585815Sobrien } 90638889Sjdp else 90785815Sobrien align = 0; 90885815Sobrien 90985815Sobrien if (localScope != 0) 91038889Sjdp { 91185815Sobrien segT old_sec; 91285815Sobrien int old_subsec; 91385815Sobrien char *pfrag; 91485815Sobrien 91585815Sobrien old_sec = now_seg; 91685815Sobrien old_subsec = now_subseg; 91785815Sobrien record_alignment (bss_section, align); 91885815Sobrien subseg_set (bss_section, 0); /* ??? subseg_set (bss_section, 1); ??? */ 91985815Sobrien 92085815Sobrien if (align) 92185815Sobrien /* Do alignment. */ 92285815Sobrien frag_align (align, 0, 0); 92385815Sobrien 92485815Sobrien /* Detach from old frag. */ 92585815Sobrien if (S_GET_SEGMENT (symbolP) == bss_section) 92685815Sobrien symbolP->sy_frag->fr_symbol = NULL; 92785815Sobrien 92885815Sobrien symbolP->sy_frag = frag_now; 92985815Sobrien pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, 93085815Sobrien (offsetT) size, (char *) 0); 93185815Sobrien *pfrag = 0; 93285815Sobrien 93385815Sobrien S_SET_SIZE (symbolP, size); 93485815Sobrien S_SET_SEGMENT (symbolP, bss_section); 93585815Sobrien S_CLEAR_EXTERNAL (symbolP); 93685815Sobrien symbolP->local = 1; 93785815Sobrien subseg_set (old_sec, old_subsec); 93838889Sjdp } 93985815Sobrien else 94085815Sobrien { 94185815Sobrien S_SET_VALUE (symbolP, (valueT) size); 94285815Sobrien S_SET_ALIGN (symbolP, align); 94385815Sobrien S_SET_EXTERNAL (symbolP); 94485815Sobrien S_SET_SEGMENT (symbolP, bfd_com_section_ptr); 94585815Sobrien } 94685815Sobrien 94785815Sobrien symbolP->bsym->flags |= BSF_OBJECT; 94885815Sobrien 94985815Sobrien demand_empty_rest_of_line (); 95038889Sjdp} 95185815Sobrien 95285815Sobrien/* Select the cpu we're assembling for. */ 95338889Sjdp 95438889Sjdpstatic void 955218822Sdimarc_option (int ignore ATTRIBUTE_UNUSED) 95638889Sjdp{ 957218822Sdim extern int arc_get_mach (char *); 95885815Sobrien int mach; 95938889Sjdp char c; 96085815Sobrien char *cpu; 96138889Sjdp 96285815Sobrien cpu = input_line_pointer; 96338889Sjdp c = get_symbol_end (); 96485815Sobrien mach = arc_get_mach (cpu); 96538889Sjdp *input_line_pointer = c; 96638889Sjdp 96785815Sobrien /* If an instruction has already been seen, it's too late. */ 96885815Sobrien if (cpu_tables_init_p) 96938889Sjdp { 97085815Sobrien as_bad ("\".option\" directive must appear before any instructions"); 97138889Sjdp ignore_rest_of_line (); 97238889Sjdp return; 97338889Sjdp } 97438889Sjdp 97585815Sobrien if (mach == -1) 97685815Sobrien goto bad_cpu; 97785815Sobrien 97885815Sobrien if (mach_type_specified_p && mach != arc_mach_type) 97938889Sjdp { 98085815Sobrien as_bad ("\".option\" directive conflicts with initial definition"); 98138889Sjdp ignore_rest_of_line (); 98238889Sjdp return; 98338889Sjdp } 98485815Sobrien else 98585815Sobrien { 98685815Sobrien /* The cpu may have been selected on the command line. */ 98785815Sobrien if (mach != arc_mach_type) 98885815Sobrien as_warn ("\".option\" directive overrides command-line (default) value"); 98985815Sobrien arc_mach_type = mach; 99085815Sobrien if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, mach)) 99185815Sobrien as_fatal ("could not set architecture and machine"); 99285815Sobrien mach_type_specified_p = 1; 99385815Sobrien } 99485815Sobrien demand_empty_rest_of_line (); 99585815Sobrien return; 99638889Sjdp 99785815Sobrien bad_cpu: 99885815Sobrien as_bad ("invalid identifier for \".option\""); 99985815Sobrien ignore_rest_of_line (); 100038889Sjdp} 100138889Sjdp 100285815Sobrien/* Turn a string in input_line_pointer into a floating point constant 100385815Sobrien of type TYPE, and store the appropriate bytes in *LITP. The number 100485815Sobrien of LITTLENUMS emitted is stored in *SIZEP. An error message is 100585815Sobrien returned, or NULL on OK. */ 100638889Sjdp 100785815Sobrien/* Equal to MAX_PRECISION in atof-ieee.c */ 100838889Sjdp#define MAX_LITTLENUMS 6 100938889Sjdp 101038889Sjdpchar * 1011218822Sdimmd_atof (int type, char *litP, int *sizeP) 101238889Sjdp{ 101338889Sjdp int prec; 101438889Sjdp LITTLENUM_TYPE words[MAX_LITTLENUMS]; 101538889Sjdp LITTLENUM_TYPE *wordP; 101638889Sjdp char *t; 101738889Sjdp 101838889Sjdp switch (type) 101938889Sjdp { 102038889Sjdp case 'f': 102138889Sjdp case 'F': 102238889Sjdp prec = 2; 102338889Sjdp break; 102438889Sjdp 102538889Sjdp case 'd': 102638889Sjdp case 'D': 102738889Sjdp prec = 4; 102838889Sjdp break; 102938889Sjdp 103038889Sjdp default: 103138889Sjdp *sizeP = 0; 103285815Sobrien return "bad call to md_atof"; 103338889Sjdp } 103438889Sjdp 103538889Sjdp t = atof_ieee (input_line_pointer, type, words); 103638889Sjdp if (t) 103738889Sjdp input_line_pointer = t; 103838889Sjdp *sizeP = prec * sizeof (LITTLENUM_TYPE); 103938889Sjdp for (wordP = words; prec--;) 104038889Sjdp { 104138889Sjdp md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE)); 104238889Sjdp litP += sizeof (LITTLENUM_TYPE); 104338889Sjdp } 104438889Sjdp 104538889Sjdp return NULL; 104638889Sjdp} 104738889Sjdp 104838889Sjdp/* Write a value out to the object file, using the appropriate 104938889Sjdp endianness. */ 105038889Sjdp 105138889Sjdpvoid 1052218822Sdimmd_number_to_chars (char *buf, valueT val, int n) 105338889Sjdp{ 105438889Sjdp if (target_big_endian) 105538889Sjdp number_to_chars_bigendian (buf, val, n); 105638889Sjdp else 105738889Sjdp number_to_chars_littleendian (buf, val, n); 105838889Sjdp} 105938889Sjdp 106085815Sobrien/* Round up a section size to the appropriate boundary. */ 106138889Sjdp 106238889SjdpvalueT 1063218822Sdimmd_section_align (segT segment, valueT size) 106438889Sjdp{ 106538889Sjdp int align = bfd_get_section_alignment (stdoutput, segment); 106638889Sjdp 106738889Sjdp return ((size + (1 << align) - 1) & (-1 << align)); 106838889Sjdp} 106938889Sjdp 107038889Sjdp/* We don't have any form of relaxing. */ 107138889Sjdp 107238889Sjdpint 1073218822Sdimmd_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED, 1074218822Sdim asection *seg ATTRIBUTE_UNUSED) 107538889Sjdp{ 107685815Sobrien as_fatal (_("md_estimate_size_before_relax\n")); 107785815Sobrien return 1; 107838889Sjdp} 107938889Sjdp 108038889Sjdp/* Convert a machine dependent frag. We never generate these. */ 108138889Sjdp 108238889Sjdpvoid 1083218822Sdimmd_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, 1084218822Sdim asection *sec ATTRIBUTE_UNUSED, 1085218822Sdim fragS *fragp ATTRIBUTE_UNUSED) 108638889Sjdp{ 108785815Sobrien as_fatal (_("md_convert_frag\n")); 108838889Sjdp} 108938889Sjdp 1090218822Sdimstatic void 1091218822Sdimarc_code_symbol (expressionS *expressionP) 109285815Sobrien{ 109389857Sobrien if (expressionP->X_op == O_symbol && expressionP->X_add_number == 0) 109485815Sobrien { 109585815Sobrien expressionS two; 1096218822Sdim 109785815Sobrien expressionP->X_op = O_right_shift; 109885815Sobrien expressionP->X_add_symbol->sy_value.X_op = O_constant; 109985815Sobrien two.X_op = O_constant; 110085815Sobrien two.X_add_symbol = two.X_op_symbol = NULL; 110185815Sobrien two.X_add_number = 2; 110285815Sobrien expressionP->X_op_symbol = make_expr_symbol (&two); 110385815Sobrien } 110485815Sobrien /* Allow %st(sym1-sym2) */ 110585815Sobrien else if (expressionP->X_op == O_subtract 110685815Sobrien && expressionP->X_add_symbol != NULL 110785815Sobrien && expressionP->X_op_symbol != NULL 110885815Sobrien && expressionP->X_add_number == 0) 110985815Sobrien { 111085815Sobrien expressionS two; 1111218822Sdim 111285815Sobrien expressionP->X_add_symbol = make_expr_symbol (expressionP); 111385815Sobrien expressionP->X_op = O_right_shift; 111485815Sobrien two.X_op = O_constant; 111585815Sobrien two.X_add_symbol = two.X_op_symbol = NULL; 111685815Sobrien two.X_add_number = 2; 111785815Sobrien expressionP->X_op_symbol = make_expr_symbol (&two); 111885815Sobrien } 111985815Sobrien else 1120218822Sdim as_bad ("expression too complex code symbol"); 112185815Sobrien} 112285815Sobrien 112338889Sjdp/* Parse an operand that is machine-specific. 112438889Sjdp 112538889Sjdp The ARC has a special %-op to adjust addresses so they're usable in 112638889Sjdp branches. The "st" is short for the STatus register. 112738889Sjdp ??? Later expand this to take a flags value too. 112838889Sjdp 112938889Sjdp ??? We can't create new expression types so we map the %-op's onto the 113038889Sjdp existing syntax. This means that the user could use the chosen syntax 113185815Sobrien to achieve the same effect. */ 113238889Sjdp 113385815Sobrienvoid 1134218822Sdimmd_operand (expressionS *expressionP) 113538889Sjdp{ 113638889Sjdp char *p = input_line_pointer; 113738889Sjdp 1138218822Sdim if (*p != '%') 1139218822Sdim return; 114038889Sjdp 1141218822Sdim if (strncmp (p, "%st(", 4) == 0) 1142218822Sdim { 1143218822Sdim input_line_pointer += 4; 1144218822Sdim expression (expressionP); 1145218822Sdim if (*input_line_pointer != ')') 1146218822Sdim { 1147218822Sdim as_bad ("missing ')' in %%-op"); 1148218822Sdim return; 1149218822Sdim } 1150218822Sdim ++input_line_pointer; 1151218822Sdim arc_code_symbol (expressionP); 1152218822Sdim } 1153218822Sdim else 1154218822Sdim { 1155218822Sdim /* It could be a register. */ 1156218822Sdim int i, l; 1157218822Sdim struct arc_ext_operand_value *ext_oper = arc_ext_operands; 1158218822Sdim p++; 1159218822Sdim 1160218822Sdim while (ext_oper) 1161218822Sdim { 1162218822Sdim l = strlen (ext_oper->operand.name); 1163218822Sdim if (!strncmp (p, ext_oper->operand.name, l) && !ISALNUM (*(p + l))) 1164218822Sdim { 1165218822Sdim input_line_pointer += l + 1; 1166218822Sdim expressionP->X_op = O_register; 1167218822Sdim expressionP->X_add_number = (offsetT) &ext_oper->operand; 1168218822Sdim return; 1169218822Sdim } 1170218822Sdim ext_oper = ext_oper->next; 1171218822Sdim } 1172218822Sdim for (i = 0; i < arc_reg_names_count; i++) 1173218822Sdim { 1174218822Sdim l = strlen (arc_reg_names[i].name); 1175218822Sdim if (!strncmp (p, arc_reg_names[i].name, l) && !ISALNUM (*(p + l))) 1176218822Sdim { 1177218822Sdim input_line_pointer += l + 1; 1178218822Sdim expressionP->X_op = O_register; 1179218822Sdim expressionP->X_add_number = (offsetT) &arc_reg_names[i]; 1180218822Sdim break; 1181218822Sdim } 1182218822Sdim } 1183218822Sdim } 118438889Sjdp} 118538889Sjdp 118638889Sjdp/* We have no need to default values of symbols. 118738889Sjdp We could catch register names here, but that is handled by inserting 118838889Sjdp them all in the symbol table to begin with. */ 118938889Sjdp 119038889SjdpsymbolS * 1191218822Sdimmd_undefined_symbol (char *name ATTRIBUTE_UNUSED) 119238889Sjdp{ 119338889Sjdp return 0; 119438889Sjdp} 119538889Sjdp 119638889Sjdp/* Functions concerning expressions. */ 119738889Sjdp 119838889Sjdp/* Parse a .byte, .word, etc. expression. 119938889Sjdp 120038889Sjdp Values for the status register are specified with %st(label). 120138889Sjdp `label' will be right shifted by 2. */ 120238889Sjdp 120338889Sjdpvoid 1204218822Sdimarc_parse_cons_expression (expressionS *exp, 1205218822Sdim unsigned int nbytes ATTRIBUTE_UNUSED) 120638889Sjdp{ 120785815Sobrien char *p = input_line_pointer; 120885815Sobrien int code_symbol_fix = 0; 120985815Sobrien 121085815Sobrien for (; ! is_end_of_line[(unsigned char) *p]; p++) 121185815Sobrien if (*p == '@' && !strncmp (p, "@h30", 4)) 121285815Sobrien { 121385815Sobrien code_symbol_fix = 1; 121485815Sobrien strcpy (p, "; "); 121585815Sobrien } 1216218822Sdim expression_and_evaluate (exp); 121785815Sobrien if (code_symbol_fix) 121885815Sobrien { 121985815Sobrien arc_code_symbol (exp); 122085815Sobrien input_line_pointer = p; 122185815Sobrien } 122238889Sjdp} 122338889Sjdp 122438889Sjdp/* Record a fixup for a cons expression. */ 122538889Sjdp 122638889Sjdpvoid 1227218822Sdimarc_cons_fix_new (fragS *frag, 1228218822Sdim int where, 1229218822Sdim int nbytes, 1230218822Sdim expressionS *exp) 123138889Sjdp{ 123238889Sjdp if (nbytes == 4) 123338889Sjdp { 123438889Sjdp int reloc_type; 123538889Sjdp expressionS exptmp; 123638889Sjdp 123738889Sjdp /* This may be a special ARC reloc (eg: %st()). */ 123838889Sjdp reloc_type = get_arc_exp_reloc_type (1, BFD_RELOC_32, exp, &exptmp); 123938889Sjdp fix_new_exp (frag, where, nbytes, &exptmp, 0, reloc_type); 124038889Sjdp } 124138889Sjdp else 124238889Sjdp { 124338889Sjdp fix_new_exp (frag, where, nbytes, exp, 0, 124438889Sjdp nbytes == 2 ? BFD_RELOC_16 124538889Sjdp : nbytes == 8 ? BFD_RELOC_64 124638889Sjdp : BFD_RELOC_32); 124738889Sjdp } 124838889Sjdp} 124938889Sjdp 125038889Sjdp/* Functions concerning relocs. */ 125138889Sjdp 125238889Sjdp/* The location from which a PC relative jump should be calculated, 125338889Sjdp given a PC relative reloc. */ 125438889Sjdp 125585815Sobrienlong 1256218822Sdimmd_pcrel_from (fixS *fixP) 125738889Sjdp{ 125838889Sjdp /* Return the address of the delay slot. */ 125938889Sjdp return fixP->fx_frag->fr_address + fixP->fx_where + fixP->fx_size; 126038889Sjdp} 126138889Sjdp 126238889Sjdp/* Apply a fixup to the object code. This is called for all the 126338889Sjdp fixups we generated by the call to fix_new_exp, above. In the call 126438889Sjdp above we used a reloc code which was the largest legal reloc code 126538889Sjdp plus the operand index. Here we undo that to recover the operand 126638889Sjdp index. At this point all symbol values should be fully resolved, 126738889Sjdp and we attempt to completely resolve the reloc. If we can not do 126838889Sjdp that, we determine the correct reloc code and put it back in the fixup. */ 126938889Sjdp 127089857Sobrienvoid 1271218822Sdimmd_apply_fix (fixS *fixP, valueT * valP, segT seg) 127238889Sjdp{ 127389857Sobrien valueT value = * valP; 127438889Sjdp 127538889Sjdp if (fixP->fx_addsy == (symbolS *) NULL) 127689857Sobrien fixP->fx_done = 1; 127789857Sobrien 127838889Sjdp else if (fixP->fx_pcrel) 127938889Sjdp { 1280130561Sobrien /* Hack around bfd_install_relocation brain damage. */ 1281130561Sobrien if (S_GET_SEGMENT (fixP->fx_addsy) != seg) 128238889Sjdp value += md_pcrel_from (fixP); 128338889Sjdp } 128438889Sjdp 1285130561Sobrien /* We can't actually support subtracting a symbol. */ 1286130561Sobrien if (fixP->fx_subsy != NULL) 1287130561Sobrien as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex")); 1288130561Sobrien 128938889Sjdp if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED) 129038889Sjdp { 129138889Sjdp int opindex; 129238889Sjdp const struct arc_operand *operand; 129338889Sjdp char *where; 129438889Sjdp arc_insn insn; 129538889Sjdp 129638889Sjdp opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED; 129738889Sjdp 129838889Sjdp operand = &arc_operands[opindex]; 129938889Sjdp 130038889Sjdp /* Fetch the instruction, insert the fully resolved operand 130138889Sjdp value, and stuff the instruction back again. */ 130238889Sjdp where = fixP->fx_frag->fr_literal + fixP->fx_where; 130338889Sjdp if (target_big_endian) 130438889Sjdp insn = bfd_getb32 ((unsigned char *) where); 130538889Sjdp else 130638889Sjdp insn = bfd_getl32 ((unsigned char *) where); 130738889Sjdp insn = arc_insert_operand (insn, operand, -1, NULL, (offsetT) value, 130838889Sjdp fixP->fx_file, fixP->fx_line); 130938889Sjdp if (target_big_endian) 131038889Sjdp bfd_putb32 ((bfd_vma) insn, (unsigned char *) where); 131138889Sjdp else 131238889Sjdp bfd_putl32 ((bfd_vma) insn, (unsigned char *) where); 131338889Sjdp 131438889Sjdp if (fixP->fx_done) 1315218822Sdim /* Nothing else to do here. */ 1316218822Sdim return; 131738889Sjdp 131838889Sjdp /* Determine a BFD reloc value based on the operand information. 131938889Sjdp We are only prepared to turn a few of the operands into relocs. 132038889Sjdp !!! Note that we can't handle limm values here. Since we're using 132138889Sjdp implicit addends the addend must be inserted into the instruction, 132238889Sjdp however, the opcode insertion routines currently do nothing with 132338889Sjdp limm values. */ 132438889Sjdp if (operand->fmt == 'B') 132538889Sjdp { 132638889Sjdp assert ((operand->flags & ARC_OPERAND_RELATIVE_BRANCH) != 0 132738889Sjdp && operand->bits == 20 132838889Sjdp && operand->shift == 7); 132938889Sjdp fixP->fx_r_type = BFD_RELOC_ARC_B22_PCREL; 133038889Sjdp } 133185815Sobrien else if (operand->fmt == 'J') 133238889Sjdp { 133338889Sjdp assert ((operand->flags & ARC_OPERAND_ABSOLUTE_BRANCH) != 0 133438889Sjdp && operand->bits == 24 133538889Sjdp && operand->shift == 32); 133638889Sjdp fixP->fx_r_type = BFD_RELOC_ARC_B26; 133738889Sjdp } 133885815Sobrien else if (operand->fmt == 'L') 133938889Sjdp { 134038889Sjdp assert ((operand->flags & ARC_OPERAND_LIMM) != 0 134138889Sjdp && operand->bits == 32 134238889Sjdp && operand->shift == 32); 134338889Sjdp fixP->fx_r_type = BFD_RELOC_32; 134438889Sjdp } 134538889Sjdp else 134638889Sjdp { 134738889Sjdp as_bad_where (fixP->fx_file, fixP->fx_line, 134885815Sobrien "unresolved expression that must be resolved"); 134938889Sjdp fixP->fx_done = 1; 135089857Sobrien return; 135138889Sjdp } 135238889Sjdp } 135338889Sjdp else 135438889Sjdp { 135538889Sjdp switch (fixP->fx_r_type) 135638889Sjdp { 135738889Sjdp case BFD_RELOC_8: 135838889Sjdp md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 135938889Sjdp value, 1); 136038889Sjdp break; 136138889Sjdp case BFD_RELOC_16: 136238889Sjdp md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 136338889Sjdp value, 2); 136438889Sjdp break; 136538889Sjdp case BFD_RELOC_32: 136638889Sjdp md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 136738889Sjdp value, 4); 136838889Sjdp break; 136938889Sjdp case BFD_RELOC_ARC_B26: 137038889Sjdp /* If !fixP->fx_done then `value' is an implicit addend. 137138889Sjdp We must shift it right by 2 in this case as well because the 137238889Sjdp linker performs the relocation and then adds this in (as opposed 137338889Sjdp to adding this in and then shifting right by 2). */ 137438889Sjdp value >>= 2; 137538889Sjdp md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 137638889Sjdp value, 4); 137738889Sjdp break; 137838889Sjdp default: 137938889Sjdp abort (); 138038889Sjdp } 138138889Sjdp } 138238889Sjdp} 138338889Sjdp 138438889Sjdp/* Translate internal representation of relocation info to BFD target 138538889Sjdp format. */ 138638889Sjdp 138738889Sjdparelent * 1388218822Sdimtc_gen_reloc (asection *section ATTRIBUTE_UNUSED, 1389218822Sdim fixS *fixP) 139038889Sjdp{ 139138889Sjdp arelent *reloc; 139238889Sjdp 1393218822Sdim reloc = xmalloc (sizeof (arelent)); 1394218822Sdim reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); 139538889Sjdp 1396218822Sdim *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy); 139738889Sjdp reloc->address = fixP->fx_frag->fr_address + fixP->fx_where; 139838889Sjdp reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type); 139938889Sjdp if (reloc->howto == (reloc_howto_type *) NULL) 140038889Sjdp { 140138889Sjdp as_bad_where (fixP->fx_file, fixP->fx_line, 140285815Sobrien "internal error: can't export reloc type %d (`%s')", 140385815Sobrien fixP->fx_r_type, 140485815Sobrien bfd_get_reloc_code_name (fixP->fx_r_type)); 140538889Sjdp return NULL; 140638889Sjdp } 140738889Sjdp 140838889Sjdp assert (!fixP->fx_pcrel == !reloc->howto->pc_relative); 140938889Sjdp 141085815Sobrien /* Set addend to account for PC being advanced one insn before the 1411130561Sobrien target address is computed. */ 141238889Sjdp 141385815Sobrien reloc->addend = (fixP->fx_pcrel ? -4 : 0); 141485815Sobrien 141538889Sjdp return reloc; 141638889Sjdp} 1417218822Sdim 1418218822Sdimconst pseudo_typeS md_pseudo_table[] = 1419218822Sdim{ 1420218822Sdim { "align", s_align_bytes, 0 }, /* Defaulting is invalid (0). */ 1421218822Sdim { "comm", arc_common, 0 }, 1422218822Sdim { "common", arc_common, 0 }, 1423218822Sdim { "lcomm", arc_common, 1 }, 1424218822Sdim { "lcommon", arc_common, 1 }, 1425218822Sdim { "2byte", cons, 2 }, 1426218822Sdim { "half", cons, 2 }, 1427218822Sdim { "short", cons, 2 }, 1428218822Sdim { "3byte", cons, 3 }, 1429218822Sdim { "4byte", cons, 4 }, 1430218822Sdim { "word", cons, 4 }, 1431218822Sdim { "option", arc_option, 0 }, 1432218822Sdim { "cpu", arc_option, 0 }, 1433218822Sdim { "block", s_space, 0 }, 1434218822Sdim { "extcondcode", arc_extoper, 0 }, 1435218822Sdim { "extcoreregister", arc_extoper, 1 }, 1436218822Sdim { "extauxregister", arc_extoper, 2 }, 1437218822Sdim { "extinstruction", arc_extinst, 0 }, 1438218822Sdim { NULL, 0, 0 }, 1439218822Sdim}; 1440218822Sdim 1441218822Sdim/* This routine is called for each instruction to be assembled. */ 1442218822Sdim 1443218822Sdimvoid 1444218822Sdimmd_assemble (char *str) 1445218822Sdim{ 1446218822Sdim const struct arc_opcode *opcode; 1447218822Sdim const struct arc_opcode *std_opcode; 1448218822Sdim struct arc_opcode *ext_opcode; 1449218822Sdim char *start; 1450218822Sdim const char *last_errmsg = 0; 1451218822Sdim arc_insn insn; 1452218822Sdim static int init_tables_p = 0; 1453218822Sdim 1454218822Sdim /* Opcode table initialization is deferred until here because we have to 1455218822Sdim wait for a possible .option command. */ 1456218822Sdim if (!init_tables_p) 1457218822Sdim { 1458218822Sdim init_opcode_tables (arc_mach_type); 1459218822Sdim init_tables_p = 1; 1460218822Sdim } 1461218822Sdim 1462218822Sdim /* Skip leading white space. */ 1463218822Sdim while (ISSPACE (*str)) 1464218822Sdim str++; 1465218822Sdim 1466218822Sdim /* The instructions are stored in lists hashed by the first letter (though 1467218822Sdim we needn't care how they're hashed). Get the first in the list. */ 1468218822Sdim 1469218822Sdim ext_opcode = arc_ext_opcodes; 1470218822Sdim std_opcode = arc_opcode_lookup_asm (str); 1471218822Sdim 1472218822Sdim /* Keep looking until we find a match. */ 1473218822Sdim start = str; 1474218822Sdim for (opcode = (ext_opcode ? ext_opcode : std_opcode); 1475218822Sdim opcode != NULL; 1476218822Sdim opcode = (ARC_OPCODE_NEXT_ASM (opcode) 1477218822Sdim ? ARC_OPCODE_NEXT_ASM (opcode) 1478218822Sdim : (ext_opcode ? ext_opcode = NULL, std_opcode : NULL))) 1479218822Sdim { 1480218822Sdim int past_opcode_p, fc, num_suffixes; 1481218822Sdim int fix_up_at = 0; 1482218822Sdim char *syn; 1483218822Sdim struct arc_fixup fixups[MAX_FIXUPS]; 1484218822Sdim /* Used as a sanity check. If we need a limm reloc, make sure we ask 1485218822Sdim for an extra 4 bytes from frag_more. */ 1486218822Sdim int limm_reloc_p; 1487218822Sdim int ext_suffix_p; 1488218822Sdim const struct arc_operand_value *insn_suffixes[MAX_SUFFIXES]; 1489218822Sdim 1490218822Sdim /* Is this opcode supported by the selected cpu? */ 1491218822Sdim if (! arc_opcode_supported (opcode)) 1492218822Sdim continue; 1493218822Sdim 1494218822Sdim /* Scan the syntax string. If it doesn't match, try the next one. */ 1495218822Sdim arc_opcode_init_insert (); 1496218822Sdim insn = opcode->value; 1497218822Sdim fc = 0; 1498218822Sdim past_opcode_p = 0; 1499218822Sdim num_suffixes = 0; 1500218822Sdim limm_reloc_p = 0; 1501218822Sdim ext_suffix_p = 0; 1502218822Sdim 1503218822Sdim /* We don't check for (*str != '\0') here because we want to parse 1504218822Sdim any trailing fake arguments in the syntax string. */ 1505218822Sdim for (str = start, syn = opcode->syntax; *syn != '\0';) 1506218822Sdim { 1507218822Sdim int mods; 1508218822Sdim const struct arc_operand *operand; 1509218822Sdim 1510218822Sdim /* Non operand chars must match exactly. */ 1511218822Sdim if (*syn != '%' || *++syn == '%') 1512218822Sdim { 1513218822Sdim if (*str == *syn) 1514218822Sdim { 1515218822Sdim if (*syn == ' ') 1516218822Sdim past_opcode_p = 1; 1517218822Sdim ++syn; 1518218822Sdim ++str; 1519218822Sdim } 1520218822Sdim else 1521218822Sdim break; 1522218822Sdim continue; 1523218822Sdim } 1524218822Sdim 1525218822Sdim /* We have an operand. Pick out any modifiers. */ 1526218822Sdim mods = 0; 1527218822Sdim while (ARC_MOD_P (arc_operands[arc_operand_map[(int) *syn]].flags)) 1528218822Sdim { 1529218822Sdim mods |= arc_operands[arc_operand_map[(int) *syn]].flags & ARC_MOD_BITS; 1530218822Sdim ++syn; 1531218822Sdim } 1532218822Sdim operand = arc_operands + arc_operand_map[(int) *syn]; 1533218822Sdim if (operand->fmt == 0) 1534218822Sdim as_fatal ("unknown syntax format character `%c'", *syn); 1535218822Sdim 1536218822Sdim if (operand->flags & ARC_OPERAND_FAKE) 1537218822Sdim { 1538218822Sdim const char *errmsg = NULL; 1539218822Sdim if (operand->insert) 1540218822Sdim { 1541218822Sdim insn = (*operand->insert) (insn, operand, mods, NULL, 0, &errmsg); 1542218822Sdim if (errmsg != (const char *) NULL) 1543218822Sdim { 1544218822Sdim last_errmsg = errmsg; 1545218822Sdim if (operand->flags & ARC_OPERAND_ERROR) 1546218822Sdim { 1547218822Sdim as_bad (errmsg); 1548218822Sdim return; 1549218822Sdim } 1550218822Sdim else if (operand->flags & ARC_OPERAND_WARN) 1551218822Sdim as_warn (errmsg); 1552218822Sdim break; 1553218822Sdim } 1554218822Sdim if (limm_reloc_p 1555218822Sdim && (operand->flags && operand->flags & ARC_OPERAND_LIMM) 1556218822Sdim && (operand->flags & 1557218822Sdim (ARC_OPERAND_ABSOLUTE_BRANCH | ARC_OPERAND_ADDRESS))) 1558218822Sdim { 1559218822Sdim fixups[fix_up_at].opindex = arc_operand_map[operand->fmt]; 1560218822Sdim } 1561218822Sdim } 1562218822Sdim ++syn; 1563218822Sdim } 1564218822Sdim /* Are we finished with suffixes? */ 1565218822Sdim else if (!past_opcode_p) 1566218822Sdim { 1567218822Sdim int found; 1568218822Sdim char c; 1569218822Sdim char *s, *t; 1570218822Sdim const struct arc_operand_value *suf, *suffix_end; 1571218822Sdim const struct arc_operand_value *suffix = NULL; 1572218822Sdim 1573218822Sdim if (!(operand->flags & ARC_OPERAND_SUFFIX)) 1574218822Sdim abort (); 1575218822Sdim 1576218822Sdim /* If we're at a space in the input string, we want to skip the 1577218822Sdim remaining suffixes. There may be some fake ones though, so 1578218822Sdim just go on to try the next one. */ 1579218822Sdim if (*str == ' ') 1580218822Sdim { 1581218822Sdim ++syn; 1582218822Sdim continue; 1583218822Sdim } 1584218822Sdim 1585218822Sdim s = str; 1586218822Sdim if (mods & ARC_MOD_DOT) 1587218822Sdim { 1588218822Sdim if (*s != '.') 1589218822Sdim break; 1590218822Sdim ++s; 1591218822Sdim } 1592218822Sdim else 1593218822Sdim { 1594218822Sdim /* This can happen in "b.nd foo" and we're currently looking 1595218822Sdim for "%q" (ie: a condition code suffix). */ 1596218822Sdim if (*s == '.') 1597218822Sdim { 1598218822Sdim ++syn; 1599218822Sdim continue; 1600218822Sdim } 1601218822Sdim } 1602218822Sdim 1603218822Sdim /* Pick the suffix out and look it up via the hash table. */ 1604218822Sdim for (t = s; *t && ISALNUM (*t); ++t) 1605218822Sdim continue; 1606218822Sdim c = *t; 1607218822Sdim *t = '\0'; 1608218822Sdim if ((suf = get_ext_suffix (s))) 1609218822Sdim ext_suffix_p = 1; 1610218822Sdim else 1611218822Sdim suf = hash_find (arc_suffix_hash, s); 1612218822Sdim if (!suf) 1613218822Sdim { 1614218822Sdim /* This can happen in "blle foo" and we're currently using 1615218822Sdim the template "b%q%.n %j". The "bl" insn occurs later in 1616218822Sdim the table so "lle" isn't an illegal suffix. */ 1617218822Sdim *t = c; 1618218822Sdim break; 1619218822Sdim } 1620218822Sdim 1621218822Sdim /* Is it the right type? Note that the same character is used 1622218822Sdim several times, so we have to examine all of them. This is 1623218822Sdim relatively efficient as equivalent entries are kept 1624218822Sdim together. If it's not the right type, don't increment `str' 1625218822Sdim so we try the next one in the series. */ 1626218822Sdim found = 0; 1627218822Sdim if (ext_suffix_p && arc_operands[suf->type].fmt == *syn) 1628218822Sdim { 1629218822Sdim /* Insert the suffix's value into the insn. */ 1630218822Sdim *t = c; 1631218822Sdim if (operand->insert) 1632218822Sdim insn = (*operand->insert) (insn, operand, 1633218822Sdim mods, NULL, suf->value, 1634218822Sdim NULL); 1635218822Sdim else 1636218822Sdim insn |= suf->value << operand->shift; 1637218822Sdim suffix = suf; 1638218822Sdim str = t; 1639218822Sdim found = 1; 1640218822Sdim } 1641218822Sdim else 1642218822Sdim { 1643218822Sdim *t = c; 1644218822Sdim suffix_end = arc_suffixes + arc_suffixes_count; 1645218822Sdim for (suffix = suf; 1646218822Sdim suffix < suffix_end && strcmp (suffix->name, suf->name) == 0; 1647218822Sdim ++suffix) 1648218822Sdim { 1649218822Sdim if (arc_operands[suffix->type].fmt == *syn) 1650218822Sdim { 1651218822Sdim /* Insert the suffix's value into the insn. */ 1652218822Sdim if (operand->insert) 1653218822Sdim insn = (*operand->insert) (insn, operand, 1654218822Sdim mods, NULL, suffix->value, 1655218822Sdim NULL); 1656218822Sdim else 1657218822Sdim insn |= suffix->value << operand->shift; 1658218822Sdim 1659218822Sdim str = t; 1660218822Sdim found = 1; 1661218822Sdim break; 1662218822Sdim } 1663218822Sdim } 1664218822Sdim } 1665218822Sdim ++syn; 1666218822Sdim if (!found) 1667218822Sdim /* Wrong type. Just go on to try next insn entry. */ 1668218822Sdim ; 1669218822Sdim else 1670218822Sdim { 1671218822Sdim if (num_suffixes == MAX_SUFFIXES) 1672218822Sdim as_bad ("too many suffixes"); 1673218822Sdim else 1674218822Sdim insn_suffixes[num_suffixes++] = suffix; 1675218822Sdim } 1676218822Sdim } 1677218822Sdim else 1678218822Sdim /* This is either a register or an expression of some kind. */ 1679218822Sdim { 1680218822Sdim char *hold; 1681218822Sdim const struct arc_operand_value *reg = NULL; 1682218822Sdim long value = 0; 1683218822Sdim expressionS exp; 1684218822Sdim 1685218822Sdim if (operand->flags & ARC_OPERAND_SUFFIX) 1686218822Sdim abort (); 1687218822Sdim 1688218822Sdim /* Is there anything left to parse? 1689218822Sdim We don't check for this at the top because we want to parse 1690218822Sdim any trailing fake arguments in the syntax string. */ 1691218822Sdim if (is_end_of_line[(unsigned char) *str]) 1692218822Sdim break; 1693218822Sdim 1694218822Sdim /* Parse the operand. */ 1695218822Sdim hold = input_line_pointer; 1696218822Sdim input_line_pointer = str; 1697218822Sdim expression (&exp); 1698218822Sdim str = input_line_pointer; 1699218822Sdim input_line_pointer = hold; 1700218822Sdim 1701218822Sdim if (exp.X_op == O_illegal) 1702218822Sdim as_bad ("illegal operand"); 1703218822Sdim else if (exp.X_op == O_absent) 1704218822Sdim as_bad ("missing operand"); 1705218822Sdim else if (exp.X_op == O_constant) 1706218822Sdim value = exp.X_add_number; 1707218822Sdim else if (exp.X_op == O_register) 1708218822Sdim reg = (struct arc_operand_value *) exp.X_add_number; 1709218822Sdim#define IS_REG_DEST_OPERAND(o) ((o) == 'a') 1710218822Sdim else if (IS_REG_DEST_OPERAND (*syn)) 1711218822Sdim as_bad ("symbol as destination register"); 1712218822Sdim else 1713218822Sdim { 1714218822Sdim if (!strncmp (str, "@h30", 4)) 1715218822Sdim { 1716218822Sdim arc_code_symbol (&exp); 1717218822Sdim str += 4; 1718218822Sdim } 1719218822Sdim /* We need to generate a fixup for this expression. */ 1720218822Sdim if (fc >= MAX_FIXUPS) 1721218822Sdim as_fatal ("too many fixups"); 1722218822Sdim fixups[fc].exp = exp; 1723218822Sdim /* We don't support shimm relocs. break here to force 1724218822Sdim the assembler to output a limm. */ 1725218822Sdim#define IS_REG_SHIMM_OFFSET(o) ((o) == 'd') 1726218822Sdim if (IS_REG_SHIMM_OFFSET (*syn)) 1727218822Sdim break; 1728218822Sdim /* If this is a register constant (IE: one whose 1729218822Sdim register value gets stored as 61-63) then this 1730218822Sdim must be a limm. */ 1731218822Sdim /* ??? This bit could use some cleaning up. 1732218822Sdim Referencing the format chars like this goes 1733218822Sdim against style. */ 1734218822Sdim if (IS_SYMBOL_OPERAND (*syn)) 1735218822Sdim { 1736218822Sdim const char *junk; 1737218822Sdim limm_reloc_p = 1; 1738218822Sdim /* Save this, we don't yet know what reloc to use. */ 1739218822Sdim fix_up_at = fc; 1740218822Sdim /* Tell insert_reg we need a limm. This is 1741218822Sdim needed because the value at this point is 1742218822Sdim zero, a shimm. */ 1743218822Sdim /* ??? We need a cleaner interface than this. */ 1744218822Sdim (*arc_operands[arc_operand_map['Q']].insert) 1745218822Sdim (insn, operand, mods, reg, 0L, &junk); 1746218822Sdim } 1747218822Sdim else 1748218822Sdim fixups[fc].opindex = arc_operand_map[(int) *syn]; 1749218822Sdim ++fc; 1750218822Sdim value = 0; 1751218822Sdim } 1752218822Sdim 1753218822Sdim /* Insert the register or expression into the instruction. */ 1754218822Sdim if (operand->insert) 1755218822Sdim { 1756218822Sdim const char *errmsg = NULL; 1757218822Sdim insn = (*operand->insert) (insn, operand, mods, 1758218822Sdim reg, (long) value, &errmsg); 1759218822Sdim if (errmsg != (const char *) NULL) 1760218822Sdim { 1761218822Sdim last_errmsg = errmsg; 1762218822Sdim if (operand->flags & ARC_OPERAND_ERROR) 1763218822Sdim { 1764218822Sdim as_bad (errmsg); 1765218822Sdim return; 1766218822Sdim } 1767218822Sdim else if (operand->flags & ARC_OPERAND_WARN) 1768218822Sdim as_warn (errmsg); 1769218822Sdim break; 1770218822Sdim } 1771218822Sdim } 1772218822Sdim else 1773218822Sdim insn |= (value & ((1 << operand->bits) - 1)) << operand->shift; 1774218822Sdim 1775218822Sdim ++syn; 1776218822Sdim } 1777218822Sdim } 1778218822Sdim 1779218822Sdim /* If we're at the end of the syntax string, we're done. */ 1780218822Sdim /* FIXME: try to move this to a separate function. */ 1781218822Sdim if (*syn == '\0') 1782218822Sdim { 1783218822Sdim int i; 1784218822Sdim char *f; 1785218822Sdim long limm, limm_p; 1786218822Sdim 1787218822Sdim /* For the moment we assume a valid `str' can only contain blanks 1788218822Sdim now. IE: We needn't try again with a longer version of the 1789218822Sdim insn and it is assumed that longer versions of insns appear 1790218822Sdim before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3). */ 1791218822Sdim 1792218822Sdim while (ISSPACE (*str)) 1793218822Sdim ++str; 1794218822Sdim 1795218822Sdim if (!is_end_of_line[(unsigned char) *str]) 1796218822Sdim as_bad ("junk at end of line: `%s'", str); 1797218822Sdim 1798218822Sdim /* Is there a limm value? */ 1799218822Sdim limm_p = arc_opcode_limm_p (&limm); 1800218822Sdim 1801218822Sdim /* Perform various error and warning tests. */ 1802218822Sdim 1803218822Sdim { 1804218822Sdim static int in_delay_slot_p = 0; 1805218822Sdim static int prev_insn_needs_cc_nop_p = 0; 1806218822Sdim /* delay slot type seen */ 1807218822Sdim int delay_slot_type = ARC_DELAY_NONE; 1808218822Sdim /* conditional execution flag seen */ 1809218822Sdim int conditional = 0; 1810218822Sdim /* 1 if condition codes are being set */ 1811218822Sdim int cc_set_p = 0; 1812218822Sdim /* 1 if conditional branch, including `b' "branch always" */ 1813218822Sdim int cond_branch_p = opcode->flags & ARC_OPCODE_COND_BRANCH; 1814218822Sdim 1815218822Sdim for (i = 0; i < num_suffixes; ++i) 1816218822Sdim { 1817218822Sdim switch (arc_operands[insn_suffixes[i]->type].fmt) 1818218822Sdim { 1819218822Sdim case 'n': 1820218822Sdim delay_slot_type = insn_suffixes[i]->value; 1821218822Sdim break; 1822218822Sdim case 'q': 1823218822Sdim conditional = insn_suffixes[i]->value; 1824218822Sdim break; 1825218822Sdim case 'f': 1826218822Sdim cc_set_p = 1; 1827218822Sdim break; 1828218822Sdim } 1829218822Sdim } 1830218822Sdim 1831218822Sdim /* Putting an insn with a limm value in a delay slot is supposed to 1832218822Sdim be legal, but let's warn the user anyway. Ditto for 8 byte 1833218822Sdim jumps with delay slots. */ 1834218822Sdim if (in_delay_slot_p && limm_p) 1835218822Sdim as_warn ("8 byte instruction in delay slot"); 1836218822Sdim if (delay_slot_type != ARC_DELAY_NONE 1837218822Sdim && limm_p && arc_insn_not_jl (insn)) /* except for jl addr */ 1838218822Sdim as_warn ("8 byte jump instruction with delay slot"); 1839218822Sdim in_delay_slot_p = (delay_slot_type != ARC_DELAY_NONE) && !limm_p; 1840218822Sdim 1841218822Sdim /* Warn when a conditional branch immediately follows a set of 1842218822Sdim the condition codes. Note that this needn't be done if the 1843218822Sdim insn that sets the condition codes uses a limm. */ 1844218822Sdim if (cond_branch_p && conditional != 0 /* 0 = "always" */ 1845218822Sdim && prev_insn_needs_cc_nop_p && arc_mach_type == bfd_mach_arc_5) 1846218822Sdim as_warn ("conditional branch follows set of flags"); 1847218822Sdim prev_insn_needs_cc_nop_p = 1848218822Sdim /* FIXME: ??? not required: 1849218822Sdim (delay_slot_type != ARC_DELAY_NONE) && */ 1850218822Sdim cc_set_p && !limm_p; 1851218822Sdim } 1852218822Sdim 1853218822Sdim /* Write out the instruction. 1854218822Sdim It is important to fetch enough space in one call to `frag_more'. 1855218822Sdim We use (f - frag_now->fr_literal) to compute where we are and we 1856218822Sdim don't want frag_now to change between calls. */ 1857218822Sdim if (limm_p) 1858218822Sdim { 1859218822Sdim f = frag_more (8); 1860218822Sdim md_number_to_chars (f, insn, 4); 1861218822Sdim md_number_to_chars (f + 4, limm, 4); 1862218822Sdim dwarf2_emit_insn (8); 1863218822Sdim } 1864218822Sdim else if (limm_reloc_p) 1865218822Sdim /* We need a limm reloc, but the tables think we don't. */ 1866218822Sdim abort (); 1867218822Sdim else 1868218822Sdim { 1869218822Sdim f = frag_more (4); 1870218822Sdim md_number_to_chars (f, insn, 4); 1871218822Sdim dwarf2_emit_insn (4); 1872218822Sdim } 1873218822Sdim 1874218822Sdim /* Create any fixups. */ 1875218822Sdim for (i = 0; i < fc; ++i) 1876218822Sdim { 1877218822Sdim int op_type, reloc_type; 1878218822Sdim expressionS exptmp; 1879218822Sdim const struct arc_operand *operand; 1880218822Sdim 1881218822Sdim /* Create a fixup for this operand. 1882218822Sdim At this point we do not use a bfd_reloc_code_real_type for 1883218822Sdim operands residing in the insn, but instead just use the 1884218822Sdim operand index. This lets us easily handle fixups for any 1885218822Sdim operand type, although that is admittedly not a very exciting 1886218822Sdim feature. We pick a BFD reloc type in md_apply_fix. 1887218822Sdim 1888218822Sdim Limm values (4 byte immediate "constants") must be treated 1889218822Sdim normally because they're not part of the actual insn word 1890218822Sdim and thus the insertion routines don't handle them. */ 1891218822Sdim 1892218822Sdim if (arc_operands[fixups[i].opindex].flags & ARC_OPERAND_LIMM) 1893218822Sdim { 1894218822Sdim /* Modify the fixup addend as required by the cpu. */ 1895218822Sdim fixups[i].exp.X_add_number += arc_limm_fixup_adjust (insn); 1896218822Sdim op_type = fixups[i].opindex; 1897218822Sdim /* FIXME: can we add this data to the operand table? */ 1898218822Sdim if (op_type == arc_operand_map['L'] 1899218822Sdim || op_type == arc_operand_map['s'] 1900218822Sdim || op_type == arc_operand_map['o'] 1901218822Sdim || op_type == arc_operand_map['O']) 1902218822Sdim reloc_type = BFD_RELOC_32; 1903218822Sdim else if (op_type == arc_operand_map['J']) 1904218822Sdim reloc_type = BFD_RELOC_ARC_B26; 1905218822Sdim else 1906218822Sdim abort (); 1907218822Sdim reloc_type = get_arc_exp_reloc_type (1, reloc_type, 1908218822Sdim &fixups[i].exp, 1909218822Sdim &exptmp); 1910218822Sdim } 1911218822Sdim else 1912218822Sdim { 1913218822Sdim op_type = get_arc_exp_reloc_type (0, fixups[i].opindex, 1914218822Sdim &fixups[i].exp, &exptmp); 1915218822Sdim reloc_type = op_type + (int) BFD_RELOC_UNUSED; 1916218822Sdim } 1917218822Sdim operand = &arc_operands[op_type]; 1918218822Sdim fix_new_exp (frag_now, 1919218822Sdim ((f - frag_now->fr_literal) 1920218822Sdim + (operand->flags & ARC_OPERAND_LIMM ? 4 : 0)), 4, 1921218822Sdim &exptmp, 1922218822Sdim (operand->flags & ARC_OPERAND_RELATIVE_BRANCH) != 0, 1923218822Sdim (bfd_reloc_code_real_type) reloc_type); 1924218822Sdim } 1925218822Sdim return; 1926218822Sdim } 1927218822Sdim } 1928218822Sdim 1929218822Sdim if (NULL == last_errmsg) 1930218822Sdim as_bad ("bad instruction `%s'", start); 1931218822Sdim else 1932218822Sdim as_bad (last_errmsg); 1933218822Sdim} 1934